Merge "VT: fixes possible nullptr case in ARTPConnection."
diff --git a/OWNERS b/OWNERS
index 7f523a2..0be1196 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,10 +1,8 @@
-chz@google.com
+# Bug component: 1344
elaurent@google.com
etalvala@google.com
hkuang@google.com
lajos@google.com
-marcone@google.com
-# LON
-olly@google.com
-andrewlewis@google.com
+# go/android-fwk-media-solutions for info on areas of ownership.
+include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index a82a61d..5ce7241 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -65,7 +65,7 @@
],
static_libs: [
- "resourcemanager_aidl_interface-ndk_platform",
+ "resourcemanager_aidl_interface-ndk",
],
export_shared_lib_headers: [
diff --git a/drm/libmediadrm/fuzzer/Android.bp b/drm/libmediadrm/fuzzer/Android.bp
index 2b04702..9faed3a 100644
--- a/drm/libmediadrm/fuzzer/Android.bp
+++ b/drm/libmediadrm/fuzzer/Android.bp
@@ -35,7 +35,7 @@
static_libs: [
"libmediadrm",
"liblog",
- "resourcemanager_aidl_interface-ndk_platform",
+ "resourcemanager_aidl_interface-ndk",
],
header_libs: [
"libmedia_headers",
diff --git a/media/OWNERS b/media/OWNERS
index 3e194f0..099729f 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -1,24 +1,21 @@
-andrewlewis@google.com
-chz@google.com
-dwkang@google.com
+# Bug component: 1344
elaurent@google.com
essick@google.com
-gkasten@google.com
hkuang@google.com
hunga@google.com
jiabin@google.com
jmtrivi@google.com
lajos@google.com
-marcone@google.com
mnaganov@google.com
nchalko@google.com
-pawin@google.com
philburk@google.com
pmclean@google.com
quxiangfang@google.com
-rachad@google.com
rago@google.com
robertshih@google.com
taklee@google.com
-wjia@google.com
wonsik@google.com
+ytai@google.com
+
+# go/android-fwk-media-solutions for info on areas of ownership.
+include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
diff --git a/media/codec2/components/mp3/C2SoftMp3Dec.cpp b/media/codec2/components/mp3/C2SoftMp3Dec.cpp
index 30d7394..50690af 100644
--- a/media/codec2/components/mp3/C2SoftMp3Dec.cpp
+++ b/media/codec2/components/mp3/C2SoftMp3Dec.cpp
@@ -321,6 +321,13 @@
return C2_OK;
}
+static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
+ work->worklets.front()->output.flags = work->input.flags;
+ work->worklets.front()->output.buffers.clear();
+ work->worklets.front()->output.ordinal = work->input.ordinal;
+ work->workletsProcessed = 1u;
+}
+
// TODO: Can overall error checking be improved? As in the check for validity of
// work, pool ptr, work->input.buffers.size() == 1, ...
// TODO: Blind removal of 529 samples from the output may not work. Because
@@ -486,17 +493,17 @@
}
}
- int64_t outTimeStamp = mProcessedSamples * 1000000ll / samplingRate;
- mProcessedSamples += ((outSize - outOffset) / (numChannels * sizeof(int16_t)));
- 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();
- work->worklets.front()->output.buffers.push_back(
- createLinearBuffer(block, outOffset, outSize - outOffset));
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->worklets.front()->output.ordinal.timestamp = mAnchorTimeStamp + outTimeStamp;
+ fillEmptyWork(work);
+ if (samplingRate && numChannels) {
+ int64_t outTimeStamp = mProcessedSamples * 1000000ll / samplingRate;
+ mProcessedSamples += ((outSize - outOffset) / (numChannels * sizeof(int16_t)));
+ ALOGV("out buffer attr. offset %d size %d timestamp %" PRId64 " ", outOffset,
+ outSize - outOffset, mAnchorTimeStamp + outTimeStamp);
+ decodedSizes.clear();
+ work->worklets.front()->output.buffers.push_back(
+ createLinearBuffer(block, outOffset, outSize - outOffset));
+ work->worklets.front()->output.ordinal.timestamp = mAnchorTimeStamp + outTimeStamp;
+ }
if (eos) {
mSignalledOutputEos = true;
ALOGV("signalled EOS");
diff --git a/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp b/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp
index ddd312f..60d6b44 100644
--- a/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp
+++ b/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp
@@ -243,11 +243,13 @@
}
c2_status_t C2SoftMpeg4Dec::onStop() {
- if (mInitialized) {
- if (mDecHandle) {
+ if (mDecHandle) {
+ if (mInitialized) {
PVCleanUpVideoDecoder(mDecHandle);
+ mInitialized = false;
}
- mInitialized = false;
+ delete mDecHandle;
+ mDecHandle = nullptr;
}
for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
if (mOutputBuffer[i]) {
@@ -269,23 +271,10 @@
}
void C2SoftMpeg4Dec::onRelease() {
- if (mInitialized) {
- if (mDecHandle) {
- PVCleanUpVideoDecoder(mDecHandle);
- delete mDecHandle;
- mDecHandle = nullptr;
- }
- mInitialized = false;
- }
+ (void)onStop();
if (mOutBlock) {
mOutBlock.reset();
}
- for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
- if (mOutputBuffer[i]) {
- free(mOutputBuffer[i]);
- mOutputBuffer[i] = nullptr;
- }
- }
}
c2_status_t C2SoftMpeg4Dec::onFlush_sm() {
diff --git a/media/codec2/components/mpeg4_h263/C2SoftMpeg4Enc.cpp b/media/codec2/components/mpeg4_h263/C2SoftMpeg4Enc.cpp
index 3c87531..3bfec66 100644
--- a/media/codec2/components/mpeg4_h263/C2SoftMpeg4Enc.cpp
+++ b/media/codec2/components/mpeg4_h263/C2SoftMpeg4Enc.cpp
@@ -436,16 +436,18 @@
}
++mNumInputFrames;
- std::unique_ptr<C2StreamInitDataInfo::output> csd =
- C2StreamInitDataInfo::output::AllocUnique(outputSize, 0u);
- if (!csd) {
- ALOGE("CSD allocation failed");
- mSignalledError = true;
- work->result = C2_NO_MEMORY;
- return;
+ if (outputSize) {
+ std::unique_ptr<C2StreamInitDataInfo::output> csd =
+ C2StreamInitDataInfo::output::AllocUnique(outputSize, 0u);
+ if (!csd) {
+ ALOGE("CSD allocation failed");
+ mSignalledError = true;
+ work->result = C2_NO_MEMORY;
+ return;
+ }
+ memcpy(csd->m.value, outPtr, outputSize);
+ work->worklets.front()->output.configUpdate.push_back(std::move(csd));
}
- memcpy(csd->m.value, outPtr, outputSize);
- work->worklets.front()->output.configUpdate.push_back(std::move(csd));
}
// handle dynamic bitrate change
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/janitors/media_solutions_OWNERS b/media/janitors/media_solutions_OWNERS
new file mode 100644
index 0000000..8dc1c7b
--- /dev/null
+++ b/media/janitors/media_solutions_OWNERS
@@ -0,0 +1,10 @@
+# Bug component: 1344
+# go/android-fwk-media-solutions for info on areas of ownership.
+
+# Main owners:
+aquilescanta@google.com
+krocard@google.com
+
+# In case of emergency:
+andrewlewis@google.com #{LAST_RESORT_SUGGESTION}
+olly@google.com #{LAST_RESORT_SUGGESTION}
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/libmedia/Android.bp b/media/libmedia/Android.bp
index 6214f5e..8115880 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -394,11 +394,11 @@
],
static_libs: [
- "resourcemanager_aidl_interface-ndk_platform",
+ "resourcemanager_aidl_interface-ndk",
],
export_static_lib_headers: [
- "resourcemanager_aidl_interface-ndk_platform",
+ "resourcemanager_aidl_interface-ndk",
],
export_include_dirs: [
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/tests/Android.bp b/media/libmediaplayerservice/tests/Android.bp
index 98626fd..99202b8 100644
--- a/media/libmediaplayerservice/tests/Android.bp
+++ b/media/libmediaplayerservice/tests/Android.bp
@@ -30,7 +30,7 @@
],
static_libs: [
- "resourcemanager_aidl_interface-ndk_platform",
+ "resourcemanager_aidl_interface-ndk",
],
include_dirs: [
diff --git a/media/libmediatranscoding/Android.bp b/media/libmediatranscoding/Android.bp
index 9375e4e..058d0c0 100644
--- a/media/libmediatranscoding/Android.bp
+++ b/media/libmediatranscoding/Android.bp
@@ -58,7 +58,7 @@
export_include_dirs: ["include"],
static_libs: [
- "mediatranscoding_aidl_interface-ndk_platform",
+ "mediatranscoding_aidl_interface-ndk",
],
cflags: [
diff --git a/media/libmediatranscoding/tests/Android.bp b/media/libmediatranscoding/tests/Android.bp
index 17a43df..80a055e 100644
--- a/media/libmediatranscoding/tests/Android.bp
+++ b/media/libmediatranscoding/tests/Android.bp
@@ -25,7 +25,7 @@
],
static_libs: [
- "mediatranscoding_aidl_interface-ndk_platform",
+ "mediatranscoding_aidl_interface-ndk",
],
cflags: [
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/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 0107c32..b07f8f7 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -943,10 +943,17 @@
sp<MediaCodecBuffer> outbuf;
status_t err = mEncoder->getOutputBuffer(index, &outbuf);
- if (err != OK || outbuf == NULL || outbuf->data() == NULL
- || outbuf->size() == 0) {
+ if (err != OK || outbuf == NULL || outbuf->data() == NULL) {
signalEOS();
break;
+ } else if (outbuf->size() == 0) {
+ // Zero length CSD buffers are not treated as an error
+ if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
+ mEncoder->releaseOutputBuffer(index);
+ } else {
+ signalEOS();
+ }
+ break;
}
MediaBufferBase *mbuf = new MediaBuffer(outbuf->size());
diff --git a/media/libstagefright/OWNERS b/media/libstagefright/OWNERS
index 0cc2294..e67496e 100644
--- a/media/libstagefright/OWNERS
+++ b/media/libstagefright/OWNERS
@@ -1,11 +1,9 @@
+# Bug component: 1344
set noparent
-chz@google.com
essick@google.com
lajos@google.com
-marcone@google.com
taklee@google.com
wonsik@google.com
-# LON
-olly@google.com
-andrewlewis@google.com
+# go/android-fwk-media-solutions for info on areas of ownership.
+include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
diff --git a/media/libstagefright/httplive/Android.bp b/media/libstagefright/httplive/Android.bp
index 0b0acbf..7acf735 100644
--- a/media/libstagefright/httplive/Android.bp
+++ b/media/libstagefright/httplive/Android.bp
@@ -29,7 +29,6 @@
],
include_dirs: [
- "frameworks/av/media/libstagefright",
"frameworks/native/include/media/openmax",
],
@@ -65,6 +64,8 @@
header_libs: [
"libbase_headers",
+ "libstagefright_headers",
+ "libstagefright_httplive_headers",
],
static_libs: [
@@ -74,3 +75,8 @@
],
}
+
+cc_library_headers {
+ name: "libstagefright_httplive_headers",
+ export_include_dirs: ["."],
+}
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 3bad015..0d7cadd 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -23,7 +23,7 @@
#include "M3UParser.h"
#include "PlaylistFetcher.h"
-#include "mpeg2ts/AnotherPacketSource.h"
+#include <AnotherPacketSource.h>
#include <cutils/properties.h>
#include <media/MediaHTTPService.h>
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index 7a6d487..ceea41d 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -24,7 +24,7 @@
#include <utils/String8.h>
-#include "mpeg2ts/ATSParser.h"
+#include <ATSParser.h>
namespace android {
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index b23aa8a..907b326 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -24,9 +24,9 @@
#include "HTTPDownloader.h"
#include "LiveSession.h"
#include "M3UParser.h"
-#include "include/ID3.h"
-#include "mpeg2ts/AnotherPacketSource.h"
-#include "mpeg2ts/HlsSampleDecryptor.h"
+#include <ID3.h>
+#include <AnotherPacketSource.h>
+#include <HlsSampleDecryptor.h>
#include <datasource/DataURISource.h>
#include <media/stagefright/foundation/ABitReader.h>
diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h
index 5d3f9c1..2e28164 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.h
+++ b/media/libstagefright/httplive/PlaylistFetcher.h
@@ -21,7 +21,7 @@
#include <media/stagefright/foundation/AHandler.h>
#include <openssl/aes.h>
-#include "mpeg2ts/ATSParser.h"
+#include <ATSParser.h>
#include "LiveSession.h"
namespace android {
diff --git a/media/libstagefright/httplive/fuzzer/Android.bp b/media/libstagefright/httplive/fuzzer/Android.bp
new file mode 100644
index 0000000..58e5af6
--- /dev/null
+++ b/media/libstagefright/httplive/fuzzer/Android.bp
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+cc_fuzz {
+ name: "httplive_fuzzer",
+ srcs: [
+ "httplive_fuzzer.cpp",
+ ],
+ static_libs: [
+ "libstagefright_httplive",
+ "libstagefright_id3",
+ "libstagefright_metadatautils",
+ "libstagefright_mpeg2support",
+ "liblog",
+ "libcutils",
+ "libdatasource",
+ "libmedia",
+ "libstagefright",
+ "libutils",
+ ],
+ header_libs: [
+ "libbase_headers",
+ "libstagefright_foundation_headers",
+ "libstagefright_headers",
+ "libstagefright_httplive_headers",
+ ],
+ shared_libs: [
+ "libcrypto",
+ "libstagefright_foundation",
+ "libhidlbase",
+ "libhidlmemory",
+ "android.hidl.allocator@1.0",
+ ],
+ corpus: ["corpus/*"],
+ dictionary: "httplive_fuzzer.dict",
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 155276,
+ },
+}
diff --git a/media/libstagefright/httplive/fuzzer/README.md b/media/libstagefright/httplive/fuzzer/README.md
new file mode 100644
index 0000000..3a64ea4
--- /dev/null
+++ b/media/libstagefright/httplive/fuzzer/README.md
@@ -0,0 +1,56 @@
+# Fuzzer for libstagefright_httplive
+
+## Plugin Design Considerations
+The fuzzer plugin for libstagefright_httplive 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.Also, several .m3u8 files are hand-crafted and added to the corpus directory to increase the code coverage. This ensures more code paths are reached by the fuzzer.
+
+libstagefright_httplive supports the following parameters:
+1. Final Result (parameter name: `finalResult`)
+2. Flags (parameter name: `flags`)
+3. Time Us (parameter name: `timeUs`)
+4. Track Index (parameter name: `trackIndex`)
+5. Index (parameter name: `index`)
+6. Select (parameter name: `select`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `finalResult` | `-34` to `-1` | Value obtained from FuzzedDataProvider|
+| `flags` | `0` to `1` | Value obtained from FuzzedDataProvider|
+| `timeUs` | `0` to `10000000` | Value obtained from FuzzedDataProvider|
+| `trackIndex` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `index` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `select` | `True` to `False` | 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 httplive 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 httplive_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+ $ mm -j$(nproc) httplive_fuzzer
+```
+#### Steps to run
+To run on device
+```
+ $ adb push $ANDROID_PRODUCT_OUT/data/fuzz/$(TARGET_ARCH)/lib /data/fuzz/$(TARGET_ARCH)/lib
+ $ adb push $ANDROID_PRODUCT_OUT/data/fuzz/$(TARGET_ARCH)/httplive_fuzzer /data/fuzz/$(TARGET_ARCH)/httplive_fuzzer
+ $ adb shell /data/fuzz/${TARGET_ARCH}/httplive_fuzzer/httplive_fuzzer /data/fuzz/${TARGET_ARCH}/httplive_fuzzer/corpus
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/media/libstagefright/httplive/fuzzer/corpus/crypt.key b/media/libstagefright/httplive/fuzzer/corpus/crypt.key
new file mode 100644
index 0000000..f9d5d7f
--- /dev/null
+++ b/media/libstagefright/httplive/fuzzer/corpus/crypt.key
@@ -0,0 +1,2 @@
+Û
+ÏüÐ5Ð_xïHÎ3
diff --git a/media/libstagefright/httplive/fuzzer/corpus/encrypted.m3u8 b/media/libstagefright/httplive/fuzzer/corpus/encrypted.m3u8
new file mode 100644
index 0000000..32b0eac
--- /dev/null
+++ b/media/libstagefright/httplive/fuzzer/corpus/encrypted.m3u8
@@ -0,0 +1,12 @@
+#EXTM3U
+#EXT-X-TARGETDURATION:10
+#EXT-X-ALLOW-CACHE:YES
+#EXT-X-PLAYLIST-TYPE:VOD
+#EXT-X-VERSION:3
+#EXT-X-MEDIA-SEQUENCE:1
+#EXT-X-KEY:METHOD=AES-128,URI="../../fuzz/arm64/httplive_fuzzer/corpus/crypt.key"
+#EXTINF:10.000,
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence1.ts
+#EXTINF:5.092,
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence1.ts
+#EXT-X-ENDLIST
diff --git a/media/libstagefright/httplive/fuzzer/corpus/hls.m3u8 b/media/libstagefright/httplive/fuzzer/corpus/hls.m3u8
new file mode 100644
index 0000000..9338e04
--- /dev/null
+++ b/media/libstagefright/httplive/fuzzer/corpus/hls.m3u8
@@ -0,0 +1,8 @@
+#EXTM3U
+#EXT-X-TARGETDURATION:10
+#EXT-X-MEDIA-SEQUENCE:0
+#EXTINF:10, no desc
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence1.ts
+#EXTINF:10, no desc
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence2.ts
+#EXT-X-ENDLIST
diff --git a/media/libstagefright/httplive/fuzzer/corpus/index1.m3u8 b/media/libstagefright/httplive/fuzzer/corpus/index1.m3u8
new file mode 100644
index 0000000..e1eff58
--- /dev/null
+++ b/media/libstagefright/httplive/fuzzer/corpus/index1.m3u8
@@ -0,0 +1,14 @@
+#EXTM3U
+#EXT-X-VERSION:4
+#EXT-X-TARGETDURATION:5
+#EXT-X-KEY:METHOD=NONE
+#EXT-X-DISCONTINUITY-SEQUENCE:0
+#EXT-X-PLAYLIST-TYPE:VOD
+#EXTINF:5,
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence0.ts
+#EXT-X-DISCONTINUITY
+#EXTINF:5,
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence1.ts
+#EXTINF:5,
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence2.ts
+#EXT-X-ENDLIST
diff --git a/media/libstagefright/httplive/fuzzer/corpus/index2.m3u8 b/media/libstagefright/httplive/fuzzer/corpus/index2.m3u8
new file mode 100644
index 0000000..37a0189
--- /dev/null
+++ b/media/libstagefright/httplive/fuzzer/corpus/index2.m3u8
@@ -0,0 +1,6 @@
+#EXTM3U
+#EXT-X-INDEPENDENT-SEGMENTS
+#EXT-X-STREAM-INF:CLOSED-CAPTIONS=NONE,BANDWIDTH=165340,RESOLUTION=256x144,CODECS="mp4a.40.5,avc1.42c00b"
+https://non.existentsite.com/test-doesnt-dereference-these-paths/prog_index.m3u8
+#EXT-X-STREAM-INF:CLOSED-CAPTIONS=NONE,BANDWIDTH=344388,RESOLUTION=426x240,CODECS="mp4a.40.5,avc1.4d4015"
+https://non.existentsite.com/test-doesnt-dereference-these-paths/prog_index1.m3u8
diff --git a/media/libstagefright/httplive/fuzzer/corpus/index3.m3u8 b/media/libstagefright/httplive/fuzzer/corpus/index3.m3u8
new file mode 100644
index 0000000..1b7f489
--- /dev/null
+++ b/media/libstagefright/httplive/fuzzer/corpus/index3.m3u8
@@ -0,0 +1,13 @@
+#EXTM3U
+#EXT-X-VERSION:4
+#EXT-X-TARGETDURATION:5
+#EXT-X-KEY:METHOD=AES-128,URI="https://demo.unified-streaming.com/video/tears-of-steel/aes.key",IV=0X99b74007b6254e4bd1c6e03631cad15b
+#EXT-X-PLAYLIST-TYPE:VOD
+#EXTINF:5,
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence1.ts
+#EXT-X-DISCONTINUITY
+#EXTINF:5,
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence2.ts
+#EXTINF:5,
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence3.ts
+#EXT-X-ENDLIST
diff --git a/media/libstagefright/httplive/fuzzer/corpus/index4.m3u8 b/media/libstagefright/httplive/fuzzer/corpus/index4.m3u8
new file mode 100644
index 0000000..89ba37c
--- /dev/null
+++ b/media/libstagefright/httplive/fuzzer/corpus/index4.m3u8
@@ -0,0 +1,15 @@
+#EXTM3U
+#EXT-X-VERSION:4
+#EXT-X-TARGETDURATION:5
+#EXT-X-KEY:METHOD=SAMPLE-AES,URI="data:text/plain;charset=utf-8,a4cd9995a1aa91e1",IV=0X99b74007b6254e4bd1c6e03631cad15b
+#EXT-X-DISCONTINUITY-SEQUENCE:0
+#EXT-X-PLAYLIST-TYPE:VOD
+#EXT-X-DISCONTINUITY
+#EXTINF:5,
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence0.ts
+#EXTINF:5,
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence1.ts
+#EXT-X-DISCONTINUITY
+#EXTINF:5,
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence2.ts
+#EXT-X-ENDLIST
diff --git a/media/libstagefright/httplive/fuzzer/corpus/index5.m3u8 b/media/libstagefright/httplive/fuzzer/corpus/index5.m3u8
new file mode 100644
index 0000000..2120de4
--- /dev/null
+++ b/media/libstagefright/httplive/fuzzer/corpus/index5.m3u8
@@ -0,0 +1,14 @@
+#EXTM3U
+#EXT-X-TARGETDURATION:11
+#EXT-X-KEY:METHOD=NONE
+#EXT-X-MEDIA-SEQUENCE:0
+#EXT-X-VERSION:4
+#EXTINF:10.0,
+#EXT-X-BYTERANGE:10@0
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence1.ts
+#EXTINF:10.0,
+#EXT-X-BYTERANGE:20@10
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence1.ts
+#EXTINF:10.0,
+#EXT-X-BYTERANGE:80
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence1.ts
diff --git a/media/libstagefright/httplive/fuzzer/corpus/index6.m3u8 b/media/libstagefright/httplive/fuzzer/corpus/index6.m3u8
new file mode 100644
index 0000000..588368a
--- /dev/null
+++ b/media/libstagefright/httplive/fuzzer/corpus/index6.m3u8
@@ -0,0 +1,12 @@
+#EXTM3U
+#EXT-X-VERSION:4
+#EXT-X-TARGETDURATION:5
+#EXT-X-KEY:METHOD=AES-128,URI="data:text/plain;charset=utf-8,a4cd9995a1aa91e1",IV=0x30303030303030303030303030303030
+#EXT-X-PLAYLIST-TYPE:VOD
+#EXTINF:5,
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence1.ts
+#EXTINF:5,
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence2.ts
+#EXTINF:5,
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence3.ts
+#EXT-X-ENDLIST
diff --git a/media/libstagefright/httplive/fuzzer/corpus/index7.m3u8 b/media/libstagefright/httplive/fuzzer/corpus/index7.m3u8
new file mode 100644
index 0000000..b09948e
--- /dev/null
+++ b/media/libstagefright/httplive/fuzzer/corpus/index7.m3u8
@@ -0,0 +1,46 @@
+#EXTM3U
+#EXT-X-VERSION:4
+## Created with Unified Streaming Platform (version=1.11.3-24438)
+#EXT-X-SESSION-KEY:METHOD=AES-128,URI="https://demo.unified-streaming.com/video/tears-of-steel/aes.key"
+
+# AUDIO groups
+#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio-aacl-64",LANGUAGE="en",NAME="English",DEFAULT=YES,AUTOSELECT=YES,CHANNELS="2"
+#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio-aacl-128",LANGUAGE="en",NAME="English",DEFAULT=YES,AUTOSELECT=YES,CHANNELS="2"
+
+# SUBTITLES groups
+#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="textstream",LANGUAGE="en",NAME="English",DEFAULT=YES,AUTOSELECT=YES,URI="tears-of-steel-aes-textstream_eng=1000.m3u8"
+#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="textstream",LANGUAGE="ru",NAME="Russian",AUTOSELECT=YES,URI="tears-of-steel-aes-textstream_rus=1000.m3u8"
+
+# variants
+#EXT-X-STREAM-INF:BANDWIDTH=494000,CODECS="mp4a.40.2,avc1.42C00D",RESOLUTION=224x100,FRAME-RATE=24,AUDIO="audio-aacl-64",SUBTITLES="textstream",CLOSED-CAPTIONS=NONE
+tears-of-steel-aes-audio_eng=64008-video_eng=401000.m3u8
+#EXT-X-STREAM-INF:BANDWIDTH=933000,CODECS="mp4a.40.2,avc1.42C016",RESOLUTION=448x200,FRAME-RATE=24,AUDIO="audio-aacl-128",SUBTITLES="textstream",CLOSED-CAPTIONS=NONE
+tears-of-steel-aes-audio_eng=128002-video_eng=751000.m3u8
+#EXT-X-STREAM-INF:BANDWIDTH=1198000,CODECS="mp4a.40.2,avc1.4D401F",RESOLUTION=784x350,FRAME-RATE=24,AUDIO="audio-aacl-128",SUBTITLES="textstream",CLOSED-CAPTIONS=NONE
+tears-of-steel-aes-audio_eng=128002-video_eng=1001000.m3u8
+#EXT-X-STREAM-INF:BANDWIDTH=1728000,CODECS="mp4a.40.2,avc1.640028",RESOLUTION=1680x750,FRAME-RATE=24,VIDEO-RANGE=SDR,AUDIO="audio-aacl-128",SUBTITLES="textstream",CLOSED-CAPTIONS=NONE
+tears-of-steel-aes-audio_eng=128002-video_eng=1501000.m3u8
+#EXT-X-STREAM-INF:BANDWIDTH=2469000,CODECS="mp4a.40.2,avc1.640028",RESOLUTION=1680x750,FRAME-RATE=24,VIDEO-RANGE=SDR,AUDIO="audio-aacl-128",SUBTITLES="textstream",CLOSED-CAPTIONS=NONE
+tears-of-steel-aes-audio_eng=128002-video_eng=2200000.m3u8
+
+# variants
+#EXT-X-STREAM-INF:BANDWIDTH=1025000,CODECS="mp4a.40.2,hvc1.1.6.L150.90",RESOLUTION=1680x750,FRAME-RATE=24,VIDEO-RANGE=SDR,AUDIO="audio-aacl-64",SUBTITLES="textstream",CLOSED-CAPTIONS=NONE
+tears-of-steel-aes-audio_eng=64008-video_eng_1=902000.m3u8
+#EXT-X-STREAM-INF:BANDWIDTH=1368000,CODECS="mp4a.40.2,hvc1.1.6.L150.90",RESOLUTION=2576x1150,FRAME-RATE=24,VIDEO-RANGE=SDR,AUDIO="audio-aacl-128",SUBTITLES="textstream",CLOSED-CAPTIONS=NONE
+tears-of-steel-aes-audio_eng=128002-video_eng_1=1161000.m3u8
+#EXT-X-STREAM-INF:BANDWIDTH=1815000,CODECS="mp4a.40.2,hvc1.1.6.L150.90",RESOLUTION=3360x1500,FRAME-RATE=24,VIDEO-RANGE=SDR,AUDIO="audio-aacl-128",SUBTITLES="textstream",CLOSED-CAPTIONS=NONE
+tears-of-steel-aes-audio_eng=128002-video_eng_1=1583000.m3u8
+
+# variants
+#EXT-X-STREAM-INF:BANDWIDTH=69000,CODECS="mp4a.40.2",AUDIO="audio-aacl-64",SUBTITLES="textstream"
+tears-of-steel-aes-audio_eng=64008.m3u8
+#EXT-X-STREAM-INF:BANDWIDTH=137000,CODECS="mp4a.40.2",AUDIO="audio-aacl-128",SUBTITLES="textstream"
+tears-of-steel-aes-audio_eng=128002.m3u8
+
+# keyframes
+#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=54000,CODECS="avc1.42C00D",RESOLUTION=224x100,URI="keyframes/tears-of-steel-aes-video_eng=401000.m3u8"
+#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=100000,CODECS="avc1.42C016",RESOLUTION=448x200,URI="keyframes/tears-of-steel-aes-video_eng=751000.m3u8"
+#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=133000,CODECS="avc1.4D401F",RESOLUTION=784x350,URI="keyframes/tears-of-steel-aes-video_eng=1001000.m3u8"
+#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=120000,CODECS="hvc1.1.6.L150.90",RESOLUTION=1680x750,VIDEO-RANGE=SDR,URI="keyframes/tears-of-steel-aes-video_eng_1=902000.m3u8"
+#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=154000,CODECS="hvc1.1.6.L150.90",RESOLUTION=2576x1150,VIDEO-RANGE=SDR,URI="keyframes/tears-of-steel-aes-video_eng_1=1161000.m3u8"
+#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=210000,CODECS="hvc1.1.6.L150.90",RESOLUTION=3360x1500,VIDEO-RANGE=SDR,URI="keyframes/tears-of-steel-aes-video_eng_1=1583000.m3u8"
diff --git a/media/libstagefright/httplive/fuzzer/corpus/index8.m3u8 b/media/libstagefright/httplive/fuzzer/corpus/index8.m3u8
new file mode 100644
index 0000000..353d589
--- /dev/null
+++ b/media/libstagefright/httplive/fuzzer/corpus/index8.m3u8
@@ -0,0 +1,13 @@
+#EXTM3U
+#EXT-X-VERSION:5
+
+#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="English stereo",LANGUAGE="en",AUTOSELECT=YES,URI="../../fuzz/arm64/httplive_fuzzer/index1.m3u8"
+
+#EXT-X-STREAM-INF:BANDWIDTH=628000,CODECS="avc1.42c00d,mp4a.40.2",RESOLUTION=320x180,AUDIO="audio"
+../../fuzz/arm64/httplive_fuzzer/index1.m3u8
+#EXT-X-STREAM-INF:BANDWIDTH=928000,CODECS="avc1.42c00d,mp4a.40.2",RESOLUTION=480x270,AUDIO="audio"
+../../fuzz/arm64/httplive_fuzzer/index2.m3u8
+#EXT-X-STREAM-INF:BANDWIDTH=1728000,CODECS="avc1.42c00d,mp4a.40.2",RESOLUTION=640x360,AUDIO="audio"
+../../fuzz/arm64/httplive_fuzzer/index3.m3u8
+#EXT-X-STREAM-INF:BANDWIDTH=2528000,CODECS="avc1.42c00d,mp4a.40.2",RESOLUTION=960x540,AUDIO="audio"
+../../fuzz/arm64/httplive_fuzzer/index1.m3u8
diff --git a/media/libstagefright/httplive/fuzzer/corpus/prog_index.m3u8 b/media/libstagefright/httplive/fuzzer/corpus/prog_index.m3u8
new file mode 100644
index 0000000..eb88422
--- /dev/null
+++ b/media/libstagefright/httplive/fuzzer/corpus/prog_index.m3u8
@@ -0,0 +1,17 @@
+#EXTM3U
+#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",LANGUAGE="eng",NAME="English",AUTOSELECT=YES,DEFAULT=YES,URI="corpus/index1.m3u8"
+#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",LANGUAGE="fre",NAME="Français",AUTOSELECT=YES,DEFAULT=NO,URI="corpus/index1.m3u8"
+#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",LANGUAGE="sp",NAME="Espanol",AUTOSELECT=YES,DEFAULT=NO,URI="corpus/index1.m3u8"
+#EXT-X-VERSION:4
+#EXT-X-TARGETDURATION:5
+#EXT-X-KEY:METHOD=NONE
+#EXT-X-DISCONTINUITY-SEQUENCE:0
+#EXT-X-PLAYLIST-TYPE:VOD
+#EXTINF:5,
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence1.ts
+#EXT-X-DISCONTINUITY
+#EXTINF:5,
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence1.ts
+#EXTINF:5,
+https://non.existentsite.com/test-doesnt-dereference-these-paths/fileSequence1.ts
+#EXT-X-ENDLIST
diff --git a/media/libstagefright/httplive/fuzzer/httplive_fuzzer.cpp b/media/libstagefright/httplive/fuzzer/httplive_fuzzer.cpp
new file mode 100644
index 0000000..348d526
--- /dev/null
+++ b/media/libstagefright/httplive/fuzzer/httplive_fuzzer.cpp
@@ -0,0 +1,302 @@
+/*
+ * 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 <fstream>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <LiveDataSource.h>
+#include <LiveSession.h>
+#include <media/MediaHTTPConnection.h>
+#include <media/MediaHTTPService.h>
+#include <media/mediaplayer_common.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/ALooperRoster.h>
+#include <string>
+#include <utils/Log.h>
+
+using namespace std;
+using namespace android;
+
+constexpr char kFileNamePrefix[] = "/data/local/tmp/httplive-";
+constexpr char kFileNameSuffix[] = ".m3u8";
+constexpr char kFileUrlPrefix[] = "file://";
+constexpr int64_t kOffSet = 0;
+constexpr int32_t kReadyMarkMs = 5000;
+constexpr int32_t kPrepareMarkMs = 1500;
+constexpr int32_t kErrorNoMax = -1;
+constexpr int32_t kErrorNoMin = -34;
+constexpr int32_t kMaxTimeUs = 1000;
+constexpr int32_t kRandomStringLength = 64;
+constexpr int32_t kRangeMin = 0;
+constexpr int32_t kRangeMax = 1000;
+
+constexpr LiveSession::StreamType kValidStreamType[] = {
+ LiveSession::STREAMTYPE_AUDIO, LiveSession::STREAMTYPE_VIDEO,
+ LiveSession::STREAMTYPE_SUBTITLES, LiveSession::STREAMTYPE_METADATA};
+
+constexpr MediaSource::ReadOptions::SeekMode kValidSeekMode[] = {
+ MediaSource::ReadOptions::SeekMode::SEEK_PREVIOUS_SYNC,
+ MediaSource::ReadOptions::SeekMode::SEEK_NEXT_SYNC,
+ MediaSource::ReadOptions::SeekMode::SEEK_CLOSEST_SYNC,
+ MediaSource::ReadOptions::SeekMode::SEEK_CLOSEST,
+ MediaSource::ReadOptions::SeekMode::SEEK_FRAME_INDEX};
+
+constexpr media_track_type kValidMediaTrackType[] = {
+ MEDIA_TRACK_TYPE_UNKNOWN, MEDIA_TRACK_TYPE_VIDEO,
+ MEDIA_TRACK_TYPE_AUDIO, MEDIA_TRACK_TYPE_TIMEDTEXT,
+ MEDIA_TRACK_TYPE_SUBTITLE, MEDIA_TRACK_TYPE_METADATA};
+
+struct TestAHandler : public AHandler {
+public:
+ TestAHandler(std::function<void()> signalEosFunction)
+ : mSignalEosFunction(signalEosFunction) {}
+ virtual ~TestAHandler() {}
+
+protected:
+ void onMessageReceived(const sp<AMessage> &msg) override {
+ int32_t what = -1;
+ msg->findInt32("what", &what);
+ switch (what) {
+ case LiveSession::kWhatError:
+ case LiveSession::kWhatPrepared:
+ case LiveSession::kWhatPreparationFailed: {
+ mSignalEosFunction();
+ break;
+ }
+ }
+ return;
+ }
+
+private:
+ std::function<void()> mSignalEosFunction;
+};
+
+struct TestMediaHTTPConnection : public MediaHTTPConnection {
+public:
+ TestMediaHTTPConnection() {}
+ virtual ~TestMediaHTTPConnection() {}
+
+ virtual bool connect(const char * /*uri*/,
+ const KeyedVector<String8, String8> * /*headers*/) {
+ return true;
+ }
+
+ virtual void disconnect() { return; }
+
+ virtual ssize_t readAt(off64_t /*offset*/, void * /*data*/, size_t size) {
+ return size;
+ }
+
+ virtual off64_t getSize() { return 0; }
+ virtual status_t getMIMEType(String8 * /*mimeType*/) { return NO_ERROR; }
+ virtual status_t getUri(String8 * /*uri*/) { return NO_ERROR; }
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(TestMediaHTTPConnection);
+};
+
+struct TestMediaHTTPService : public MediaHTTPService {
+public:
+ TestMediaHTTPService() {}
+ ~TestMediaHTTPService(){};
+
+ virtual sp<MediaHTTPConnection> makeHTTPConnection() {
+ mediaHTTPConnection = sp<TestMediaHTTPConnection>::make();
+ return mediaHTTPConnection;
+ }
+
+private:
+ sp<TestMediaHTTPConnection> mediaHTTPConnection = nullptr;
+ DISALLOW_EVIL_CONSTRUCTORS(TestMediaHTTPService);
+};
+
+class HttpLiveFuzzer {
+public:
+ void process(const uint8_t *data, size_t size);
+ void deInitLiveSession();
+ ~HttpLiveFuzzer() { deInitLiveSession(); }
+
+private:
+ void invokeLiveDataSource();
+ void createM3U8File(const uint8_t *data, size_t size);
+ void initLiveDataSource();
+ void invokeLiveSession();
+ void initLiveSession();
+ void invokeDequeueAccessUnit();
+ void invokeConnectAsync();
+ void invokeSeekTo();
+ void invokeGetConfig();
+ void signalEos();
+ string generateFileName();
+ sp<LiveDataSource> mLiveDataSource = nullptr;
+ sp<LiveSession> mLiveSession = nullptr;
+ sp<ALooper> mLiveLooper = nullptr;
+ sp<TestMediaHTTPService> httpService = nullptr;
+ sp<TestAHandler> mHandler = nullptr;
+ FuzzedDataProvider *mFDP = nullptr;
+ bool mEosReached = false;
+ std::mutex mDownloadCompleteMutex;
+ std::condition_variable mConditionalVariable;
+};
+
+string HttpLiveFuzzer::generateFileName() {
+ return kFileNamePrefix + to_string(getpid()) + kFileNameSuffix;
+}
+
+void HttpLiveFuzzer::createM3U8File(const uint8_t *data, size_t size) {
+ ofstream m3u8File;
+ string currentFileName = generateFileName();
+ m3u8File.open(currentFileName, ios::out | ios::binary);
+ m3u8File.write((char *)data, size);
+ m3u8File.close();
+}
+
+void HttpLiveFuzzer::initLiveDataSource() {
+ mLiveDataSource = sp<LiveDataSource>::make();
+}
+
+void HttpLiveFuzzer::invokeLiveDataSource() {
+ initLiveDataSource();
+ size_t size = mFDP->ConsumeIntegralInRange<size_t>(kRangeMin, kRangeMax);
+ sp<ABuffer> buffer = new ABuffer(size);
+ mLiveDataSource->queueBuffer(buffer);
+ uint8_t *data = new uint8_t[size];
+ mLiveDataSource->readAtNonBlocking(kOffSet, data, size);
+ int32_t finalResult = mFDP->ConsumeIntegralInRange(kErrorNoMin, kErrorNoMax);
+ mLiveDataSource->queueEOS(finalResult);
+ mLiveDataSource->reset();
+ mLiveDataSource->countQueuedBuffers();
+ mLiveDataSource->initCheck();
+ delete[] data;
+}
+
+void HttpLiveFuzzer::initLiveSession() {
+ ALooperRoster looperRoster;
+ mHandler =
+ sp<TestAHandler>::make(std::bind(&HttpLiveFuzzer::signalEos, this));
+ mLiveLooper = sp<ALooper>::make();
+ mLiveLooper->setName("http live");
+ mLiveLooper->start();
+ sp<AMessage> notify = sp<AMessage>::make(0, mHandler);
+ httpService = new TestMediaHTTPService();
+ uint32_t flags = mFDP->ConsumeIntegral<uint32_t>();
+ mLiveSession = sp<LiveSession>::make(notify, flags, httpService);
+ mLiveLooper->registerHandler(mLiveSession);
+ looperRoster.registerHandler(mLiveLooper, mHandler);
+}
+
+void HttpLiveFuzzer::invokeDequeueAccessUnit() {
+ LiveSession::StreamType stream = mFDP->PickValueInArray(kValidStreamType);
+ sp<ABuffer> buffer;
+ mLiveSession->dequeueAccessUnit(stream, &buffer);
+}
+
+void HttpLiveFuzzer::invokeSeekTo() {
+ int64_t timeUs = mFDP->ConsumeIntegralInRange<int64_t>(0, kMaxTimeUs);
+ MediaSource::ReadOptions::SeekMode mode =
+ mFDP->PickValueInArray(kValidSeekMode);
+ mLiveSession->seekTo(timeUs, mode);
+}
+
+void HttpLiveFuzzer::invokeGetConfig() {
+ mLiveSession->getTrackCount();
+ size_t trackIndex = mFDP->ConsumeIntegral<size_t>();
+ mLiveSession->getTrackInfo(trackIndex);
+ media_track_type type = mFDP->PickValueInArray(kValidMediaTrackType);
+ mLiveSession->getSelectedTrack(type);
+ sp<MetaData> meta;
+ LiveSession::StreamType stream = mFDP->PickValueInArray(kValidStreamType);
+ mLiveSession->getStreamFormatMeta(stream, &meta);
+ mLiveSession->getKeyForStream(stream);
+ if (stream != LiveSession::STREAMTYPE_SUBTITLES) {
+ mLiveSession->getSourceTypeForStream(stream);
+ }
+}
+
+void HttpLiveFuzzer::invokeConnectAsync() {
+ string currentFileName = generateFileName();
+ size_t fileUrlLength =
+ strlen(currentFileName.c_str()) + strlen(kFileUrlPrefix);
+ char *url = new char[fileUrlLength + 1];
+ strcpy(url, kFileUrlPrefix);
+ strcat(url, currentFileName.c_str());
+ string str_1 = mFDP->ConsumeRandomLengthString(kRandomStringLength);
+ string str_2 = mFDP->ConsumeRandomLengthString(kRandomStringLength);
+
+ KeyedVector<String8, String8> headers;
+ headers.add(String8(str_1.c_str()), String8(str_2.c_str()));
+ mLiveSession->connectAsync(url, &headers);
+}
+
+void HttpLiveFuzzer::invokeLiveSession() {
+ initLiveSession();
+ BufferingSettings bufferingSettings;
+ bufferingSettings.mInitialMarkMs = kPrepareMarkMs;
+ bufferingSettings.mResumePlaybackMarkMs = kReadyMarkMs;
+ mLiveSession->setBufferingSettings(bufferingSettings);
+ invokeConnectAsync();
+ std::unique_lock waitForDownloadComplete(mDownloadCompleteMutex);
+ mConditionalVariable.wait(waitForDownloadComplete,
+ [this] { return mEosReached; });
+ if (mLiveSession->isSeekable()) {
+ invokeSeekTo();
+ }
+ invokeDequeueAccessUnit();
+ size_t index = mFDP->ConsumeIntegral<size_t>();
+ bool select = mFDP->ConsumeBool();
+ mLiveSession->selectTrack(index, select);
+ mLiveSession->hasDynamicDuration();
+ int64_t firstTimeUs =
+ mFDP->ConsumeIntegralInRange<int64_t>(kRangeMin, kRangeMax);
+ int64_t timeUs = mFDP->ConsumeIntegralInRange<int64_t>(kRangeMin, kRangeMax);
+ int32_t discontinuitySeq = mFDP->ConsumeIntegral<int32_t>();
+ mLiveSession->calculateMediaTimeUs(firstTimeUs, timeUs, discontinuitySeq);
+ invokeGetConfig();
+}
+
+void HttpLiveFuzzer::process(const uint8_t *data, size_t size) {
+ mFDP = new FuzzedDataProvider(data, size);
+ createM3U8File(data, size);
+ invokeLiveDataSource();
+ invokeLiveSession();
+ delete mFDP;
+}
+
+void HttpLiveFuzzer::deInitLiveSession() {
+ if (mLiveSession != nullptr) {
+ mLiveSession->disconnect();
+ mLiveLooper->unregisterHandler(mLiveSession->id());
+ mLiveLooper->stop();
+ }
+ mLiveSession.clear();
+ mLiveLooper.clear();
+}
+
+void HttpLiveFuzzer::signalEos() {
+ mEosReached = true;
+ {
+ std::lock_guard<std::mutex> waitForDownloadComplete(mDownloadCompleteMutex);
+ }
+ mConditionalVariable.notify_one();
+ return;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ HttpLiveFuzzer httpliveFuzzer;
+ httpliveFuzzer.process(data, size);
+ return 0;
+}
diff --git a/media/libstagefright/httplive/fuzzer/httplive_fuzzer.dict b/media/libstagefright/httplive/fuzzer/httplive_fuzzer.dict
new file mode 100644
index 0000000..703cc7e
--- /dev/null
+++ b/media/libstagefright/httplive/fuzzer/httplive_fuzzer.dict
@@ -0,0 +1,15 @@
+#m3u8-Tags
+kw1="#EXTM3U"
+kw2="#EXT-X-VERSION:"
+kw3="#EXT-X-TARGETDURATION:"
+kw4="#EXT-X-PLAYLIST-TYPE:"
+kw5="#EXTINF:"
+kw6="#EXT-X-ENDLIST"
+kw7="#EXT-X-MEDIA-SEQUENCE:"
+kw8="#EXT-X-KEY:METHOD=NONE"
+kw9="#EXT-X-DISCONTINUITY:"
+kw10="#EXT-X-DISCONTINUITY-SEQUENCE:0"
+kw11="#EXT-X-STREAM-INF:BANDWIDTH="
+kw12="#EXT-X-STREAM-INF:CODECS="
+kw13="#EXT-X-BYTERANGE:"
+kw14="#EXT-X-MEDIA"
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/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index 4c69485..ffccbb1 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"
@@ -306,6 +304,12 @@
break;
}
+ case kWhatAlarmStream:
+ {
+ onAlarmStream(msg);
+ break;
+ }
+
case kWhatInjectPacket:
{
onInjectPacket(msg);
@@ -573,6 +577,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");
@@ -658,12 +669,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) {
@@ -745,9 +750,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;
@@ -804,14 +823,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();
@@ -908,7 +925,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();
@@ -1090,11 +1107,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);
@@ -1142,7 +1162,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
}
}
@@ -1173,7 +1193,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 adf9670..36cca31 100644
--- a/media/libstagefright/rtsp/ARTPConnection.h
+++ b/media/libstagefright/rtsp/ARTPConnection.h
@@ -73,6 +73,7 @@
kWhatRemoveStream,
kWhatPollStreams,
kWhatInjectPacket,
+ kWhatAlarmStream,
};
static const int64_t kSelectTimeoutUs;
@@ -98,6 +99,7 @@
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 f960482..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,20 +126,32 @@
}
}
+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();
}
void ARTPSource::timeReset() {
mFirstRtpTime = 0;
mFirstSysTime = 0;
+ mSysAnchorTime = 0;
+ mLastSysAnchorTimeUpdatedUs = 0;
mFirstSsrc = 0;
mHighestNackNumber = 0;
mHighestSeqNumber = 0;
@@ -142,25 +161,100 @@
mPrevNumBuffersReceived = 0;
mPrevExpectedForRR = 0;
mPrevNumBuffersReceivedForRR = 0;
- mLastNTPTime = 0;
- mLastNTPTimeUpdateUs = 0;
+ mLatestRtpTime = 0;
+ mLastSrRtpTime = 0;
+ mLastSrNtpTime = 0;
+ mLastSrUpdateTimeUs = 0;
+ mIsFirstRtpRtcpGap = true;
+ mAvgRtpRtcpGapMs = 0;
+ mAvgUnderlineDelayMs = 0;
mIssueFIRByAssembler = false;
mLastFIRRequestUs = -1;
}
-bool ARTPSource::queuePacket(const sp<ABuffer> &buffer) {
- uint32_t seqNum = (uint32_t)buffer->int32Data();
+void ARTPSource::calcTimeGapRtpRtcp(const sp<ABuffer> &buffer, int64_t nowUs) {
+ if (mLastSrUpdateTimeUs == 0) {
+ return;
+ }
- int32_t ssrc = 0;
+ 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);
@@ -179,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.
@@ -363,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;
@@ -566,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;
@@ -576,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();
@@ -590,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 2d804d8..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,7 @@
};
void processRTPPacket(const sp<ABuffer> &buffer);
+ void processRTPPacket();
void timeReset();
void timeUpdate(uint32_t rtpTime, uint64_t ntpTime);
void byeReceived();
@@ -77,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;
@@ -104,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;
@@ -121,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;
@@ -131,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 29e263d..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();
}
@@ -646,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;
@@ -780,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";
@@ -981,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 =
@@ -1156,9 +1183,6 @@
offset += size;
}
}
-
- mLastRTPTime = rtpTime;
- mLastNTPTime = GetNowNTP();
}
void ARTPWriter::sendAVCData(MediaBufferBase *mediaBuf) {
@@ -1170,7 +1194,7 @@
sendSPSPPSIfIFrame(mediaBuf, timeUs);
- uint32_t rtpTime = mRTPTimeBase + (timeUs * 9 / 100LL);
+ uint32_t rtpTime = getRtpTime(timeUs);
CHECK(mediaBuf->range_length() > 0);
const uint8_t *mediaData =
@@ -1343,9 +1367,6 @@
offset += size;
}
}
-
- mLastRTPTime = rtpTime;
- mLastNTPTime = GetNowNTP();
}
void ARTPWriter::sendH263Data(MediaBufferBase *mediaBuf) {
@@ -1354,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();
@@ -1405,9 +1426,6 @@
++mNumRTPSent;
mNumRTPOctetsSent += buffer->size() - 12;
}
-
- mLastRTPTime = rtpTime;
- mLastNTPTime = GetNowNTP();
}
void ARTPWriter::updateCVODegrees(int32_t cvoDegrees) {
@@ -1490,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);
@@ -1564,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/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index af21a99..b1a7f43 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -412,17 +412,19 @@
uint32_t flags) {
sp<AMessage> nativeFormat;
AMediaFormat_getFormat(format, &nativeFormat);
- ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str());
+ // create our shallow copy, so we aren't victim to any later changes.
+ sp<AMessage> dupNativeFormat = nativeFormat->dup();
+ ALOGV("configure with format: %s", dupNativeFormat->debugString(0).c_str());
sp<Surface> surface = NULL;
if (window != NULL) {
surface = (Surface*) window;
}
- status_t err = mData->mCodec->configure(nativeFormat, surface,
+ status_t err = mData->mCodec->configure(dupNativeFormat, surface,
crypto ? crypto->mCrypto : NULL, flags);
if (err != OK) {
ALOGE("configure: err(%d), failed with format: %s",
- err, nativeFormat->debugString(0).c_str());
+ err, dupNativeFormat->debugString(0).c_str());
}
return translate_error(err);
}
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/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/fuzzer/Android.bp b/services/mediacodec/registrant/fuzzer/Android.bp
index 22c10a8..43afbf1 100644
--- a/services/mediacodec/registrant/fuzzer/Android.bp
+++ b/services/mediacodec/registrant/fuzzer/Android.bp
@@ -14,6 +14,15 @@
* 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: [
diff --git a/services/mediacodec/registrant/fuzzer/codecServiceRegistrant_fuzzer.cpp b/services/mediacodec/registrant/fuzzer/codecServiceRegistrant_fuzzer.cpp
index c8a8d8a..e5983e4 100644
--- a/services/mediacodec/registrant/fuzzer/codecServiceRegistrant_fuzzer.cpp
+++ b/services/mediacodec/registrant/fuzzer/codecServiceRegistrant_fuzzer.cpp
@@ -132,7 +132,10 @@
mH2C2->querySupportedValues_sm(query);
mH2C2->getName();
- mH2C2->getParamReflector();
+ shared_ptr<C2ParamReflector> paramReflector = mH2C2->getParamReflector();
+ if (paramReflector) {
+ paramReflector->describe(C2ComponentDomainSetting::CORE_INDEX);
+ }
mH2C2->listComponents();
shared_ptr<C2GraphicBuffer> src;
shared_ptr<C2GraphicBuffer> dst;
diff --git a/services/mediatranscoding/Android.bp b/services/mediatranscoding/Android.bp
index a895071..6c390c8 100644
--- a/services/mediatranscoding/Android.bp
+++ b/services/mediatranscoding/Android.bp
@@ -32,7 +32,7 @@
],
static_libs: [
- "mediatranscoding_aidl_interface-ndk_platform",
+ "mediatranscoding_aidl_interface-ndk",
],
cflags: [
@@ -60,7 +60,7 @@
],
static_libs: [
- "mediatranscoding_aidl_interface-ndk_platform",
+ "mediatranscoding_aidl_interface-ndk",
],
init_rc: ["mediatranscoding.rc"],
diff --git a/services/mediatranscoding/tests/Android.bp b/services/mediatranscoding/tests/Android.bp
index a856c05..9b18d43 100644
--- a/services/mediatranscoding/tests/Android.bp
+++ b/services/mediatranscoding/tests/Android.bp
@@ -34,7 +34,7 @@
],
static_libs: [
- "mediatranscoding_aidl_interface-ndk_platform",
+ "mediatranscoding_aidl_interface-ndk",
],
}
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",