Merge "C2SoftMpeg4Enc: Do not return 0 byte CSD for H263"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index ae920c0..b1c81bf 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,2 +1,5 @@
[Hook Scripts]
mainline_hook = ${REPO_ROOT}/frameworks/av/tools/mainline_hook_partial.sh ${REPO_ROOT} ${PREUPLOAD_FILES}
+
+hidden_api_txt_checksorted_hook = ${REPO_ROOT}/tools/platform-compat/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
+
diff --git a/apex/Android.bp b/apex/Android.bp
index 701f5dc..85fc7c9 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -91,6 +91,15 @@
contents: ["updatable-media"],
apex_available: ["com.android.media"],
+ api: {
+ stub_libs: [
+ // Stubs for the APIs provided by updatable-media. This has to be
+ // specified explicitly because updatable-media is not a
+ // java_sdk_library.
+ "framework-media",
+ ],
+ },
+
// The bootclasspath_fragments that provide APIs on which this depends.
fragments: [
{
@@ -98,6 +107,18 @@
module: "art-bootclasspath-fragment",
},
],
+
+ // Additional stubs libraries that this fragment's contents use which are
+ // not provided by another bootclasspath_fragment.
+ additional_stubs: [
+ "android-non-updatable",
+ ],
+
+ // Additional hidden API flag files to override the defaults. This must only be
+ // modified by the Soong or platform compat team.
+ hidden_api: {
+ max_target_o_low_priority: ["hiddenapi/hiddenapi-max-target-o-low-priority.txt"],
+ },
}
filegroup {
diff --git a/apex/hiddenapi/OWNERS b/apex/hiddenapi/OWNERS
new file mode 100644
index 0000000..ac8a2b6
--- /dev/null
+++ b/apex/hiddenapi/OWNERS
@@ -0,0 +1,5 @@
+# soong-team@ as the hiddenapi files are tightly coupled with Soong
+file:platform/build/soong:/OWNERS
+
+# compat-team@ for changes to hiddenapi files
+file:tools/platform-compat:/OWNERS
diff --git a/apex/hiddenapi/hiddenapi-max-target-o-low-priority.txt b/apex/hiddenapi/hiddenapi-max-target-o-low-priority.txt
new file mode 100644
index 0000000..32bbb10
--- /dev/null
+++ b/apex/hiddenapi/hiddenapi-max-target-o-low-priority.txt
@@ -0,0 +1,6 @@
+Landroid/media/MediaSession2$ControllerInfo;-><init>(Landroid/content/Context;IILjava/lang/String;Landroid/os/IInterface;)V
+Landroid/media/MediaSession2$ControllerInfo;->getPackageName()Ljava/lang/String;
+Landroid/media/MediaSession2$ControllerInfo;->getProvider()Landroid/media/update/MediaSession2Provider$ControllerInfoProvider;
+Landroid/media/MediaSession2$ControllerInfo;->getUid()I
+Landroid/media/MediaSession2$ControllerInfo;->isTrusted()Z
+Landroid/media/MediaSession2$ControllerInfo;->mProvider:Landroid/media/update/MediaSession2Provider$ControllerInfoProvider;
diff --git a/media/OWNERS b/media/OWNERS
index 3e194f0..8675015 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -22,3 +22,4 @@
taklee@google.com
wjia@google.com
wonsik@google.com
+ytai@google.com
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.cpp b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
index 4bc1777..b7a5686 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
@@ -245,6 +245,19 @@
})
.withSetter(CodedColorAspectsSetter, mColorAspects)
.build());
+
+ addParameter(
+ DefineParam(mPictureQuantization, C2_PARAMKEY_PICTURE_QUANTIZATION)
+ .withDefault(C2StreamPictureQuantizationTuning::output::AllocShared(
+ 0 /* flexCount */, 0u /* stream */))
+ .withFields({C2F(mPictureQuantization, m.values[0].type_).oneOf(
+ {C2Config::picture_type_t(I_FRAME),
+ C2Config::picture_type_t(P_FRAME),
+ C2Config::picture_type_t(B_FRAME)}),
+ C2F(mPictureQuantization, m.values[0].min).any(),
+ C2F(mPictureQuantization, m.values[0].max).any()})
+ .withSetter(PictureQuantizationSetter)
+ .build());
}
static C2R InputDelaySetter(
@@ -464,9 +477,69 @@
me.set().matrix = coded.v.matrix;
return C2R::Ok();
}
+ static C2R PictureQuantizationSetter(bool mayBlock,
+ C2P<C2StreamPictureQuantizationTuning::output> &me) {
+ (void)mayBlock;
+
+ // these are the ones we're going to set, so want them to default
+ // to the DEFAULT values for the codec
+ int32_t iMin = HEVC_QP_MIN, pMin = HEVC_QP_MIN, bMin = HEVC_QP_MIN;
+ int32_t iMax = HEVC_QP_MAX, pMax = HEVC_QP_MAX, bMax = HEVC_QP_MAX;
+
+ for (size_t i = 0; i < me.v.flexCount(); ++i) {
+ const C2PictureQuantizationStruct &layer = me.v.m.values[i];
+
+ // layerMin is clamped to [HEVC_QP_MIN, layerMax] to avoid error
+ // cases where layer.min > layer.max
+ int32_t layerMax = std::clamp(layer.max, HEVC_QP_MIN, HEVC_QP_MAX);
+ int32_t layerMin = std::clamp(layer.min, HEVC_QP_MIN, layerMax);
+ if (layer.type_ == C2Config::picture_type_t(I_FRAME)) {
+ iMax = layerMax;
+ iMin = layerMin;
+ ALOGV("iMin %d iMax %d", iMin, iMax);
+ } else if (layer.type_ == C2Config::picture_type_t(P_FRAME)) {
+ pMax = layerMax;
+ pMin = layerMin;
+ ALOGV("pMin %d pMax %d", pMin, pMax);
+ } else if (layer.type_ == C2Config::picture_type_t(B_FRAME)) {
+ bMax = layerMax;
+ bMin = layerMin;
+ ALOGV("bMin %d bMax %d", bMin, bMax);
+ }
+ }
+
+ ALOGV("PictureQuantizationSetter(entry): i %d-%d p %d-%d b %d-%d",
+ iMin, iMax, pMin, pMax, bMin, bMax);
+
+ int32_t maxFrameQP = std::min(std::min(iMax, pMax), bMax);
+ int32_t minFrameQP = std::max(std::max(iMin, pMin), bMin);
+ if (minFrameQP > maxFrameQP) {
+ minFrameQP = maxFrameQP;
+ }
+
+ // put them back into the structure
+ for (size_t i = 0; i < me.v.flexCount(); ++i) {
+ const C2PictureQuantizationStruct &layer = me.v.m.values[i];
+
+ if (layer.type_ == C2Config::picture_type_t(I_FRAME) ||
+ layer.type_ == C2Config::picture_type_t(P_FRAME) ||
+ layer.type_ == C2Config::picture_type_t(B_FRAME)) {
+ me.set().m.values[i].max = maxFrameQP;
+ me.set().m.values[i].min = minFrameQP;
+ }
+ }
+
+ ALOGV("PictureQuantizationSetter(exit): i = p = b = %d-%d",
+ minFrameQP, maxFrameQP);
+
+ return C2R::Ok();
+ }
std::shared_ptr<C2StreamColorAspectsInfo::output> getCodedColorAspects_l() {
return mCodedColorAspects;
}
+ std::shared_ptr<C2StreamPictureQuantizationTuning::output> getPictureQuantization_l() const {
+ return mPictureQuantization;
+ }
private:
std::shared_ptr<C2StreamUsageTuning::input> mUsage;
@@ -482,6 +555,7 @@
std::shared_ptr<C2StreamGopTuning::output> mGop;
std::shared_ptr<C2StreamColorAspectsInfo::input> mColorAspects;
std::shared_ptr<C2StreamColorAspectsInfo::output> mCodedColorAspects;
+ std::shared_ptr<C2StreamPictureQuantizationTuning::output> mPictureQuantization;
};
static size_t GetCPUCoreCount() {
@@ -654,12 +728,41 @@
mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 3;
}
- switch (mBitrateMode->value) {
- case C2Config::BITRATE_IGNORE:
- mEncParams.s_config_prms.i4_rate_control_mode = 3;
- mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_frame_qp[0] =
- getQpFromQuality(mQuality->value);
+ // we resolved out-of-bound and unspecified values in PictureQuantizationSetter()
+ // so we can start with defaults that are overridden as needed.
+ int32_t maxFrameQP = mEncParams.s_config_prms.i4_max_frame_qp;
+ int32_t minFrameQP = mEncParams.s_config_prms.i4_min_frame_qp;
+
+ for (size_t i = 0; i < mQpBounds->flexCount(); ++i) {
+ const C2PictureQuantizationStruct &layer = mQpBounds->m.values[i];
+
+ // no need to loop, hevc library takes same range for I/P/B picture type
+ if (layer.type_ == C2Config::picture_type_t(I_FRAME) ||
+ layer.type_ == C2Config::picture_type_t(P_FRAME) ||
+ layer.type_ == C2Config::picture_type_t(B_FRAME)) {
+
+ maxFrameQP = layer.max;
+ minFrameQP = layer.min;
break;
+ }
+ }
+ mEncParams.s_config_prms.i4_max_frame_qp = maxFrameQP;
+ mEncParams.s_config_prms.i4_min_frame_qp = minFrameQP;
+
+ ALOGV("MaxFrameQp: %d MinFrameQp: %d", maxFrameQP, minFrameQP);
+
+ mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_frame_qp[0] =
+ std::clamp(kDefaultInitQP, minFrameQP, maxFrameQP);
+
+ switch (mBitrateMode->value) {
+ case C2Config::BITRATE_IGNORE: {
+ mEncParams.s_config_prms.i4_rate_control_mode = 3;
+ // ensure initial qp values are within our newly configured bounds
+ int32_t frameQp = getQpFromQuality(mQuality->value);
+ mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_frame_qp[0] =
+ std::clamp(frameQp, minFrameQP, maxFrameQP);
+ break;
+ }
case C2Config::BITRATE_CONST:
mEncParams.s_config_prms.i4_rate_control_mode = 5;
break;
@@ -723,6 +826,7 @@
mGop = mIntf->getGop_l();
mRequestSync = mIntf->getRequestSync_l();
mColorAspects = mIntf->getCodedColorAspects_l();
+ mQpBounds = mIntf->getPictureQuantization_l();;
}
c2_status_t status = initEncParams();
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.h b/media/codec2/components/hevc/C2SoftHevcEnc.h
index 9dbf682..4217a8b 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.h
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.h
@@ -42,6 +42,11 @@
#define DEFAULT_B_FRAMES 0
#define DEFAULT_RC_LOOKAHEAD 0
+#define HEVC_QP_MIN 1
+#define HEVC_QP_MAX 51
+
+constexpr int32_t kDefaultInitQP = 32;
+
struct C2SoftHevcEnc : public SimpleC2Component {
class IntfImpl;
@@ -90,6 +95,7 @@
std::shared_ptr<C2StreamGopTuning::output> mGop;
std::shared_ptr<C2StreamRequestSyncFrameTuning::output> mRequestSync;
std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects;
+ std::shared_ptr<C2StreamPictureQuantizationTuning::output> mQpBounds;
#ifdef FILE_DUMP_ENABLE
char mInFile[200];
char mOutFile[200];
diff --git a/media/codec2/components/mp3/C2SoftMp3Dec.cpp b/media/codec2/components/mp3/C2SoftMp3Dec.cpp
index 7137767..30d7394 100644
--- a/media/codec2/components/mp3/C2SoftMp3Dec.cpp
+++ b/media/codec2/components/mp3/C2SoftMp3Dec.cpp
@@ -16,6 +16,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "C2SoftMp3Dec"
+#include <inttypes.h>
#include <log/log.h>
#include <numeric>
@@ -485,10 +486,10 @@
}
}
- uint64_t outTimeStamp = mProcessedSamples * 1000000ll / samplingRate;
+ int64_t outTimeStamp = mProcessedSamples * 1000000ll / samplingRate;
mProcessedSamples += ((outSize - outOffset) / (numChannels * sizeof(int16_t)));
- ALOGV("out buffer attr. offset %d size %d timestamp %u", outOffset, outSize - outOffset,
- (uint32_t)(mAnchorTimeStamp + outTimeStamp));
+ ALOGV("out buffer attr. offset %d size %d timestamp %" PRId64 " ", outOffset,
+ outSize - outOffset, mAnchorTimeStamp + outTimeStamp);
decodedSizes.clear();
work->worklets.front()->output.flags = work->input.flags;
work->worklets.front()->output.buffers.clear();
diff --git a/media/codec2/components/mp3/C2SoftMp3Dec.h b/media/codec2/components/mp3/C2SoftMp3Dec.h
index 402bdc4..e2dfcf3 100644
--- a/media/codec2/components/mp3/C2SoftMp3Dec.h
+++ b/media/codec2/components/mp3/C2SoftMp3Dec.h
@@ -63,7 +63,7 @@
bool mSignalledError;
bool mSignalledOutputEos;
bool mGaplessBytes;
- uint64_t mAnchorTimeStamp;
+ int64_t mAnchorTimeStamp;
uint64_t mProcessedSamples;
status_t initDecoder();
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
index abd8b2d..74b099c 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
@@ -46,8 +46,8 @@
{"mp4a-latm", "bbb_aac_stereo_128kbps_48000hz.aac", "bbb_aac_stereo_128kbps_48000hz.info"},
{"mp4a-latm", "bbb_aac_stereo_128kbps_48000hz.aac",
"bbb_aac_stereo_128kbps_48000hz_multi_frame.info"},
- {"audio/mpeg", "bbb_mp3_stereo_192kbps_48000hz.mp3", "bbb_mp3_stereo_192kbps_48000hz.info"},
- {"audio/mpeg", "bbb_mp3_stereo_192kbps_48000hz.mp3",
+ {"mpeg", "bbb_mp3_stereo_192kbps_48000hz.mp3", "bbb_mp3_stereo_192kbps_48000hz.info"},
+ {"mpeg", "bbb_mp3_stereo_192kbps_48000hz.mp3",
"bbb_mp3_stereo_192kbps_48000hz_multi_frame.info"},
{"3gpp", "sine_amrnb_1ch_12kbps_8000hz.amrnb", "sine_amrnb_1ch_12kbps_8000hz.info"},
{"3gpp", "sine_amrnb_1ch_12kbps_8000hz.amrnb",
@@ -303,7 +303,7 @@
int streamCount = 0;
for (size_t i = 0; i < gCompToFiles.size(); ++i) {
- if (mMime.find(gCompToFiles[i].mime) != std::string::npos) {
+ if (!mMime.compare("audio/" + gCompToFiles[i].mime)) {
if (streamCount == streamIndex) {
mInputFile = sResourceDir + gCompToFiles[i].inputFile;
mInfoFile = sResourceDir + gCompToFiles[i].infoFile;
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
index d77b943..c487fa3 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
@@ -301,13 +301,23 @@
c2_status_t Codec2AudioEncHidlTestBase::getSamplesPerFrame(int32_t nChannels,
int32_t* samplesPerFrame) {
std::vector<std::unique_ptr<C2Param>> queried;
- c2_status_t c2err = mComponent->query({}, {C2StreamMaxBufferSizeInfo::input::PARAM_TYPE},
+ c2_status_t c2err = mComponent->query({}, {C2StreamAudioFrameSizeInfo::input::PARAM_TYPE},
C2_DONT_BLOCK, &queried);
- if (c2err != C2_OK || queried.size() == 0) return c2err;
-
size_t offset = sizeof(C2Param);
- C2Param* param = queried[0].get();
- uint32_t maxInputSize = *(uint32_t*)((uint8_t*)param + offset);
+ uint32_t maxInputSize = 0;
+ if (c2err == C2_OK && queried.size()) {
+ C2Param* param = queried[0].get();
+ maxInputSize = *(uint32_t*)((uint8_t*)param + offset);
+ }
+
+ if (0 == maxInputSize) {
+ c2err = mComponent->query({}, {C2StreamMaxBufferSizeInfo::input::PARAM_TYPE}, C2_DONT_BLOCK,
+ &queried);
+ if (c2err != C2_OK || queried.size() == 0) return c2err;
+
+ C2Param* param = queried[0].get();
+ maxInputSize = *(uint32_t*)((uint8_t*)param + offset);
+ }
*samplesPerFrame = std::min((maxInputSize / (nChannels * 2)), kMaxSamplesPerFrame);
return C2_OK;
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
index c331d0b..73af188 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
@@ -64,13 +64,15 @@
{"3gpp", "bbb_h263_352x288_300kbps_12fps.h263", "bbb_h263_352x288_300kbps_12fps.info", ""},
{"mp4v-es", "bbb_mpeg4_352x288_512kbps_30fps.m4v", "bbb_mpeg4_352x288_512kbps_30fps.info",
""},
- {"vp8", "bbb_vp8_176x144_240kbps_60fps.vp8", "bbb_vp8_176x144_240kbps_60fps.info", ""},
- {"vp8", "bbb_vp8_640x360_2mbps_30fps.vp8", "bbb_vp8_640x360_2mbps_30fps.info",
+ {"x-vnd.on2.vp8", "bbb_vp8_176x144_240kbps_60fps.vp8", "bbb_vp8_176x144_240kbps_60fps.info",
+ ""},
+ {"x-vnd.on2.vp8", "bbb_vp8_640x360_2mbps_30fps.vp8", "bbb_vp8_640x360_2mbps_30fps.info",
"bbb_vp8_640x360_2mbps_30fps_chksm.md5"},
- {"vp9", "bbb_vp9_176x144_285kbps_60fps.vp9", "bbb_vp9_176x144_285kbps_60fps.info", ""},
- {"vp9", "bbb_vp9_640x360_1600kbps_30fps.vp9", "bbb_vp9_640x360_1600kbps_30fps.info",
- "bbb_vp9_640x360_1600kbps_30fps_chksm.md5"},
- {"vp9", "bbb_vp9_704x480_280kbps_24fps_altref_2.vp9",
+ {"x-vnd.on2.vp9", "bbb_vp9_176x144_285kbps_60fps.vp9", "bbb_vp9_176x144_285kbps_60fps.info",
+ ""},
+ {"x-vnd.on2.vp9", "bbb_vp9_640x360_1600kbps_30fps.vp9",
+ "bbb_vp9_640x360_1600kbps_30fps.info", "bbb_vp9_640x360_1600kbps_30fps_chksm.md5"},
+ {"x-vnd.on2.vp9", "bbb_vp9_704x480_280kbps_24fps_altref_2.vp9",
"bbb_vp9_704x480_280kbps_24fps_altref_2.info", ""},
{"av01", "bbb_av1_640_360.av1", "bbb_av1_640_360.info", "bbb_av1_640_360_chksum.md5"},
{"av01", "bbb_av1_176_144.av1", "bbb_av1_176_144.info", "bbb_av1_176_144_chksm.md5"},
@@ -379,7 +381,7 @@
int streamCount = 0;
for (size_t i = 0; i < gCompToFiles.size(); ++i) {
- if (mMime.find(gCompToFiles[i].mime) != std::string::npos) {
+ if (!mMime.compare("video/" + gCompToFiles[i].mime)) {
if (streamCount == streamIndex) {
mInputFile = sResourceDir + gCompToFiles[i].inputFile;
mInfoFile = sResourceDir + gCompToFiles[i].infoFile;
diff --git a/media/codec2/hidl/services/Android.bp b/media/codec2/hidl/services/Android.bp
index 5a23217..4ec67b0 100644
--- a/media/codec2/hidl/services/Android.bp
+++ b/media/codec2/hidl/services/Android.bp
@@ -52,7 +52,7 @@
// minijail is used to protect against unexpected system calls.
shared_libs: [
- "libavservices_minijail_vendor",
+ "libavservices_minijail",
"libbinder",
],
required: ["android.hardware.media.c2@1.1-default-seccomp_policy"],
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 2dc63f3..cdd9275 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -248,7 +248,7 @@
bool released = input->buffers->releaseBuffer(buffer, nullptr, true);
ALOGV("[%s] queueInputBuffer: buffer copied; %sreleased",
mName, released ? "" : "not ");
- buffer.clear();
+ buffer = copy;
} else {
ALOGW("[%s] queueInputBuffer: failed to copy a buffer; this may cause input "
"buffer starvation on component.", mName);
@@ -276,6 +276,12 @@
}
}
} else if (eos) {
+ Mutexed<Input>::Locked input(mInput);
+ if (input->frameReassembler) {
+ usesFrameReassembler = true;
+ // drain any pending items with eos
+ input->frameReassembler.process(buffer, &items);
+ }
flags |= C2FrameData::FLAG_END_OF_STREAM;
}
if (usesFrameReassembler) {
@@ -335,10 +341,10 @@
} else {
Mutexed<Input>::Locked input(mInput);
bool released = false;
- if (buffer) {
- released = input->buffers->releaseBuffer(buffer, nullptr, true);
- } else if (copy) {
+ if (copy) {
released = input->extraBuffers.releaseSlot(copy, nullptr, true);
+ } else if (buffer) {
+ released = input->buffers->releaseBuffer(buffer, nullptr, true);
}
ALOGV("[%s] queueInputBuffer: buffer%s %sreleased",
mName, (buffer == nullptr) ? "(copy)" : "", released ? "" : "not ");
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
index ba44074..cfa89cf 100644
--- a/media/codec2/sfplugin/CCodecBuffers.cpp
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -129,6 +129,7 @@
if (!copy->copy(c2buffer)) {
return nullptr;
}
+ copy->meta()->extend(buffer->meta());
return copy;
}
diff --git a/media/codec2/sfplugin/FrameReassembler.cpp b/media/codec2/sfplugin/FrameReassembler.cpp
index cf1be17..b52506c 100644
--- a/media/codec2/sfplugin/FrameReassembler.cpp
+++ b/media/codec2/sfplugin/FrameReassembler.cpp
@@ -88,8 +88,7 @@
const sp<MediaCodecBuffer> &buffer,
std::list<std::unique_ptr<C2Work>> *items) {
int64_t timeUs;
- if (buffer->size() == 0u
- || !buffer->meta()->findInt64("timeUs", &timeUs)) {
+ if (!buffer->meta()->findInt64("timeUs", &timeUs)) {
return C2_BAD_VALUE;
}
diff --git a/media/codec2/sfplugin/tests/FrameReassembler_test.cpp b/media/codec2/sfplugin/tests/FrameReassembler_test.cpp
index 6738ee7..0be934a 100644
--- a/media/codec2/sfplugin/tests/FrameReassembler_test.cpp
+++ b/media/codec2/sfplugin/tests/FrameReassembler_test.cpp
@@ -53,7 +53,8 @@
C2Config::pcm_encoding_t encoding,
size_t inputFrameSizeInBytes,
size_t count,
- size_t expectedOutputSize) {
+ size_t expectedOutputSize,
+ bool separateEos) {
FrameReassembler frameReassembler;
frameReassembler.init(
mPool,
@@ -67,7 +68,7 @@
size_t inputIndex = 0, outputIndex = 0;
size_t expectCount = 0;
- for (size_t i = 0; i < count; ++i) {
+ for (size_t i = 0; i < count + (separateEos ? 1 : 0); ++i) {
sp<MediaCodecBuffer> buffer = new MediaCodecBuffer(
new AMessage, new ABuffer(inputFrameSizeInBytes));
buffer->setRange(0, inputFrameSizeInBytes);
@@ -77,8 +78,12 @@
if (i == count - 1) {
buffer->meta()->setInt32("eos", 1);
}
- for (size_t j = 0; j < inputFrameSizeInBytes; ++j, ++inputIndex) {
- buffer->base()[j] = (inputIndex & 0xFF);
+ if (i == count && separateEos) {
+ buffer->setRange(0, 0);
+ } else {
+ for (size_t j = 0; j < inputFrameSizeInBytes; ++j, ++inputIndex) {
+ buffer->base()[j] = (inputIndex & 0xFF);
+ }
}
std::list<std::unique_ptr<C2Work>> items;
ASSERT_EQ(C2_OK, frameReassembler.process(buffer, &items));
@@ -105,7 +110,8 @@
ASSERT_EQ(encoderFrameSize * BytesPerSample(encoding), view.capacity());
for (size_t j = 0; j < view.capacity(); ++j, ++outputIndex) {
ASSERT_TRUE(outputIndex < inputIndex
- || inputIndex == inputFrameSizeInBytes * count);
+ || inputIndex == inputFrameSizeInBytes * count)
+ << "inputIndex = " << inputIndex << " outputIndex = " << outputIndex;
uint8_t expected = outputIndex < inputIndex ? (outputIndex & 0xFF) : 0;
if (expectCount < 10) {
++expectCount;
@@ -137,204 +143,239 @@
// Push frames with exactly the same size as the encoder requested.
TEST_F(FrameReassemblerTest, PushExactFrameSize) {
ASSERT_EQ(OK, initStatus());
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_8,
- 1024 /* input frame size in bytes = 1024 samples * 1 channel * 1 bytes/sample */,
- 10 /* count */,
- 10240 /* expected output size = 10 * 1024 bytes/frame */);
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_16,
- 2048 /* input frame size in bytes = 1024 samples * 1 channel * 2 bytes/sample */,
- 10 /* count */,
- 20480 /* expected output size = 10 * 2048 bytes/frame */);
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_FLOAT,
- 4096 /* input frame size in bytes = 1024 samples * 1 channel * 4 bytes/sample */,
- 10 /* count */,
- 40960 /* expected output size = 10 * 4096 bytes/frame */);
+ for (bool separateEos : {false, true}) {
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_8,
+ 1024 /* input frame size in bytes = 1024 samples * 1 channel * 1 bytes/sample */,
+ 10 /* count */,
+ 10240 /* expected output size = 10 * 1024 bytes/frame */,
+ separateEos);
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_16,
+ 2048 /* input frame size in bytes = 1024 samples * 1 channel * 2 bytes/sample */,
+ 10 /* count */,
+ 20480 /* expected output size = 10 * 2048 bytes/frame */,
+ separateEos);
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_FLOAT,
+ 4096 /* input frame size in bytes = 1024 samples * 1 channel * 4 bytes/sample */,
+ 10 /* count */,
+ 40960 /* expected output size = 10 * 4096 bytes/frame */,
+ separateEos);
+ }
}
// Push frames with half the size that the encoder requested.
TEST_F(FrameReassemblerTest, PushHalfFrameSize) {
ASSERT_EQ(OK, initStatus());
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_8,
- 512 /* input frame size in bytes = 512 samples * 1 channel * 1 bytes per sample */,
- 10 /* count */,
- 5120 /* expected output size = 5 * 1024 bytes/frame */);
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_16,
- 1024 /* input frame size in bytes = 512 samples * 1 channel * 2 bytes per sample */,
- 10 /* count */,
- 10240 /* expected output size = 5 * 2048 bytes/frame */);
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_FLOAT,
- 2048 /* input frame size in bytes = 512 samples * 1 channel * 4 bytes per sample */,
- 10 /* count */,
- 20480 /* expected output size = 5 * 4096 bytes/frame */);
+ for (bool separateEos : {false, true}) {
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_8,
+ 512 /* input frame size in bytes = 512 samples * 1 channel * 1 bytes/sample */,
+ 10 /* count */,
+ 5120 /* expected output size = 5 * 1024 bytes/frame */,
+ separateEos);
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_16,
+ 1024 /* input frame size in bytes = 512 samples * 1 channel * 2 bytes/sample */,
+ 10 /* count */,
+ 10240 /* expected output size = 5 * 2048 bytes/frame */,
+ separateEos);
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_FLOAT,
+ 2048 /* input frame size in bytes = 512 samples * 1 channel * 4 bytes/sample */,
+ 10 /* count */,
+ 20480 /* expected output size = 5 * 4096 bytes/frame */,
+ separateEos);
+ }
}
// Push frames with twice the size that the encoder requested.
TEST_F(FrameReassemblerTest, PushDoubleFrameSize) {
ASSERT_EQ(OK, initStatus());
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_8,
- 2048 /* input frame size in bytes = 2048 samples * 1 channel * 1 bytes per sample */,
- 10 /* count */,
- 20480 /* expected output size = 20 * 1024 bytes/frame */);
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_16,
- 4096 /* input frame size in bytes = 2048 samples * 1 channel * 2 bytes per sample */,
- 10 /* count */,
- 40960 /* expected output size = 20 * 2048 bytes/frame */);
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_FLOAT,
- 8192 /* input frame size in bytes = 2048 samples * 1 channel * 4 bytes per sample */,
- 10 /* count */,
- 81920 /* expected output size = 20 * 4096 bytes/frame */);
+ for (bool separateEos : {false, true}) {
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_8,
+ 2048 /* input frame size in bytes = 2048 samples * 1 channel * 1 bytes/sample */,
+ 10 /* count */,
+ 20480 /* expected output size = 20 * 1024 bytes/frame */,
+ separateEos);
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_16,
+ 4096 /* input frame size in bytes = 2048 samples * 1 channel * 2 bytes/sample */,
+ 10 /* count */,
+ 40960 /* expected output size = 20 * 2048 bytes/frame */,
+ separateEos);
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_FLOAT,
+ 8192 /* input frame size in bytes = 2048 samples * 1 channel * 4 bytes/sample */,
+ 10 /* count */,
+ 81920 /* expected output size = 20 * 4096 bytes/frame */,
+ separateEos);
+ }
}
// Push frames with a little bit larger (+5 samples) than the requested size.
TEST_F(FrameReassemblerTest, PushLittleLargerFrameSize) {
ASSERT_EQ(OK, initStatus());
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_8,
- 1029 /* input frame size in bytes = 1029 samples * 1 channel * 1 bytes per sample */,
- 10 /* count */,
- 11264 /* expected output size = 11 * 1024 bytes/frame */);
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_16,
- 2058 /* input frame size in bytes = 1029 samples * 1 channel * 2 bytes per sample */,
- 10 /* count */,
- 22528 /* expected output size = 11 * 2048 bytes/frame */);
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_FLOAT,
- 4116 /* input frame size in bytes = 1029 samples * 1 channel * 4 bytes per sample */,
- 10 /* count */,
- 45056 /* expected output size = 11 * 4096 bytes/frame */);
+ for (bool separateEos : {false, true}) {
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_8,
+ 1029 /* input frame size in bytes = 1029 samples * 1 channel * 1 bytes/sample */,
+ 10 /* count */,
+ 11264 /* expected output size = 11 * 1024 bytes/frame */,
+ separateEos);
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_16,
+ 2058 /* input frame size in bytes = 1029 samples * 1 channel * 2 bytes/sample */,
+ 10 /* count */,
+ 22528 /* expected output size = 11 * 2048 bytes/frame */,
+ separateEos);
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_FLOAT,
+ 4116 /* input frame size in bytes = 1029 samples * 1 channel * 4 bytes/sample */,
+ 10 /* count */,
+ 45056 /* expected output size = 11 * 4096 bytes/frame */,
+ separateEos);
+ }
}
// Push frames with a little bit smaller (-5 samples) than the requested size.
TEST_F(FrameReassemblerTest, PushLittleSmallerFrameSize) {
ASSERT_EQ(OK, initStatus());
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_8,
- 1019 /* input frame size in bytes = 1019 samples * 1 channel * 1 bytes per sample */,
- 10 /* count */,
- 10240 /* expected output size = 10 * 1024 bytes/frame */);
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_16,
- 2038 /* input frame size in bytes = 1019 samples * 1 channel * 2 bytes per sample */,
- 10 /* count */,
- 20480 /* expected output size = 10 * 2048 bytes/frame */);
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_FLOAT,
- 4076 /* input frame size in bytes = 1019 samples * 1 channel * 4 bytes per sample */,
- 10 /* count */,
- 40960 /* expected output size = 10 * 4096 bytes/frame */);
+ for (bool separateEos : {false, true}) {
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_8,
+ 1019 /* input frame size in bytes = 1019 samples * 1 channel * 1 bytes/sample */,
+ 10 /* count */,
+ 10240 /* expected output size = 10 * 1024 bytes/frame */,
+ separateEos);
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_16,
+ 2038 /* input frame size in bytes = 1019 samples * 1 channel * 2 bytes/sample */,
+ 10 /* count */,
+ 20480 /* expected output size = 10 * 2048 bytes/frame */,
+ separateEos);
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_FLOAT,
+ 4076 /* input frame size in bytes = 1019 samples * 1 channel * 4 bytes/sample */,
+ 10 /* count */,
+ 40960 /* expected output size = 10 * 4096 bytes/frame */,
+ separateEos);
+ }
}
// Push single-byte frames
TEST_F(FrameReassemblerTest, PushSingleByte) {
ASSERT_EQ(OK, initStatus());
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_8,
- 1 /* input frame size in bytes */,
- 100000 /* count */,
- 100352 /* expected output size = 98 * 1024 bytes/frame */);
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_16,
- 1 /* input frame size in bytes */,
- 100000 /* count */,
- 100352 /* expected output size = 49 * 2048 bytes/frame */);
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_FLOAT,
- 1 /* input frame size in bytes */,
- 100000 /* count */,
- 102400 /* expected output size = 25 * 4096 bytes/frame */);
+ for (bool separateEos : {false, true}) {
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_8,
+ 1 /* input frame size in bytes */,
+ 100000 /* count */,
+ 100352 /* expected output size = 98 * 1024 bytes/frame */,
+ separateEos);
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_16,
+ 1 /* input frame size in bytes */,
+ 100000 /* count */,
+ 100352 /* expected output size = 49 * 2048 bytes/frame */,
+ separateEos);
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_FLOAT,
+ 1 /* input frame size in bytes */,
+ 100000 /* count */,
+ 102400 /* expected output size = 25 * 4096 bytes/frame */,
+ separateEos);
+ }
}
// Push one big chunk.
TEST_F(FrameReassemblerTest, PushBigChunk) {
ASSERT_EQ(OK, initStatus());
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_8,
- 100000 /* input frame size in bytes */,
- 1 /* count */,
- 100352 /* expected output size = 98 * 1024 bytes/frame */);
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_16,
- 100000 /* input frame size in bytes */,
- 1 /* count */,
- 100352 /* expected output size = 49 * 2048 bytes/frame */);
- testPushSameSize(
- 1024 /* frame size in samples */,
- 48000 /* sample rate */,
- 1 /* channel count */,
- PCM_FLOAT,
- 100000 /* input frame size in bytes */,
- 1 /* count */,
- 102400 /* expected output size = 25 * 4096 bytes/frame */);
+ for (bool separateEos : {false, true}) {
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_8,
+ 100000 /* input frame size in bytes */,
+ 1 /* count */,
+ 100352 /* expected output size = 98 * 1024 bytes/frame */,
+ separateEos);
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_16,
+ 100000 /* input frame size in bytes */,
+ 1 /* count */,
+ 100352 /* expected output size = 49 * 2048 bytes/frame */,
+ separateEos);
+ testPushSameSize(
+ 1024 /* frame size in samples */,
+ 48000 /* sample rate */,
+ 1 /* channel count */,
+ PCM_FLOAT,
+ 100000 /* input frame size in bytes */,
+ 1 /* count */,
+ 102400 /* expected output size = 25 * 4096 bytes/frame */,
+ separateEos);
+ }
}
} // namespace android
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index bee6b7f..54f4cff 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -748,6 +748,16 @@
// We really don't know what this is; lock the buffer and pass it through ---
// the client may know how to interpret it.
+
+ // unlock previous allocation if it was successful
+ if (err == OK) {
+ err = GraphicBufferMapper::get().unlock(mBuffer);
+ if (err) {
+ ALOGE("failed transaction: unlock");
+ return C2_CORRUPTED;
+ }
+ }
+
void *pointer = nullptr;
err = GraphicBufferMapper::get().lock(
const_cast<native_handle_t *>(mBuffer), grallocUsage, rect, &pointer);
diff --git a/media/codecs/m4v_h263/enc/src/mp4enc_api.cpp b/media/codecs/m4v_h263/enc/src/mp4enc_api.cpp
index 4555203..cc4f222 100644
--- a/media/codecs/m4v_h263/enc/src/mp4enc_api.cpp
+++ b/media/codecs/m4v_h263/enc/src/mp4enc_api.cpp
@@ -498,13 +498,16 @@
/* check frame rate */
for (i = 0; i < encParams->nLayers; i++)
{
+ if (encOption->encFrameRate[i] <= 0. || encOption->encFrameRate[i] > 120)
+ {
+ goto CLEAN_UP;
+ }
encParams->LayerFrameRate[i] = encOption->encFrameRate[i];
}
if (encParams->nLayers > 1)
{
- if (encOption->encFrameRate[0] == encOption->encFrameRate[1] ||
- encOption->encFrameRate[0] == 0. || encOption->encFrameRate[1] == 0.) /* 7/31/03 */
+ if (encOption->encFrameRate[0] == encOption->encFrameRate[1])
goto CLEAN_UP;
}
/* set max frame rate */
diff --git a/media/codecs/mp3dec/src/pvmp3_stereo_proc.cpp b/media/codecs/mp3dec/src/pvmp3_stereo_proc.cpp
index 4338c43..c04f7f3 100644
--- a/media/codecs/mp3dec/src/pvmp3_stereo_proc.cpp
+++ b/media/codecs/mp3dec/src/pvmp3_stereo_proc.cpp
@@ -219,6 +219,9 @@
; FUNCTION CODE
----------------------------------------------------------------------------*/
+#if __has_attribute(no_sanitize)
+__attribute__((no_sanitize("integer")))
+#endif
void pvmp3_st_intensity(int32 xr[SUBBANDS_NUMBER*FILTERBANK_BANDS],
int32 xl[SUBBANDS_NUMBER*FILTERBANK_BANDS],
int32 is_pos,
diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
index 273d91c..fcac551 100644
--- a/media/libheif/HeifDecoderImpl.cpp
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -15,6 +15,7 @@
*/
//#define LOG_NDEBUG 0
+#include "include/HeifDecoderAPI.h"
#define LOG_TAG "HeifDecoderImpl"
#include "HeifDecoderImpl.h"
@@ -464,7 +465,7 @@
}
bool HeifDecoderImpl::setOutputColor(HeifColorFormat heifColor) {
- if (heifColor == mOutputColor) {
+ if (heifColor == (HeifColorFormat)mOutputColor) {
return true;
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 389249e..3eb2f06 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -2854,10 +2854,43 @@
CHECK(msg->findInt32("payload-type", &payloadType));
+ int32_t rtpSeq = 0, rtpTime = 0;
+ int64_t ntpTime = 0, recvTimeUs = 0;
+
Parcel in;
in.writeInt32(payloadType);
switch (payloadType) {
+ case ARTPSource::RTP_FIRST_PACKET:
+ {
+ CHECK(msg->findInt32("rtp-time", &rtpTime));
+ CHECK(msg->findInt32("rtp-seq-num", &rtpSeq));
+ CHECK(msg->findInt64("recv-time-us", &recvTimeUs));
+ in.writeInt32(rtpTime);
+ in.writeInt32(rtpSeq);
+ in.writeInt32(recvTimeUs >> 32);
+ in.writeInt32(recvTimeUs & 0xFFFFFFFF);
+ break;
+ }
+ case ARTPSource::RTCP_FIRST_PACKET:
+ {
+ CHECK(msg->findInt64("recv-time-us", &recvTimeUs));
+ in.writeInt32(recvTimeUs >> 32);
+ in.writeInt32(recvTimeUs & 0xFFFFFFFF);
+ break;
+ }
+ case ARTPSource::RTCP_SR:
+ {
+ CHECK(msg->findInt32("rtp-time", &rtpTime));
+ CHECK(msg->findInt64("ntp-time", &ntpTime));
+ CHECK(msg->findInt64("recv-time-us", &recvTimeUs));
+ in.writeInt32(rtpTime);
+ in.writeInt32(ntpTime >> 32);
+ in.writeInt32(ntpTime & 0xFFFFFFFF);
+ in.writeInt32(recvTimeUs >> 32);
+ in.writeInt32(recvTimeUs & 0xFFFFFFFF);
+ break;
+ }
case ARTPSource::RTCP_TSFB: // RTCP TSFB
case ARTPSource::RTCP_PSFB: // RTCP PSFB
case ARTPSource::RTP_AUTODOWN:
@@ -2880,6 +2913,8 @@
int32_t feedbackType, bitrate;
int32_t highestSeqNum, baseSeqNum, prevExpected;
int32_t numBufRecv, prevNumBufRecv;
+ int32_t latestRtpTime, jbTimeMs, rtpRtcpSrTimeGapMs;
+ int64_t recvTimeUs;
CHECK(msg->findInt32("feedback-type", &feedbackType));
CHECK(msg->findInt32("bit-rate", &bitrate));
CHECK(msg->findInt32("highest-seq-num", &highestSeqNum));
@@ -2887,6 +2922,10 @@
CHECK(msg->findInt32("prev-expected", &prevExpected));
CHECK(msg->findInt32("num-buf-recv", &numBufRecv));
CHECK(msg->findInt32("prev-num-buf-recv", &prevNumBufRecv));
+ CHECK(msg->findInt32("latest-rtp-time", &latestRtpTime));
+ CHECK(msg->findInt64("recv-time-us", &recvTimeUs));
+ CHECK(msg->findInt32("rtp-jitter-time-ms", &jbTimeMs));
+ CHECK(msg->findInt32("rtp-rtcpsr-time-gap-ms", &rtpRtcpSrTimeGapMs));
in.writeInt32(feedbackType);
in.writeInt32(bitrate);
in.writeInt32(highestSeqNum);
@@ -2894,6 +2933,11 @@
in.writeInt32(prevExpected);
in.writeInt32(numBufRecv);
in.writeInt32(prevNumBufRecv);
+ in.writeInt32(latestRtpTime);
+ in.writeInt32(recvTimeUs >> 32);
+ in.writeInt32(recvTimeUs & 0xFFFFFFFF);
+ in.writeInt32(jbTimeMs);
+ in.writeInt32(rtpRtcpSrTimeGapMs);
break;
}
case ARTPSource::RTP_CVO:
diff --git a/media/libmediaplayerservice/nuplayer/RTPSource.cpp b/media/libmediaplayerservice/nuplayer/RTPSource.cpp
index d2d978a..4d6a483 100644
--- a/media/libmediaplayerservice/nuplayer/RTPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTPSource.cpp
@@ -395,23 +395,13 @@
CHECK(msg->findInt64("ntp-time", (int64_t *)&ntpTime));
onTimeUpdate(trackIndex, rtpTime, ntpTime);
- break;
- }
-
- int32_t firstRTCP;
- if (msg->findInt32("first-rtcp", &firstRTCP)) {
- // There won't be an access unit here, it's just a notification
- // that the data communication worked since we got the first
- // rtcp packet.
- ALOGV("first-rtcp");
- break;
}
int32_t IMSRxNotice;
if (msg->findInt32("rtcp-event", &IMSRxNotice)) {
- int32_t payloadType, feedbackType;
+ int32_t payloadType = 0, feedbackType = 0;
CHECK(msg->findInt32("payload-type", &payloadType));
- CHECK(msg->findInt32("feedback-type", &feedbackType));
+ msg->findInt32("feedback-type", &feedbackType);
sp<AMessage> notify = dupNotify();
notify->setInt32("what", kWhatIMSRxNotice);
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 9533ae5..8e05de8 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -145,15 +145,17 @@
return;
}
- // Close socket before posting message to RTSPSource message handler.
- if (mHandler != NULL) {
- close(mHandler->getARTSPConnection()->getSocket());
- }
-
sp<AMessage> msg = new AMessage(kWhatDisconnect, this);
sp<AMessage> dummy;
msg->postAndAwaitResponse(&dummy);
+
+ // Close socket after posting message to RTSPSource message handler.
+ if (mHandler != NULL && mHandler->getARTSPConnection()->getSocket() >= 0) {
+ ALOGD("closing rtsp socket if not closed yet.");
+ close(mHandler->getARTSPConnection()->getSocket());
+ }
+
}
status_t NuPlayer::RTSPSource::feedMoreTSData() {
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 224ec8b..4cd8996 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -3270,10 +3270,12 @@
if (err != OK) {
ALOGE("native_window_set_sideband_stream(%p) failed! (err %d).",
sidebandHandle, err);
- return err;
}
- return OK;
+ native_handle_close(sidebandHandle);
+ native_handle_delete(sidebandHandle);
+
+ return err;
}
status_t ACodec::setVideoPortFormatType(
@@ -5361,21 +5363,21 @@
err = mOMXNode->getParameter(
(OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAacDrcPresentation,
&presentation, sizeof(presentation));
- if (err != OK) {
- return err;
+ if (err == OK) {
+ notify->setInt32("aac-encoded-target-level",
+ presentation.nEncodedTargetLevel);
+ notify->setInt32("aac-drc-cut-level", presentation.nDrcCut);
+ notify->setInt32("aac-drc-boost-level", presentation.nDrcBoost);
+ notify->setInt32("aac-drc-heavy-compression",
+ presentation.nHeavyCompression);
+ notify->setInt32("aac-target-ref-level",
+ presentation.nTargetReferenceLevel);
+ notify->setInt32("aac-drc-effect-type",
+ presentation.nDrcEffectType);
+ notify->setInt32("aac-drc-album-mode", presentation.nDrcAlbumMode);
+ notify->setInt32("aac-drc-output-loudness",
+ presentation.nDrcOutputLoudness);
}
- notify->setInt32("aac-encoded-target-level",
- presentation.nEncodedTargetLevel);
- notify->setInt32("aac-drc-cut-level", presentation.nDrcCut);
- notify->setInt32("aac-drc-boost-level", presentation.nDrcBoost);
- notify->setInt32("aac-drc-heavy-compression",
- presentation.nHeavyCompression);
- notify->setInt32("aac-target-ref-level",
- presentation.nTargetReferenceLevel);
- notify->setInt32("aac-drc-effect-type", presentation.nDrcEffectType);
- notify->setInt32("aac-drc-album-mode", presentation.nDrcAlbumMode);
- notify->setInt32("aac-drc-output-loudness",
- presentation.nDrcOutputLoudness);
}
}
break;
diff --git a/media/libstagefright/rtsp/AAVCAssembler.cpp b/media/libstagefright/rtsp/AAVCAssembler.cpp
index e1cc5ec..3f4d662 100644
--- a/media/libstagefright/rtsp/AAVCAssembler.cpp
+++ b/media/libstagefright/rtsp/AAVCAssembler.cpp
@@ -44,6 +44,7 @@
mNextExpectedSeqNo(0),
mAccessUnitDamaged(false),
mFirstIFrameProvided(false),
+ mLastCvo(-1),
mLastIFrameProvidedAtMs(0),
mLastRtpTimeJitterDataUs(0),
mWidth(0),
@@ -137,7 +138,7 @@
}
source->putInterArrivalJitterData(rtpTime, nowTimeUs);
- const int64_t startTimeMs = source->mFirstSysTime / 1000;
+ const int64_t startTimeMs = source->mSysAnchorTime / 1000;
const int64_t nowTimeMs = nowTimeUs / 1000;
const int32_t staticJitterTimeMs = source->getStaticJitterTimeMs();
const int32_t baseJitterTimeMs = source->getBaseJitterTimeMs();
@@ -195,33 +196,38 @@
if (!isExpired) {
ALOGV("buffering in jitter buffer.");
+ // set an alarm for jitter buffer time expiration.
+ // adding 1ms because jitter buffer time is keep changing.
+ int64_t expTimeUs = (RtpToMs(std::abs(diffTimeRtp), clockRate) + 1) * 1000;
+ source->setJbAlarmTime(nowTimeUs, expTimeUs);
return NOT_ENOUGH_DATA;
}
if (isFirstLineBroken) {
- if (isSecondLineBroken) {
- int64_t totalDiffTimeMs = RtpToMs(diffTimeRtp + jitterTimeRtp, clockRate);
- ALOGE("buffer too late... \t RTP diff from exp =%lld \t MS diff from stamp = %lld\t\t"
+ int64_t totalDiffTimeMs = RtpToMs(diffTimeRtp + jitterTimeRtp, clockRate);
+ String8 info;
+ info.appendFormat("RTP diff from exp =%lld \t MS diff from stamp = %lld\t\t"
"Seq# %d \t ExpSeq# %d \t"
"JitterMs %d + (%d + %d * %.3f)",
(long long)diffTimeRtp, (long long)totalDiffTimeMs,
buffer->int32Data(), mNextExpectedSeqNo,
jitterTimeMs, tryJbTimeMs, dynamicJbTimeMs, JITTER_MULTIPLE);
+ if (isSecondLineBroken) {
+ ALOGE("%s", info.string());
printNowTimeMs(startTimeMs, nowTimeMs, playedTimeMs);
printRTPTime(rtpTime, playedTimeRtp, expiredTimeRtp, isExpired);
- mNextExpectedSeqNo = pickProperSeq(queue, firstRTPTime, playedTimeRtp, jitterTimeRtp);
} else {
- ALOGW("=== WARNING === buffer arrived after %d + %d = %d ms === WARNING === ",
- jitterTimeMs, tryJbTimeMs, jitterTimeMs + tryJbTimeMs);
+ ALOGW("%s", info.string());
}
}
if (mNextExpectedSeqNoValid) {
- int32_t size = queue->size();
+ mNextExpectedSeqNo = pickStartSeq(queue, firstRTPTime, playedTimeRtp, jitterTimeRtp);
int32_t cntRemove = deleteUnitUnderSeq(queue, mNextExpectedSeqNo);
if (cntRemove > 0) {
+ int32_t size = queue->size();
source->noticeAbandonBuffer(cntRemove);
ALOGW("delete %d of %d buffers", cntRemove, size);
}
@@ -441,7 +447,6 @@
uint32_t rtpTimeStartAt;
CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTimeStartAt));
uint32_t startSeqNo = buffer->int32Data();
- bool pFrame = nalType == 0x1;
if (data[1] & 0x40) {
// Huh? End bit also set on the first buffer.
@@ -451,8 +456,6 @@
complete = true;
} else {
List<sp<ABuffer> >::iterator it = ++queue->begin();
- int32_t connected = 1;
- bool snapped = false;
while (it != queue->end()) {
ALOGV("sequence length %zu", totalCount);
@@ -463,33 +466,26 @@
if ((uint32_t)buffer->int32Data() != expectedSeqNo) {
ALOGD("sequence not complete, expected seqNo %u, got %u, nalType %u",
- expectedSeqNo, (unsigned)buffer->int32Data(), nalType);
- snapped = true;
-
- if (!pFrame) {
- return WRONG_SEQUENCE_NUMBER;
- }
- }
-
- if (!snapped) {
- connected++;
+ expectedSeqNo, (uint32_t)buffer->int32Data(), nalType);
}
uint32_t rtpTime;
CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
- if (size < 2
- || data[0] != indicator
+ if (size < 2) {
+ ALOGV("Ignoring malformed FU buffer.");
+ it = queue->erase(it);
+ continue;
+ }
+ if (data[0] != indicator
|| (data[1] & 0x1f) != nalType
|| (data[1] & 0x80)
|| rtpTime != rtpTimeStartAt) {
- ALOGV("Ignoring malformed FU buffer.");
-
- // Delete the whole start of the FU.
-
- mNextExpectedSeqNo = expectedSeqNo + 1;
- deleteUnitUnderSeq(queue, mNextExpectedSeqNo);
-
- return MALFORMED_PACKET;
+ // Assembler already have given enough time by jitter buffer
+ ALOGD("Seems another frame. Incomplete frame [%d ~ %d) \t %d FUs",
+ startSeqNo, expectedSeqNo, (int)queue->distance(queue->begin(), it));
+ expectedSeqNo = (uint32_t)buffer->int32Data();
+ complete = true;
+ break;
}
totalSize += size - 2;
@@ -498,14 +494,6 @@
expectedSeqNo = (uint32_t)buffer->int32Data() + 1;
if (data[1] & 0x40) {
- if (pFrame && !recycleUnit(startSeqNo, expectedSeqNo,
- connected, totalCount, 0.5f)) {
- mNextExpectedSeqNo = expectedSeqNo;
- deleteUnitUnderSeq(queue, mNextExpectedSeqNo);
-
- return MALFORMED_PACKET;
- }
-
// This is the last fragment.
complete = true;
break;
@@ -557,6 +545,9 @@
if (cvo >= 0) {
unit->meta()->setInt32("cvo", cvo);
+ mLastCvo = cvo;
+ } else if (mLastCvo >= 0) {
+ unit->meta()->setInt32("cvo", mLastCvo);
}
if (source != nullptr) {
unit->meta()->setObject("source", source);
@@ -621,35 +612,32 @@
msg->post();
}
-int32_t AAVCAssembler::pickProperSeq(const Queue *queue,
+int32_t AAVCAssembler::pickStartSeq(const Queue *queue,
uint32_t first, int64_t play, int64_t jit) {
+ // pick the first sequence number has the start bit.
sp<ABuffer> buffer = *(queue->begin());
- int32_t nextSeqNo = buffer->int32Data();
+ int32_t firstSeqNo = buffer->int32Data();
- Queue::const_iterator it = queue->begin();
- while (it != queue->end()) {
- int64_t rtpTime = findRTPTime(first, *it);
- // if pkt in time exists, that should be the next pivot
+ // This only works for FU-A type & non-start sequence
+ unsigned nalType = buffer->data()[0] & 0x1f;
+ if (nalType != 28 || buffer->data()[1] & 0x80) {
+ return firstSeqNo;
+ }
+
+ for (auto it : *queue) {
+ const uint8_t *data = it->data();
+ int64_t rtpTime = findRTPTime(first, it);
if (rtpTime + jit >= play) {
- nextSeqNo = (*it)->int32Data();
break;
}
- it++;
+ if ((data[1] & 0x80)) {
+ const int32_t seqNo = it->int32Data();
+ ALOGE("finding [HEAD] pkt. \t Seq# (%d ~ )[%d", firstSeqNo, seqNo);
+ firstSeqNo = seqNo;
+ break;
+ }
}
- return nextSeqNo;
-}
-
-bool AAVCAssembler::recycleUnit(uint32_t start, uint32_t end, uint32_t connected,
- size_t avail, float goodRatio) {
- float total = end - start;
- float valid = connected;
- float exist = avail;
- bool isRecycle = (valid / total) >= goodRatio;
-
- ALOGV("checking p-frame losses.. recvBufs %f valid %f diff %f recycle? %d",
- exist, valid, total, isRecycle);
-
- return isRecycle;
+ return firstSeqNo;
}
int32_t AAVCAssembler::deleteUnitUnderSeq(Queue *queue, uint32_t seq) {
diff --git a/media/libstagefright/rtsp/AAVCAssembler.h b/media/libstagefright/rtsp/AAVCAssembler.h
index 8d19773..2f8b8ba 100644
--- a/media/libstagefright/rtsp/AAVCAssembler.h
+++ b/media/libstagefright/rtsp/AAVCAssembler.h
@@ -22,6 +22,7 @@
#include <utils/List.h>
#include <utils/RefBase.h>
+#include <utils/String8.h>
namespace android {
@@ -47,6 +48,7 @@
uint32_t mNextExpectedSeqNo;
bool mAccessUnitDamaged;
bool mFirstIFrameProvided;
+ int32_t mLastCvo;
uint64_t mLastIFrameProvidedAtMs;
int64_t mLastRtpTimeJitterDataUs;
int32_t mWidth;
@@ -64,9 +66,7 @@
void submitAccessUnit();
- int32_t pickProperSeq(const Queue *q, uint32_t first, int64_t play, int64_t jit);
- bool recycleUnit(uint32_t start, uint32_t end, uint32_t connected,
- size_t avail, float goodRatio);
+ int32_t pickStartSeq(const Queue *q, uint32_t first, int64_t play, int64_t jit);
int32_t deleteUnitUnderSeq(Queue *q, uint32_t seq);
DISALLOW_EVIL_CONSTRUCTORS(AAVCAssembler);
diff --git a/media/libstagefright/rtsp/AHEVCAssembler.cpp b/media/libstagefright/rtsp/AHEVCAssembler.cpp
index d32e85d..b240339 100644
--- a/media/libstagefright/rtsp/AHEVCAssembler.cpp
+++ b/media/libstagefright/rtsp/AHEVCAssembler.cpp
@@ -51,6 +51,7 @@
mNextExpectedSeqNo(0),
mAccessUnitDamaged(false),
mFirstIFrameProvided(false),
+ mLastCvo(-1),
mLastIFrameProvidedAtMs(0),
mLastRtpTimeJitterDataUs(0),
mWidth(0),
@@ -147,7 +148,7 @@
}
source->putInterArrivalJitterData(rtpTime, nowTimeUs);
- const int64_t startTimeMs = source->mFirstSysTime / 1000;
+ const int64_t startTimeMs = source->mSysAnchorTime / 1000;
const int64_t nowTimeMs = nowTimeUs / 1000;
const int32_t staticJitterTimeMs = source->getStaticJitterTimeMs();
const int32_t baseJitterTimeMs = source->getBaseJitterTimeMs();
@@ -205,33 +206,38 @@
if (!isExpired) {
ALOGV("buffering in jitter buffer.");
+ // set an alarm for jitter buffer time expiration.
+ // adding 1ms because jitter buffer time is keep changing.
+ int64_t expTimeUs = (RtpToMs(std::abs(diffTimeRtp), clockRate) + 1) * 1000;
+ source->setJbAlarmTime(nowTimeUs, expTimeUs);
return NOT_ENOUGH_DATA;
}
if (isFirstLineBroken) {
- if (isSecondLineBroken) {
- int64_t totalDiffTimeMs = RtpToMs(diffTimeRtp + jitterTimeRtp, clockRate);
- ALOGE("buffer too late... \t RTP diff from exp =%lld \t MS diff from stamp = %lld\t\t"
+ int64_t totalDiffTimeMs = RtpToMs(diffTimeRtp + jitterTimeRtp, clockRate);
+ String8 info;
+ info.appendFormat("RTP diff from exp =%lld \t MS diff from stamp = %lld\t\t"
"Seq# %d \t ExpSeq# %d \t"
"JitterMs %d + (%d + %d * %.3f)",
(long long)diffTimeRtp, (long long)totalDiffTimeMs,
buffer->int32Data(), mNextExpectedSeqNo,
jitterTimeMs, tryJbTimeMs, dynamicJbTimeMs, JITTER_MULTIPLE);
+ if (isSecondLineBroken) {
+ ALOGE("%s", info.string());
printNowTimeMs(startTimeMs, nowTimeMs, playedTimeMs);
printRTPTime(rtpTime, playedTimeRtp, expiredTimeRtp, isExpired);
- mNextExpectedSeqNo = pickProperSeq(queue, firstRTPTime, playedTimeRtp, jitterTimeRtp);
} else {
- ALOGW("=== WARNING === buffer arrived after %d + %d = %d ms === WARNING === ",
- jitterTimeMs, tryJbTimeMs, jitterTimeMs + tryJbTimeMs);
+ ALOGW("%s", info.string());
}
}
if (mNextExpectedSeqNoValid) {
- int32_t size = queue->size();
+ mNextExpectedSeqNo = pickStartSeq(queue, firstRTPTime, playedTimeRtp, jitterTimeRtp);
int32_t cntRemove = deleteUnitUnderSeq(queue, mNextExpectedSeqNo);
if (cntRemove > 0) {
+ int32_t size = queue->size();
source->noticeAbandonBuffer(cntRemove);
ALOGW("delete %d of %d buffers", cntRemove, size);
}
@@ -466,7 +472,6 @@
uint32_t rtpTimeStartAt;
CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTimeStartAt));
uint32_t startSeqNo = buffer->int32Data();
- bool pFrame = (nalType < 0x10);
if (data[2] & 0x40) {
// Huh? End bit also set on the first buffer.
@@ -476,8 +481,6 @@
complete = true;
} else {
List<sp<ABuffer> >::iterator it = ++queue->begin();
- int32_t connected = 1;
- bool snapped = false;
while (it != queue->end()) {
ALOGV("sequence length %zu", totalCount);
@@ -488,33 +491,26 @@
if ((uint32_t)buffer->int32Data() != expectedSeqNo) {
ALOGV("sequence not complete, expected seqNo %u, got %u, nalType %u",
- expectedSeqNo, (uint32_t)buffer->int32Data(), nalType);
- snapped = true;
-
- if (!pFrame) {
- return WRONG_SEQUENCE_NUMBER;
- }
- }
-
- if (!snapped) {
- connected++;
+ expectedSeqNo, (unsigned)buffer->int32Data(), nalType);
}
uint32_t rtpTime;
CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
- if (size < 3
- || ((data[0] >> 1) & H265_NALU_MASK) != indicator
+ if (size < 3) {
+ ALOGV("Ignoring malformed FU buffer.");
+ it = queue->erase(it);
+ continue;
+ }
+ if (((data[0] >> 1) & H265_NALU_MASK) != indicator
|| (data[2] & H265_NALU_MASK) != nalType
|| (data[2] & 0x80)
|| rtpTime != rtpTimeStartAt) {
- ALOGV("Ignoring malformed FU buffer.");
-
- // Delete the whole start of the FU.
-
- mNextExpectedSeqNo = expectedSeqNo + 1;
- deleteUnitUnderSeq(queue, mNextExpectedSeqNo);
-
- return MALFORMED_PACKET;
+ // Assembler already have given enough time by jitter buffer
+ ALOGD("Seems another frame. Incomplete frame [%d ~ %d) \t %d FUs",
+ startSeqNo, expectedSeqNo, (int)queue->distance(queue->begin(), it));
+ expectedSeqNo = (uint32_t)buffer->int32Data();
+ complete = true;
+ break;
}
totalSize += size - 3;
@@ -523,13 +519,6 @@
expectedSeqNo = (uint32_t)buffer->int32Data() + 1;
if (data[2] & 0x40) {
- if (pFrame && !recycleUnit(startSeqNo, expectedSeqNo,
- connected, totalCount, 0.5f)) {
- mNextExpectedSeqNo = expectedSeqNo;
- deleteUnitUnderSeq(queue, mNextExpectedSeqNo);
-
- return MALFORMED_PACKET;
- }
// This is the last fragment.
complete = true;
break;
@@ -579,6 +568,9 @@
if (cvo >= 0) {
unit->meta()->setInt32("cvo", cvo);
+ mLastCvo = cvo;
+ } else if (mLastCvo >= 0) {
+ unit->meta()->setInt32("cvo", mLastCvo);
}
addSingleNALUnit(unit);
@@ -635,35 +627,32 @@
msg->post();
}
-int32_t AHEVCAssembler::pickProperSeq(const Queue *queue,
+int32_t AHEVCAssembler::pickStartSeq(const Queue *queue,
uint32_t first, int64_t play, int64_t jit) {
+ // pick the first sequence number has the start bit.
sp<ABuffer> buffer = *(queue->begin());
- int32_t nextSeqNo = buffer->int32Data();
+ int32_t firstSeqNo = buffer->int32Data();
- Queue::const_iterator it = queue->begin();
- while (it != queue->end()) {
- int64_t rtpTime = findRTPTime(first, *it);
- // if pkt in time exists, that should be the next pivot
+ // This only works for FU-A type & non-start sequence
+ unsigned nalType = buffer->data()[0] & 0x1f;
+ if (nalType != 28 || buffer->data()[2] & 0x80) {
+ return firstSeqNo;
+ }
+
+ for (auto it : *queue) {
+ const uint8_t *data = it->data();
+ int64_t rtpTime = findRTPTime(first, it);
if (rtpTime + jit >= play) {
- nextSeqNo = (*it)->int32Data();
break;
}
- it++;
+ if ((data[2] & 0x80)) {
+ const int32_t seqNo = it->int32Data();
+ ALOGE("finding [HEAD] pkt. \t Seq# (%d ~ )[%d", firstSeqNo, seqNo);
+ firstSeqNo = seqNo;
+ break;
+ }
}
- return nextSeqNo;
-}
-
-bool AHEVCAssembler::recycleUnit(uint32_t start, uint32_t end, uint32_t connected,
- size_t avail, float goodRatio) {
- float total = end - start;
- float valid = connected;
- float exist = avail;
- bool isRecycle = (valid / total) >= goodRatio;
-
- ALOGV("checking p-frame losses.. recvBufs %f valid %f diff %f recycle? %d",
- exist, valid, total, isRecycle);
-
- return isRecycle;
+ return firstSeqNo;
}
int32_t AHEVCAssembler::deleteUnitUnderSeq(Queue *queue, uint32_t seq) {
diff --git a/media/libstagefright/rtsp/AHEVCAssembler.h b/media/libstagefright/rtsp/AHEVCAssembler.h
index 68777a7..9575d8c 100644
--- a/media/libstagefright/rtsp/AHEVCAssembler.h
+++ b/media/libstagefright/rtsp/AHEVCAssembler.h
@@ -22,6 +22,7 @@
#include <utils/List.h>
#include <utils/RefBase.h>
+#include <utils/String8.h>
namespace android {
@@ -48,6 +49,7 @@
uint32_t mNextExpectedSeqNo;
bool mAccessUnitDamaged;
bool mFirstIFrameProvided;
+ int32_t mLastCvo;
uint64_t mLastIFrameProvidedAtMs;
int64_t mLastRtpTimeJitterDataUs;
int32_t mWidth;
@@ -65,9 +67,7 @@
void submitAccessUnit();
- int32_t pickProperSeq(const Queue *q, uint32_t first, int64_t play, int64_t jit);
- bool recycleUnit(uint32_t start, uint32_t end, uint32_t connected,
- size_t avail, float goodRatio);
+ int32_t pickStartSeq(const Queue *q, uint32_t first, int64_t play, int64_t jit);
int32_t deleteUnitUnderSeq(Queue *queue, uint32_t seq);
DISALLOW_EVIL_CONSTRUCTORS(AHEVCAssembler);
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 8f4df8e..169df46 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -594,4 +594,15 @@
return mFormat;
}
+bool APacketSource::isVideo() {
+ bool isVideo = false;
+
+ const char *mime;
+ if (mFormat->findCString(kKeyMIMEType, &mime)) {
+ isVideo = !strncasecmp(mime, "video/", 6);
+ }
+
+ return isVideo;
+}
+
} // namespace android
diff --git a/media/libstagefright/rtsp/APacketSource.h b/media/libstagefright/rtsp/APacketSource.h
index 530e537..2b9b5ba 100644
--- a/media/libstagefright/rtsp/APacketSource.h
+++ b/media/libstagefright/rtsp/APacketSource.h
@@ -33,6 +33,8 @@
virtual sp<MetaData> getFormat();
+ bool isVideo();
+
protected:
virtual ~APacketSource();
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index 33c85a7..74acdda 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -18,9 +18,7 @@
#define LOG_TAG "ARTPConnection"
#include <utils/Log.h>
-#include "ARTPAssembler.h"
#include "ARTPConnection.h"
-
#include "ARTPSource.h"
#include "ASessionDescription.h"
@@ -104,6 +102,11 @@
msg->post();
}
+void ARTPConnection::seekStream() {
+ sp<AMessage> msg = new AMessage(kWhatSeekStream, this);
+ msg->post();
+}
+
void ARTPConnection::removeStream(int rtpSocket, int rtcpSocket) {
sp<AMessage> msg = new AMessage(kWhatRemoveStream, this);
msg->setInt32("rtp-socket", rtpSocket);
@@ -283,6 +286,12 @@
break;
}
+ case kWhatSeekStream:
+ {
+ onSeekStream(msg);
+ break;
+ }
+
case kWhatRemoveStream:
{
onRemoveStream(msg);
@@ -295,6 +304,12 @@
break;
}
+ case kWhatAlarmStream:
+ {
+ onAlarmStream(msg);
+ break;
+ }
+
case kWhatInjectPacket:
{
onInjectPacket(msg);
@@ -353,6 +368,18 @@
}
}
+void ARTPConnection::onSeekStream(const sp<AMessage> &msg) {
+ (void)msg; // unused param as of now.
+ List<StreamInfo>::iterator it = mStreams.begin();
+ while (it != mStreams.end()) {
+ for (size_t i = 0; i < it->mSources.size(); ++i) {
+ sp<ARTPSource> source = it->mSources.valueAt(i);
+ source->timeReset();
+ }
+ ++it;
+ }
+}
+
void ARTPConnection::onRemoveStream(const sp<AMessage> &msg) {
int32_t rtpSocket, rtcpSocket;
CHECK(msg->findInt32("rtp-socket", &rtpSocket));
@@ -548,6 +575,13 @@
}
}
+void ARTPConnection::onAlarmStream(const sp<AMessage> msg) {
+ sp<ARTPSource> source = nullptr;
+ if (msg->findObject("source", (sp<android::RefBase>*)&source)) {
+ source->processRTPPacket();
+ }
+}
+
status_t ARTPConnection::receive(StreamInfo *s, bool receiveRTP) {
ALOGV("receiving %s", receiveRTP ? "RTP" : "RTCP");
@@ -633,12 +667,6 @@
}
status_t ARTPConnection::parseRTP(StreamInfo *s, const sp<ABuffer> &buffer) {
- if (s->mNumRTPPacketsReceived++ == 0) {
- sp<AMessage> notify = s->mNotifyMsg->dup();
- notify->setInt32("first-rtp", true);
- notify->post();
- }
-
size_t size = buffer->size();
if (size < 12) {
@@ -720,9 +748,23 @@
meta->setInt32("cvo", cvoDegrees);
}
- buffer->setInt32Data(u16at(&data[2]));
+ int32_t seq = u16at(&data[2]);
+ buffer->setInt32Data(seq);
buffer->setRange(payloadOffset, size - payloadOffset);
+ if (s->mNumRTPPacketsReceived++ == 0) {
+ sp<AMessage> notify = s->mNotifyMsg->dup();
+ notify->setInt32("first-rtp", true);
+ notify->setInt32("rtcp-event", 1);
+ notify->setInt32("payload-type", ARTPSource::RTP_FIRST_PACKET);
+ notify->setInt32("rtp-time", (int32_t)rtpTime);
+ notify->setInt32("rtp-seq-num", seq);
+ notify->setInt64("recv-time-us", ALooper::GetNowUs());
+ notify->post();
+
+ ALOGD("send first-rtp event to upper layer");
+ }
+
source->processRTPPacket(buffer);
return OK;
@@ -779,14 +821,12 @@
if (s->mNumRTCPPacketsReceived++ == 0) {
sp<AMessage> notify = s->mNotifyMsg->dup();
notify->setInt32("first-rtcp", true);
+ notify->setInt32("rtcp-event", 1);
+ notify->setInt32("payload-type", ARTPSource::RTCP_FIRST_PACKET);
+ notify->setInt64("recv-time-us", ALooper::GetNowUs());
notify->post();
- ALOGI("send first-rtcp event to upper layer as ImsRxNotice");
- sp<AMessage> imsNotify = s->mNotifyMsg->dup();
- imsNotify->setInt32("rtcp-event", 1);
- imsNotify->setInt32("payload-type", 101);
- imsNotify->setInt32("feedback-type", 0);
- imsNotify->post();
+ ALOGD("send first-rtcp event to upper layer");
}
const uint8_t *data = buffer->data();
@@ -883,7 +923,7 @@
int64_t nowUs = ALooper::GetNowUs();
int32_t timeDiff = (nowUs - mLastBitrateReportTimeUs) / 1000000ll;
int32_t bitrate = mCumulativeBytes * 8 / timeDiff;
- source->notifyPktInfo(bitrate, true /* isRegular */);
+ source->notifyPktInfo(bitrate, nowUs, true /* isRegular */);
source->byeReceived();
@@ -1065,11 +1105,14 @@
srcId, info->mSessionDesc, info->mIndex, info->mNotifyMsg);
if (mFlags & kViLTEConnection) {
+ setStaticJitterTimeMs(50);
source->setPeriodicFIR(false);
}
source->setSelfID(mSelfID);
source->setStaticJitterTimeMs(mStaticJitterTimeMs);
+ sp<AMessage> timer = new AMessage(kWhatAlarmStream, this);
+ source->setJbTimer(timer);
info->mSources.add(srcId, source);
} else {
source = info->mSources.valueAt(index);
@@ -1117,7 +1160,7 @@
for (size_t i = 0; i < s->mSources.size(); ++i) {
sp<ARTPSource> source = s->mSources.valueAt(i);
if (source->isNeedToEarlyNotify()) {
- source->notifyPktInfo(bitrate, false /* isRegular */);
+ source->notifyPktInfo(bitrate, nowUs, false /* isRegular */);
mLastEarlyNotifyTimeUs = nowUs + (1000000ll * 3600 * 24); // after 1 day
}
}
@@ -1148,7 +1191,7 @@
buffer->setRange(0, 0);
for (size_t i = 0; i < s->mSources.size(); ++i) {
sp<ARTPSource> source = s->mSources.valueAt(i);
- source->notifyPktInfo(bitrate, true /* isRegular */);
+ source->notifyPktInfo(bitrate, nowUs, true /* isRegular */);
}
++it;
}
diff --git a/media/libstagefright/rtsp/ARTPConnection.h b/media/libstagefright/rtsp/ARTPConnection.h
index ea0a374..36cca31 100644
--- a/media/libstagefright/rtsp/ARTPConnection.h
+++ b/media/libstagefright/rtsp/ARTPConnection.h
@@ -40,7 +40,7 @@
const sp<ASessionDescription> &sessionDesc, size_t index,
const sp<AMessage> ¬ify,
bool injected);
-
+ void seekStream();
void removeStream(int rtpSocket, int rtcpSocket);
void injectPacket(int index, const sp<ABuffer> &buffer);
@@ -69,9 +69,11 @@
private:
enum {
kWhatAddStream,
+ kWhatSeekStream,
kWhatRemoveStream,
kWhatPollStreams,
kWhatInjectPacket,
+ kWhatAlarmStream,
};
static const int64_t kSelectTimeoutUs;
@@ -94,8 +96,10 @@
int32_t mCumulativeBytes;
void onAddStream(const sp<AMessage> &msg);
+ void onSeekStream(const sp<AMessage> &msg);
void onRemoveStream(const sp<AMessage> &msg);
void onPollStreams();
+ void onAlarmStream(const sp<AMessage> msg);
void onInjectPacket(const sp<AMessage> &msg);
void onSendReceiverReports();
void checkRxBitrate(int64_t nowUs);
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index 8787d65..38a370b 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -44,10 +44,11 @@
uint32_t id,
const sp<ASessionDescription> &sessionDesc, size_t index,
const sp<AMessage> ¬ify)
- : mFirstSeqNumber(0),
- mFirstRtpTime(0),
+ : mFirstRtpTime(0),
mFirstSysTime(0),
mClockRate(0),
+ mSysAnchorTime(0),
+ mLastSysAnchorTimeUpdatedUs(0),
mFirstSsrc(0),
mHighestNackNumber(0),
mID(id),
@@ -58,9 +59,14 @@
mPrevNumBuffersReceived(0),
mPrevExpectedForRR(0),
mPrevNumBuffersReceivedForRR(0),
+ mLatestRtpTime(0),
mStaticJbTimeMs(kStaticJitterTimeMs),
- mLastNTPTime(0),
- mLastNTPTimeUpdateUs(0),
+ mLastSrRtpTime(0),
+ mLastSrNtpTime(0),
+ mLastSrUpdateTimeUs(0),
+ mIsFirstRtpRtcpGap(true),
+ mAvgRtpRtcpGapMs(0),
+ mAvgUnderlineDelayMs(0),
mIssueFIRRequests(false),
mIssueFIRByAssembler(false),
mLastFIRRequestUs(-1),
@@ -106,6 +112,7 @@
int32_t clockRate, numChannels;
ASessionDescription::ParseFormatDesc(desc.c_str(), &clockRate, &numChannels);
mClockRate = clockRate;
+ mLastJbAlarmTimeUs = 0;
mJitterCalc = new JitterCalc(mClockRate);
}
@@ -119,34 +126,144 @@
}
}
+void ARTPSource::processRTPPacket() {
+ if (mAssembler != NULL && !mQueue.empty()) {
+ mAssembler->onPacketReceived(this);
+ }
+}
+
void ARTPSource::timeUpdate(uint32_t rtpTime, uint64_t ntpTime) {
- mLastNTPTime = ntpTime;
- mLastNTPTimeUpdateUs = ALooper::GetNowUs();
+ mLastSrRtpTime = rtpTime;
+ mLastSrNtpTime = ntpTime;
+ mLastSrUpdateTimeUs = ALooper::GetNowUs();
sp<AMessage> notify = mNotify->dup();
notify->setInt32("time-update", true);
notify->setInt32("rtp-time", rtpTime);
notify->setInt64("ntp-time", ntpTime);
+ notify->setInt32("rtcp-event", 1);
+ notify->setInt32("payload-type", RTCP_SR);
+ notify->setInt64("recv-time-us", mLastSrUpdateTimeUs);
notify->post();
}
-bool ARTPSource::queuePacket(const sp<ABuffer> &buffer) {
- uint32_t seqNum = (uint32_t)buffer->int32Data();
+void ARTPSource::timeReset() {
+ mFirstRtpTime = 0;
+ mFirstSysTime = 0;
+ mSysAnchorTime = 0;
+ mLastSysAnchorTimeUpdatedUs = 0;
+ mFirstSsrc = 0;
+ mHighestNackNumber = 0;
+ mHighestSeqNumber = 0;
+ mPrevExpected = 0;
+ mBaseSeqNumber = 0;
+ mNumBuffersReceived = 0;
+ mPrevNumBuffersReceived = 0;
+ mPrevExpectedForRR = 0;
+ mPrevNumBuffersReceivedForRR = 0;
+ mLatestRtpTime = 0;
+ mLastSrRtpTime = 0;
+ mLastSrNtpTime = 0;
+ mLastSrUpdateTimeUs = 0;
+ mIsFirstRtpRtcpGap = true;
+ mAvgRtpRtcpGapMs = 0;
+ mAvgUnderlineDelayMs = 0;
+ mIssueFIRByAssembler = false;
+ mLastFIRRequestUs = -1;
+}
- int32_t ssrc = 0;
+void ARTPSource::calcTimeGapRtpRtcp(const sp<ABuffer> &buffer, int64_t nowUs) {
+ if (mLastSrUpdateTimeUs == 0) {
+ return;
+ }
+
+ int64_t elapsedMs = (nowUs - mLastSrUpdateTimeUs) / 1000;
+ int64_t elapsedRtpTime = (elapsedMs * (mClockRate / 1000));
+ uint32_t rtpTime;
+ CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+
+ int64_t anchorRtpTime = mLastSrRtpTime + elapsedRtpTime;
+ int64_t rtpTimeGap = anchorRtpTime - rtpTime;
+ // rtpTime can not be faster than it's anchor time.
+ // because rtpTime(of rtp packet) represents it's a frame captured time and
+ // anchorRtpTime(of rtcp:sr packet) represents it's a rtp packetized time.
+ if (rtpTimeGap < 0 || rtpTimeGap > (mClockRate * 60)) {
+ // ignore invalid delay gap such as negative delay or later than 1 min.
+ return;
+ }
+
+ int64_t rtpTimeGapMs = (rtpTimeGap * 1000 / mClockRate);
+ if (mIsFirstRtpRtcpGap) {
+ mIsFirstRtpRtcpGap = false;
+ mAvgRtpRtcpGapMs = rtpTimeGapMs;
+ } else {
+ // This is measuring avg rtp timestamp distance between rtp and rtcp:sr packet.
+ // Rtp timestamp of rtp packet represents it's raw frame captured time.
+ // Rtp timestamp of rtcp:sr packet represents it's packetization time.
+ // So that, this value is showing how much time delayed to be a rtp packet
+ // from a raw frame captured time.
+ // This value maybe referred to know a/v sync and sender's own delay of this media stream.
+ mAvgRtpRtcpGapMs = ((mAvgRtpRtcpGapMs * 15) + rtpTimeGapMs) / 16;
+ }
+}
+
+void ARTPSource::calcUnderlineDelay(const sp<ABuffer> &buffer, int64_t nowUs) {
+ int64_t elapsedMs = (nowUs - mSysAnchorTime) / 1000;
+ int64_t elapsedRtpTime = (elapsedMs * (mClockRate / 1000));
+ int64_t expectedRtpTime = mFirstRtpTime + elapsedRtpTime;
+
+ int32_t rtpTime;
+ CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+ int32_t delayMs = (expectedRtpTime - rtpTime) / (mClockRate / 1000);
+
+ mAvgUnderlineDelayMs = ((mAvgUnderlineDelayMs * 15) + delayMs) / 16;
+}
+
+void ARTPSource::adjustAnchorTimeIfRequired(int64_t nowUs) {
+ if (nowUs - mLastSysAnchorTimeUpdatedUs < 1000000L) {
+ return;
+ }
+
+ if (mAvgUnderlineDelayMs < -30) {
+ // adjust underline delay a quarter of desired delay like step by step.
+ mSysAnchorTime += (int64_t)(mAvgUnderlineDelayMs * 1000 / 4);
+ ALOGD("anchor time updated: original(%lld), anchor(%lld), diffMs(%lld)",
+ (long long)mFirstSysTime, (long long)mSysAnchorTime,
+ (long long)(mFirstSysTime - mSysAnchorTime) / 1000);
+
+ mAvgUnderlineDelayMs = 0;
+ mLastSysAnchorTimeUpdatedUs = nowUs;
+
+ // reset a jitter stastics since an anchor time adjusted.
+ mJitterCalc->init(mFirstRtpTime, mSysAnchorTime, 0, mStaticJbTimeMs * 1000);
+ }
+}
+
+bool ARTPSource::queuePacket(const sp<ABuffer> &buffer) {
+ int64_t nowUs = ALooper::GetNowUs();
+ uint32_t seqNum = (uint32_t)buffer->int32Data();
+ int32_t ssrc = 0, rtpTime = 0;
+
buffer->meta()->findInt32("ssrc", &ssrc);
+ CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+ mLatestRtpTime = rtpTime;
if (mNumBuffersReceived++ == 0 && mFirstSysTime == 0) {
- uint32_t firstRtpTime;
- CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&firstRtpTime));
- mFirstSysTime = ALooper::GetNowUs();
+ mFirstSysTime = nowUs;
+ mSysAnchorTime = nowUs;
+ mLastSysAnchorTimeUpdatedUs = nowUs;
mHighestSeqNumber = seqNum;
mBaseSeqNumber = seqNum;
- mFirstRtpTime = firstRtpTime;
+ mFirstRtpTime = rtpTime;
mFirstSsrc = ssrc;
ALOGD("first-rtp arrived: first-rtp-time=%u, sys-time=%lld, seq-num=%u, ssrc=%d",
mFirstRtpTime, (long long)mFirstSysTime, mHighestSeqNumber, mFirstSsrc);
mJitterCalc->init(mFirstRtpTime, mFirstSysTime, 0, mStaticJbTimeMs * 1000);
+ if (mQueue.size() > 0) {
+ ALOGD("clearing buffers which belonged to previous timeline"
+ " since a base timeline has been changed.");
+ mQueue.clear();
+ }
mQueue.push_back(buffer);
return true;
}
@@ -156,6 +273,10 @@
return false;
}
+ calcTimeGapRtpRtcp(buffer, nowUs);
+ calcUnderlineDelay(buffer, nowUs);
+ adjustAnchorTimeIfRequired(nowUs);
+
// Only the lower 16-bit of the sequence numbers are transmitted,
// derive the high-order bits by choosing the candidate closest
// to the highest sequence number (extended to 32 bits) received so far.
@@ -340,11 +461,11 @@
uint32_t LSR = 0;
uint32_t DLSR = 0;
- if (mLastNTPTime != 0) {
- LSR = (mLastNTPTime >> 16) & 0xffffffff;
+ if (mLastSrNtpTime != 0) {
+ LSR = (mLastSrNtpTime >> 16) & 0xffffffff;
DLSR = (uint32_t)
- ((ALooper::GetNowUs() - mLastNTPTimeUpdateUs) * 65536.0 / 1E6);
+ ((ALooper::GetNowUs() - mLastSrUpdateTimeUs) * 65536.0 / 1E6);
}
data[24] = LSR >> 24;
@@ -543,6 +664,35 @@
mJitterCalc->putInterArrivalData(timeStamp, arrivalTime);
}
+void ARTPSource::setJbTimer(const sp<AMessage> timer) {
+ mJbTimer = timer;
+}
+
+void ARTPSource::setJbAlarmTime(int64_t nowTimeUs, int64_t alarmAfterUs) {
+ if (mJbTimer == NULL) {
+ return;
+ }
+ int64_t alarmTimeUs = nowTimeUs + alarmAfterUs;
+ bool alarm = false;
+ if (mLastJbAlarmTimeUs <= nowTimeUs) {
+ // no more alarm in pending.
+ mLastJbAlarmTimeUs = nowTimeUs + alarmAfterUs;
+ alarm = true;
+ } else if (mLastJbAlarmTimeUs > alarmTimeUs + 5000L) {
+ // bring an alarm forward more than 5ms.
+ mLastJbAlarmTimeUs = alarmTimeUs;
+ alarm = true;
+ } else {
+ // would not set alarm if it is close with before one.
+ }
+
+ if (alarm) {
+ sp<AMessage> notify = mJbTimer->dup();
+ notify->setObject("source", this);
+ notify->post(alarmAfterUs);
+ }
+}
+
bool ARTPSource::isNeedToEarlyNotify() {
uint32_t expected = mHighestSeqNumber - mBaseSeqNumber + 1;
int32_t intervalExpectedInNow = expected - mPrevExpected;
@@ -553,7 +703,7 @@
return false;
}
-void ARTPSource::notifyPktInfo(int32_t bitrate, bool isRegular) {
+void ARTPSource::notifyPktInfo(int32_t bitrate, int64_t nowUs, bool isRegular) {
int32_t payloadType = isRegular ? RTP_QUALITY : RTP_QUALITY_EMC;
sp<AMessage> notify = mNotify->dup();
@@ -567,6 +717,11 @@
notify->setInt32("prev-expected", mPrevExpected);
notify->setInt32("num-buf-recv", mNumBuffersReceived);
notify->setInt32("prev-num-buf-recv", mPrevNumBuffersReceived);
+ notify->setInt32("latest-rtp-time", mLatestRtpTime);
+ notify->setInt64("recv-time-us", nowUs);
+ notify->setInt32("rtp-jitter-time-ms",
+ std::max(getBaseJitterTimeMs(), getStaticJitterTimeMs()));
+ notify->setInt32("rtp-rtcpsr-time-gap-ms", (int32_t)mAvgRtpRtcpGapMs);
notify->post();
if (isRegular) {
diff --git a/media/libstagefright/rtsp/ARTPSource.h b/media/libstagefright/rtsp/ARTPSource.h
index 0edff23..4984e91 100644
--- a/media/libstagefright/rtsp/ARTPSource.h
+++ b/media/libstagefright/rtsp/ARTPSource.h
@@ -31,7 +31,7 @@
namespace android {
-const uint32_t kStaticJitterTimeMs = 50; // 50ms
+const uint32_t kStaticJitterTimeMs = 100; // 100ms
struct ABuffer;
struct AMessage;
@@ -49,6 +49,8 @@
RTCP_FIRST_PACKET = 101,
RTP_QUALITY = 102,
RTP_QUALITY_EMC = 103,
+ RTCP_SR = 200,
+ RTCP_RR = 201,
RTCP_TSFB = 205,
RTCP_PSFB = 206,
RTP_CVO = 300,
@@ -56,6 +58,8 @@
};
void processRTPPacket(const sp<ABuffer> &buffer);
+ void processRTPPacket();
+ void timeReset();
void timeUpdate(uint32_t rtpTime, uint64_t ntpTime);
void byeReceived();
@@ -76,19 +80,23 @@
void setStaticJitterTimeMs(const uint32_t jbTimeMs);
void putBaseJitterData(uint32_t timeStamp, int64_t arrivalTime);
void putInterArrivalJitterData(uint32_t timeStamp, int64_t arrivalTime);
+ void setJbTimer(const sp<AMessage> timer);
+ void setJbAlarmTime(int64_t nowTimeUs, int64_t alarmAfterUs);
bool isNeedToEarlyNotify();
- void notifyPktInfo(int32_t bitrate, bool isRegular);
+ void notifyPktInfo(int32_t bitrate, int64_t nowUs, bool isRegular);
// FIR needs to be sent by missing packet or broken video image.
void onIssueFIRByAssembler();
void noticeAbandonBuffer(int cnt=1);
- int32_t mFirstSeqNumber;
uint32_t mFirstRtpTime;
int64_t mFirstSysTime;
int32_t mClockRate;
+ int64_t mSysAnchorTime;
+ int64_t mLastSysAnchorTimeUpdatedUs;
+
int32_t mFirstSsrc;
int32_t mHighestNackNumber;
@@ -103,11 +111,14 @@
uint32_t mPrevExpectedForRR;
int32_t mPrevNumBuffersReceivedForRR;
+ uint32_t mLatestRtpTime;
+
List<sp<ABuffer> > mQueue;
sp<ARTPAssembler> mAssembler;
int32_t mStaticJbTimeMs;
sp<JitterCalc> mJitterCalc;
+ sp<AMessage> mJbTimer;
typedef struct infoNACK {
uint16_t seqNum;
@@ -120,8 +131,14 @@
std::map<uint16_t, infoNACK> mNACKMap;
int getSeqNumToNACK(List<int>& list, int size);
- uint64_t mLastNTPTime;
- int64_t mLastNTPTimeUpdateUs;
+ uint32_t mLastSrRtpTime;
+ uint64_t mLastSrNtpTime;
+ int64_t mLastSrUpdateTimeUs;
+
+ bool mIsFirstRtpRtcpGap;
+ double mAvgRtpRtcpGapMs;
+ double mAvgUnderlineDelayMs;
+ int64_t mLastJbAlarmTimeUs;
bool mIssueFIRRequests;
bool mIssueFIRByAssembler;
@@ -130,6 +147,10 @@
sp<AMessage> mNotify;
+ void calcTimeGapRtpRtcp(const sp<ABuffer> &buffer, int64_t nowUs);
+ void calcUnderlineDelay(const sp<ABuffer> &buffer, int64_t nowUs);
+ void adjustAnchorTimeIfRequired(int64_t nowUs);
+
bool queuePacket(const sp<ABuffer> &buffer);
DISALLOW_EVIL_CONSTRUCTORS(ARTPSource);
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index ec70952..11c7aeb 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -204,8 +204,6 @@
mRTPTimeBase = 0;
mNumRTPSent = 0;
mNumRTPOctetsSent = 0;
- mLastRTPTime = 0;
- mLastNTPTime = 0;
mOpponentID = 0;
mBitrate = 192000;
@@ -216,6 +214,7 @@
mRTPSockNetwork = 0;
mMode = INVALID;
+ mClockRate = 16000;
}
status_t ARTPWriter::addSource(const sp<MediaSource> &source) {
@@ -265,15 +264,28 @@
updateSocketNetwork(sockNetwork);
if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+ // rfc6184: RTP Payload Format for H.264 Video
+ // The clock rate in the "a=rtpmap" line MUST be 90000.
mMode = H264;
+ mClockRate = 90000;
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
+ // rfc7798: RTP Payload Format for High Efficiency Video Coding (HEVC)
+ // The clock rate in the "a=rtpmap" line MUST be 90000.
mMode = H265;
+ mClockRate = 90000;
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_H263)) {
mMode = H263;
+ // rfc4629: RTP Payload Format for ITU-T Rec. H.263 Video
+ // The clock rate in the "a=rtpmap" line MUST be 90000.
+ mClockRate = 90000;
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {
mMode = AMR_NB;
+ // rfc4867: RTP Payload Format ... (AMR) and (AMR-WB)
+ // The RTP clock rate in "a=rtpmap" MUST be 8000 for AMR and 16000 for AMR-WB
+ mClockRate = 8000;
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
mMode = AMR_WB;
+ mClockRate = 16000;
} else {
TRESPASS();
}
@@ -327,16 +339,17 @@
while (buffer->range_length() > 0) {
const uint8_t *NALPtr = (const uint8_t *)buffer->data() + buffer->range_offset();
+ uint8_t nalType = (*NALPtr) & H264_NALU_MASK;
MediaBufferBase **targetPtr = NULL;
- if ((*NALPtr & H264_NALU_MASK) == H264_NALU_SPS) {
+ if (nalType == H264_NALU_SPS) {
targetPtr = spsBuffer;
- } else if ((*NALPtr & H264_NALU_MASK) == H264_NALU_PPS) {
+ } else if (nalType == H264_NALU_PPS) {
targetPtr = ppsBuffer;
} else {
return;
}
- ALOGV("SPS(7) or PPS(8) found. Type %d", *NALPtr & H264_NALU_MASK);
+ ALOGV("SPS(7) or PPS(8) found. Type %d", nalType);
uint32_t bufferSize = buffer->range_length();
MediaBufferBase *&target = *targetPtr;
@@ -417,18 +430,18 @@
}
}
+ uint32_t targetSize;
if (target != NULL) {
target->release();
}
- uint32_t targetSize;
// note that targetSize is never 0 as the first byte is never part
// of a start prefix
if (isBoundFound) {
targetSize = i - SPCSize + 1;
- target = MediaBufferBase::Create(j);
+ target = MediaBufferBase::Create(targetSize);
memcpy(target->data(),
(const uint8_t *)buffer->data() + buffer->range_offset(),
- j);
+ targetSize);
buffer->set_range(buffer->range_offset() + targetSize + SPCSize,
buffer->range_length() - targetSize - SPCSize);
} else {
@@ -645,19 +658,27 @@
data[6] = (mSourceID >> 8) & 0xff;
data[7] = mSourceID & 0xff;
- data[8] = mLastNTPTime >> (64 - 8);
- data[9] = (mLastNTPTime >> (64 - 16)) & 0xff;
- data[10] = (mLastNTPTime >> (64 - 24)) & 0xff;
- data[11] = (mLastNTPTime >> 32) & 0xff;
- data[12] = (mLastNTPTime >> 24) & 0xff;
- data[13] = (mLastNTPTime >> 16) & 0xff;
- data[14] = (mLastNTPTime >> 8) & 0xff;
- data[15] = mLastNTPTime & 0xff;
+ uint64_t ntpTime = GetNowNTP();
+ data[8] = ntpTime >> (64 - 8);
+ data[9] = (ntpTime >> (64 - 16)) & 0xff;
+ data[10] = (ntpTime >> (64 - 24)) & 0xff;
+ data[11] = (ntpTime >> 32) & 0xff;
+ data[12] = (ntpTime >> 24) & 0xff;
+ data[13] = (ntpTime >> 16) & 0xff;
+ data[14] = (ntpTime >> 8) & 0xff;
+ data[15] = ntpTime & 0xff;
- data[16] = (mLastRTPTime >> 24) & 0xff;
- data[17] = (mLastRTPTime >> 16) & 0xff;
- data[18] = (mLastRTPTime >> 8) & 0xff;
- data[19] = mLastRTPTime & 0xff;
+ // A current rtpTime can be calculated from ALooper::GetNowUs().
+ // This is expecting a timestamp of raw frame from a media source is
+ // on the same time context across components in android media framework
+ // which can be queried by ALooper::GetNowUs().
+ // In other words, ALooper::GetNowUs() is on the same timeline as the time
+ // of kKeyTime in a MediaBufferBase
+ uint32_t rtpTime = getRtpTime(ALooper::GetNowUs());
+ data[16] = (rtpTime >> 24) & 0xff;
+ data[17] = (rtpTime >> 16) & 0xff;
+ data[18] = (rtpTime >> 8) & 0xff;
+ data[19] = rtpTime & 0xff;
data[20] = mNumRTPSent >> 24;
data[21] = (mNumRTPSent >> 16) & 0xff;
@@ -779,6 +800,13 @@
return (hi << 32) | lo;
}
+uint32_t ARTPWriter::getRtpTime(int64_t timeUs) {
+ int32_t clockPerMs = mClockRate / 1000;
+ int64_t rtpTime = mRTPTimeBase + (timeUs * clockPerMs / 1000LL);
+
+ return (uint32_t)rtpTime;
+}
+
void ARTPWriter::dumpSessionDesc() {
AString sdp;
sdp = "v=0\r\n";
@@ -980,7 +1008,7 @@
sendVPSSPSPPSIfIFrame(mediaBuf, timeUs);
- uint32_t rtpTime = mRTPTimeBase + (timeUs * 9 / 100ll);
+ uint32_t rtpTime = getRtpTime(timeUs);
CHECK(mediaBuf->range_length() > 0);
const uint8_t *mediaData =
@@ -994,12 +1022,14 @@
}
sp<ABuffer> buffer = new ABuffer(kMaxPacketSize);
-
if (mediaBuf->range_length() + TCPIP_HEADER_SIZE + RTP_HEADER_SIZE + RTP_HEADER_EXT_SIZE
+ RTP_PAYLOAD_ROOM_SIZE <= buffer->capacity()) {
// The data fits into a single packet
uint8_t *data = buffer->data();
data[0] = 0x80;
+ if (mRTPCVOExtMap > 0) {
+ data[0] |= 0x10;
+ }
if (isNonVCL) {
data[1] = mPayloadType; // Marker bit should not be set in case of Non-VCL
} else {
@@ -1016,144 +1046,6 @@
data[10] = (mSourceID >> 8) & 0xff;
data[11] = mSourceID & 0xff;
- memcpy(&data[12],
- mediaData, mediaBuf->range_length());
-
- buffer->setRange(0, mediaBuf->range_length() + 12);
-
- send(buffer, false /* isRTCP */);
-
- ++mSeqNo;
- ++mNumRTPSent;
- mNumRTPOctetsSent += buffer->size() - 12;
- } else {
- // FU-A
-
- unsigned nalType = (mediaData[0] >> 1) & H265_NALU_MASK;
- ALOGV("H265 nalType 0x%x, data[0]=0x%x", nalType, mediaData[0]);
- size_t offset = 2; //H265 payload header is 16 bit.
-
- bool firstPacket = true;
- while (offset < mediaBuf->range_length()) {
- size_t size = mediaBuf->range_length() - offset;
- bool lastPacket = true;
- if (size + TCPIP_HEADER_SIZE + RTP_HEADER_SIZE + RTP_HEADER_EXT_SIZE +
- RTP_FU_HEADER_SIZE + RTP_PAYLOAD_ROOM_SIZE > buffer->capacity()) {
- lastPacket = false;
- size = buffer->capacity() - TCPIP_HEADER_SIZE - RTP_HEADER_SIZE -
- RTP_HEADER_EXT_SIZE - RTP_FU_HEADER_SIZE - RTP_PAYLOAD_ROOM_SIZE;
- }
-
- uint8_t *data = buffer->data();
- data[0] = 0x80;
- data[1] = (lastPacket ? (1 << 7) : 0x00) | mPayloadType; // M-bit
- data[2] = (mSeqNo >> 8) & 0xff;
- data[3] = mSeqNo & 0xff;
- data[4] = rtpTime >> 24;
- data[5] = (rtpTime >> 16) & 0xff;
- data[6] = (rtpTime >> 8) & 0xff;
- data[7] = rtpTime & 0xff;
- data[8] = mSourceID >> 24;
- data[9] = (mSourceID >> 16) & 0xff;
- data[10] = (mSourceID >> 8) & 0xff;
- data[11] = mSourceID & 0xff;
-
- /* H265 payload header is 16 bit
- 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |F| Type | Layer ID | TID |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- ALOGV("H265 payload header 0x%x %x", mediaData[0], mediaData[1]);
- // excludes Type from 1st byte of H265 payload header.
- data[12] = mediaData[0] & 0x81;
- // fills Type as FU (49 == 0x31)
- data[12] = data[12] | (0x31 << 1);
- data[13] = mediaData[1];
-
- ALOGV("H265 FU header 0x%x %x", data[12], data[13]);
-
- CHECK(!firstPacket || !lastPacket);
- /*
- FU INDICATOR HDR
- 0 1 2 3 4 5 6 7
- +-+-+-+-+-+-+-+
- |S|E| Type |
- +-+-+-+-+-+-+-+
- */
-
- data[14] =
- (firstPacket ? 0x80 : 0x00)
- | (lastPacket ? 0x40 : 0x00)
- | (nalType & H265_NALU_MASK);
- ALOGV("H265 FU indicator 0x%x", data[14]);
-
- memcpy(&data[15], &mediaData[offset], size);
-
- buffer->setRange(0, 15 + size);
-
- send(buffer, false /* isRTCP */);
-
- ++mSeqNo;
- ++mNumRTPSent;
- mNumRTPOctetsSent += buffer->size() - 12;
-
- firstPacket = false;
- offset += size;
- }
- }
-
- mLastRTPTime = rtpTime;
- mLastNTPTime = GetNowNTP();
-
-}
-
-void ARTPWriter::sendAVCData(MediaBufferBase *mediaBuf) {
- // 12 bytes RTP header + 2 bytes for the FU-indicator and FU-header.
- CHECK_GE(kMaxPacketSize, 12u + 2u);
-
- int64_t timeUs;
- CHECK(mediaBuf->meta_data().findInt64(kKeyTime, &timeUs));
-
- sendSPSPPSIfIFrame(mediaBuf, timeUs);
-
- uint32_t rtpTime = mRTPTimeBase + (timeUs * 9 / 100LL);
-
- CHECK(mediaBuf->range_length() > 0);
- const uint8_t *mediaData =
- (const uint8_t *)mediaBuf->data() + mediaBuf->range_offset();
-
- int32_t sps, pps;
- bool isSpsPps = false;
- if (mediaBuf->meta_data().findInt32(kKeySps, &sps) ||
- mediaBuf->meta_data().findInt32(kKeyPps, &pps)) {
- isSpsPps = true;
- }
-
- mTrafficRec->updateClock(ALooper::GetNowUs() / 1000);
- sp<ABuffer> buffer = new ABuffer(kMaxPacketSize);
- if (mediaBuf->range_length() + TCPIP_HEADER_SIZE + RTP_HEADER_SIZE + RTP_HEADER_EXT_SIZE
- + RTP_PAYLOAD_ROOM_SIZE <= buffer->capacity()) {
- // The data fits into a single packet
- uint8_t *data = buffer->data();
- data[0] = 0x80;
- if (mRTPCVOExtMap > 0)
- data[0] |= 0x10;
- if (isSpsPps)
- data[1] = mPayloadType; // Marker bit should not be set in case of sps/pps
- else
- data[1] = (1 << 7) | mPayloadType;
- data[2] = (mSeqNo >> 8) & 0xff;
- data[3] = mSeqNo & 0xff;
- data[4] = rtpTime >> 24;
- data[5] = (rtpTime >> 16) & 0xff;
- data[6] = (rtpTime >> 8) & 0xff;
- data[7] = rtpTime & 0xff;
- data[8] = mSourceID >> 24;
- data[9] = (mSourceID >> 16) & 0xff;
- data[10] = (mSourceID >> 8) & 0xff;
- data[11] = mSourceID & 0xff;
-
int rtpExtIndex = 0;
if (mRTPCVOExtMap > 0) {
/*
@@ -1202,8 +1094,9 @@
} else {
// FU-A
- unsigned nalType = mediaData[0];
- size_t offset = 1;
+ unsigned nalType = (mediaData[0] >> 1) & H265_NALU_MASK;
+ ALOGV("H265 nalType 0x%x, data[0]=0x%x", nalType, mediaData[0]);
+ size_t offset = 2; //H265 payload header is 16 bit.
bool firstPacket = true;
while (offset < mediaBuf->range_length()) {
@@ -1218,8 +1111,9 @@
uint8_t *data = buffer->data();
data[0] = 0x80;
- if (lastPacket && mRTPCVOExtMap > 0)
+ if (lastPacket && mRTPCVOExtMap > 0) {
data[0] |= 0x10;
+ }
data[1] = (lastPacket ? (1 << 7) : 0x00) | mPayloadType; // M-bit
data[2] = (mSeqNo >> 8) & 0xff;
data[3] = mSeqNo & 0xff;
@@ -1245,14 +1139,219 @@
rtpExtIndex = 8;
}
- data[12 + rtpExtIndex] = 28 | (nalType & 0xe0);
+ /* H265 payload header is 16 bit
+ 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |F| Type | Layer ID | TID |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ ALOGV("H265 payload header 0x%x %x", mediaData[0], mediaData[1]);
+ // excludes Type from 1st byte of H265 payload header.
+ data[12 + rtpExtIndex] = mediaData[0] & 0x81;
+ // fills Type as FU (49 == 0x31)
+ data[12 + rtpExtIndex] = data[12 + rtpExtIndex] | (0x31 << 1);
+ data[13 + rtpExtIndex] = mediaData[1];
+
+ ALOGV("H265 FU header 0x%x %x", data[12 + rtpExtIndex], data[13 + rtpExtIndex]);
CHECK(!firstPacket || !lastPacket);
+ /*
+ FU INDICATOR HDR
+ 0 1 2 3 4 5 6 7
+ +-+-+-+-+-+-+-+-+
+ |S|E| Type |
+ +-+-+-+-+-+-+-+-+
+ */
+
+ data[14 + rtpExtIndex] =
+ (firstPacket ? 0x80 : 0x00)
+ | (lastPacket ? 0x40 : 0x00)
+ | (nalType & H265_NALU_MASK);
+ ALOGV("H265 FU indicator 0x%x", data[14]);
+
+ memcpy(&data[15 + rtpExtIndex], &mediaData[offset], size);
+
+ buffer->setRange(0, 15 + rtpExtIndex + size);
+
+ send(buffer, false /* isRTCP */);
+
+ ++mSeqNo;
+ ++mNumRTPSent;
+ mNumRTPOctetsSent += buffer->size() - (12 + rtpExtIndex);
+
+ firstPacket = false;
+ offset += size;
+ }
+ }
+}
+
+void ARTPWriter::sendAVCData(MediaBufferBase *mediaBuf) {
+ // 12 bytes RTP header + 2 bytes for the FU-indicator and FU-header.
+ CHECK_GE(kMaxPacketSize, 12u + 2u);
+
+ int64_t timeUs;
+ CHECK(mediaBuf->meta_data().findInt64(kKeyTime, &timeUs));
+
+ sendSPSPPSIfIFrame(mediaBuf, timeUs);
+
+ uint32_t rtpTime = getRtpTime(timeUs);
+
+ CHECK(mediaBuf->range_length() > 0);
+ const uint8_t *mediaData =
+ (const uint8_t *)mediaBuf->data() + mediaBuf->range_offset();
+
+ int32_t sps, pps;
+ bool isSpsPps = false;
+ if (mediaBuf->meta_data().findInt32(kKeySps, &sps) ||
+ mediaBuf->meta_data().findInt32(kKeyPps, &pps)) {
+ isSpsPps = true;
+ }
+
+ mTrafficRec->updateClock(ALooper::GetNowUs() / 1000);
+ sp<ABuffer> buffer = new ABuffer(kMaxPacketSize);
+ if (mediaBuf->range_length() + TCPIP_HEADER_SIZE + RTP_HEADER_SIZE + RTP_HEADER_EXT_SIZE
+ + RTP_PAYLOAD_ROOM_SIZE <= buffer->capacity()) {
+ // The data fits into a single packet
+ uint8_t *data = buffer->data();
+ data[0] = 0x80;
+ if (mRTPCVOExtMap > 0) {
+ data[0] |= 0x10;
+ }
+ if (isSpsPps) {
+ data[1] = mPayloadType; // Marker bit should not be set in case of sps/pps
+ } else {
+ data[1] = (1 << 7) | mPayloadType;
+ }
+ data[2] = (mSeqNo >> 8) & 0xff;
+ data[3] = mSeqNo & 0xff;
+ data[4] = rtpTime >> 24;
+ data[5] = (rtpTime >> 16) & 0xff;
+ data[6] = (rtpTime >> 8) & 0xff;
+ data[7] = rtpTime & 0xff;
+ data[8] = mSourceID >> 24;
+ data[9] = (mSourceID >> 16) & 0xff;
+ data[10] = (mSourceID >> 8) & 0xff;
+ data[11] = mSourceID & 0xff;
+
+ int rtpExtIndex = 0;
+ if (mRTPCVOExtMap > 0) {
+ /*
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 0xBE | 0xDE | length=3 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ID | L=0 | data | ID | L=1 | data...
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ...data | 0 (pad) | 0 (pad) | ID | L=3 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | data |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+ In the one-byte header form of extensions, the 16-bit value required
+ by the RTP specification for a header extension, labeled in the RTP
+ specification as "defined by profile", takes the fixed bit pattern
+ 0xBEDE (the first version of this specification was written on the
+ feast day of the Venerable Bede).
+ */
+ data[12] = 0xBE;
+ data[13] = 0xDE;
+ // put a length of RTP Extension.
+ data[14] = 0x00;
+ data[15] = 0x01;
+ // put extmap of RTP assigned for CVO.
+ data[16] = (mRTPCVOExtMap << 4) | 0x0;
+ // put image degrees as per CVO specification.
+ data[17] = mRTPCVODegrees;
+ data[18] = 0x0;
+ data[19] = 0x0;
+ rtpExtIndex = 8;
+ }
+
+ memcpy(&data[12 + rtpExtIndex],
+ mediaData, mediaBuf->range_length());
+
+ buffer->setRange(0, mediaBuf->range_length() + (12 + rtpExtIndex));
+
+ send(buffer, false /* isRTCP */);
+
+ ++mSeqNo;
+ ++mNumRTPSent;
+ mNumRTPOctetsSent += buffer->size() - (12 + rtpExtIndex);
+ } else {
+ // FU-A
+
+ unsigned nalType = mediaData[0] & H264_NALU_MASK;
+ ALOGV("H264 nalType 0x%x, data[0]=0x%x", nalType, mediaData[0]);
+ size_t offset = 1;
+
+ bool firstPacket = true;
+ while (offset < mediaBuf->range_length()) {
+ size_t size = mediaBuf->range_length() - offset;
+ bool lastPacket = true;
+ if (size + TCPIP_HEADER_SIZE + RTP_HEADER_SIZE + RTP_HEADER_EXT_SIZE +
+ RTP_FU_HEADER_SIZE + RTP_PAYLOAD_ROOM_SIZE > buffer->capacity()) {
+ lastPacket = false;
+ size = buffer->capacity() - TCPIP_HEADER_SIZE - RTP_HEADER_SIZE -
+ RTP_HEADER_EXT_SIZE - RTP_FU_HEADER_SIZE - RTP_PAYLOAD_ROOM_SIZE;
+ }
+
+ uint8_t *data = buffer->data();
+ data[0] = 0x80;
+ if (lastPacket && mRTPCVOExtMap > 0) {
+ data[0] |= 0x10;
+ }
+ data[1] = (lastPacket ? (1 << 7) : 0x00) | mPayloadType; // M-bit
+ data[2] = (mSeqNo >> 8) & 0xff;
+ data[3] = mSeqNo & 0xff;
+ data[4] = rtpTime >> 24;
+ data[5] = (rtpTime >> 16) & 0xff;
+ data[6] = (rtpTime >> 8) & 0xff;
+ data[7] = rtpTime & 0xff;
+ data[8] = mSourceID >> 24;
+ data[9] = (mSourceID >> 16) & 0xff;
+ data[10] = (mSourceID >> 8) & 0xff;
+ data[11] = mSourceID & 0xff;
+
+ int rtpExtIndex = 0;
+ if (lastPacket && mRTPCVOExtMap > 0) {
+ data[12] = 0xBE;
+ data[13] = 0xDE;
+ data[14] = 0x00;
+ data[15] = 0x01;
+ data[16] = (mRTPCVOExtMap << 4) | 0x0;
+ data[17] = mRTPCVODegrees;
+ data[18] = 0x0;
+ data[19] = 0x0;
+ rtpExtIndex = 8;
+ }
+
+ /* H264 payload header is 8 bit
+ 0 1 2 3 4 5 6 7
+ +-+-+-+-+-+-+-+-+
+ |F|NRI| Type |
+ +-+-+-+-+-+-+-+-+
+ */
+ ALOGV("H264 payload header 0x%x", mediaData[0]);
+ // excludes Type from 1st byte of H264 payload header.
+ data[12 + rtpExtIndex] = mediaData[0] & 0xe0;
+ // fills Type as FU (28 == 0x1C)
+ data[12 + rtpExtIndex] = data[12 + rtpExtIndex] | 0x1C;
+
+ CHECK(!firstPacket || !lastPacket);
+ /*
+ FU header
+ 0 1 2 3 4 5 6 7
+ +-+-+-+-+-+-+-+-+
+ |S|E|R| Type |
+ +-+-+-+-+-+-+-+-+
+ */
data[13 + rtpExtIndex] =
(firstPacket ? 0x80 : 0x00)
| (lastPacket ? 0x40 : 0x00)
- | (nalType & 0x1f);
+ | (nalType & H264_NALU_MASK);
+ ALOGV("H264 FU header 0x%x", data[13]);
memcpy(&data[14 + rtpExtIndex], &mediaData[offset], size);
@@ -1268,9 +1367,6 @@
offset += size;
}
}
-
- mLastRTPTime = rtpTime;
- mLastNTPTime = GetNowNTP();
}
void ARTPWriter::sendH263Data(MediaBufferBase *mediaBuf) {
@@ -1279,7 +1375,7 @@
int64_t timeUs;
CHECK(mediaBuf->meta_data().findInt64(kKeyTime, &timeUs));
- uint32_t rtpTime = mRTPTimeBase + (timeUs * 9 / 100LL);
+ uint32_t rtpTime = getRtpTime(timeUs);
const uint8_t *mediaData =
(const uint8_t *)mediaBuf->data() + mediaBuf->range_offset();
@@ -1330,9 +1426,6 @@
++mNumRTPSent;
mNumRTPOctetsSent += buffer->size() - 12;
}
-
- mLastRTPTime = rtpTime;
- mLastNTPTime = GetNowNTP();
}
void ARTPWriter::updateCVODegrees(int32_t cvoDegrees) {
@@ -1415,7 +1508,7 @@
int64_t timeUs;
CHECK(mediaBuf->meta_data().findInt64(kKeyTime, &timeUs));
- uint32_t rtpTime = mRTPTimeBase + (timeUs / (isWide ? 250 : 125));
+ uint32_t rtpTime = getRtpTime(timeUs);
// hexdump(mediaData, mediaLength);
@@ -1489,9 +1582,6 @@
++mSeqNo;
++mNumRTPSent;
mNumRTPOctetsSent += buffer->size() - 12;
-
- mLastRTPTime = rtpTime;
- mLastNTPTime = GetNowNTP();
}
void ARTPWriter::makeSocketPairAndBind(String8& localIp, int localPort,
diff --git a/media/libstagefright/rtsp/ARTPWriter.h b/media/libstagefright/rtsp/ARTPWriter.h
index 28d6ec5..2982cf6 100644
--- a/media/libstagefright/rtsp/ARTPWriter.h
+++ b/media/libstagefright/rtsp/ARTPWriter.h
@@ -108,14 +108,13 @@
MediaBufferBase *mSPSBuf;
MediaBufferBase *mPPSBuf;
+ uint32_t mClockRate;
uint32_t mSourceID;
uint32_t mPayloadType;
uint32_t mSeqNo;
uint32_t mRTPTimeBase;
uint32_t mNumRTPSent;
uint32_t mNumRTPOctetsSent;
- uint32_t mLastRTPTime;
- uint64_t mLastNTPTime;
uint32_t mOpponentID;
uint32_t mBitrate;
@@ -136,6 +135,7 @@
} mMode;
static uint64_t GetNowNTP();
+ uint32_t getRtpTime(int64_t timeUs);
void initState();
void onRead(const sp<AMessage> &msg);
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 0fdf431..988cec7 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -74,7 +74,8 @@
// The allowed maximum number of stale access units at the beginning of
// a new sequence.
-static int32_t kMaxAllowedStaleAccessUnits = 20;
+static int32_t kMaxAllowedStaleAudioAccessUnits = 20;
+static int32_t kMaxAllowedStaleVideoAccessUnits = 400;
static int64_t kTearDownTimeoutUs = 3000000ll;
@@ -108,6 +109,10 @@
}
}
+static int32_t GetMaxAllowedStaleCount(bool isVideo) {
+ return isVideo ? kMaxAllowedStaleVideoAccessUnits : kMaxAllowedStaleAudioAccessUnits;
+}
+
struct MyHandler : public AHandler {
enum {
kWhatConnected = 'conn',
@@ -1330,6 +1335,8 @@
ALOGV("rtp-info: %s", response->mHeaders.valueAt(i).c_str());
+ mRTPConn->seekStream();
+
ALOGI("seek completed.");
}
}
@@ -1514,7 +1521,7 @@
TrackInfo *info = &mTracks.editItemAt(trackIndex);
info->mFirstSeqNumInSegment = seq;
info->mNewSegment = true;
- info->mAllowedStaleAccessUnits = kMaxAllowedStaleAccessUnits;
+ info->mAllowedStaleAccessUnits = GetMaxAllowedStaleCount(info->mIsVideo);
CHECK(GetAttribute((*it).c_str(), "rtptime", &val));
@@ -1556,6 +1563,7 @@
int mRTPSocket;
int mRTCPSocket;
bool mUsingInterleavedTCP;
+ bool mIsVideo;
uint32_t mFirstSeqNumInSegment;
bool mNewSegment;
int32_t mAllowedStaleAccessUnits;
@@ -1640,9 +1648,10 @@
info->mURL = trackURL;
info->mPacketSource = source;
info->mUsingInterleavedTCP = false;
+ info->mIsVideo = source->isVideo();
info->mFirstSeqNumInSegment = 0;
info->mNewSegment = true;
- info->mAllowedStaleAccessUnits = kMaxAllowedStaleAccessUnits;
+ info->mAllowedStaleAccessUnits = GetMaxAllowedStaleCount(info->mIsVideo);
info->mRTPSocket = -1;
info->mRTCPSocket = -1;
info->mRTPAnchor = 0;
@@ -1838,11 +1847,12 @@
// by ARTPSource. Only the low 16 bits of seq in RTP-Info of reply of
// RTSP "PLAY" command should be used to detect the first RTP packet
// after seeking.
+ int32_t maxAllowedStaleAccessUnits = GetMaxAllowedStaleCount(track->mIsVideo);
if (mSeekable) {
if (track->mAllowedStaleAccessUnits > 0) {
uint32_t seqNum16 = seqNum & 0xffff;
uint32_t firstSeqNumInSegment16 = track->mFirstSeqNumInSegment & 0xffff;
- if (seqNum16 > firstSeqNumInSegment16 + kMaxAllowedStaleAccessUnits
+ if (seqNum16 > firstSeqNumInSegment16 + maxAllowedStaleAccessUnits
|| seqNum16 < firstSeqNumInSegment16) {
// Not the first rtp packet of the stream after seeking, discarding.
track->mAllowedStaleAccessUnits--;
@@ -1857,7 +1867,7 @@
mNumAccessUnitsReceived = 0;
ALOGW_IF(track->mAllowedStaleAccessUnits == 0,
"Still no first rtp packet after %d stale ones",
- kMaxAllowedStaleAccessUnits);
+ maxAllowedStaleAccessUnits);
track->mAllowedStaleAccessUnits = -1;
return UNKNOWN_ERROR;
}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 4ac46b7..b8782d7 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -976,8 +976,9 @@
}
}
}
-
- setAudioHwSyncForSession_l(thread, sessionId);
+ if ((output.flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) == AUDIO_OUTPUT_FLAG_HW_AV_SYNC) {
+ setAudioHwSyncForSession_l(thread, sessionId);
+ }
}
if (lStatus != NO_ERROR) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp
index 8c61b90..5986069 100644
--- a/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp
@@ -30,9 +30,9 @@
// --- PolicyAudioPort class implementation
void PolicyAudioPort::attach(const sp<HwModule>& module)
{
+ mModule = module;
ALOGV("%s: attaching module %s to port %s",
__FUNCTION__, getModuleName(), asAudioPort()->getName().c_str());
- mModule = module;
}
void PolicyAudioPort::detach()
diff --git a/services/audiopolicy/config/bluetooth_audio_policy_configuration.xml b/services/audiopolicy/config/bluetooth_audio_policy_configuration.xml
index 98415b7..22ff954 100644
--- a/services/audiopolicy/config/bluetooth_audio_policy_configuration.xml
+++ b/services/audiopolicy/config/bluetooth_audio_policy_configuration.xml
@@ -22,6 +22,17 @@
samplingRates="8000,16000,24000,32000,44100,48000"
channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort>
+ <mixPort name="le audio input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000,16000,24000,32000,44100,48000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/>
+ <profile name="" format="AUDIO_FORMAT_PCM_24_BIT_PACKED"
+ samplingRates="8000,16000,24000,32000,44100,48000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/>
+ <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
+ samplingRates="8000,16000,24000,32000,44100,48000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
</mixPorts>
<devicePorts>
<!-- A2DP Audio Ports -->
@@ -49,6 +60,7 @@
-->
<devicePort tagName="BLE Headset Out" type="AUDIO_DEVICE_OUT_BLE_HEADSET" role="sink"/>
<devicePort tagName="BLE Speaker Out" type="AUDIO_DEVICE_OUT_BLE_SPEAKER" role="sink"/>
+ <devicePort tagName="BLE Headset In" type="AUDIO_DEVICE_IN_BLE_HEADSET" role="source"/>
</devicePorts>
<routes>
<route type="mix" sink="BT A2DP Out"
@@ -61,6 +73,8 @@
sources="hearing aid output"/>
<route type="mix" sink="BLE Headset Out"
sources="le audio output"/>
+ <route type="mix" sink="le audio input"
+ sources="BLE Headset In"/>
<route type="mix" sink="BLE Speaker Out"
sources="le audio output"/>
</routes>
diff --git a/services/audiopolicy/config/bluetooth_audio_policy_configuration_7_0.xml b/services/audiopolicy/config/bluetooth_audio_policy_configuration_7_0.xml
index fbe7571..aad00d6 100644
--- a/services/audiopolicy/config/bluetooth_audio_policy_configuration_7_0.xml
+++ b/services/audiopolicy/config/bluetooth_audio_policy_configuration_7_0.xml
@@ -22,6 +22,17 @@
samplingRates="8000 16000 24000 32000 44100 48000"
channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort>
+ <mixPort name="le audio input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000 16000 24000 32000 44100 48000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/>
+ <profile name="" format="AUDIO_FORMAT_PCM_24_BIT_PACKED"
+ samplingRates="8000 16000 24000 32000 44100 48000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/>
+ <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
+ samplingRates="8000 16000 24000 32000 44100 48000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
</mixPorts>
<devicePorts>
<!-- A2DP Audio Ports -->
@@ -45,6 +56,7 @@
<!-- BLE Audio Ports -->
<devicePort tagName="BLE Headset Out" type="AUDIO_DEVICE_OUT_BLE_HEADSET" role="sink"/>
<devicePort tagName="BLE Speaker Out" type="AUDIO_DEVICE_OUT_BLE_SPEAKER" role="sink"/>
+ <devicePort tagName="BLE Headset In" type="AUDIO_DEVICE_IN_BLE_HEADSET" role="source"/>
</devicePorts>
<routes>
<route type="mix" sink="BT A2DP Out"
@@ -57,6 +69,8 @@
sources="hearing aid output"/>
<route type="mix" sink="BLE Headset Out"
sources="le audio output"/>
+ <route type="mix" sink="le audio input"
+ sources="BLE Headset In"/>
<route type="mix" sink="BLE Speaker Out"
sources="le audio output"/>
</routes>
diff --git a/services/audiopolicy/config/le_audio_policy_configuration.xml b/services/audiopolicy/config/le_audio_policy_configuration.xml
index a3dc72b..dcdd805 100644
--- a/services/audiopolicy/config/le_audio_policy_configuration.xml
+++ b/services/audiopolicy/config/le_audio_policy_configuration.xml
@@ -7,13 +7,20 @@
samplingRates="8000,16000,24000,32000,44100,48000"
channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort>
+ <mixPort name="le audio input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT,AUDIO_FORMAT_PCM_24_BIT,AUDIO_FORMAT_PCM_32_BIT"
+ samplingRates="8000,16000,24000,32000,44100,48000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
</mixPorts>
<devicePorts>
<devicePort tagName="BLE Headset Out" type="AUDIO_DEVICE_OUT_BLE_HEADSET" role="sink"/>
<devicePort tagName="BLE Speaker Out" type="AUDIO_DEVICE_OUT_BLE_SPEAKER" role="sink"/>
+ <devicePort tagName="BLE Headset In" type="AUDIO_DEVICE_IN_BLE_HEADSET" role="source"/>
</devicePorts>
<routes>
<route type="mix" sink="BLE Headset Out" sources="le audio output"/>
<route type="mix" sink="BLE Speaker Out" sources="le audio output"/>
+ <route type="mix" sink="le audio input" sources="BLE Headset In"/>
</routes>
</module>
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index e0a0bbb..1fda6f1 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -479,7 +479,7 @@
switch (commDeviceType) {
case AUDIO_DEVICE_OUT_BLE_HEADSET:
device = availableDevices.getDevice(
- AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT);
+ AUDIO_DEVICE_IN_BLE_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT);
break;
case AUDIO_DEVICE_OUT_SPEAKER:
device = availableDevices.getFirstExistingDevice({
diff --git a/services/mediacodec/registrant/Android.bp b/services/mediacodec/registrant/Android.bp
index 696b967..d10e339 100644
--- a/services/mediacodec/registrant/Android.bp
+++ b/services/mediacodec/registrant/Android.bp
@@ -7,7 +7,7 @@
default_applicable_licenses: ["frameworks_av_services_mediacodec_license"],
}
-cc_library_shared {
+cc_library {
name: "libmedia_codecserviceregistrant",
vendor_available: true,
srcs: [
diff --git a/services/mediacodec/registrant/fuzzer/Android.bp b/services/mediacodec/registrant/fuzzer/Android.bp
new file mode 100644
index 0000000..43afbf1
--- /dev/null
+++ b/services/mediacodec/registrant/fuzzer/Android.bp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_av_services_mediacodec_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_av_services_mediacodec_license"],
+}
+
+cc_fuzz {
+ name: "codecServiceRegistrant_fuzzer",
+ srcs: [
+ "codecServiceRegistrant_fuzzer.cpp",
+ ],
+ static_libs: [
+ "libmedia_codecserviceregistrant",
+ ],
+ header_libs: [
+ "libmedia_headers",
+ ],
+ defaults: [
+ "libcodec2-hidl-defaults",
+ ],
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 155276,
+ },
+}
diff --git a/services/mediacodec/registrant/fuzzer/README.md b/services/mediacodec/registrant/fuzzer/README.md
new file mode 100644
index 0000000..0ffa063
--- /dev/null
+++ b/services/mediacodec/registrant/fuzzer/README.md
@@ -0,0 +1,56 @@
+# Fuzzer for libmedia_codecserviceregistrant
+
+## Plugin Design Considerations
+The fuzzer plugin for libmedia_codecserviceregistrant is designed based on the understanding of the library and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+libmedia_codecserviceregistrant supports the following parameters:
+1. C2String (parameter name: `c2String`)
+2. Width (parameter name: `width`)
+3. Height (parameter name: `height`)
+4. SamplingRate (parameter name: `samplingRate`)
+5. Channels (parameter name: `channels`)
+6. Stream (parameter name: `stream`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `c2String` |`String` | Value obtained from FuzzedDataProvider|
+| `width` |`UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `height` |`UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `samplingRate` |`UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `channels` |`UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `stream` |`UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+
+This also ensures that the plugin is always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the libmedia_codecserviceregistrant module.
+This ensures that the plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesnt `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build codecServiceRegistrant_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+ $ mm -j$(nproc) codecServiceRegistrant_fuzzer
+```
+#### Steps to run
+
+To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/${TARGET_ARCH}/codecServiceRegistrant_fuzzer/codecServiceRegistrant_fuzzer
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/services/mediacodec/registrant/fuzzer/codecServiceRegistrant_fuzzer.cpp b/services/mediacodec/registrant/fuzzer/codecServiceRegistrant_fuzzer.cpp
new file mode 100644
index 0000000..e5983e4
--- /dev/null
+++ b/services/mediacodec/registrant/fuzzer/codecServiceRegistrant_fuzzer.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "../CodecServiceRegistrant.cpp"
+#include "fuzzer/FuzzedDataProvider.h"
+#include <C2Config.h>
+#include <C2Param.h>
+
+using namespace std;
+
+constexpr char kServiceName[] = "software";
+
+class CodecServiceRegistrantFuzzer {
+public:
+ void process(const uint8_t *data, size_t size);
+ ~CodecServiceRegistrantFuzzer() {
+ delete mH2C2;
+ if (mInputSize) {
+ delete mInputSize;
+ }
+ if (mSampleRateInfo) {
+ delete mSampleRateInfo;
+ }
+ if (mChannelCountInfo) {
+ delete mChannelCountInfo;
+ }
+ }
+
+private:
+ void initH2C2ComponentStore();
+ void invokeH2C2ComponentStore();
+ void invokeConfigSM();
+ void invokeQuerySM();
+ H2C2ComponentStore *mH2C2 = nullptr;
+ C2StreamPictureSizeInfo::input *mInputSize = nullptr;
+ C2StreamSampleRateInfo::output *mSampleRateInfo = nullptr;
+ C2StreamChannelCountInfo::output *mChannelCountInfo = nullptr;
+ C2Param::Index mIndex = C2StreamProfileLevelInfo::output::PARAM_TYPE;
+ C2StreamFrameRateInfo::output mFrameRate;
+ FuzzedDataProvider *mFDP = nullptr;
+};
+
+void CodecServiceRegistrantFuzzer::initH2C2ComponentStore() {
+ using namespace ::android::hardware::media::c2;
+ shared_ptr<C2ComponentStore> store =
+ android::GetCodec2PlatformComponentStore();
+ if (!store) {
+ return;
+ }
+ android::sp<V1_1::IComponentStore> storeV1_1 =
+ new V1_1::utils::ComponentStore(store);
+ if (storeV1_1->registerAsService(string(kServiceName)) != android::OK) {
+ return;
+ }
+ string const preferredStoreName = string(kServiceName);
+ sp<IComponentStore> preferredStore =
+ IComponentStore::getService(preferredStoreName.c_str());
+ mH2C2 = new H2C2ComponentStore(preferredStore);
+}
+
+void CodecServiceRegistrantFuzzer::invokeConfigSM() {
+ vector<C2Param *> configParams;
+ uint32_t width = mFDP->ConsumeIntegral<uint32_t>();
+ uint32_t height = mFDP->ConsumeIntegral<uint32_t>();
+ uint32_t samplingRate = mFDP->ConsumeIntegral<uint32_t>();
+ uint32_t channels = mFDP->ConsumeIntegral<uint32_t>();
+ if (mFDP->ConsumeBool()) {
+ mInputSize = new C2StreamPictureSizeInfo::input(0u, width, height);
+ configParams.push_back(mInputSize);
+ } else {
+ if (mFDP->ConsumeBool()) {
+ mSampleRateInfo = new C2StreamSampleRateInfo::output(0u, samplingRate);
+ configParams.push_back(mSampleRateInfo);
+ }
+ if (mFDP->ConsumeBool()) {
+ mChannelCountInfo = new C2StreamChannelCountInfo::output(0u, channels);
+ configParams.push_back(mChannelCountInfo);
+ }
+ }
+ vector<unique_ptr<C2SettingResult>> failures;
+ mH2C2->config_sm(configParams, &failures);
+}
+
+void CodecServiceRegistrantFuzzer::invokeQuerySM() {
+ vector<C2Param *> stackParams;
+ vector<C2Param::Index> heapParamIndices;
+ if (mFDP->ConsumeBool()) {
+ stackParams = {};
+ heapParamIndices = {};
+ } else {
+ uint32_t stream = mFDP->ConsumeIntegral<uint32_t>();
+ mFrameRate.setStream(stream);
+ stackParams.push_back(&mFrameRate);
+ heapParamIndices.push_back(mIndex);
+ }
+ vector<unique_ptr<C2Param>> heapParams;
+ mH2C2->query_sm(stackParams, heapParamIndices, &heapParams);
+}
+
+void CodecServiceRegistrantFuzzer::invokeH2C2ComponentStore() {
+ initH2C2ComponentStore();
+ shared_ptr<C2Component> component;
+ shared_ptr<C2ComponentInterface> interface;
+ string c2String = mFDP->ConsumeRandomLengthString();
+ mH2C2->createComponent(c2String, &component);
+ mH2C2->createInterface(c2String, &interface);
+ invokeConfigSM();
+ invokeQuerySM();
+
+ vector<shared_ptr<C2ParamDescriptor>> params;
+ mH2C2->querySupportedParams_nb(¶ms);
+
+ C2StoreIonUsageInfo usageInfo;
+ std::vector<C2FieldSupportedValuesQuery> query = {
+ C2FieldSupportedValuesQuery::Possible(
+ C2ParamField::Make(usageInfo, usageInfo.usage)),
+ C2FieldSupportedValuesQuery::Possible(
+ C2ParamField::Make(usageInfo, usageInfo.capacity)),
+ };
+ mH2C2->querySupportedValues_sm(query);
+
+ mH2C2->getName();
+ shared_ptr<C2ParamReflector> paramReflector = mH2C2->getParamReflector();
+ if (paramReflector) {
+ paramReflector->describe(C2ComponentDomainSetting::CORE_INDEX);
+ }
+ mH2C2->listComponents();
+ shared_ptr<C2GraphicBuffer> src;
+ shared_ptr<C2GraphicBuffer> dst;
+ mH2C2->copyBuffer(src, dst);
+}
+
+void CodecServiceRegistrantFuzzer::process(const uint8_t *data, size_t size) {
+ mFDP = new FuzzedDataProvider(data, size);
+ invokeH2C2ComponentStore();
+ /** RegisterCodecServices is called here to improve code coverage */
+ /** as currently it is not called by codecServiceRegistrant */
+ RegisterCodecServices();
+ delete mFDP;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ CodecServiceRegistrantFuzzer codecServiceRegistrantFuzzer;
+ codecServiceRegistrantFuzzer.process(data, size);
+ return 0;
+}
diff --git a/services/mediametrics/TransactionLog.h b/services/mediametrics/TransactionLog.h
index 0ca4639..fd42518 100644
--- a/services/mediametrics/TransactionLog.h
+++ b/services/mediametrics/TransactionLog.h
@@ -158,7 +158,7 @@
++it) {
if (ll <= 0) break;
if (prefix != nullptr && !startsWith(it->first, prefix)) break;
- auto [s, l] = dumpMapTimeItem(it->second, ll - 1, sinceNs, prefix);
+ std::tie(s, l) = dumpMapTimeItem(it->second, ll - 1, sinceNs, prefix);
if (l == 0) continue; // don't show empty groups (due to sinceNs).
ss << " " << it->first << "\n" << s;
ll -= l + 1;
diff --git a/services/minijail/Android.bp b/services/minijail/Android.bp
index 3a89e12..038197f 100644
--- a/services/minijail/Android.bp
+++ b/services/minijail/Android.bp
@@ -31,17 +31,6 @@
export_include_dirs: ["."],
}
-// By adding "vendor_available: true" to "libavservices_minijail", we don't
-// need to have "libavservices_minijail_vendor" any longer.
-// "libavservices_minijail_vendor" will be removed, once we replace it with
-// "libavservices_minijail" in all vendor modules. (b/146313710)
-cc_library_shared {
- name: "libavservices_minijail_vendor",
- vendor: true,
- defaults: ["libavservices_minijail_defaults"],
- export_include_dirs: ["."],
-}
-
// Unit tests.
cc_test {
name: "libavservices_minijail_unittest",