Merge "MPEG4Writer:Avoid deadlock when reset internally"
diff --git a/camera/CaptureResult.cpp b/camera/CaptureResult.cpp
index 9cbfdb0..755051c 100644
--- a/camera/CaptureResult.cpp
+++ b/camera/CaptureResult.cpp
@@ -49,6 +49,9 @@
}
errorPhysicalCameraId = cameraId;
}
+ parcel->readInt64(&lastCompletedRegularFrameNumber);
+ parcel->readInt64(&lastCompletedReprocessFrameNumber);
+ parcel->readInt64(&lastCompletedZslFrameNumber);
return OK;
}
@@ -76,6 +79,9 @@
} else {
parcel->writeBool(false);
}
+ parcel->writeInt64(lastCompletedRegularFrameNumber);
+ parcel->writeInt64(lastCompletedReprocessFrameNumber);
+ parcel->writeInt64(lastCompletedZslFrameNumber);
return OK;
}
diff --git a/camera/include/camera/CaptureResult.h b/camera/include/camera/CaptureResult.h
index dc3d282..f163c1e 100644
--- a/camera/include/camera/CaptureResult.h
+++ b/camera/include/camera/CaptureResult.h
@@ -76,6 +76,34 @@
*/
String16 errorPhysicalCameraId;
+ // The last completed frame numbers shouldn't be checked in onResultReceived() and notifyError()
+ // because the output buffers could be arriving after onResultReceived() and
+ // notifyError(). Given this constraint, we check it for each
+ // onCaptureStarted, and if there is no further onCaptureStarted(),
+ // check for onDeviceIdle() to clear out all pending frame numbers.
+
+ /**
+ * The latest regular request frameNumber for which all buffers and capture result have been
+ * returned or notified as an BUFFER_ERROR/RESULT_ERROR/REQUEST_ERROR. -1 if
+ * none has completed.
+ */
+ int64_t lastCompletedRegularFrameNumber;
+
+ /**
+ * The latest reprocess request frameNumber for which all buffers and capture result have been
+ * returned or notified as an BUFFER_ERROR/RESULT_ERROR/REQUEST_ERROR. -1 if
+ * none has completed.
+ */
+ int64_t lastCompletedReprocessFrameNumber;
+
+ /**
+ * The latest Zsl request frameNumber for which all buffers and capture result have been
+ * returned or notified as an BUFFER_ERROR/RESULT_ERROR/REQUEST_ERROR. -1 if
+ * none has completed.
+ */
+ int64_t lastCompletedZslFrameNumber;
+
+
/**
* Constructor initializes object as invalid by setting requestId to be -1.
*/
@@ -87,7 +115,10 @@
frameNumber(0),
partialResultCount(0),
errorStreamId(-1),
- errorPhysicalCameraId() {
+ errorPhysicalCameraId(),
+ lastCompletedRegularFrameNumber(-1),
+ lastCompletedReprocessFrameNumber(-1),
+ lastCompletedZslFrameNumber(-1) {
}
/**
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 0d7180a..c15c5a5 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -1336,56 +1336,97 @@
void
CameraDevice::checkAndFireSequenceCompleteLocked() {
int64_t completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
- //std::map<int, int64_t> mSequenceLastFrameNumberMap;
auto it = mSequenceLastFrameNumberMap.begin();
while (it != mSequenceLastFrameNumberMap.end()) {
int sequenceId = it->first;
- int64_t lastFrameNumber = it->second;
- bool seqCompleted = false;
- bool hasCallback = true;
+ int64_t lastFrameNumber = it->second.lastFrameNumber;
+ bool hasCallback = true;
+
+ if (mRemote == nullptr) {
+ ALOGW("Camera %s closed while checking sequence complete", getId());
+ return;
+ }
+ ALOGV("%s: seq %d's last frame number %" PRId64 ", completed %" PRId64,
+ __FUNCTION__, sequenceId, lastFrameNumber, completedFrameNumber);
+ if (!it->second.isSequenceCompleted) {
+ // Check if there is callback for this sequence
+ // This should not happen because we always register callback (with nullptr inside)
+ if (mSequenceCallbackMap.count(sequenceId) == 0) {
+ ALOGW("No callback found for sequenceId %d", sequenceId);
+ hasCallback = false;
+ }
+
+ if (lastFrameNumber <= completedFrameNumber) {
+ ALOGV("Mark sequenceId %d as sequence completed", sequenceId);
+ it->second.isSequenceCompleted = true;
+ }
+
+ if (it->second.isSequenceCompleted && hasCallback) {
+ auto cbIt = mSequenceCallbackMap.find(sequenceId);
+ CallbackHolder cbh = cbIt->second;
+
+ // send seq complete callback
+ sp<AMessage> msg = new AMessage(kWhatCaptureSeqEnd, mHandler);
+ msg->setPointer(kContextKey, cbh.mContext);
+ msg->setObject(kSessionSpKey, cbh.mSession);
+ msg->setPointer(kCallbackFpKey, (void*) cbh.mOnCaptureSequenceCompleted);
+ msg->setInt32(kSequenceIdKey, sequenceId);
+ msg->setInt64(kFrameNumberKey, lastFrameNumber);
+
+ // Clear the session sp before we send out the message
+ // This will guarantee the rare case where the message is processed
+ // before cbh goes out of scope and causing we call the session
+ // destructor while holding device lock
+ cbh.mSession.clear();
+ postSessionMsgAndCleanup(msg);
+ }
+ }
+
+ if (it->second.isSequenceCompleted && it->second.isInflightCompleted) {
+ if (mSequenceCallbackMap.find(sequenceId) != mSequenceCallbackMap.end()) {
+ mSequenceCallbackMap.erase(sequenceId);
+ }
+ it = mSequenceLastFrameNumberMap.erase(it);
+ ALOGV("%s: Remove holder for sequenceId %d", __FUNCTION__, sequenceId);
+ } else {
+ ++it;
+ }
+ }
+}
+
+void
+CameraDevice::removeCompletedCallbackHolderLocked(int64_t lastCompletedRegularFrameNumber) {
+ auto it = mSequenceLastFrameNumberMap.begin();
+ while (it != mSequenceLastFrameNumberMap.end()) {
+ int sequenceId = it->first;
+ int64_t lastFrameNumber = it->second.lastFrameNumber;
if (mRemote == nullptr) {
ALOGW("Camera %s closed while checking sequence complete", getId());
return;
}
- // Check if there is callback for this sequence
- // This should not happen because we always register callback (with nullptr inside)
- if (mSequenceCallbackMap.count(sequenceId) == 0) {
- ALOGW("No callback found for sequenceId %d", sequenceId);
- hasCallback = false;
- }
+ ALOGV("%s: seq %d's last frame number %" PRId64
+ ", completed inflight frame number %" PRId64,
+ __FUNCTION__, sequenceId, lastFrameNumber,
+ lastCompletedRegularFrameNumber);
+ if (lastFrameNumber <= lastCompletedRegularFrameNumber) {
+ if (it->second.isSequenceCompleted) {
+ // Check if there is callback for this sequence
+ // This should not happen because we always register callback (with nullptr inside)
+ if (mSequenceCallbackMap.count(sequenceId) == 0) {
+ ALOGW("No callback found for sequenceId %d", sequenceId);
+ } else {
+ mSequenceCallbackMap.erase(sequenceId);
+ }
- if (lastFrameNumber <= completedFrameNumber) {
- ALOGV("seq %d reached last frame %" PRId64 ", completed %" PRId64,
- sequenceId, lastFrameNumber, completedFrameNumber);
- seqCompleted = true;
- }
-
- if (seqCompleted && hasCallback) {
- // remove callback holder from callback map
- auto cbIt = mSequenceCallbackMap.find(sequenceId);
- CallbackHolder cbh = cbIt->second;
- mSequenceCallbackMap.erase(cbIt);
- // send seq complete callback
- sp<AMessage> msg = new AMessage(kWhatCaptureSeqEnd, mHandler);
- msg->setPointer(kContextKey, cbh.mContext);
- msg->setObject(kSessionSpKey, cbh.mSession);
- msg->setPointer(kCallbackFpKey, (void*) cbh.mOnCaptureSequenceCompleted);
- msg->setInt32(kSequenceIdKey, sequenceId);
- msg->setInt64(kFrameNumberKey, lastFrameNumber);
-
- // Clear the session sp before we send out the message
- // This will guarantee the rare case where the message is processed
- // before cbh goes out of scope and causing we call the session
- // destructor while holding device lock
- cbh.mSession.clear();
- postSessionMsgAndCleanup(msg);
- }
-
- // No need to track sequence complete if there is no callback registered
- if (seqCompleted || !hasCallback) {
- it = mSequenceLastFrameNumberMap.erase(it);
+ it = mSequenceLastFrameNumberMap.erase(it);
+ ALOGV("%s: Remove holder for sequenceId %d", __FUNCTION__, sequenceId);
+ } else {
+ ALOGV("Mark sequenceId %d as inflight completed", sequenceId);
+ it->second.isInflightCompleted = true;
+ ++it;
+ }
} else {
++it;
}
@@ -1480,6 +1521,9 @@
return ret;
}
+ dev->removeCompletedCallbackHolderLocked(
+ std::numeric_limits<int64_t>::max()/*lastCompletedRegularFrameNumber*/);
+
if (dev->mIdle) {
// Already in idle state. Possibly other thread did waitUntilIdle
return ret;
@@ -1522,6 +1566,9 @@
return ret;
}
+ dev->removeCompletedCallbackHolderLocked(
+ resultExtras.lastCompletedRegularFrameNumber);
+
int sequenceId = resultExtras.requestId;
int32_t burstId = resultExtras.burstId;
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 6c2ceb3..d937865 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -267,8 +267,23 @@
static const int REQUEST_ID_NONE = -1;
int mRepeatingSequenceId = REQUEST_ID_NONE;
- // sequence id -> last frame number map
- std::map<int, int64_t> mSequenceLastFrameNumberMap;
+ // sequence id -> last frame number holder map
+ struct RequestLastFrameNumberHolder {
+ int64_t lastFrameNumber;
+ // Whether the current sequence is completed (capture results are
+ // generated). May be set to true, but
+ // not removed from the map if not all inflight requests in the sequence
+ // have been completed.
+ bool isSequenceCompleted = false;
+ // Whether all inflight requests in the sequence are completed
+ // (capture results and buffers are generated). May be
+ // set to true, but not removed from the map yet if the capture results
+ // haven't been delivered to the app yet.
+ bool isInflightCompleted = false;
+ RequestLastFrameNumberHolder(int64_t lastFN) :
+ lastFrameNumber(lastFN) {}
+ };
+ std::map<int, RequestLastFrameNumberHolder> mSequenceLastFrameNumberMap;
struct CallbackHolder {
CallbackHolder(sp<ACameraCaptureSession> session,
@@ -338,6 +353,7 @@
void checkRepeatingSequenceCompleteLocked(const int sequenceId, const int64_t lastFrameNumber);
void checkAndFireSequenceCompleteLocked();
+ void removeCompletedCallbackHolderLocked(int64_t lastCompletedRegularFrameNumber);
// Misc variables
int32_t mShadingMapSize[2]; // const after constructor
diff --git a/media/codec2/components/aac/C2SoftAacDec.cpp b/media/codec2/components/aac/C2SoftAacDec.cpp
index f39620e..9884733 100644
--- a/media/codec2/components/aac/C2SoftAacDec.cpp
+++ b/media/codec2/components/aac/C2SoftAacDec.cpp
@@ -89,11 +89,18 @@
addParameter(
DefineParam(mChannelCount, C2_PARAMKEY_CHANNEL_COUNT)
.withDefault(new C2StreamChannelCountInfo::output(0u, 1))
- .withFields({C2F(mChannelCount, value).inRange(1, 8)})
+ .withFields({C2F(mChannelCount, value).inRange(1, MAX_CHANNEL_COUNT)})
.withSetter(Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps)
.build());
addParameter(
+ DefineParam(mMaxChannelCount, C2_PARAMKEY_MAX_CHANNEL_COUNT)
+ .withDefault(new C2StreamMaxChannelCountInfo::input(0u, MAX_CHANNEL_COUNT))
+ .withFields({C2F(mMaxChannelCount, value).inRange(1, MAX_CHANNEL_COUNT)})
+ .withSetter(Setter<decltype(*mMaxChannelCount)>::StrictValueWithNoDeps)
+ .build());
+
+ addParameter(
DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
.withDefault(new C2StreamBitrateInfo::input(0u, 64000))
.withFields({C2F(mBitrate, value).inRange(8000, 960000)})
@@ -225,6 +232,7 @@
int32_t getDrcAttenuationFactor() const { return mDrcAttenuationFactor->value * 127. + 0.5; }
int32_t getDrcEffectType() const { return mDrcEffectType->value; }
int32_t getDrcAlbumMode() const { return mDrcAlbumMode->value; }
+ u_int32_t getMaxChannelCount() const { return mMaxChannelCount->value; }
int32_t getDrcOutputLoudness() const { return (mDrcOutputLoudness->value <= 0 ? -mDrcOutputLoudness->value * 4. + 0.5 : -1); }
private:
@@ -241,6 +249,7 @@
std::shared_ptr<C2StreamDrcAttenuationFactorTuning::input> mDrcAttenuationFactor;
std::shared_ptr<C2StreamDrcEffectTypeTuning::input> mDrcEffectType;
std::shared_ptr<C2StreamDrcAlbumModeTuning::input> mDrcAlbumMode;
+ std::shared_ptr<C2StreamMaxChannelCountInfo::input> mMaxChannelCount;
std::shared_ptr<C2StreamDrcOutputLoudnessTuning::output> mDrcOutputLoudness;
// TODO Add : C2StreamAacSbrModeTuning
};
@@ -366,9 +375,10 @@
ALOGV("AAC decoder using MPEG-D DRC album mode %d", albumMode);
aacDecoder_SetParam(mAACDecoder, AAC_UNIDRC_ALBUM_MODE, albumMode);
- // By default, the decoder creates a 5.1 channel downmix signal.
- // For seven and eight channel input streams, enable 6.1 and 7.1 channel output
- aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, -1);
+ // AAC_PCM_MAX_OUTPUT_CHANNELS
+ u_int32_t maxChannelCount = mIntf->getMaxChannelCount();
+ ALOGV("AAC decoder using maximum output channel count %d", maxChannelCount);
+ aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, maxChannelCount);
return status;
}
@@ -707,6 +717,11 @@
ALOGV("AAC decoder using MPEG-D DRC album mode %d", albumMode);
aacDecoder_SetParam(mAACDecoder, AAC_UNIDRC_ALBUM_MODE, albumMode);
+ // AAC_PCM_MAX_OUTPUT_CHANNELS
+ int32_t maxChannelCount = mIntf->getMaxChannelCount();
+ ALOGV("AAC decoder using maximum output channel count %d", maxChannelCount);
+ aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, maxChannelCount);
+
mDrcWrap.update();
UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
@@ -847,6 +862,51 @@
ALOGE("Getting output loudness failed");
}
}
+
+ // update config with values used for decoding:
+ // Album mode, target reference level, DRC effect type, DRC attenuation and boost
+ // factor, DRC compression mode, encoder target level and max channel count
+ // with input values as they were not modified by decoder
+
+ C2StreamDrcAttenuationFactorTuning::input currentAttenuationFactor(0u,
+ (C2FloatValue) (attenuationFactor/127.));
+ work->worklets.front()->output.configUpdate.push_back(
+ C2Param::Copy(currentAttenuationFactor));
+
+ C2StreamDrcBoostFactorTuning::input currentBoostFactor(0u,
+ (C2FloatValue) (boostFactor/127.));
+ work->worklets.front()->output.configUpdate.push_back(
+ C2Param::Copy(currentBoostFactor));
+
+ C2StreamDrcCompressionModeTuning::input currentCompressMode(0u,
+ (C2Config::drc_compression_mode_t) compressMode);
+ work->worklets.front()->output.configUpdate.push_back(
+ C2Param::Copy(currentCompressMode));
+
+ C2StreamDrcEncodedTargetLevelTuning::input currentEncodedTargetLevel(0u,
+ (C2FloatValue) (encTargetLevel*-0.25));
+ work->worklets.front()->output.configUpdate.push_back(
+ C2Param::Copy(currentEncodedTargetLevel));
+
+ C2StreamDrcAlbumModeTuning::input currentAlbumMode(0u,
+ (C2Config::drc_album_mode_t) albumMode);
+ work->worklets.front()->output.configUpdate.push_back(
+ C2Param::Copy(currentAlbumMode));
+
+ C2StreamDrcTargetReferenceLevelTuning::input currentTargetRefLevel(0u,
+ (float) (targetRefLevel*-0.25));
+ work->worklets.front()->output.configUpdate.push_back(
+ C2Param::Copy(currentTargetRefLevel));
+
+ C2StreamDrcEffectTypeTuning::input currentEffectype(0u,
+ (C2Config::drc_effect_type_t) effectType);
+ work->worklets.front()->output.configUpdate.push_back(
+ C2Param::Copy(currentEffectype));
+
+ C2StreamMaxChannelCountInfo::input currentMaxChannelCnt(0u, maxChannelCount);
+ work->worklets.front()->output.configUpdate.push_back(
+ C2Param::Copy(currentMaxChannelCnt));
+
} while (decoderErr == AAC_DEC_OK);
}
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 2cd357b..0626c8d 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -732,6 +732,9 @@
std::shared_ptr<const C2StreamHdr10PlusInfo::output> hdr10PlusInfo =
std::static_pointer_cast<const C2StreamHdr10PlusInfo::output>(
c2Buffer->getInfo(C2StreamHdr10PlusInfo::output::PARAM_TYPE));
+ if (hdr10PlusInfo && hdr10PlusInfo->flexCount() == 0) {
+ hdr10PlusInfo.reset();
+ }
{
Mutexed<OutputSurface>::Locked output(mOutputSurface);
@@ -783,7 +786,7 @@
.maxLuminance = hdrStaticInfo->mastering.maxLuminance,
.minLuminance = hdrStaticInfo->mastering.minLuminance,
};
- hdr.validTypes = HdrMetadata::SMPTE2086;
+ hdr.validTypes |= HdrMetadata::SMPTE2086;
hdr.smpte2086 = smpte2086_meta;
}
// If the content light level fields are 0, do not use them, it
diff --git a/media/extractors/fuzzers/Android.bp b/media/extractors/fuzzers/Android.bp
index 0a70815..502743e 100644
--- a/media/extractors/fuzzers/Android.bp
+++ b/media/extractors/fuzzers/Android.bp
@@ -17,13 +17,8 @@
*****************************************************************************
* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
*/
-
-cc_library {
- name: "libextractorfuzzerbase",
-
- srcs: [
- "ExtractorFuzzerBase.cpp",
- ],
+cc_defaults {
+ name: "extractor-fuzzerbase-defaults",
local_include_dirs: [
"include",
@@ -43,16 +38,10 @@
shared_libs: [
"libutils",
"libbinder",
+ "libbase",
+ "libcutils",
],
- /* GETEXTRACTORDEF is not defined as extractor library is not linked in the
- * base class. It will be included when the extractor fuzzer binary is
- * generated.
- */
- allow_undefined_symbols: true,
-
- host_supported: true,
-
target: {
darwin: {
enabled: false,
@@ -60,8 +49,64 @@
},
}
+cc_defaults {
+ name: "extractor-fuzzer-defaults",
+ defaults: ["extractor-fuzzerbase-defaults"],
+
+ static_libs: [
+ "libextractorfuzzerbase",
+ ],
+
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 155276,
+ },
+}
+
+cc_defaults {
+ name: "mpeg2-extractor-fuzzer-defaults",
+ defaults: ["extractor-fuzzer-defaults"],
+
+ include_dirs: [
+ "frameworks/av/media/extractors/mpeg2",
+ "frameworks/av/media/libstagefright",
+ ],
+
+ static_libs: [
+ "libstagefright_foundation_without_imemory",
+ "libstagefright_mpeg2support",
+ "libstagefright_mpeg2extractor",
+ "libstagefright_esds",
+ "libmpeg2extractor",
+ ],
+
+ shared_libs: [
+ "android.hardware.cas@1.0",
+ "android.hardware.cas.native@1.0",
+ "android.hidl.token@1.0-utils",
+ "android.hidl.allocator@1.0",
+ "libcrypto",
+ "libhidlmemory",
+ "libhidlbase",
+ ],
+}
+
+cc_library_static {
+ name: "libextractorfuzzerbase",
+ defaults: ["extractor-fuzzerbase-defaults"],
+ host_supported: true,
+
+ srcs: [
+ "ExtractorFuzzerBase.cpp",
+ ],
+}
+
cc_fuzz {
name: "mp4_extractor_fuzzer",
+ defaults: ["extractor-fuzzer-defaults"],
+ host_supported: true,
srcs: [
"mp4_extractor_fuzzer.cpp",
@@ -76,35 +121,17 @@
],
static_libs: [
- "liblog",
- "libstagefright_foundation",
- "libmediandk_format",
- "libmedia_ndkformatpriv",
- "libextractorfuzzerbase",
"libstagefright_id3",
"libstagefright_esds",
"libmp4extractor",
],
- shared_libs: [
- "libutils",
- "libbinder",
- ],
-
dictionary: "mp4_extractor_fuzzer.dict",
-
- fuzz_config: {
- cc: [
- "android-media-fuzzing-reports@google.com",
- ],
- componentid: 155276,
- },
-
- host_supported: true,
}
cc_fuzz {
name: "wav_extractor_fuzzer",
+ defaults: ["extractor-fuzzer-defaults"],
srcs: [
"wav_extractor_fuzzer.cpp",
@@ -115,32 +142,18 @@
],
static_libs: [
- "liblog",
- "libstagefright_foundation",
- "libmedia",
- "libextractorfuzzerbase",
"libfifo",
"libwavextractor",
],
shared_libs: [
- "libutils",
- "libmediandk",
- "libbinder",
"libbinder_ndk",
- "libbase",
],
-
- fuzz_config: {
- cc: [
- "android-media-fuzzing-reports@google.com",
- ],
- componentid: 155276,
- },
}
cc_fuzz {
name: "amr_extractor_fuzzer",
+ defaults: ["extractor-fuzzer-defaults"],
srcs: [
"amr_extractor_fuzzer.cpp",
@@ -151,31 +164,15 @@
],
static_libs: [
- "liblog",
- "libstagefright_foundation",
- "libmedia",
- "libextractorfuzzerbase",
"libamrextractor",
],
- shared_libs: [
- "libutils",
- "libmediandk",
- "libbinder",
- ],
-
dictionary: "amr_extractor_fuzzer.dict",
-
- fuzz_config: {
- cc: [
- "android-media-fuzzing-reports@google.com",
- ],
- componentid: 155276,
- },
}
cc_fuzz {
name: "mkv_extractor_fuzzer",
+ defaults: ["extractor-fuzzer-defaults"],
srcs: [
"mkv_extractor_fuzzer.cpp",
@@ -186,10 +183,6 @@
],
static_libs: [
- "liblog",
- "libstagefright_foundation",
- "libmedia",
- "libextractorfuzzerbase",
"libwebm",
"libstagefright_flacdec",
"libstagefright_metadatautils",
@@ -197,24 +190,12 @@
"libFLAC",
],
- shared_libs: [
- "libutils",
- "libmediandk",
- "libbinder",
- ],
-
dictionary: "mkv_extractor_fuzzer.dict",
-
- fuzz_config: {
- cc: [
- "android-media-fuzzing-reports@google.com",
- ],
- componentid: 155276,
- },
}
cc_fuzz {
name: "ogg_extractor_fuzzer",
+ defaults: ["extractor-fuzzer-defaults"],
srcs: [
"ogg_extractor_fuzzer.cpp",
@@ -225,129 +206,43 @@
],
static_libs: [
- "liblog",
- "libstagefright_foundation",
- "libmedia",
- "libextractorfuzzerbase",
"libstagefright_metadatautils",
"libvorbisidec",
"liboggextractor",
],
- shared_libs: [
- "libutils",
- "libmediandk",
- "libbinder",
- ],
-
dictionary: "ogg_extractor_fuzzer.dict",
-
- fuzz_config: {
- cc: [
- "android-media-fuzzing-reports@google.com",
- ],
- componentid: 155276,
- },
}
cc_fuzz {
name: "mpeg2ps_extractor_fuzzer",
+ defaults: ["mpeg2-extractor-fuzzer-defaults"],
srcs: [
"mpeg2_extractor_fuzzer.cpp",
],
- include_dirs: [
- "frameworks/av/media/extractors/mpeg2",
- "frameworks/av/media/libstagefright",
- ],
-
- static_libs: [
- "liblog",
- "libstagefright_foundation_without_imemory",
- "libmedia",
- "libextractorfuzzerbase",
- "libstagefright_mpeg2support",
- "libstagefright_mpeg2extractor",
- "libstagefright_esds",
- "libmpeg2extractor",
- ],
-
cflags: [
"-DMPEG2PS",
],
- shared_libs: [
- "libutils",
- "libmediandk",
- "libbinder",
- "android.hardware.cas@1.0",
- "android.hardware.cas.native@1.0",
- "android.hidl.token@1.0-utils",
- "android.hidl.allocator@1.0",
- "libcrypto",
- "libhidlmemory",
- "libhidlbase",
- ],
-
dictionary: "mpeg2ps_extractor_fuzzer.dict",
-
- fuzz_config: {
- cc: [
- "android-media-fuzzing-reports@google.com",
- ],
- componentid: 155276,
- },
}
cc_fuzz {
name: "mpeg2ts_extractor_fuzzer",
+ defaults: ["mpeg2-extractor-fuzzer-defaults"],
srcs: [
"mpeg2_extractor_fuzzer.cpp",
],
- include_dirs: [
- "frameworks/av/media/extractors/mpeg2",
- "frameworks/av/media/libstagefright",
- ],
-
- static_libs: [
- "liblog",
- "libstagefright_foundation_without_imemory",
- "libmedia",
- "libextractorfuzzerbase",
- "libstagefright_mpeg2support",
- "libstagefright_mpeg2extractor",
- "libstagefright_esds",
- "libmpeg2extractor",
- ],
-
- shared_libs: [
- "libutils",
- "libmediandk",
- "libbinder",
- "android.hardware.cas@1.0",
- "android.hardware.cas.native@1.0",
- "android.hidl.token@1.0-utils",
- "android.hidl.allocator@1.0",
- "libcrypto",
- "libhidlmemory",
- "libhidlbase",
- ],
-
dictionary: "mpeg2ts_extractor_fuzzer.dict",
-
- fuzz_config: {
- cc: [
- "android-media-fuzzing-reports@google.com",
- ],
- componentid: 155276,
- },
}
cc_fuzz {
name: "mp3_extractor_fuzzer",
+ defaults: ["extractor-fuzzer-defaults"],
srcs: [
"mp3_extractor_fuzzer.cpp",
@@ -358,31 +253,15 @@
],
static_libs: [
- "liblog",
- "libstagefright_foundation",
- "libmedia",
- "libextractorfuzzerbase",
"libfifo",
"libmp3extractor",
"libstagefright_id3",
],
-
- shared_libs: [
- "libutils",
- "libmediandk",
- "libbinder",
- ],
-
- fuzz_config: {
- cc: [
- "android-media-fuzzing-reports@google.com",
- ],
- componentid: 155276,
- },
}
cc_fuzz {
name: "aac_extractor_fuzzer",
+ defaults: ["extractor-fuzzer-defaults"],
srcs: [
"aac_extractor_fuzzer.cpp",
@@ -393,30 +272,14 @@
],
static_libs: [
- "liblog",
- "libstagefright_foundation",
- "libmedia",
- "libextractorfuzzerbase",
"libaacextractor",
"libstagefright_metadatautils",
],
-
- shared_libs: [
- "libutils",
- "libmediandk",
- "libbinder",
- ],
-
- fuzz_config: {
- cc: [
- "android-media-fuzzing-reports@google.com",
- ],
- componentid: 155276,
- },
}
cc_fuzz {
name: "flac_extractor_fuzzer",
+ defaults: ["extractor-fuzzer-defaults"],
srcs: [
"flac_extractor_fuzzer.cpp",
@@ -427,29 +290,14 @@
],
static_libs: [
- "liblog",
- "libstagefright_foundation",
- "libmedia",
- "libextractorfuzzerbase",
"libstagefright_metadatautils",
"libFLAC",
"libflacextractor",
],
shared_libs: [
- "libutils",
- "libmediandk",
- "libbinder",
"libbinder_ndk",
- "libbase",
],
dictionary: "flac_extractor_fuzzer.dict",
-
- fuzz_config: {
- cc: [
- "android-media-fuzzing-reports@google.com",
- ],
- componentid: 155276,
- },
}
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 7c85952..1d828df 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -2879,6 +2879,21 @@
break;
}
+ case FOURCC("pasp"):
+ {
+ *offset += chunk_size;
+ // this must be in a VisualSampleEntry box under the Sample Description Box ('stsd')
+ // ignore otherwise
+ if (depth >= 2 && mPath[depth - 2] == FOURCC("stsd")) {
+ status_t err = parsePaspBox(data_offset, chunk_data_size);
+ if (err != OK) {
+ return err;
+ }
+ }
+
+ break;
+ }
+
case FOURCC("titl"):
case FOURCC("perf"):
case FOURCC("auth"):
@@ -4050,6 +4065,26 @@
return OK;
}
+status_t MPEG4Extractor::parsePaspBox(off64_t offset, size_t size) {
+ if (size < 8 || size == SIZE_MAX || mLastTrack == NULL) {
+ return ERROR_MALFORMED;
+ }
+
+ uint32_t data[2]; // hSpacing, vSpacing
+ if (mDataSource->readAt(offset, data, 8) < 8) {
+ return ERROR_IO;
+ }
+ uint32_t hSpacing = ntohl(data[0]);
+ uint32_t vSpacing = ntohl(data[1]);
+
+ if (hSpacing != 0 && vSpacing != 0) {
+ AMediaFormat_setInt32(mLastTrack->meta, AMEDIAFORMAT_KEY_SAR_WIDTH, hSpacing);
+ AMediaFormat_setInt32(mLastTrack->meta, AMEDIAFORMAT_KEY_SAR_HEIGHT, vSpacing);
+ }
+
+ return OK;
+}
+
status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int depth) {
if (size < 4 || size == SIZE_MAX) {
return ERROR_MALFORMED;
diff --git a/media/extractors/mp4/MPEG4Extractor.h b/media/extractors/mp4/MPEG4Extractor.h
index 1e49d50..bafc7f5 100644
--- a/media/extractors/mp4/MPEG4Extractor.h
+++ b/media/extractors/mp4/MPEG4Extractor.h
@@ -160,6 +160,7 @@
status_t parseChunk(off64_t *offset, int depth);
status_t parseITunesMetaData(off64_t offset, size_t size);
status_t parseColorInfo(off64_t offset, size_t size);
+ status_t parsePaspBox(off64_t offset, size_t size);
status_t parse3GPPMetaData(off64_t offset, size_t size, int depth);
void parseID3v2MetaData(off64_t offset, uint64_t size);
status_t parseQTMetaKey(off64_t data_offset, size_t data_size);
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
index bc8632c..187803a 100644
--- a/media/extractors/mpeg2/Android.bp
+++ b/media/extractors/mpeg2/Android.bp
@@ -19,7 +19,7 @@
"libaudioclient_headers",
"libbase_headers",
"libstagefright_headers",
- "libmedia_headers",
+ "libmedia_datasource_headers",
],
static_libs: [
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl
index b130a88..8e32269 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl
@@ -74,7 +74,7 @@
boolean isForTesting = false;
/**
- * Test configuration. This is only valid when isForTesting is set to true.
+ * Test configuration. This will be available only when isForTesting is set to true.
*/
- TranscodingTestConfig testConfig;
+ @nullable TranscodingTestConfig testConfig;
}
diff --git a/media/libmediatranscoding/tests/assets/backyard_hevc_1920x1080_20Mbps.mp4 b/media/libmediatranscoding/tests/assets/backyard_hevc_1920x1080_20Mbps.mp4
new file mode 100644
index 0000000..80d1ec3
--- /dev/null
+++ b/media/libmediatranscoding/tests/assets/backyard_hevc_1920x1080_20Mbps.mp4
Binary files differ
diff --git a/media/libmediatranscoding/transcoder/tests/assets/cubicle_avc_480x240_aac_24KHz.mp4 b/media/libmediatranscoding/tests/assets/cubicle_avc_480x240_aac_24KHz.mp4
similarity index 100%
rename from media/libmediatranscoding/transcoder/tests/assets/cubicle_avc_480x240_aac_24KHz.mp4
rename to media/libmediatranscoding/tests/assets/cubicle_avc_480x240_aac_24KHz.mp4
Binary files differ
diff --git a/media/libmediatranscoding/tests/assets/jets_hevc_1280x720_20Mbps.mp4 b/media/libmediatranscoding/tests/assets/jets_hevc_1280x720_20Mbps.mp4
new file mode 100644
index 0000000..7794b99
--- /dev/null
+++ b/media/libmediatranscoding/tests/assets/jets_hevc_1280x720_20Mbps.mp4
Binary files differ
diff --git a/media/libmediatranscoding/tests/assets/plex_hevc_3840x2160_12Mbps.mp4 b/media/libmediatranscoding/tests/assets/plex_hevc_3840x2160_12Mbps.mp4
new file mode 100644
index 0000000..92dda3b
--- /dev/null
+++ b/media/libmediatranscoding/tests/assets/plex_hevc_3840x2160_12Mbps.mp4
Binary files differ
diff --git a/media/libmediatranscoding/tests/assets/plex_hevc_3840x2160_20Mbps.mp4 b/media/libmediatranscoding/tests/assets/plex_hevc_3840x2160_20Mbps.mp4
new file mode 100644
index 0000000..2fe37bd
--- /dev/null
+++ b/media/libmediatranscoding/tests/assets/plex_hevc_3840x2160_20Mbps.mp4
Binary files differ
diff --git a/media/libmediatranscoding/tests/assets/push_assets.sh b/media/libmediatranscoding/tests/assets/push_assets.sh
new file mode 100755
index 0000000..2fcb233
--- /dev/null
+++ b/media/libmediatranscoding/tests/assets/push_assets.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+#
+# Pushes the assets to the /data/local/tmp.
+#
+
+if [ "$SYNC_FINISHED" != true ]; then
+ if [ -z "$ANDROID_BUILD_TOP" ]; then
+ echo "Android build environment not set"
+ exit -1
+ fi
+
+ # ensure we have mm
+ . $ANDROID_BUILD_TOP/build/envsetup.sh
+
+ mm
+
+ echo "waiting for device"
+
+ adb root && adb wait-for-device remount
+fi
+
+#TODO(hkuang): Check if the destination folder already exists. If so, skip the copying.
+echo "Copying files to device"
+adb push $ANDROID_BUILD_TOP/frameworks/av/media/libmediatranscoding/tests/assets /data/local/tmp/TranscodingTestAssets
+echo "Copy done"
diff --git a/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
index 3a281ba..b485826 100644
--- a/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
@@ -102,6 +102,12 @@
return false;
}
+void MediaTrackTranscoder::notifyTrackFormatAvailable() {
+ if (auto callbacks = mTranscoderCallback.lock()) {
+ callbacks->onTrackFormatAvailable(this);
+ }
+}
+
std::shared_ptr<MediaSampleQueue> MediaTrackTranscoder::getOutputQueue() const {
return mOutputQueue;
}
diff --git a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
index cee3702..69932f4 100644
--- a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
@@ -100,6 +100,36 @@
}
}
+void MediaTranscoder::onTrackFormatAvailable(const MediaTrackTranscoder* transcoder) {
+ LOG(INFO) << "TrackTranscoder " << transcoder << " format available.";
+
+ std::scoped_lock lock{mTracksAddedMutex};
+
+ // Ignore duplicate format change.
+ if (mTracksAdded.count(transcoder) > 0) {
+ return;
+ }
+
+ // Add track to the writer.
+ const bool ok =
+ mSampleWriter->addTrack(transcoder->getOutputQueue(), transcoder->getOutputFormat());
+ if (!ok) {
+ LOG(ERROR) << "Unable to add track to sample writer.";
+ sendCallback(AMEDIA_ERROR_UNKNOWN);
+ return;
+ }
+
+ mTracksAdded.insert(transcoder);
+ if (mTracksAdded.size() == mTrackTranscoders.size()) {
+ LOG(INFO) << "Starting sample writer.";
+ bool started = mSampleWriter->start();
+ if (!started) {
+ LOG(ERROR) << "Unable to start sample writer.";
+ sendCallback(AMEDIA_ERROR_UNKNOWN);
+ }
+ }
+}
+
void MediaTranscoder::onTrackFinished(const MediaTrackTranscoder* transcoder) {
LOG(DEBUG) << "TrackTranscoder " << transcoder << " finished";
}
@@ -267,25 +297,9 @@
return AMEDIA_ERROR_INVALID_OPERATION;
}
- // Add tracks to the writer.
- for (auto& transcoder : mTrackTranscoders) {
- const bool ok = mSampleWriter->addTrack(transcoder->getOutputQueue(),
- transcoder->getOutputFormat());
- if (!ok) {
- LOG(ERROR) << "Unable to add track to sample writer.";
- return AMEDIA_ERROR_UNKNOWN;
- }
- }
-
- bool started = mSampleWriter->start();
- if (!started) {
- LOG(ERROR) << "Unable to start sample writer.";
- return AMEDIA_ERROR_UNKNOWN;
- }
-
// Start transcoders
for (auto& transcoder : mTrackTranscoders) {
- started = transcoder->start();
+ bool started = transcoder->start();
if (!started) {
LOG(ERROR) << "Unable to start track transcoder.";
cancel();
diff --git a/media/libmediatranscoding/transcoder/PassthroughTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/PassthroughTrackTranscoder.cpp
index 7806208..a4cbf33 100644
--- a/media/libmediatranscoding/transcoder/PassthroughTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/PassthroughTrackTranscoder.cpp
@@ -96,6 +96,9 @@
MediaSampleInfo info;
std::shared_ptr<MediaSample> sample;
+ // Notify the track format as soon as we start. It's same as the source format.
+ notifyTrackFormatAvailable();
+
MediaSample::OnSampleReleasedCallback bufferReleaseCallback =
[bufferPool = mBufferPool](MediaSample* sample) {
bufferPool->returnBuffer(const_cast<uint8_t*>(sample->buffer));
diff --git a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
index 3818545..96e2e61 100644
--- a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
@@ -86,6 +86,10 @@
VideoTrackTranscoder* transcoder = static_cast<VideoTrackTranscoder*>(userdata);
const char* kCodecName = (codec == transcoder->mDecoder ? "Decoder" : "Encoder");
LOG(DEBUG) << kCodecName << " format changed: " << AMediaFormat_toString(format);
+ if (codec == transcoder->mEncoder.get()) {
+ transcoder->mCodecMessageQueue.push(
+ [transcoder, format] { transcoder->updateTrackFormat(format); });
+ }
}
static void onAsyncError(AMediaCodec* codec, void* userdata, media_status_t error,
@@ -311,6 +315,56 @@
}
}
+void VideoTrackTranscoder::updateTrackFormat(AMediaFormat* outputFormat) {
+ if (mActualOutputFormat != nullptr) {
+ LOG(WARNING) << "Ignoring duplicate format change.";
+ return;
+ }
+
+ AMediaFormat* formatCopy = AMediaFormat_new();
+ if (!formatCopy || AMediaFormat_copy(formatCopy, outputFormat) != AMEDIA_OK) {
+ LOG(ERROR) << "Unable to copy outputFormat";
+ AMediaFormat_delete(formatCopy);
+ mStatus = AMEDIA_ERROR_INVALID_PARAMETER;
+ return;
+ }
+
+ // Generate the actual track format for muxer based on the encoder output format,
+ // since many vital information comes in the encoder format (eg. CSD).
+ // Transfer necessary fields from the user-configured track format (derived from
+ // source track format and user transcoding request) where needed.
+
+ // Transfer SAR settings:
+ // If mDestinationFormat has SAR set, it means the original source has SAR specified
+ // at container level. This is supposed to override any SAR settings in the bitstream,
+ // thus should always be transferred to the container of the transcoded file.
+ int32_t sarWidth, sarHeight;
+ if (AMediaFormat_getInt32(mDestinationFormat.get(), AMEDIAFORMAT_KEY_SAR_WIDTH, &sarWidth) &&
+ (sarWidth > 0) &&
+ AMediaFormat_getInt32(mDestinationFormat.get(), AMEDIAFORMAT_KEY_SAR_HEIGHT, &sarHeight) &&
+ (sarHeight > 0)) {
+ AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_SAR_WIDTH, sarWidth);
+ AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_SAR_HEIGHT, sarHeight);
+ }
+ // Transfer DAR settings.
+ int32_t displayWidth, displayHeight;
+ if (AMediaFormat_getInt32(mDestinationFormat.get(), AMEDIAFORMAT_KEY_DISPLAY_WIDTH,
+ &displayWidth) &&
+ (displayWidth > 0) &&
+ AMediaFormat_getInt32(mDestinationFormat.get(), AMEDIAFORMAT_KEY_DISPLAY_HEIGHT,
+ &displayHeight) &&
+ (displayHeight > 0)) {
+ AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_DISPLAY_WIDTH, displayWidth);
+ AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_DISPLAY_HEIGHT, displayHeight);
+ }
+
+ // TODO: transfer other fields as required.
+
+ mActualOutputFormat = std::shared_ptr<AMediaFormat>(formatCopy, &AMediaFormat_delete);
+
+ notifyTrackFormatAvailable();
+}
+
media_status_t VideoTrackTranscoder::runTranscodeLoop() {
media_status_t status = AMEDIA_OK;
@@ -350,7 +404,7 @@
}
std::shared_ptr<AMediaFormat> VideoTrackTranscoder::getOutputFormat() const {
- return mDestinationFormat;
+ return mActualOutputFormat;
}
} // namespace android
diff --git a/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoder.h b/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoder.h
index 0a35a57..60a9139 100644
--- a/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoder.h
+++ b/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoder.h
@@ -94,6 +94,9 @@
: mOutputQueue(std::make_shared<MediaSampleQueue>()),
mTranscoderCallback(transcoderCallback){};
+ // Called by subclasses when the actual track format becomes available.
+ void notifyTrackFormatAvailable();
+
// configureDestinationFormat needs to be implemented by subclasses, and gets called on an
// external thread before start.
virtual media_status_t configureDestinationFormat(
diff --git a/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoderCallback.h b/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoderCallback.h
index d535ada..654171e 100644
--- a/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoderCallback.h
+++ b/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoderCallback.h
@@ -27,6 +27,11 @@
class MediaTrackTranscoderCallback {
public:
/**
+ * Called when the MediaTrackTranscoder's actual track format becomes available.
+ * @param transcoder The MediaTrackTranscoder whose track format becomes available.
+ */
+ virtual void onTrackFormatAvailable(const MediaTrackTranscoder* transcoder);
+ /**
* Called when the MediaTrackTranscoder instance have finished transcoding all media samples
* successfully.
* @param transcoder The MediaTrackTranscoder that finished the transcoding.
diff --git a/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h b/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h
index 72a5559..e5a5d64 100644
--- a/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h
+++ b/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h
@@ -22,9 +22,11 @@
#include <media/MediaTrackTranscoderCallback.h>
#include <media/NdkMediaError.h>
#include <media/NdkMediaFormat.h>
+#include <utils/Mutex.h>
#include <atomic>
#include <memory>
+#include <mutex>
#include <unordered_set>
namespace android {
@@ -116,6 +118,7 @@
MediaTranscoder(const std::shared_ptr<CallbackInterface>& callbacks);
// MediaTrackTranscoderCallback
+ virtual void onTrackFormatAvailable(const MediaTrackTranscoder* transcoder) override;
virtual void onTrackFinished(const MediaTrackTranscoder* transcoder) override;
virtual void onTrackError(const MediaTrackTranscoder* transcoder,
media_status_t status) override;
@@ -128,6 +131,8 @@
std::unique_ptr<MediaSampleWriter> mSampleWriter;
std::vector<std::shared_ptr<AMediaFormat>> mSourceTrackFormats;
std::vector<std::unique_ptr<MediaTrackTranscoder>> mTrackTranscoders;
+ std::mutex mTracksAddedMutex;
+ std::unordered_set<const MediaTrackTranscoder*> mTracksAdded GUARDED_BY(mTracksAddedMutex);
std::atomic_bool mCallbackSent = false;
std::atomic_bool mCancelled = false;
diff --git a/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h b/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h
index c47e4b7..1ba205b 100644
--- a/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h
+++ b/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h
@@ -73,6 +73,9 @@
// Dequeues an encoded buffer from the encoder and adds it to the output queue.
void dequeueOutputSample(int32_t bufferIndex, AMediaCodecBufferInfo bufferInfo);
+ // Updates the video track's actual format based on encoder output format.
+ void updateTrackFormat(AMediaFormat* outputFormat);
+
AMediaCodec* mDecoder = nullptr;
// Sample release callback holds a reference to the encoder, hence the shared_ptr.
std::shared_ptr<AMediaCodec> mEncoder;
@@ -84,6 +87,7 @@
MediaSampleInfo mSampleInfo;
BlockingQueue<std::function<void()>> mCodecMessageQueue;
std::shared_ptr<AMediaFormat> mDestinationFormat;
+ std::shared_ptr<AMediaFormat> mActualOutputFormat;
};
} // namespace android
diff --git a/media/libmediatranscoding/transcoder/tests/AndroidTestTemplate.xml b/media/libmediatranscoding/transcoder/tests/AndroidTestTemplate.xml
index 23d1bab..a9a7e2e 100644
--- a/media/libmediatranscoding/transcoder/tests/AndroidTestTemplate.xml
+++ b/media/libmediatranscoding/transcoder/tests/AndroidTestTemplate.xml
@@ -19,7 +19,7 @@
<option name="cleanup" value="false" />
<option name="push-file"
key="assets"
- value="/data/local/tmp/TranscoderTestAssets" />
+ value="/data/local/tmp/TranscodingTestAssets" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
diff --git a/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp
index 858fcb3..805095e 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp
@@ -40,7 +40,7 @@
void SetUp() override {
LOG(DEBUG) << "MediaSampleReaderNDKTests set up";
const char* sourcePath =
- "/data/local/tmp/TranscoderTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
+ "/data/local/tmp/TranscodingTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
mExtractor = AMediaExtractor_new();
ASSERT_NE(mExtractor, nullptr);
diff --git a/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp
index 752f0c9..9ffb32b 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp
@@ -131,7 +131,7 @@
public:
void init() {
static const char* sourcePath =
- "/data/local/tmp/TranscoderTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
+ "/data/local/tmp/TranscodingTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
mExtractor = AMediaExtractor_new();
ASSERT_NE(mExtractor, nullptr);
diff --git a/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
index 09c24b5..7e10558 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
@@ -67,7 +67,7 @@
};
static const char* SOURCE_PATH =
- "/data/local/tmp/TranscoderTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
+ "/data/local/tmp/TranscodingTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
// Write-only, create file if non-existent, don't overwrite existing file.
static constexpr int kOpenFlags = O_WRONLY | O_CREAT | O_EXCL;
// User R+W permission.
diff --git a/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp
index 316793a..b79f58c 100644
--- a/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp
@@ -41,7 +41,7 @@
void initSourceAndExtractor() {
const char* sourcePath =
- "/data/local/tmp/TranscoderTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
+ "/data/local/tmp/TranscodingTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
mExtractor = AMediaExtractor_new();
ASSERT_NE(mExtractor, nullptr);
diff --git a/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h b/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
index 32a1a0a..54b42fe 100644
--- a/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
+++ b/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
@@ -57,6 +57,8 @@
~TestCallback() = default;
// MediaTrackTranscoderCallback
+ void onTrackFormatAvailable(const MediaTrackTranscoder* transcoder __unused) {}
+
void onTrackFinished(const MediaTrackTranscoder* transcoder __unused) {
std::unique_lock<std::mutex> lock(mMutex);
mTranscodingFinished = true;
diff --git a/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
index 6b1f640..1eb9e5a 100644
--- a/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
@@ -42,7 +42,7 @@
void SetUp() override {
LOG(DEBUG) << "VideoTrackTranscoderTests set up";
const char* sourcePath =
- "/data/local/tmp/TranscoderTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
+ "/data/local/tmp/TranscodingTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
const int sourceFd = open(sourcePath, O_RDONLY);
ASSERT_GT(sourceFd, 0);
diff --git a/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh b/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh
index 01beeee..241178d 100755
--- a/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh
+++ b/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh
@@ -18,7 +18,9 @@
adb root && adb wait-for-device remount && adb sync
fi
-adb push assets /data/local/tmp/TranscoderTestAssets
+
+# Push the files onto the device.
+. $ANDROID_BUILD_TOP/frameworks/av/media/libmediatranscoding/tests/assets/push_assets.sh
echo "========================================"
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index fac6350..2f149de 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -144,8 +144,10 @@
header_libs: [
"libaudioclient_headers",
- "libmedia_headers",
+ "libbase_headers",
+ "libmedia_datasource_headers",
"media_ndk_headers",
+ "media_plugin_headers",
],
cflags: [
@@ -162,6 +164,18 @@
"signed-integer-overflow",
],
},
+
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ linux: {
+ cflags: [
+ "-DDISABLE_AUDIO_SYSTEM_OFFLOAD",
+ ],
+ }
+ },
}
cc_library_shared {
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index e9ff4d5..823c010 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -4717,10 +4717,18 @@
// This is useful if the pixel is not square
void MPEG4Writer::Track::writePaspBox() {
- mOwner->beginBox("pasp");
- mOwner->writeInt32(1 << 16); // hspacing
- mOwner->writeInt32(1 << 16); // vspacing
- mOwner->endBox(); // pasp
+ // Do not write 'pasp' box unless the track format specifies it.
+ // According to ISO/IEC 14496-12 (ISO base media file format), 'pasp' box
+ // is optional. If present, it overrides the SAR from the video CSD. Only
+ // set it if the track format specifically requests that.
+ int32_t hSpacing, vSpacing;
+ if (mMeta->findInt32(kKeySARWidth, &hSpacing) && (hSpacing > 0)
+ && mMeta->findInt32(kKeySARHeight, &vSpacing) && (vSpacing > 0)) {
+ mOwner->beginBox("pasp");
+ mOwner->writeInt32(hSpacing); // hspacing
+ mOwner->writeInt32(vSpacing); // vspacing
+ mOwner->endBox(); // pasp
+ }
}
int64_t MPEG4Writer::Track::getStartTimeOffsetTimeUs() const {
diff --git a/media/libstagefright/MediaAdapter.cpp b/media/libstagefright/MediaAdapter.cpp
index f1b6e8c..5a2a910 100644
--- a/media/libstagefright/MediaAdapter.cpp
+++ b/media/libstagefright/MediaAdapter.cpp
@@ -114,6 +114,13 @@
return -EINVAL;
}
+ /* As mAdapterLock is unlocked while waiting for signalBufferReturned,
+ * a new buffer for the same track could be pushed from another thread
+ * in the client process, mBufferGatingMutex will help to hold that
+ * until the previous buffer is processed.
+ */
+ std::unique_lock<std::mutex> lk(mBufferGatingMutex);
+
Mutex::Autolock autoLock(mAdapterLock);
if (!mStarted) {
ALOGE("pushBuffer called before start");
diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp
index cab4ebd..8bbffd4 100644
--- a/media/libstagefright/MediaMuxer.cpp
+++ b/media/libstagefright/MediaMuxer.cpp
@@ -175,16 +175,23 @@
status_t MediaMuxer::writeSampleData(const sp<ABuffer> &buffer, size_t trackIndex,
int64_t timeUs, uint32_t flags) {
- Mutex::Autolock autoLock(mMuxerLock);
-
if (buffer.get() == NULL) {
ALOGE("WriteSampleData() get an NULL buffer.");
return -EINVAL;
}
-
- if (mState != STARTED) {
- ALOGE("WriteSampleData() is called in invalid state %d", mState);
- return INVALID_OPERATION;
+ {
+ /* As MediaMuxer's writeSampleData handles inputs from multiple tracks,
+ * limited the scope of mMuxerLock to this inner block so that the
+ * current track's buffer does not wait until the completion
+ * of processing of previous buffer of the same or another track.
+ * It's the responsibility of individual track - MediaAdapter object
+ * to gate its buffers.
+ */
+ Mutex::Autolock autoLock(mMuxerLock);
+ if (mState != STARTED) {
+ ALOGE("WriteSampleData() is called in invalid state %d", mState);
+ return INVALID_OPERATION;
+ }
}
if (trackIndex >= mTrackList.size()) {
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index ef69827..d67874f 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -2178,7 +2178,11 @@
}
// Check if offload is possible for given format, stream type, sample rate,
// bit rate, duration, video and streaming
+#ifdef DISABLE_AUDIO_SYSTEM_OFFLOAD
+ return false;
+#else
return AudioSystem::isOffloadSupported(info);
+#endif
}
HLSTime::HLSTime(const sp<AMessage>& meta) :
diff --git a/media/libstagefright/data/media_codecs_sw.xml b/media/libstagefright/data/media_codecs_sw.xml
index dd2eed3..6571162 100644
--- a/media/libstagefright/data/media_codecs_sw.xml
+++ b/media/libstagefright/data/media_codecs_sw.xml
@@ -295,12 +295,12 @@
<Feature name="bitrate-modes" value="VBR,CBR" />
</MediaCodec>
<MediaCodec name="c2.android.hevc.encoder" type="video/hevc" variant="!slow-cpu">
- <!-- profiles and levels: ProfileMain : MainTierLevel51 -->
- <Limit name="size" min="2x2" max="512x512" />
+ <!-- profiles and levels: ProfileMain : MainTierLevel3 -->
+ <Limit name="size" min="2x2" max="960x544" />
<Limit name="alignment" value="2x2" />
<Limit name="block-size" value="8x8" />
- <Limit name="block-count" range="1-4096" /> <!-- max 512x512 -->
- <Limit name="blocks-per-second" range="1-122880" />
+ <Limit name="block-count" range="1-8160" /> <!-- max 960x544 -->
+ <Limit name="blocks-per-second" range="1-244880" />
<Limit name="frame-rate" range="1-120" />
<Limit name="bitrate" range="1-10000000" />
<Limit name="complexity" range="0-10" default="0" />
diff --git a/media/libstagefright/include/media/stagefright/MediaAdapter.h b/media/libstagefright/include/media/stagefright/MediaAdapter.h
index 177a9e9..c7d7765 100644
--- a/media/libstagefright/include/media/stagefright/MediaAdapter.h
+++ b/media/libstagefright/include/media/stagefright/MediaAdapter.h
@@ -58,6 +58,7 @@
private:
Mutex mAdapterLock;
+ std::mutex mBufferGatingMutex;
// Make sure the read() wait for the incoming buffer.
Condition mBufferReadCond;
// Make sure the pushBuffer() wait for the current buffer consumed.
diff --git a/media/libstagefright/tests/writer/WriterTest.cpp b/media/libstagefright/tests/writer/WriterTest.cpp
index f1c599f..4c0add4 100644
--- a/media/libstagefright/tests/writer/WriterTest.cpp
+++ b/media/libstagefright/tests/writer/WriterTest.cpp
@@ -49,8 +49,32 @@
int32_t channelCount;
};
+enum inputId {
+ // audio streams
+ AAC_1,
+ AAC_ADTS_1,
+ AMR_NB_1,
+ AMR_WB_1,
+ FLAC_1,
+ OPUS_1,
+ VORBIS_1,
+ // video streams
+ AV1_1,
+ AVC_1,
+ H263_1,
+ HEVC_1,
+ MPEG4_1,
+ VP8_1,
+ VP9_1,
+ // heif stream
+ HEIC_1,
+ UNUSED_ID,
+ UNKNOWN_ID,
+};
+
// LookUpTable of clips and metadata for component testing
static const struct InputData {
+ inputId inpId;
const char *mime;
string inputFile;
string info;
@@ -58,61 +82,67 @@
int32_t secondParam;
bool isAudio;
} kInputData[] = {
- {MEDIA_MIMETYPE_AUDIO_OPUS, "bbb_opus_stereo_128kbps_48000hz.opus",
- "bbb_opus_stereo_128kbps_48000hz.info", 48000, 2, true},
- {MEDIA_MIMETYPE_AUDIO_AAC, "bbb_aac_stereo_128kbps_48000hz.aac",
+ {AAC_1, MEDIA_MIMETYPE_AUDIO_AAC, "bbb_aac_stereo_128kbps_48000hz.aac",
"bbb_aac_stereo_128kbps_48000hz.info", 48000, 2, true},
- {MEDIA_MIMETYPE_AUDIO_AAC_ADTS, "Mps_2_c2_fr1_Sc1_Dc2_0x03_raw.adts",
+ {AAC_ADTS_1, MEDIA_MIMETYPE_AUDIO_AAC_ADTS, "Mps_2_c2_fr1_Sc1_Dc2_0x03_raw.adts",
"Mps_2_c2_fr1_Sc1_Dc2_0x03_raw.info", 48000, 2, true},
- {MEDIA_MIMETYPE_AUDIO_AMR_NB, "sine_amrnb_1ch_12kbps_8000hz.amrnb",
+ {AMR_NB_1, MEDIA_MIMETYPE_AUDIO_AMR_NB, "sine_amrnb_1ch_12kbps_8000hz.amrnb",
"sine_amrnb_1ch_12kbps_8000hz.info", 8000, 1, true},
- {MEDIA_MIMETYPE_AUDIO_AMR_WB, "bbb_amrwb_1ch_14kbps_16000hz.amrwb",
+ {AMR_WB_1, MEDIA_MIMETYPE_AUDIO_AMR_WB, "bbb_amrwb_1ch_14kbps_16000hz.amrwb",
"bbb_amrwb_1ch_14kbps_16000hz.info", 16000, 1, true},
- {MEDIA_MIMETYPE_AUDIO_VORBIS, "bbb_vorbis_stereo_128kbps_48000hz.vorbis",
- "bbb_vorbis_stereo_128kbps_48000hz.info", 48000, 2, true},
- {MEDIA_MIMETYPE_AUDIO_FLAC, "bbb_flac_stereo_680kbps_48000hz.flac",
+ {FLAC_1, MEDIA_MIMETYPE_AUDIO_FLAC, "bbb_flac_stereo_680kbps_48000hz.flac",
"bbb_flac_stereo_680kbps_48000hz.info", 48000, 2, true},
- {MEDIA_MIMETYPE_VIDEO_VP9, "bbb_vp9_176x144_285kbps_60fps.vp9",
- "bbb_vp9_176x144_285kbps_60fps.info", 176, 144, false},
- {MEDIA_MIMETYPE_VIDEO_VP8, "bbb_vp8_176x144_240kbps_60fps.vp8",
- "bbb_vp8_176x144_240kbps_60fps.info", 176, 144, false},
- {MEDIA_MIMETYPE_VIDEO_AVC, "bbb_avc_176x144_300kbps_60fps.h264",
+ {OPUS_1, MEDIA_MIMETYPE_AUDIO_OPUS, "bbb_opus_stereo_128kbps_48000hz.opus",
+ "bbb_opus_stereo_128kbps_48000hz.info", 48000, 2, true},
+ {VORBIS_1, MEDIA_MIMETYPE_AUDIO_VORBIS, "bbb_vorbis_stereo_128kbps_48000hz.vorbis",
+ "bbb_vorbis_stereo_128kbps_48000hz.info", 48000, 2, true},
+
+ {AV1_1, MEDIA_MIMETYPE_VIDEO_AV1, "bbb_av1_176_144.av1", "bbb_av1_176_144.info", 176, 144,
+ false},
+ {AVC_1, MEDIA_MIMETYPE_VIDEO_AVC, "bbb_avc_176x144_300kbps_60fps.h264",
"bbb_avc_176x144_300kbps_60fps.info", 176, 144, false},
- {MEDIA_MIMETYPE_VIDEO_HEVC, "bbb_hevc_176x144_176kbps_60fps.hevc",
- "bbb_hevc_176x144_176kbps_60fps.info", 176, 144, false},
- {MEDIA_MIMETYPE_VIDEO_AV1, "bbb_av1_176_144.av1", "bbb_av1_176_144.info", 176, 144, false},
- {MEDIA_MIMETYPE_VIDEO_H263, "bbb_h263_352x288_300kbps_12fps.h263",
+ {H263_1, MEDIA_MIMETYPE_VIDEO_H263, "bbb_h263_352x288_300kbps_12fps.h263",
"bbb_h263_352x288_300kbps_12fps.info", 352, 288, false},
- {MEDIA_MIMETYPE_VIDEO_MPEG4, "bbb_mpeg4_352x288_512kbps_30fps.m4v",
+ {HEVC_1, MEDIA_MIMETYPE_VIDEO_HEVC, "bbb_hevc_176x144_176kbps_60fps.hevc",
+ "bbb_hevc_176x144_176kbps_60fps.info", 176, 144, false},
+ {MPEG4_1, MEDIA_MIMETYPE_VIDEO_MPEG4, "bbb_mpeg4_352x288_512kbps_30fps.m4v",
"bbb_mpeg4_352x288_512kbps_30fps.info", 352, 288, false},
+ {VP8_1, MEDIA_MIMETYPE_VIDEO_VP8, "bbb_vp8_176x144_240kbps_60fps.vp8",
+ "bbb_vp8_176x144_240kbps_60fps.info", 176, 144, false},
+ {VP9_1, MEDIA_MIMETYPE_VIDEO_VP9, "bbb_vp9_176x144_285kbps_60fps.vp9",
+ "bbb_vp9_176x144_285kbps_60fps.info", 176, 144, false},
+
+ {HEIC_1, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC, "bbb_hevc_176x144_176kbps_60fps.hevc",
+ "bbb_heic_176x144_176kbps_60fps.info", 176, 144, false},
};
class WriterTest {
public:
- WriterTest() : mWriter(nullptr), mFileMeta(nullptr), mCurrentTrack(nullptr) {}
+ WriterTest() : mWriter(nullptr), mFileMeta(nullptr) {}
~WriterTest() {
if (mFileMeta) {
mFileMeta.clear();
mFileMeta = nullptr;
}
- if (mCurrentTrack) {
- mCurrentTrack->stop();
- mCurrentTrack.clear();
- mCurrentTrack = nullptr;
- }
if (mWriter) {
mWriter.clear();
mWriter = nullptr;
}
- mBufferInfo.clear();
- if (mInputStream.is_open()) mInputStream.close();
if (gEnv->cleanUp()) remove(OUTPUT_FILE_NAME);
+
+ for (int32_t idx = 0; idx < kMaxTrackCount; idx++) {
+ mBufferInfo[idx].clear();
+ if (mCurrentTrack[idx]) {
+ mCurrentTrack[idx]->stop();
+ mCurrentTrack[idx].clear();
+ mCurrentTrack[idx] = nullptr;
+ }
+ if (mInputStream[idx].is_open()) mInputStream[idx].close();
+ }
}
void setupWriterType(string writerFormat) {
- mNumCsds = 0;
- mInputFrameId = 0;
mWriterName = unknown_comp;
mDisableTest = false;
static const std::map<std::string, standardWriters> mapWriter = {
@@ -128,11 +158,11 @@
}
}
- void getInputBufferInfo(string inputFileName, string inputInfo);
+ void getInputBufferInfo(string inputFileName, string inputInfo, int32_t idx = 0);
int32_t createWriter(int32_t fd);
- int32_t addWriterSource(bool isAudio, configFormat params);
+ int32_t addWriterSource(bool isAudio, configFormat params, int32_t idx = 0);
enum standardWriters {
OGG,
@@ -149,38 +179,42 @@
standardWriters mWriterName;
sp<MediaWriter> mWriter;
sp<MetaData> mFileMeta;
- sp<MediaAdapter> mCurrentTrack;
+ sp<MediaAdapter> mCurrentTrack[kMaxTrackCount]{};
bool mDisableTest;
- int32_t mNumCsds;
- int32_t mInputFrameId;
- ifstream mInputStream;
- vector<BufferInfo> mBufferInfo;
+ int32_t mNumCsds[kMaxTrackCount]{};
+ int32_t mInputFrameId[kMaxTrackCount]{};
+ ifstream mInputStream[kMaxTrackCount]{};
+ vector<BufferInfo> mBufferInfo[kMaxTrackCount];
};
-class WriteFunctionalityTest : public WriterTest,
- public ::testing::TestWithParam<pair<string, int32_t>> {
+class WriteFunctionalityTest
+ : public WriterTest,
+ public ::testing::TestWithParam<tuple<string /* writerFormat*/, inputId /* inputId0*/,
+ inputId /* inputId1*/, float /* BufferInterval*/>> {
public:
- virtual void SetUp() override { setupWriterType(GetParam().first); }
+ virtual void SetUp() override { setupWriterType(get<0>(GetParam())); }
};
-void WriterTest::getInputBufferInfo(string inputFileName, string inputInfo) {
+void WriterTest::getInputBufferInfo(string inputFileName, string inputInfo, int32_t idx) {
std::ifstream eleInfo;
eleInfo.open(inputInfo.c_str());
ASSERT_EQ(eleInfo.is_open(), true);
int32_t bytesCount = 0;
uint32_t flags = 0;
int64_t timestamp = 0;
+ int32_t numCsds = 0;
while (1) {
if (!(eleInfo >> bytesCount)) break;
eleInfo >> flags;
eleInfo >> timestamp;
- mBufferInfo.push_back({bytesCount, flags, timestamp});
- if (flags == CODEC_CONFIG_FLAG) mNumCsds++;
+ mBufferInfo[idx].push_back({bytesCount, flags, timestamp});
+ if (flags == CODEC_CONFIG_FLAG) numCsds++;
}
eleInfo.close();
- mInputStream.open(inputFileName.c_str(), std::ifstream::binary);
- ASSERT_EQ(mInputStream.is_open(), true);
+ mNumCsds[idx] = numCsds;
+ mInputStream[idx].open(inputFileName.c_str(), std::ifstream::binary);
+ ASSERT_EQ(mInputStream[idx].is_open(), true);
}
int32_t WriterTest::createWriter(int32_t fd) {
@@ -226,10 +260,10 @@
return 0;
}
-int32_t WriterTest::addWriterSource(bool isAudio, configFormat params) {
- if (mInputFrameId) return -1;
+int32_t WriterTest::addWriterSource(bool isAudio, configFormat params, int32_t idx) {
+ if (mInputFrameId[idx]) return -1;
sp<AMessage> format = new AMessage;
- if (mInputStream.is_open()) {
+ if (mInputStream[idx].is_open()) {
format->setString("mime", params.mime);
if (isAudio) {
format->setInt32("channel-count", params.channelCount);
@@ -238,25 +272,34 @@
format->setInt32("width", params.width);
format->setInt32("height", params.height);
}
-
- int32_t status =
- writeHeaderBuffers(mInputStream, mBufferInfo, mInputFrameId, format, mNumCsds);
- if (status != 0) return -1;
+ if (mNumCsds[idx]) {
+ int32_t status = writeHeaderBuffers(mInputStream[idx], mBufferInfo[idx],
+ mInputFrameId[idx], format, mNumCsds[idx]);
+ if (status != 0) return -1;
+ }
}
+
sp<MetaData> trackMeta = new MetaData;
convertMessageToMetaData(format, trackMeta);
- mCurrentTrack = new MediaAdapter(trackMeta);
- if (mCurrentTrack == nullptr) {
+ mCurrentTrack[idx] = new MediaAdapter(trackMeta);
+ if (mCurrentTrack[idx] == nullptr) {
ALOGE("MediaAdapter returned nullptr");
return -1;
}
- status_t result = mWriter->addSource(mCurrentTrack);
+ status_t result = mWriter->addSource(mCurrentTrack[idx]);
return result;
}
void getFileDetails(string &inputFilePath, string &info, configFormat ¶ms, bool &isAudio,
- int32_t streamIndex = 0) {
- if (streamIndex >= sizeof(kInputData) / sizeof(kInputData[0])) {
+ inputId inpId) {
+ int32_t inputDataSize = sizeof(kInputData) / sizeof(kInputData[0]);
+ int32_t streamIndex = 0;
+ for (; streamIndex < inputDataSize; streamIndex++) {
+ if (inpId == kInputData[streamIndex].inpId) {
+ break;
+ }
+ }
+ if (streamIndex == inputDataSize) {
return;
}
inputFilePath += kInputData[streamIndex].inputFile;
@@ -284,14 +327,14 @@
// Creating writer within a test scope. Destructor should be called when the test ends
ASSERT_EQ((status_t)OK, createWriter(fd))
- << "Failed to create writer for output format:" << GetParam().first;
+ << "Failed to create writer for output format:" << get<0>(GetParam());
}
TEST_P(WriteFunctionalityTest, WriterTest) {
if (mDisableTest) return;
ALOGV("Checks if for a given input, a valid muxed file has been created or not");
- string writerFormat = GetParam().first;
+ string writerFormat = get<0>(GetParam());
string outputFile = OUTPUT_FILE_NAME;
int32_t fd =
open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
@@ -300,25 +343,49 @@
int32_t status = createWriter(fd);
ASSERT_EQ((status_t)OK, status) << "Failed to create writer for output format:" << writerFormat;
- string inputFile = gEnv->getRes();
- string inputInfo = gEnv->getRes();
- configFormat param;
- bool isAudio;
- int32_t inputFileIdx = GetParam().second;
- getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
- ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
+ inputId inpId[] = {get<1>(GetParam()), get<2>(GetParam())};
+ ASSERT_NE(inpId[0], UNUSED_ID) << "Test expects first inputId to be a valid id";
- ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
- status = addWriterSource(isAudio, param);
- ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
+ int32_t numTracks = 1;
+ if (inpId[1] != UNUSED_ID) {
+ numTracks++;
+ }
+ for (int32_t idx = 0; idx < numTracks; idx++) {
+ string inputFile = gEnv->getRes();
+ string inputInfo = gEnv->getRes();
+ configFormat param;
+ bool isAudio;
+ getFileDetails(inputFile, inputInfo, param, isAudio, inpId[idx]);
+ ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
+
+ ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo, idx));
+ status = addWriterSource(isAudio, param, idx);
+ ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
+ }
status = mWriter->start(mFileMeta.get());
ASSERT_EQ((status_t)OK, status);
- status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack, 0,
- mBufferInfo.size());
- ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
- mCurrentTrack->stop();
+ float interval = get<3>(GetParam());
+ ASSERT_LE(interval, 1.0f) << "Buffer interval invalid. Should be less than or equal to 1.0";
+ size_t range = 0;
+ int32_t loopCount = 0;
+ int32_t offset[kMaxTrackCount]{};
+ while (loopCount < ceil(1.0 / interval)) {
+ for (int32_t idx = 0; idx < numTracks; idx++) {
+ range = mBufferInfo[idx].size() * interval;
+ status = sendBuffersToWriter(mInputStream[idx], mBufferInfo[idx], mInputFrameId[idx],
+ mCurrentTrack[idx], offset[idx], range);
+ ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
+ offset[idx] += range;
+ }
+ loopCount++;
+ }
+ for (int32_t idx = 0; idx < kMaxTrackCount; idx++) {
+ if (mCurrentTrack[idx]) {
+ mCurrentTrack[idx]->stop();
+ }
+ }
status = mWriter->stop();
ASSERT_EQ((status_t)OK, status) << "Failed to stop the writer";
close(fd);
@@ -328,7 +395,7 @@
if (mDisableTest) return;
ALOGV("Validates the pause() api of writers");
- string writerFormat = GetParam().first;
+ string writerFormat = get<0>(GetParam());
string outputFile = OUTPUT_FILE_NAME;
int32_t fd =
open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
@@ -341,8 +408,10 @@
string inputInfo = gEnv->getRes();
configFormat param;
bool isAudio;
- int32_t inputFileIdx = GetParam().second;
- getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
+ inputId inpId = get<1>(GetParam());
+ ASSERT_NE(inpId, UNUSED_ID) << "Test expects first inputId to be a valid id";
+
+ getFileDetails(inputFile, inputInfo, param, isAudio, inpId);
ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
@@ -351,8 +420,8 @@
status = mWriter->start(mFileMeta.get());
ASSERT_EQ((status_t)OK, status);
- status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack, 0,
- mBufferInfo.size() / 4);
+ status = sendBuffersToWriter(mInputStream[0], mBufferInfo[0], mInputFrameId[0],
+ mCurrentTrack[0], 0, mBufferInfo[0].size() / 4);
ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
bool isPaused = false;
@@ -362,19 +431,19 @@
isPaused = true;
}
// In the pause state, writers shouldn't write anything. Testing the writers for the same
- int32_t numFramesPaused = mBufferInfo.size() / 4;
- status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack,
- mInputFrameId, numFramesPaused, isPaused);
+ int32_t numFramesPaused = mBufferInfo[0].size() / 4;
+ status = sendBuffersToWriter(mInputStream[0], mBufferInfo[0], mInputFrameId[0],
+ mCurrentTrack[0], mInputFrameId[0], numFramesPaused, isPaused);
ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
if (isPaused) {
status = mWriter->start(mFileMeta.get());
ASSERT_EQ((status_t)OK, status);
}
- status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack,
- mInputFrameId, mBufferInfo.size());
+ status = sendBuffersToWriter(mInputStream[0], mBufferInfo[0], mInputFrameId[0],
+ mCurrentTrack[0], mInputFrameId[0], mBufferInfo[0].size());
ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
- mCurrentTrack->stop();
+ mCurrentTrack[0]->stop();
status = mWriter->stop();
ASSERT_EQ((status_t)OK, status) << "Failed to stop the writer";
@@ -392,7 +461,7 @@
open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
ASSERT_GE(fd, 0) << "Failed to open output file to dump writer's data";
- string writerFormat = GetParam().first;
+ string writerFormat = get<0>(GetParam());
int32_t status = createWriter(fd);
ASSERT_EQ(status, (status_t)OK) << "Failed to create writer for output format:" << writerFormat;
@@ -400,8 +469,10 @@
string inputInfo = gEnv->getRes();
configFormat param;
bool isAudio;
- int32_t inputFileIdx = GetParam().second;
- getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
+ inputId inpId = get<1>(GetParam());
+ ASSERT_NE(inpId, UNUSED_ID) << "Test expects first inputId to be a valid id";
+
+ getFileDetails(inputFile, inputInfo, param, isAudio, inpId);
ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
@@ -418,8 +489,8 @@
mWriter->start(mFileMeta.get());
}
- status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack, 0,
- mBufferInfo.size() / 4);
+ status = sendBuffersToWriter(mInputStream[0], mBufferInfo[0], mInputFrameId[0],
+ mCurrentTrack[0], 0, mBufferInfo[0].size() / 4);
ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
for (int32_t count = 0; count < kMaxCount; count++) {
@@ -428,20 +499,20 @@
}
mWriter->pause();
- int32_t numFramesPaused = mBufferInfo.size() / 4;
- status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack,
- mInputFrameId, numFramesPaused, true);
+ int32_t numFramesPaused = mBufferInfo[0].size() / 4;
+ status = sendBuffersToWriter(mInputStream[0], mBufferInfo[0], mInputFrameId[0],
+ mCurrentTrack[0], mInputFrameId[0], numFramesPaused, true);
ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
for (int32_t count = 0; count < kMaxCount; count++) {
mWriter->start(mFileMeta.get());
}
- status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack,
- mInputFrameId, mBufferInfo.size());
+ status = sendBuffersToWriter(mInputStream[0], mBufferInfo[0], mInputFrameId[0],
+ mCurrentTrack[0], mInputFrameId[0], mBufferInfo[0].size());
ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
- mCurrentTrack->stop();
+ mCurrentTrack[0]->stop();
// first stop should succeed.
status = mWriter->stop();
@@ -454,15 +525,13 @@
close(fd);
}
-class ListenerTest : public WriterTest,
- public ::testing::TestWithParam<
- tuple<string /* writerFormat*/, int32_t /* inputFileIdx*/,
- float /* FileSizeLimit*/, float /* FileDurationLimit*/>> {
+class ListenerTest
+ : public WriterTest,
+ public ::testing::TestWithParam<tuple<
+ string /* writerFormat*/, inputId /* inputId0*/, inputId /* inputId1*/,
+ float /* FileSizeLimit*/, float /* FileDurationLimit*/, float /* BufferInterval*/>> {
public:
- virtual void SetUp() override {
- tuple<string, int32_t, float, float> params = GetParam();
- setupWriterType(get<0>(params));
- }
+ virtual void SetUp() override { setupWriterType(get<0>(GetParam())); }
};
TEST_P(ListenerTest, SetMaxFileLimitsTest) {
@@ -470,8 +539,7 @@
if (mDisableTest || mWriterName != MPEG4) return;
ALOGV("Validates writer when max file limits are set");
- tuple<string, int32_t, float, float> params = GetParam();
- string writerFormat = get<0>(params);
+ string writerFormat = get<0>(GetParam());
string outputFile = OUTPUT_FILE_NAME;
int32_t fd =
open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
@@ -480,30 +548,42 @@
int32_t status = createWriter(fd);
ASSERT_EQ((status_t)OK, status) << "Failed to create writer for output format:" << writerFormat;
- string inputFile = gEnv->getRes();
- string inputInfo = gEnv->getRes();
- configFormat param;
- bool isAudio;
- int32_t inputFileIdx = get<1>(params);
- getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
- ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
+ inputId inpId[] = {get<1>(GetParam()), get<2>(GetParam())};
+ ASSERT_NE(inpId[0], UNUSED_ID) << "Test expects first inputId to be a valid id";
- ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
- status = addWriterSource(isAudio, param);
- ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
+ size_t inputFileSize = 0;
+ int64_t lastFrameTimeStampUs = INT_MAX;
+ int32_t numTracks = 1;
+ if (inpId[1] != UNUSED_ID) {
+ numTracks++;
+ }
+ for (int32_t idx = 0; idx < numTracks; idx++) {
+ string inputFile = gEnv->getRes();
+ string inputInfo = gEnv->getRes();
+ configFormat param;
+ bool isAudio;
+ getFileDetails(inputFile, inputInfo, param, isAudio, inpId[idx]);
+ ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
- // Read file properties
- struct stat buf;
- status = stat(inputFile.c_str(), &buf);
- ASSERT_EQ(0, status);
+ ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo, idx));
+ status = addWriterSource(isAudio, param, idx);
+ ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
- float fileSizeLimit = get<2>(params);
- float fileDurationLimit = get<3>(params);
+ // Read file properties
+ struct stat buf;
+ status = stat(inputFile.c_str(), &buf);
+ ASSERT_EQ(0, status);
+
+ inputFileSize += buf.st_size;
+ if (lastFrameTimeStampUs > mBufferInfo[idx][mBufferInfo[idx].size() - 1].timeUs) {
+ lastFrameTimeStampUs = mBufferInfo[idx][mBufferInfo[idx].size() - 1].timeUs;
+ }
+ }
+
+ float fileSizeLimit = get<3>(GetParam());
+ float fileDurationLimit = get<4>(GetParam());
int64_t maxFileSize = 0;
int64_t maxFileDuration = 0;
-
- size_t inputFileSize = buf.st_size;
- int64_t lastFrameTimeStampUs = mBufferInfo[mBufferInfo.size() - 1].timeUs;
if (fileSizeLimit > 0) {
maxFileSize = (int64_t)(fileSizeLimit * inputFileSize);
mWriter->setMaxFileSize(maxFileSize);
@@ -518,14 +598,33 @@
mWriter->setListener(listener);
status = mWriter->start(mFileMeta.get());
-
ASSERT_EQ((status_t)OK, status);
- status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack, 0,
- mBufferInfo.size(), false, listener);
- ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
+
+ float interval = get<5>(GetParam());
+ ASSERT_LE(interval, 1.0f) << "Buffer interval invalid. Should be less than or equal to 1.0";
+
+ size_t range = 0;
+ int32_t loopCount = 0;
+ int32_t offset[kMaxTrackCount]{};
+ while (loopCount < ceil(1.0 / interval)) {
+ for (int32_t idx = 0; idx < numTracks; idx++) {
+ range = mBufferInfo[idx].size() * interval;
+ status = sendBuffersToWriter(mInputStream[idx], mBufferInfo[idx], mInputFrameId[idx],
+ mCurrentTrack[idx], offset[idx], range, false, listener);
+ ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
+ offset[idx] += range;
+ }
+ loopCount++;
+ }
+
ASSERT_TRUE(mWriter->reachedEOS()) << "EOS not signalled.";
- mCurrentTrack->stop();
+ for (int32_t idx = 0; idx < kMaxTrackCount; idx++) {
+ if (mCurrentTrack[idx]) {
+ mCurrentTrack[idx]->stop();
+ }
+ }
+
status = mWriter->stop();
ASSERT_EQ((status_t)OK, status) << "Failed to stop the writer";
close(fd);
@@ -552,23 +651,57 @@
// TODO: (b/150923387)
// Add WEBM input
-INSTANTIATE_TEST_SUITE_P(
- ListenerTestAll, ListenerTest,
- ::testing::Values(make_tuple("ogg", 0, 0.7, 0.3), make_tuple("aac", 1, 0.6, 0.7),
- make_tuple("mpeg4", 1, 0.4, 0.3), make_tuple("amrnb", 3, 0.2, 0.6),
- make_tuple("amrwb", 4, 0.5, 0.5), make_tuple("mpeg2Ts", 1, 0.2, 1)));
+INSTANTIATE_TEST_SUITE_P(ListenerTestAll, ListenerTest,
+ ::testing::Values(make_tuple("aac", AAC_1, UNUSED_ID, 0.6, 0.7, 1),
+ make_tuple("amrnb", AMR_NB_1, UNUSED_ID, 0.2, 0.6, 1),
+ make_tuple("amrwb", AMR_WB_1, UNUSED_ID, 0.5, 0.5, 1),
+ make_tuple("mpeg2Ts", AAC_1, UNUSED_ID, 0.2, 1, 1),
+ make_tuple("mpeg4", AAC_1, UNUSED_ID, 0.4, 0.3, 0.25),
+ make_tuple("ogg", OPUS_1, UNUSED_ID, 0.7, 0.3, 1)));
// TODO: (b/144476164)
// Add AAC_ADTS, FLAC, AV1 input
-INSTANTIATE_TEST_SUITE_P(WriterTestAll, WriteFunctionalityTest,
- ::testing::Values(make_pair("ogg", 0), make_pair("webm", 0),
- make_pair("aac", 1), make_pair("mpeg4", 1),
- make_pair("amrnb", 3), make_pair("amrwb", 4),
- make_pair("webm", 5), make_pair("webm", 7),
- make_pair("webm", 8), make_pair("mpeg4", 9),
- make_pair("mpeg4", 10), make_pair("mpeg4", 12),
- make_pair("mpeg4", 13), make_pair("mpeg2Ts", 1),
- make_pair("mpeg2Ts", 9)));
+INSTANTIATE_TEST_SUITE_P(
+ WriterTestAll, WriteFunctionalityTest,
+ ::testing::Values(
+ make_tuple("aac", AAC_1, UNUSED_ID, 1),
+
+ make_tuple("amrnb", AMR_NB_1, UNUSED_ID, 1),
+ make_tuple("amrwb", AMR_WB_1, UNUSED_ID, 1),
+
+ // TODO(b/144902018): Enable test for mpeg2ts
+ // make_tuple("mpeg2Ts", AAC_1, UNUSED_ID, 1),
+ // make_tuple("mpeg2Ts", AVC_1, UNUSED_ID, 1),
+ // TODO(b/156355857): Add multitrack for mpeg2ts
+ // make_tuple("mpeg2Ts", AAC_1, AVC_1, 0.50),
+ // make_tuple("mpeg2Ts", AVC_1, AAC_1, 0.25),
+
+ make_tuple("mpeg4", AAC_1, UNUSED_ID, 1),
+ make_tuple("mpeg4", AMR_NB_1, UNUSED_ID, 1),
+ make_tuple("mpeg4", AMR_WB_1, UNUSED_ID, 1),
+ make_tuple("mpeg4", AVC_1, UNUSED_ID, 1),
+ make_tuple("mpeg4", H263_1, UNUSED_ID, 1),
+ make_tuple("mpeg4", HEIC_1, UNUSED_ID, 1),
+ make_tuple("mpeg4", HEVC_1, UNUSED_ID, 1),
+ make_tuple("mpeg4", MPEG4_1, UNUSED_ID, 1),
+ make_tuple("mpeg4", AAC_1, AVC_1, 0.25),
+ make_tuple("mpeg4", AVC_1, AAC_1, 0.75),
+ make_tuple("mpeg4", AMR_WB_1, AAC_1, 0.75),
+ make_tuple("mpeg4", HEVC_1, AMR_WB_1, 0.25),
+ make_tuple("mpeg4", H263_1, AMR_NB_1, 0.50),
+ make_tuple("mpeg4", MPEG4_1, AAC_1, 0.75),
+ make_tuple("mpeg4", AMR_NB_1, AMR_WB_1, 0.25),
+ make_tuple("mpeg4", H263_1, AMR_NB_1, 0.50),
+ make_tuple("mpeg4", MPEG4_1, HEVC_1, 0.75),
+
+ make_tuple("ogg", OPUS_1, UNUSED_ID, 1),
+
+ make_tuple("webm", OPUS_1, UNUSED_ID, 1),
+ make_tuple("webm", VORBIS_1, UNUSED_ID, 1),
+ make_tuple("webm", VP8_1, UNUSED_ID, 1),
+ make_tuple("webm", VP9_1, UNUSED_ID, 1),
+ make_tuple("webm", VP8_1, OPUS_1, 0.50),
+ make_tuple("webm", VORBIS_1, VP8_1, 0.25)));
int main(int argc, char **argv) {
gEnv = new WriterTestEnvironment();
diff --git a/media/libstagefright/tests/writer/WriterUtility.h b/media/libstagefright/tests/writer/WriterUtility.h
index 5e19973..5e79298 100644
--- a/media/libstagefright/tests/writer/WriterUtility.h
+++ b/media/libstagefright/tests/writer/WriterUtility.h
@@ -31,6 +31,7 @@
#define CODEC_CONFIG_FLAG 32
+constexpr uint32_t kMaxTrackCount = 2;
constexpr uint32_t kMaxCSDStrlen = 16;
constexpr uint32_t kMaxCount = 20;
diff --git a/services/audioflinger/AudioStreamOut.cpp b/services/audioflinger/AudioStreamOut.cpp
index d13cb8f..7e06096 100644
--- a/services/audioflinger/AudioStreamOut.cpp
+++ b/services/audioflinger/AudioStreamOut.cpp
@@ -164,6 +164,10 @@
stream = outStream;
mHalFormatHasProportionalFrames = audio_has_proportional_frames(config->format);
status = stream->getFrameSize(&mHalFrameSize);
+ LOG_ALWAYS_FATAL_IF(status != OK, "Error retrieving frame size from HAL: %d", status);
+ LOG_ALWAYS_FATAL_IF(mHalFrameSize <= 0, "Error frame size was %zu but must be greater than"
+ " zero", mHalFrameSize);
+
}
return status;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 7e63851..b433cf9 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -6061,10 +6061,6 @@
bool trackPaused = false;
bool trackStopped = false;
- if ((mType == DIRECT) && audio_is_linear_pcm(mFormat) && !usesHwAvSync()) {
- return !mStandby;
- }
-
// do not put the HAL in standby when paused. AwesomePlayer clear the offloaded AudioTrack
// after a timeout and we will enter standby then.
if (mTracks.size() > 0) {
@@ -8435,13 +8431,14 @@
}
result = mInput->stream->getFrameSize(&mFrameSize);
LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving frame size from HAL: %d", result);
+ LOG_ALWAYS_FATAL_IF(mFrameSize <= 0, "Error frame size was %zu but must be greater than zero",
+ mFrameSize);
result = mInput->stream->getBufferSize(&mBufferSize);
LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving buffer size from HAL: %d", result);
mFrameCount = mBufferSize / mFrameSize;
- ALOGV("%p RecordThread params: mChannelCount=%u, mFormat=%#x, mFrameSize=%lld, "
- "mBufferSize=%lld, mFrameCount=%lld",
- this, mChannelCount, mFormat, (long long)mFrameSize, (long long)mBufferSize,
- (long long)mFrameCount);
+ ALOGV("%p RecordThread params: mChannelCount=%u, mFormat=%#x, mFrameSize=%zu, "
+ "mBufferSize=%zu, mFrameCount=%zu",
+ this, mChannelCount, mFormat, mFrameSize, mBufferSize, mFrameCount);
// This is the formula for calculating the temporary buffer size.
// With 7 HAL buffers, we can guarantee ability to down-sample the input by ratio of 6:1 to
// 1 full output buffer, regardless of the alignment of the available input.
@@ -9017,6 +9014,8 @@
LOG_ALWAYS_FATAL_IF(!audio_is_linear_pcm(mFormat), "HAL format %#x is not linear pcm", mFormat);
result = mHalStream->getFrameSize(&mFrameSize);
LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving frame size from HAL: %d", result);
+ LOG_ALWAYS_FATAL_IF(mFrameSize <= 0, "Error frame size was %zu but must be greater than zero",
+ mFrameSize);
result = mHalStream->getBufferSize(&mBufferSize);
LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving buffer size from HAL: %d", result);
mFrameCount = mBufferSize / mFrameSize;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 3730c34..c5c13e9 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -5770,15 +5770,6 @@
DeviceVector filteredDevices = outputDesc->filterSupportedDevices(devices);
DeviceVector prevDevices = outputDesc->devices();
- // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
- // output profile or if new device is not supported AND previous device(s) is(are) still
- // available (otherwise reset device must be done on the output)
- if (!devices.isEmpty() && filteredDevices.isEmpty() &&
- !mAvailableOutputDevices.filter(prevDevices).empty()) {
- ALOGV("%s: unsupported device %s for output", __func__, devices.toString().c_str());
- return 0;
- }
-
ALOGV("setOutputDevices() prevDevice %s", prevDevices.toString().c_str());
if (!filteredDevices.isEmpty()) {
@@ -5793,6 +5784,17 @@
muteWaitMs = 0;
}
+ // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
+ // output profile or if new device is not supported AND previous device(s) is(are) still
+ // available (otherwise reset device must be done on the output)
+ if (!devices.isEmpty() && filteredDevices.isEmpty() &&
+ !mAvailableOutputDevices.filter(prevDevices).empty()) {
+ ALOGV("%s: unsupported device %s for output", __func__, devices.toString().c_str());
+ // restore previous device after evaluating strategy mute state
+ outputDesc->setDevices(prevDevices);
+ return muteWaitMs;
+ }
+
// Do not change the routing if:
// the requested device is AUDIO_DEVICE_NONE
// OR the requested device is the same as current device
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 9577160..34d07b6 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -593,7 +593,7 @@
}
// including successes gets very verbose
- // but once we cut over to westworld, log them all.
+ // but once we cut over to statsd, log them all.
if (status != NO_ERROR) {
static constexpr char kAudioPolicy[] = "audiopolicy";
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 1a0881f..a63f402 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -620,7 +620,8 @@
if (mPendingInputFrames.find(mAppSegmentFrameNumbers.front()) == mPendingInputFrames.end()) {
ALOGE("%s: mPendingInputFrames doesn't contain frameNumber %" PRId64, __FUNCTION__,
mAppSegmentFrameNumbers.front());
- mInputYuvBuffers.erase(it);
+ mInputAppSegmentBuffers.erase(it);
+ mAppSegmentFrameNumbers.pop();
continue;
}
@@ -664,6 +665,7 @@
ALOGE("%s: mPendingInputFrames doesn't contain frameNumber %" PRId64, __FUNCTION__,
mMainImageFrameNumbers.front());
mInputYuvBuffers.erase(it);
+ mMainImageFrameNumbers.pop();
continue;
}
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index deeec7e..a898df9 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -1043,8 +1043,9 @@
}
CaptureOutputStates states {
mId,
- mInFlightLock, mInFlightMap,
- mOutputLock, mResultQueue, mResultSignal,
+ mInFlightLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mInFlightMap, mOutputLock, mResultQueue, mResultSignal,
mNextShutterFrameNumber,
mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
mNextResultFrameNumber,
@@ -1100,8 +1101,9 @@
CaptureOutputStates states {
mId,
- mInFlightLock, mInFlightMap,
- mOutputLock, mResultQueue, mResultSignal,
+ mInFlightLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mInFlightMap, mOutputLock, mResultQueue, mResultSignal,
mNextShutterFrameNumber,
mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
mNextResultFrameNumber,
@@ -1139,8 +1141,9 @@
CaptureOutputStates states {
mId,
- mInFlightLock, mInFlightMap,
- mOutputLock, mResultQueue, mResultSignal,
+ mInFlightLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mInFlightMap, mOutputLock, mResultQueue, mResultSignal,
mNextShutterFrameNumber,
mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
mNextResultFrameNumber,
@@ -5901,11 +5904,13 @@
// though technically no other thread should be talking to Camera3Device at this point
Camera3OfflineStates offlineStates(
mTagMonitor, mVendorTagId, mUseHalBufManager, mNeedFixupMonochromeTags,
- mUsePartialResult, mNumPartialResults, mNextResultFrameNumber,
- mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mNextShutterFrameNumber, mNextReprocessShutterFrameNumber,
- mNextZslStillShutterFrameNumber, mDeviceInfo, mPhysicalDeviceInfoMap,
- mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers);
+ mUsePartialResult, mNumPartialResults, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mNextResultFrameNumber, mNextReprocessResultFrameNumber,
+ mNextZslStillResultFrameNumber, mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mDeviceInfo, mPhysicalDeviceInfoMap, mDistortionMappers,
+ mZoomRatioMappers, mRotateAndCropMappers);
*session = new Camera3OfflineSession(mId, inputStream, offlineStreamSet,
std::move(bufferRecords), offlineReqs, offlineStates, offlineSession);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 2069841..408f1f9 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -1010,6 +1010,9 @@
std::mutex mInFlightLock;
camera3::InFlightRequestMap mInFlightMap;
nsecs_t mExpectedInflightDuration = 0;
+ int64_t mLastCompletedRegularFrameNumber = -1;
+ int64_t mLastCompletedReprocessFrameNumber = -1;
+ int64_t mLastCompletedZslFrameNumber = -1;
// End of mInFlightLock protection scope
int mInFlightStatusId; // const after initialize
diff --git a/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp b/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
index 5942868..95f9633 100644
--- a/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
@@ -61,6 +61,9 @@
mNeedFixupMonochromeTags(offlineStates.mNeedFixupMonochromeTags),
mUsePartialResult(offlineStates.mUsePartialResult),
mNumPartialResults(offlineStates.mNumPartialResults),
+ mLastCompletedRegularFrameNumber(offlineStates.mLastCompletedRegularFrameNumber),
+ mLastCompletedReprocessFrameNumber(offlineStates.mLastCompletedReprocessFrameNumber),
+ mLastCompletedZslFrameNumber(offlineStates.mLastCompletedZslFrameNumber),
mNextResultFrameNumber(offlineStates.mNextResultFrameNumber),
mNextReprocessResultFrameNumber(offlineStates.mNextReprocessResultFrameNumber),
mNextZslStillResultFrameNumber(offlineStates.mNextZslStillResultFrameNumber),
@@ -247,8 +250,9 @@
CaptureOutputStates states {
mId,
- mOfflineReqsLock, mOfflineReqs,
- mOutputLock, mResultQueue, mResultSignal,
+ mOfflineReqsLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
mNextShutterFrameNumber,
mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
mNextResultFrameNumber,
@@ -285,8 +289,9 @@
CaptureOutputStates states {
mId,
- mOfflineReqsLock, mOfflineReqs,
- mOutputLock, mResultQueue, mResultSignal,
+ mOfflineReqsLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
mNextShutterFrameNumber,
mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
mNextResultFrameNumber,
@@ -318,8 +323,9 @@
CaptureOutputStates states {
mId,
- mOfflineReqsLock, mOfflineReqs,
- mOutputLock, mResultQueue, mResultSignal,
+ mOfflineReqsLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
mNextShutterFrameNumber,
mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
mNextResultFrameNumber,
diff --git a/services/camera/libcameraservice/device3/Camera3OfflineSession.h b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
index 208f70d..c4c7a85 100644
--- a/services/camera/libcameraservice/device3/Camera3OfflineSession.h
+++ b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
@@ -57,10 +57,11 @@
const TagMonitor& tagMonitor, const metadata_vendor_id_t vendorTagId,
const bool useHalBufManager, const bool needFixupMonochromeTags,
const bool usePartialResult, const uint32_t numPartialResults,
- const uint32_t nextResultFN, const uint32_t nextReprocResultFN,
- const uint32_t nextZslResultFN, const uint32_t nextShutterFN,
- const uint32_t nextReprocShutterFN, const uint32_t nextZslShutterFN,
- const CameraMetadata& deviceInfo,
+ const int64_t lastCompletedRegularFN, const int64_t lastCompletedReprocessFN,
+ const int64_t lastCompletedZslFN, const uint32_t nextResultFN,
+ const uint32_t nextReprocResultFN, const uint32_t nextZslResultFN,
+ const uint32_t nextShutterFN, const uint32_t nextReprocShutterFN,
+ const uint32_t nextZslShutterFN, const CameraMetadata& deviceInfo,
const std::unordered_map<std::string, CameraMetadata>& physicalDeviceInfoMap,
const std::unordered_map<std::string, camera3::DistortionMapper>& distortionMappers,
const std::unordered_map<std::string, camera3::ZoomRatioMapper>& zoomRatioMappers,
@@ -69,6 +70,9 @@
mTagMonitor(tagMonitor), mVendorTagId(vendorTagId),
mUseHalBufManager(useHalBufManager), mNeedFixupMonochromeTags(needFixupMonochromeTags),
mUsePartialResult(usePartialResult), mNumPartialResults(numPartialResults),
+ mLastCompletedRegularFrameNumber(lastCompletedRegularFN),
+ mLastCompletedReprocessFrameNumber(lastCompletedReprocessFN),
+ mLastCompletedZslFrameNumber(lastCompletedZslFN),
mNextResultFrameNumber(nextResultFN),
mNextReprocessResultFrameNumber(nextReprocResultFN),
mNextZslStillResultFrameNumber(nextZslResultFN),
@@ -90,6 +94,15 @@
const bool mUsePartialResult;
const uint32_t mNumPartialResults;
+ // The last completed (buffers, result metadata, and error notify) regular
+ // request frame number
+ const int64_t mLastCompletedRegularFrameNumber;
+ // The last completed (buffers, result metadata, and error notify) reprocess
+ // request frame number
+ const int64_t mLastCompletedReprocessFrameNumber;
+ // The last completed (buffers, result metadata, and error notify) zsl
+ // request frame number
+ const int64_t mLastCompletedZslFrameNumber;
// the minimal frame number of the next non-reprocess result
const uint32_t mNextResultFrameNumber;
// the minimal frame number of the next reprocess result
@@ -214,6 +227,12 @@
std::mutex mOutputLock;
std::list<CaptureResult> mResultQueue;
std::condition_variable mResultSignal;
+ // the last completed frame number of regular requests
+ int64_t mLastCompletedRegularFrameNumber;
+ // the last completed frame number of reprocess requests
+ int64_t mLastCompletedReprocessFrameNumber;
+ // the last completed frame number of ZSL still capture requests
+ int64_t mLastCompletedZslFrameNumber;
// the minimal frame number of the next non-reprocess result
uint32_t mNextResultFrameNumber;
// the minimal frame number of the next reprocess result
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index 603f516..eea5ef1 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -405,8 +405,8 @@
// In the case of a successful request:
// all input and output buffers, all result metadata, shutter callback
// arrived.
- // In the case of a unsuccessful request:
- // all input and output buffers arrived.
+ // In the case of an unsuccessful request:
+ // all input and output buffers, as well as request/result error notifications, arrived.
if (request.numBuffersLeft == 0 &&
(request.skipResultMetadata ||
(request.haveResultMetadata && shutterTimestamp != 0))) {
@@ -434,7 +434,17 @@
states.useHalBufManager, states.listener,
request.pendingOutputBuffers.array(),
request.pendingOutputBuffers.size(), 0, /*timestampIncreasing*/true,
- request.outputSurfaces, request.resultExtras);
+ request.outputSurfaces, request.resultExtras,
+ request.errorBufStrategy);
+
+ // Note down the just completed frame number
+ if (request.hasInputBuffer) {
+ states.lastCompletedReprocessFrameNumber = frameNumber;
+ } else if (request.zslCapture) {
+ states.lastCompletedZslFrameNumber = frameNumber;
+ } else {
+ states.lastCompletedRegularFrameNumber = frameNumber;
+ }
removeInFlightMapEntryLocked(states, idx);
ALOGVV("%s: removed frame %d from InFlightMap", __FUNCTION__, frameNumber);
@@ -487,10 +497,13 @@
InFlightRequest &request = states.inflightMap.editValueAt(idx);
ALOGVV("%s: got InFlightRequest requestId = %" PRId32
", frameNumber = %" PRId64 ", burstId = %" PRId32
- ", partialResultCount = %d, hasCallback = %d",
+ ", partialResultCount = %d/%d, hasCallback = %d, num_output_buffers %d"
+ ", usePartialResult = %d",
__FUNCTION__, request.resultExtras.requestId,
request.resultExtras.frameNumber, request.resultExtras.burstId,
- result->partial_result, request.hasCallback);
+ result->partial_result, states.numPartialResults,
+ request.hasCallback, result->num_output_buffers,
+ states.usePartialResult);
// Always update the partial count to the latest one if it's not 0
// (buffers only). When framework aggregates adjacent partial results
// into one, the latest partial count will be used.
@@ -555,6 +568,7 @@
request.collectedPartialResult);
}
request.haveResultMetadata = true;
+ request.errorBufStrategy = ERROR_BUF_RETURN_NOTIFY;
}
uint32_t numBuffersReturned = result->num_output_buffers;
@@ -581,18 +595,14 @@
request.sensorTimestamp = entry.data.i64[0];
}
- // If shutter event isn't received yet, append the output buffers to
- // the in-flight request. Otherwise, return the output buffers to
- // streams.
- if (shutterTimestamp == 0) {
- request.pendingOutputBuffers.appendArray(result->output_buffers,
+ // If shutter event isn't received yet, do not return the pending output
+ // buffers.
+ request.pendingOutputBuffers.appendArray(result->output_buffers,
result->num_output_buffers);
- } else {
- bool timestampIncreasing = !(request.zslCapture || request.hasInputBuffer);
- returnOutputBuffers(states.useHalBufManager, states.listener,
- result->output_buffers, result->num_output_buffers,
- shutterTimestamp, timestampIncreasing,
- request.outputSurfaces, request.resultExtras);
+ if (shutterTimestamp != 0) {
+ returnAndRemovePendingOutputBuffers(
+ states.useHalBufManager, states.listener,
+ request);
}
if (result->result != NULL && !isPartialResult) {
@@ -791,10 +801,26 @@
const camera3_stream_buffer_t *outputBuffers, size_t numBuffers,
nsecs_t timestamp, bool timestampIncreasing,
const SurfaceMap& outputSurfaces,
- const CaptureResultExtras &inResultExtras) {
+ const CaptureResultExtras &inResultExtras,
+ ERROR_BUF_STRATEGY errorBufStrategy) {
for (size_t i = 0; i < numBuffers; i++)
{
+ Camera3StreamInterface *stream = Camera3Stream::cast(outputBuffers[i].stream);
+ int streamId = stream->getId();
+
+ // Call notify(ERROR_BUFFER) if necessary.
+ if (outputBuffers[i].status == CAMERA3_BUFFER_STATUS_ERROR &&
+ errorBufStrategy == ERROR_BUF_RETURN_NOTIFY) {
+ if (listener != nullptr) {
+ CaptureResultExtras extras = inResultExtras;
+ extras.errorStreamId = streamId;
+ listener->notifyError(
+ hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER,
+ extras);
+ }
+ }
+
if (outputBuffers[i].buffer == nullptr) {
if (!useHalBufManager) {
// With HAL buffer management API, HAL sometimes will have to return buffers that
@@ -805,20 +831,23 @@
continue;
}
- Camera3StreamInterface *stream = Camera3Stream::cast(outputBuffers[i].stream);
- int streamId = stream->getId();
const auto& it = outputSurfaces.find(streamId);
status_t res = OK;
- if (it != outputSurfaces.end()) {
- res = stream->returnBuffer(
- outputBuffers[i], timestamp, timestampIncreasing, it->second,
- inResultExtras.frameNumber);
- } else {
- res = stream->returnBuffer(
- outputBuffers[i], timestamp, timestampIncreasing, std::vector<size_t> (),
- inResultExtras.frameNumber);
- }
+ // Do not return the buffer if the buffer status is error, and the error
+ // buffer strategy is CACHE.
+ if (outputBuffers[i].status != CAMERA3_BUFFER_STATUS_ERROR ||
+ errorBufStrategy != ERROR_BUF_CACHE) {
+ if (it != outputSurfaces.end()) {
+ res = stream->returnBuffer(
+ outputBuffers[i], timestamp, timestampIncreasing, it->second,
+ inResultExtras.frameNumber);
+ } else {
+ res = stream->returnBuffer(
+ outputBuffers[i], timestamp, timestampIncreasing, std::vector<size_t> (),
+ inResultExtras.frameNumber);
+ }
+ }
// Note: stream may be deallocated at this point, if this buffer was
// the last reference to it.
if (res == NO_INIT || res == DEAD_OBJECT) {
@@ -848,6 +877,28 @@
}
}
+void returnAndRemovePendingOutputBuffers(bool useHalBufManager,
+ sp<NotificationListener> listener, InFlightRequest& request) {
+ bool timestampIncreasing = !(request.zslCapture || request.hasInputBuffer);
+ returnOutputBuffers(useHalBufManager, listener,
+ request.pendingOutputBuffers.array(),
+ request.pendingOutputBuffers.size(),
+ request.shutterTimestamp, timestampIncreasing,
+ request.outputSurfaces, request.resultExtras,
+ request.errorBufStrategy);
+
+ // Remove error buffers that are not cached.
+ for (auto iter = request.pendingOutputBuffers.begin();
+ iter != request.pendingOutputBuffers.end(); ) {
+ if (request.errorBufStrategy != ERROR_BUF_CACHE ||
+ iter->status != CAMERA3_BUFFER_STATUS_ERROR) {
+ iter = request.pendingOutputBuffers.erase(iter);
+ } else {
+ iter++;
+ }
+ }
+}
+
void notifyShutter(CaptureOutputStates& states, const camera3_shutter_msg_t &msg) {
ATRACE_CALL();
ssize_t idx;
@@ -899,6 +950,12 @@
msg.frame_number, r.resultExtras.requestId, msg.timestamp);
// Call listener, if any
if (states.listener != nullptr) {
+ r.resultExtras.lastCompletedRegularFrameNumber =
+ states.lastCompletedRegularFrameNumber;
+ r.resultExtras.lastCompletedReprocessFrameNumber =
+ states.lastCompletedReprocessFrameNumber;
+ r.resultExtras.lastCompletedZslFrameNumber =
+ states.lastCompletedZslFrameNumber;
states.listener->notifyShutter(r.resultExtras, msg.timestamp);
}
// send pending result and buffers
@@ -908,13 +965,8 @@
r.hasInputBuffer, r.zslCapture && r.stillCapture,
r.rotateAndCropAuto, r.cameraIdsWithZoom, r.physicalMetadatas);
}
- bool timestampIncreasing = !(r.zslCapture || r.hasInputBuffer);
- returnOutputBuffers(
- states.useHalBufManager, states.listener,
- r.pendingOutputBuffers.array(),
- r.pendingOutputBuffers.size(), r.shutterTimestamp, timestampIncreasing,
- r.outputSurfaces, r.resultExtras);
- r.pendingOutputBuffers.clear();
+ returnAndRemovePendingOutputBuffers(
+ states.useHalBufManager, states.listener, r);
removeInFlightRequestIfReadyLocked(states, idx);
}
@@ -968,7 +1020,6 @@
break;
case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST:
case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_RESULT:
- case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER:
{
std::lock_guard<std::mutex> l(states.inflightLock);
ssize_t idx = states.inflightMap.indexOfKey(msg.frame_number);
@@ -976,7 +1027,7 @@
InFlightRequest &r = states.inflightMap.editValueAt(idx);
r.requestStatus = msg.error_code;
resultExtras = r.resultExtras;
- bool logicalDeviceResultError = false;
+ bool physicalDeviceResultError = false;
if (hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_RESULT ==
errorCode) {
if (physicalCameraId.size() > 0) {
@@ -990,23 +1041,22 @@
}
r.physicalCameraIds.erase(iter);
resultExtras.errorPhysicalCameraId = physicalCameraId;
- } else {
- logicalDeviceResultError = true;
+ physicalDeviceResultError = true;
}
}
- if (logicalDeviceResultError
- || hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST ==
- errorCode) {
+ if (!physicalDeviceResultError) {
r.skipResultMetadata = true;
- }
- if (logicalDeviceResultError) {
- // In case of missing result check whether the buffers
- // returned. If they returned, then remove inflight
- // request.
- // TODO: should we call this for ERROR_CAMERA_REQUEST as well?
- // otherwise we are depending on HAL to send the buffers back after
- // calling notifyError. Not sure if that's in the spec.
+ if (hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_RESULT
+ == errorCode) {
+ r.errorBufStrategy = ERROR_BUF_RETURN_NOTIFY;
+ } else {
+ // errorCode is ERROR_CAMERA_REQUEST
+ r.errorBufStrategy = ERROR_BUF_RETURN;
+ }
+
+ // Check whether the buffers returned. If they returned,
+ // remove inflight request.
removeInFlightRequestIfReadyLocked(states, idx);
}
} else {
@@ -1024,6 +1074,10 @@
states.cameraId.string(), __FUNCTION__);
}
break;
+ case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER:
+ // Do not depend on HAL ERROR_CAMERA_BUFFER to send buffer error
+ // callback to the app. Rather, use STATUS_ERROR of image buffers.
+ break;
default:
// SET_ERR calls notifyError
SET_ERR("Unknown error message from HAL: %d", msg.error_code);
@@ -1338,8 +1392,14 @@
request.pendingOutputBuffers.array(),
request.pendingOutputBuffers.size(), 0,
/*timestampIncreasing*/true, request.outputSurfaces,
- request.resultExtras);
+ request.resultExtras, request.errorBufStrategy);
+ ALOGW("%s: Frame %d | Timestamp: %" PRId64 ", metadata"
+ " arrived: %s, buffers left: %d.\n", __FUNCTION__,
+ states.inflightMap.keyAt(idx), request.shutterTimestamp,
+ request.haveResultMetadata ? "true" : "false",
+ request.numBuffersLeft);
}
+
states.inflightMap.clear();
states.inflightIntf.onInflightMapFlushedLocked();
}
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.h b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
index fbb47f8..9946312 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
@@ -44,7 +44,9 @@
/**
* Helper methods shared between Camera3Device/Camera3OfflineSession for HAL callbacks
*/
- // helper function to return the output buffers to output streams.
+
+ // helper function to return the output buffers to output streams. The
+ // function also optionally calls notify(ERROR_BUFFER).
void returnOutputBuffers(
bool useHalBufManager,
sp<NotificationListener> listener, // Only needed when outputSurfaces is not empty
@@ -53,13 +55,25 @@
// The following arguments are only meant for surface sharing use case
const SurfaceMap& outputSurfaces = SurfaceMap{},
// Used to send buffer error callback when failing to return buffer
- const CaptureResultExtras &resultExtras = CaptureResultExtras{});
+ const CaptureResultExtras &resultExtras = CaptureResultExtras{},
+ ERROR_BUF_STRATEGY errorBufStrategy = ERROR_BUF_RETURN);
+
+ // helper function to return the output buffers to output streams, and
+ // remove the returned buffers from the inflight request's pending buffers
+ // vector.
+ void returnAndRemovePendingOutputBuffers(
+ bool useHalBufManager,
+ sp<NotificationListener> listener, // Only needed when outputSurfaces is not empty
+ InFlightRequest& request);
// Camera3Device/Camera3OfflineSession internal states used in notify/processCaptureResult
// callbacks
struct CaptureOutputStates {
const String8& cameraId;
std::mutex& inflightLock;
+ int64_t& lastCompletedRegularFrameNumber;
+ int64_t& lastCompletedZslFrameNumber;
+ int64_t& lastCompletedReprocessFrameNumber;
InFlightRequestMap& inflightMap; // end of inflightLock scope
std::mutex& outputLock;
std::list<CaptureResult>& resultQueue;
diff --git a/services/camera/libcameraservice/device3/InFlightRequest.h b/services/camera/libcameraservice/device3/InFlightRequest.h
index 424043b..da4f228 100644
--- a/services/camera/libcameraservice/device3/InFlightRequest.h
+++ b/services/camera/libcameraservice/device3/InFlightRequest.h
@@ -32,7 +32,18 @@
namespace camera3 {
+typedef enum {
+ // Cache the buffers with STATUS_ERROR within InFlightRequest
+ ERROR_BUF_CACHE,
+ // Return the buffers with STATUS_ERROR to the buffer queue
+ ERROR_BUF_RETURN,
+ // Return the buffers with STATUS_ERROR to the buffer queue, and call
+ // notify(ERROR_BUFFER) as well
+ ERROR_BUF_RETURN_NOTIFY
+} ERROR_BUF_STRATEGY;
+
struct InFlightRequest {
+
// Set by notify() SHUTTER call.
nsecs_t shutterTimestamp;
// Set by process_capture_result().
@@ -43,6 +54,9 @@
// Decremented by calls to process_capture_result with valid output
// and input buffers
int numBuffersLeft;
+
+ // The inflight request is considered complete if all buffers are returned
+
CaptureResultExtras resultExtras;
// If this request has any input buffer
bool hasInputBuffer;
@@ -79,6 +93,10 @@
// REQUEST/RESULT error.
bool skipResultMetadata;
+ // Whether the buffers with STATUS_ERROR should be cached as pending buffers,
+ // returned to the buffer queue, or returned to the buffer queue and notify with ERROR_BUFFER.
+ ERROR_BUF_STRATEGY errorBufStrategy;
+
// The physical camera ids being requested.
std::set<String8> physicalCameraIds;
@@ -114,6 +132,7 @@
hasCallback(true),
maxExpectedDuration(kDefaultExpectedDuration),
skipResultMetadata(false),
+ errorBufStrategy(ERROR_BUF_CACHE),
stillCapture(false),
zslCapture(false),
rotateAndCropAuto(false) {
@@ -134,6 +153,7 @@
hasCallback(hasAppCallback),
maxExpectedDuration(maxDuration),
skipResultMetadata(false),
+ errorBufStrategy(ERROR_BUF_CACHE),
physicalCameraIds(physicalCameraIdSet),
stillCapture(isStillCapture),
zslCapture(isZslCapture),
diff --git a/services/mediacodec/Android.bp b/services/mediacodec/Android.bp
index f4c1924..775582a 100644
--- a/services/mediacodec/Android.bp
+++ b/services/mediacodec/Android.bp
@@ -15,18 +15,6 @@
"libmedia_codecserviceregistrant",
],
- target: {
- android: {
- product_variables: {
- malloc_not_svelte: {
- // Scudo increases memory footprint, so only enable on
- // non-svelte devices.
- shared_libs: ["libc_scudo"],
- },
- },
- },
- },
-
header_libs: [
"libmedia_headers",
],
diff --git a/services/mediaextractor/Android.bp b/services/mediaextractor/Android.bp
index 05b7d22..03e1e41 100644
--- a/services/mediaextractor/Android.bp
+++ b/services/mediaextractor/Android.bp
@@ -35,17 +35,6 @@
"liblog",
"libavservices_minijail",
],
- target: {
- android: {
- product_variables: {
- malloc_not_svelte: {
- // Scudo increases memory footprint, so only enable on
- // non-svelte devices.
- shared_libs: ["libc_scudo"],
- },
- },
- },
- },
init_rc: ["mediaextractor.rc"],
cflags: [
diff --git a/services/mediametrics/AudioPowerUsage.cpp b/services/mediametrics/AudioPowerUsage.cpp
index c441110..cca6b41 100644
--- a/services/mediametrics/AudioPowerUsage.cpp
+++ b/services/mediametrics/AudioPowerUsage.cpp
@@ -34,7 +34,7 @@
#define PROP_AUDIO_METRICS_DISABLED "persist.media.audio_metrics.power_usage_disabled"
#define AUDIO_METRICS_DISABLED_DEFAULT (false)
-// property to set how long to send audio power use metrics data to westworld, default is 24hrs
+// property to set how long to send audio power use metrics data to statsd, default is 24hrs
#define PROP_AUDIO_METRICS_INTERVAL_HR "persist.media.audio_metrics.interval_hr"
#define INTERVAL_HR_DEFAULT (24)
diff --git a/services/mediametrics/MediaMetricsService.cpp b/services/mediametrics/MediaMetricsService.cpp
index d682fed..48e766e 100644
--- a/services/mediametrics/MediaMetricsService.cpp
+++ b/services/mediametrics/MediaMetricsService.cpp
@@ -185,7 +185,7 @@
}
if (!isTrusted || item->getTimestamp() == 0) {
- // Westworld logs two times for events: ElapsedRealTimeNs (BOOTTIME) and
+ // Statsd logs two times for events: ElapsedRealTimeNs (BOOTTIME) and
// WallClockTimeNs (REALTIME), but currently logs REALTIME to cloud.
//
// For consistency and correlation with other logging mechanisms
diff --git a/services/mediametrics/MediaMetricsService.h b/services/mediametrics/MediaMetricsService.h
index d152264..792b7f0 100644
--- a/services/mediametrics/MediaMetricsService.h
+++ b/services/mediametrics/MediaMetricsService.h
@@ -65,7 +65,7 @@
static nsecs_t roundTime(nsecs_t timeNs);
/**
- * Returns true if we should use uid for package name when uploading to WestWorld.
+ * Returns true if we should use uid for package name when uploading to statsd.
*/
static bool useUidForPackage(const std::string& package, const std::string& installer);
diff --git a/services/mediatranscoding/Android.bp b/services/mediatranscoding/Android.bp
index b7decbc..bfcf01f 100644
--- a/services/mediatranscoding/Android.bp
+++ b/services/mediatranscoding/Android.bp
@@ -52,18 +52,6 @@
"mediatranscoding_aidl_interface-ndk_platform",
],
- target: {
- android: {
- product_variables: {
- malloc_not_svelte: {
- // Scudo increases memory footprint, so only enable on
- // non-svelte devices.
- shared_libs: ["libc_scudo"],
- },
- },
- },
- },
-
init_rc: ["mediatranscoding.rc"],
cflags: [
diff --git a/services/mediatranscoding/SimulatedTranscoder.cpp b/services/mediatranscoding/SimulatedTranscoder.cpp
index cdced2d..5aa325f 100644
--- a/services/mediatranscoding/SimulatedTranscoder.cpp
+++ b/services/mediatranscoding/SimulatedTranscoder.cpp
@@ -50,8 +50,8 @@
void SimulatedTranscoder::start(
ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) {
- if (request.testConfig.processingTotalTimeMs > 0) {
- mJobProcessingTimeMs = request.testConfig.processingTotalTimeMs;
+ if (request.testConfig.has_value() && request.testConfig->processingTotalTimeMs > 0) {
+ mJobProcessingTimeMs = request.testConfig->processingTotalTimeMs;
}
ALOGV("%s: job {%d}: processingTime: %lld", __FUNCTION__, jobId,
(long long)mJobProcessingTimeMs);
diff --git a/services/mediatranscoding/tests/README.txt b/services/mediatranscoding/tests/README.txt
index 5ee0296..cde465e 100644
--- a/services/mediatranscoding/tests/README.txt
+++ b/services/mediatranscoding/tests/README.txt
@@ -5,4 +5,4 @@
Tests media transcoding service with real transcoder. Uses the same test assets
as the MediaTranscoder unit tests. Before running the test, please make sure
to push the test assets to /sdcard:
- adb push $TOP/frameworks/av/media/libmediatranscoding/transcoder/tests/assets /data/local/tmp/TranscoderTestAssets
\ No newline at end of file
+ adb push $TOP/frameworks/av/media/libmediatranscoding/tests/assets /data/local/tmp/TranscodingTestAssets
diff --git a/services/mediatranscoding/tests/build_and_run_all_unit_tests.sh b/services/mediatranscoding/tests/build_and_run_all_unit_tests.sh
index 37a827c..d66b340 100644
--- a/services/mediatranscoding/tests/build_and_run_all_unit_tests.sh
+++ b/services/mediatranscoding/tests/build_and_run_all_unit_tests.sh
@@ -13,6 +13,9 @@
mm
+# Push the files onto the device.
+. $ANDROID_BUILD_TOP/frameworks/av/media/libmediatranscoding/tests/assets/push_assets.sh
+
echo "[==========] installing test apps"
adb root
adb install -t -r -g -d $ANDROID_TARGET_OUT_TESTCASES/TranscodingUidPolicy_TestAppA/arm64/TranscodingUidPolicy_TestAppA.apk
diff --git a/services/mediatranscoding/tests/mediatranscodingservice_real_tests.cpp b/services/mediatranscoding/tests/mediatranscodingservice_real_tests.cpp
index 57a79f7..8cecfed 100644
--- a/services/mediatranscoding/tests/mediatranscodingservice_real_tests.cpp
+++ b/services/mediatranscoding/tests/mediatranscodingservice_real_tests.cpp
@@ -27,7 +27,7 @@
* Uses the same test assets as the MediaTranscoder unit tests. Before running the test,
* please make sure to push the test assets to /sdcard:
*
- * adb push $TOP/frameworks/av/media/libmediatranscoding/transcoder/tests/assets /data/local/tmp/TranscoderTestAssets
+ * adb push $TOP/frameworks/av/media/libmediatranscoding/transcoder/tests/assets /data/local/tmp/TranscodingTestAssets
*/
namespace android {
@@ -37,7 +37,7 @@
constexpr int64_t kJobWithPaddingUs = 10000000 + kPaddingUs;
constexpr const char* kSrcPath =
- "/data/local/tmp/TranscoderTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
+ "/data/local/tmp/TranscodingTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
class MediaTranscodingServiceRealTest : public MediaTranscodingServiceTestBase {
public: