Merge "C2SoftVpxDec: Add dynamic color aspects support" into main
diff --git a/media/aconfig/codec_fwk.aconfig b/media/aconfig/codec_fwk.aconfig
index a2b6a82..b3c02eb 100644
--- a/media/aconfig/codec_fwk.aconfig
+++ b/media/aconfig/codec_fwk.aconfig
@@ -88,6 +88,26 @@
}
flag {
+ name: "set_callback_stall"
+ namespace: "codec_fwk"
+ description: "Bugfix flag for setCallback stall"
+ bug: "326010604"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "set_state_early"
+ namespace: "codec_fwk"
+ description: "Bugfix flag for setting state early to avoid a race condition"
+ bug: "298613711"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "teamfood"
namespace: "codec_fwk"
description: "Feature flag to track teamfood population"
diff --git a/media/codec2/components/aom/C2SoftAomEnc.cpp b/media/codec2/components/aom/C2SoftAomEnc.cpp
index 256bcb8..722b13a 100644
--- a/media/codec2/components/aom/C2SoftAomEnc.cpp
+++ b/media/codec2/components/aom/C2SoftAomEnc.cpp
@@ -29,6 +29,12 @@
#include "C2SoftAomEnc.h"
+/* Quantization param values defined by the spec */
+#define AOM_QP_MIN 0
+#define AOM_QP_MAX 63
+#define AOM_QP_DEFAULT_MIN AOM_QP_MIN
+#define AOM_QP_DEFAULT_MAX AOM_QP_MAX
+
namespace android {
constexpr char COMPONENT_NAME[] = "c2.android.av1.encoder";
@@ -175,6 +181,19 @@
.inRange(C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)})
.withSetter(CodedColorAspectsSetter, mColorAspects)
.build());
+
+ addParameter(
+ DefineParam(mPictureQuantization, C2_PARAMKEY_PICTURE_QUANTIZATION)
+ .withDefault(C2StreamPictureQuantizationTuning::output::AllocShared(
+ 0 /* flexCount */, 0u /* stream */))
+ .withFields({C2F(mPictureQuantization, m.values[0].type_).oneOf(
+ {C2Config::I_FRAME, C2Config::P_FRAME}),
+ C2F(mPictureQuantization, m.values[0].min).inRange(
+ AOM_QP_DEFAULT_MIN, AOM_QP_DEFAULT_MAX),
+ C2F(mPictureQuantization, m.values[0].max).inRange(
+ AOM_QP_DEFAULT_MIN, AOM_QP_DEFAULT_MAX)})
+ .withSetter(PictureQuantizationSetter)
+ .build());
}
C2R C2SoftAomEnc::IntfImpl::BitrateSetter(bool mayBlock, C2P<C2StreamBitrateInfo::output>& me) {
@@ -307,6 +326,54 @@
return C2R::Ok();
}
+C2R C2SoftAomEnc::IntfImpl::PictureQuantizationSetter(
+ bool mayBlock, C2P<C2StreamPictureQuantizationTuning::output>& me) {
+ (void)mayBlock;
+ int32_t iMin = AOM_QP_DEFAULT_MIN, pMin = AOM_QP_DEFAULT_MIN;
+ int32_t iMax = AOM_QP_DEFAULT_MAX, pMax = AOM_QP_DEFAULT_MAX;
+ for (size_t i = 0; i < me.v.flexCount(); ++i) {
+ const C2PictureQuantizationStruct &layer = me.v.m.values[i];
+ // layerMin is clamped to [AOM_QP_MIN, layerMax] to avoid error
+ // cases where layer.min > layer.max
+ int32_t layerMax = std::clamp(layer.max, AOM_QP_MIN, AOM_QP_MAX);
+ int32_t layerMin = std::clamp(layer.min, AOM_QP_MIN, layerMax);
+ if (layer.type_ == C2Config::picture_type_t(I_FRAME)) {
+ iMax = layerMax;
+ iMin = layerMin;
+ ALOGV("iMin %d iMax %d", iMin, iMax);
+ } else if (layer.type_ == C2Config::picture_type_t(P_FRAME)) {
+ pMax = layerMax;
+ pMin = layerMin;
+ ALOGV("pMin %d pMax %d", pMin, pMax);
+ }
+ }
+ ALOGV("PictureQuantizationSetter(entry): i %d-%d p %d-%d",
+ iMin, iMax, pMin, pMax);
+
+ // aom library takes same range for I/P picture type
+ int32_t maxFrameQP = std::min(iMax, pMax);
+ int32_t minFrameQP = std::max(iMin, pMin);
+ if (minFrameQP > maxFrameQP) {
+ minFrameQP = maxFrameQP;
+ }
+ // put them back into the structure
+ for (size_t i = 0; i < me.v.flexCount(); ++i) {
+ const C2PictureQuantizationStruct &layer = me.v.m.values[i];
+
+ if (layer.type_ == C2Config::picture_type_t(I_FRAME)) {
+ me.set().m.values[i].max = maxFrameQP;
+ me.set().m.values[i].min = minFrameQP;
+ }
+ else if (layer.type_ == C2Config::picture_type_t(P_FRAME)) {
+ me.set().m.values[i].max = maxFrameQP;
+ me.set().m.values[i].min = minFrameQP;
+ }
+ }
+ ALOGV("PictureQuantizationSetter(exit): minFrameQP = %d maxFrameQP = %d",
+ minFrameQP, maxFrameQP);
+ return C2R::Ok();
+}
+
uint32_t C2SoftAomEnc::IntfImpl::getLevel_l() const {
return mProfileLevel->level - LEVEL_AV1_2;
}
@@ -558,6 +625,7 @@
mQuality = mIntf->getQuality_l();
mComplexity = mIntf->getComplexity_l();
mAV1EncLevel = mIntf->getLevel_l();
+ mQpBounds = mIntf->getPictureQuantization_l();
}
@@ -575,6 +643,18 @@
break;
}
+ if (mQpBounds->flexCount() > 0) {
+ // read min max qp for sequence
+ for (size_t i = 0; i < mQpBounds->flexCount(); ++i) {
+ const C2PictureQuantizationStruct &layer = mQpBounds->m.values[i];
+ if (layer.type_ == C2Config::picture_type_t(I_FRAME)) {
+ mMaxQuantizer = layer.max;
+ mMinQuantizer = layer.min;
+ break;
+ }
+ }
+ }
+
mCodecInterface = aom_codec_av1_cx();
if (!mCodecInterface) goto CleanUp;
diff --git a/media/codec2/components/aom/C2SoftAomEnc.h b/media/codec2/components/aom/C2SoftAomEnc.h
index 7e5ea63..067b04f 100644
--- a/media/codec2/components/aom/C2SoftAomEnc.h
+++ b/media/codec2/components/aom/C2SoftAomEnc.h
@@ -109,6 +109,7 @@
std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
std::shared_ptr<C2StreamRequestSyncFrameTuning::output> mRequestSync;
std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects;
+ std::shared_ptr<C2StreamPictureQuantizationTuning::output> mQpBounds;
aom_codec_err_t setupCodecParameters();
};
@@ -126,6 +127,8 @@
const C2P<C2StreamPictureSizeInfo::input>& size,
const C2P<C2StreamFrameRateInfo::output>& frameRate,
const C2P<C2StreamBitrateInfo::output>& bitrate);
+ static C2R PictureQuantizationSetter(bool mayBlock,
+ C2P<C2StreamPictureQuantizationTuning::output> &me);
// unsafe getters
std::shared_ptr<C2StreamPictureSizeInfo::input> getSize_l() const { return mSize; }
@@ -150,6 +153,9 @@
std::shared_ptr<C2StreamPixelFormatInfo::input> getPixelFormat_l() const {
return mPixelFormat;
}
+ std::shared_ptr<C2StreamPictureQuantizationTuning::output> getPictureQuantization_l() const {
+ return mPictureQuantization;
+ }
uint32_t getSyncFramePeriod() const;
static C2R ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::input>& me);
static C2R CodedColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output>& me,
@@ -171,6 +177,7 @@
std::shared_ptr<C2StreamColorAspectsInfo::input> mColorAspects;
std::shared_ptr<C2StreamColorAspectsInfo::output> mCodedColorAspects;
std::shared_ptr<C2StreamPixelFormatInfo::input> mPixelFormat;
+ std::shared_ptr<C2StreamPictureQuantizationTuning::output> mPictureQuantization;
};
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.cpp b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
index 66ce5ea..1c5772f 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
@@ -354,12 +354,9 @@
return (uint32_t)c2_max(c2_min(period + 0.5, double(UINT32_MAX)), 1.);
}
-C2R C2SoftVpxEnc::IntfImpl::PictureQuantizationSetter(bool mayBlock,
- C2P<C2StreamPictureQuantizationTuning::output>
- &me) {
+C2R C2SoftVpxEnc::IntfImpl::PictureQuantizationSetter(
+ bool mayBlock, C2P<C2StreamPictureQuantizationTuning::output>& me) {
(void)mayBlock;
- // these are the ones we're going to set, so want them to default
- // to the DEFAULT values for the codec
int32_t iMin = VPX_QP_DEFAULT_MIN, pMin = VPX_QP_DEFAULT_MIN;
int32_t iMax = VPX_QP_DEFAULT_MAX, pMax = VPX_QP_DEFAULT_MAX;
for (size_t i = 0; i < me.v.flexCount(); ++i) {
@@ -382,8 +379,8 @@
iMin, iMax, pMin, pMax);
// vpx library takes same range for I/P picture type
- int32_t maxFrameQP = std::min({iMax, pMax});
- int32_t minFrameQP = std::max({iMin, pMin});
+ int32_t maxFrameQP = std::min(iMax, pMax);
+ int32_t minFrameQP = std::max(iMin, pMin);
if (minFrameQP > maxFrameQP) {
minFrameQP = maxFrameQP;
}
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index e2936c8..2550dcf 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -1144,7 +1144,7 @@
std::optional<Smpte2086> smpte2086;
status_t status = mapper.getSmpte2086(buffer.get(), &smpte2086);
- if (status != OK) {
+ if (status != OK || !smpte2086) {
err = C2_CORRUPTED;
} else {
if (smpte2086) {
@@ -1164,7 +1164,7 @@
std::optional<Cta861_3> cta861_3;
status = mapper.getCta861_3(buffer.get(), &cta861_3);
- if (status != OK) {
+ if (status != OK || !cta861_3) {
err = C2_CORRUPTED;
} else {
if (cta861_3) {
@@ -1183,7 +1183,7 @@
dynamicInfo->reset();
std::optional<std::vector<uint8_t>> vec;
status_t status = mapper.getSmpte2094_40(buffer.get(), &vec);
- if (status != OK) {
+ if (status != OK || !vec) {
dynamicInfo->reset();
err = C2_CORRUPTED;
} else {
diff --git a/media/libaudioclient/aidl/fuzzer/audioflinger_aidl_fuzzer.cpp b/media/libaudioclient/aidl/fuzzer/audioflinger_aidl_fuzzer.cpp
index 1d2da6a..c7a04da 100644
--- a/media/libaudioclient/aidl/fuzzer/audioflinger_aidl_fuzzer.cpp
+++ b/media/libaudioclient/aidl/fuzzer/audioflinger_aidl_fuzzer.cpp
@@ -36,6 +36,7 @@
[[clang::no_destroy]] static std::once_flag gSmOnce;
sp<FakeServiceManager> gFakeServiceManager;
+sp<AudioFlingerServerAdapter> gAudioFlingerServerAdapter;
bool addService(const String16& serviceName, const sp<FakeServiceManager>& fakeServiceManager,
FuzzedDataProvider& fdp) {
@@ -47,22 +48,10 @@
return true;
}
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- FuzzedDataProvider fdp(data, size);
-
- std::call_once(gSmOnce, [&] {
- /* Create a FakeServiceManager instance and add required services */
- gFakeServiceManager = sp<FakeServiceManager>::make();
- setDefaultServiceManager(gFakeServiceManager);
- });
- gFakeServiceManager->clear();
-
- for (const char* service : {"activity", "sensor_privacy", "permission", "scheduling_policy",
- "batterystats", "media.metrics"}) {
- if (!addService(String16(service), gFakeServiceManager, fdp)) {
- return 0;
- }
- }
+extern "C" int LLVMFuzzerInitialize(int* /*argc*/, char*** /*argv*/) {
+ /* Create a FakeServiceManager instance and add required services */
+ gFakeServiceManager = sp<FakeServiceManager>::make();
+ setDefaultServiceManager(gFakeServiceManager);
auto configService = ndk::SharedRefBase::make<ConfigMock>();
CHECK_EQ(NO_ERROR, AServiceManager_addService(configService.get()->asBinder().get(),
@@ -80,22 +69,37 @@
// Disable creating thread pool for fuzzer instance of audio flinger and audio policy services
AudioSystem::disableThreadPool();
- const auto audioFlinger = sp<AudioFlinger>::make();
- const auto afAdapter = sp<AudioFlingerServerAdapter>::make(audioFlinger);
+ return 0;
+}
- CHECK_EQ(NO_ERROR,
- gFakeServiceManager->addService(
- String16(IAudioFlinger::DEFAULT_SERVICE_NAME), IInterface::asBinder(afAdapter),
- false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
- const auto audioPolicyService = sp<AudioPolicyService>::make();
+ for (const char* service : {"activity", "sensor_privacy", "permission", "scheduling_policy",
+ "batterystats", "media.metrics"}) {
+ if (!addService(String16(service), gFakeServiceManager, fdp)) {
+ return 0;
+ }
+ }
- CHECK_EQ(NO_ERROR,
- gFakeServiceManager->addService(String16("media.audio_policy"), audioPolicyService,
- false /* allowIsolated */,
- IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
+ // TODO(330882064) : Initialise Audio Flinger and Audio Policy services every time
+ std::call_once(gSmOnce, [&] {
+ const auto audioFlinger = sp<AudioFlinger>::make();
+ gAudioFlingerServerAdapter = sp<AudioFlingerServerAdapter>::make(audioFlinger);
+ CHECK_EQ(NO_ERROR,
+ gFakeServiceManager->addService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME),
+ IInterface::asBinder(gAudioFlingerServerAdapter),
+ false /* allowIsolated */,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
- fuzzService(media::IAudioFlingerService::asBinder(afAdapter), std::move(fdp));
+ const auto audioPolicyService = sp<AudioPolicyService>::make();
+ CHECK_EQ(NO_ERROR,
+ gFakeServiceManager->addService(String16("media.audio_policy"), audioPolicyService,
+ false /* allowIsolated */,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
+ });
+
+ fuzzService(media::IAudioFlingerService::asBinder(gAudioFlingerServerAdapter), std::move(fdp));
return 0;
}
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index fed2919..97c9659 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -366,24 +366,26 @@
if (mIsInput) {
return sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), reply);
} else {
- if (mContext.isAsynchronous()) {
+ if (const auto state = getState(); state == StreamDescriptor::State::IDLE) {
// Handle pause-flush-resume sequence. 'flush' from PAUSED goes to
// IDLE. We move here from IDLE to ACTIVE (same as 'start' from PAUSED).
- const auto state = getState();
- if (state == StreamDescriptor::State::IDLE) {
- StreamDescriptor::Reply localReply{};
- StreamDescriptor::Reply* innerReply = reply ?: &localReply;
- RETURN_STATUS_IF_ERROR(
- sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), innerReply));
- if (innerReply->state != StreamDescriptor::State::ACTIVE) {
- ALOGE("%s: unexpected stream state: %s (expected ACTIVE)",
- __func__, toString(innerReply->state).c_str());
- return INVALID_OPERATION;
- }
- return OK;
+ StreamDescriptor::Reply localReply{};
+ StreamDescriptor::Reply* innerReply = reply ?: &localReply;
+ RETURN_STATUS_IF_ERROR(
+ sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), innerReply));
+ if (innerReply->state != StreamDescriptor::State::ACTIVE) {
+ ALOGE("%s: unexpected stream state: %s (expected ACTIVE)",
+ __func__, toString(innerReply->state).c_str());
+ return INVALID_OPERATION;
}
+ return OK;
+ } else if (state == StreamDescriptor::State::PAUSED) {
+ return sendCommand(makeHalCommand<HalCommand::Tag::start>(), reply);
+ } else {
+ ALOGE("%s: unexpected stream state: %s (expected IDLE or PAUSED)",
+ __func__, toString(state).c_str());
+ return INVALID_OPERATION;
}
- return sendCommand(makeHalCommand<HalCommand::Tag::start>(), reply);
}
}
@@ -506,27 +508,31 @@
"%s %s: must be invoked from the worker thread (%d)",
__func__, command.toString().c_str(), workerTid);
}
- if (!mContext.getCommandMQ()->writeBlocking(&command, 1)) {
- ALOGE("%s: failed to write command %s to MQ", __func__, command.toString().c_str());
- return NOT_ENOUGH_DATA;
- }
StreamDescriptor::Reply localReply{};
- if (reply == nullptr) {
- reply = &localReply;
- }
- if (!mContext.getReplyMQ()->readBlocking(reply, 1)) {
- ALOGE("%s: failed to read from reply MQ, command %s", __func__, command.toString().c_str());
- return NOT_ENOUGH_DATA;
- }
{
- std::lock_guard l(mLock);
- // Not every command replies with 'latencyMs' field filled out, substitute the last
- // returned value in that case.
- if (reply->latencyMs <= 0) {
- reply->latencyMs = mLastReply.latencyMs;
+ std::lock_guard l(mCommandReplyLock);
+ if (!mContext.getCommandMQ()->writeBlocking(&command, 1)) {
+ ALOGE("%s: failed to write command %s to MQ", __func__, command.toString().c_str());
+ return NOT_ENOUGH_DATA;
}
- mLastReply = *reply;
- mLastReplyExpirationNs = uptimeNanos() + mLastReplyLifeTimeNs;
+ if (reply == nullptr) {
+ reply = &localReply;
+ }
+ if (!mContext.getReplyMQ()->readBlocking(reply, 1)) {
+ ALOGE("%s: failed to read from reply MQ, command %s",
+ __func__, command.toString().c_str());
+ return NOT_ENOUGH_DATA;
+ }
+ {
+ std::lock_guard l(mLock);
+ // Not every command replies with 'latencyMs' field filled out, substitute the last
+ // returned value in that case.
+ if (reply->latencyMs <= 0) {
+ reply->latencyMs = mLastReply.latencyMs;
+ }
+ mLastReply = *reply;
+ mLastReplyExpirationNs = uptimeNanos() + mLastReplyLifeTimeNs;
+ }
}
switch (reply->status) {
case STATUS_OK: return OK;
diff --git a/media/libaudiohal/impl/StreamHalAidl.h b/media/libaudiohal/impl/StreamHalAidl.h
index 53d46e5..b20eb00 100644
--- a/media/libaudiohal/impl/StreamHalAidl.h
+++ b/media/libaudiohal/impl/StreamHalAidl.h
@@ -243,6 +243,15 @@
const bool mIsInput;
const audio_config_base_t mConfig;
const StreamContextAidl mContext;
+ // This lock is used to make sending of a command and receiving a reply an atomic
+ // operation. Otherwise, when two threads are trying to send a command, they may both advance to
+ // reading of the reply once the HAL has consumed the command from the MQ, and that creates a
+ // race condition between them.
+ //
+ // Note that only access to command and reply MQs needs to be protected because the data MQ is
+ // only accessed by the I/O thread. Also, there is no need to protect lookup operations on the
+ // queues as they are thread-safe, only send/receive operation must be protected.
+ std::mutex mCommandReplyLock;
private:
static audio_config_base_t configToBase(const audio_config& config) {
@@ -256,6 +265,8 @@
std::lock_guard l(mLock);
return mLastReply.state;
}
+ // Note: Since `sendCommand` takes mLock while holding mCommandReplyLock, never call
+ // it with `mLock` being held.
status_t sendCommand(
const ::aidl::android::hardware::audio::core::StreamDescriptor::Command &command,
::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr,
diff --git a/media/libaudioprocessing/AudioMixerBase.cpp b/media/libaudioprocessing/AudioMixerBase.cpp
index 3d11d92..7e362f7 100644
--- a/media/libaudioprocessing/AudioMixerBase.cpp
+++ b/media/libaudioprocessing/AudioMixerBase.cpp
@@ -1122,7 +1122,7 @@
aux = t->auxBuffer + numFrames;
}
for (int outFrames = frameCount; outFrames > 0; ) {
- // t->in == nullptr can happen if the track was flushed just after having
+ // t->mIn == nullptr can happen if the track was flushed just after having
// been enabled for mixing.
if (t->mIn == nullptr) {
break;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index bb49b5a..bd43fe2 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -2098,9 +2098,12 @@
displayHeight,
cropLeft, cropTop);
} else {
- CHECK(inputFormat->findInt32("width", &displayWidth));
- CHECK(inputFormat->findInt32("height", &displayHeight));
-
+ if (!inputFormat->findInt32("width", &displayWidth)
+ || !inputFormat->findInt32("height", &displayHeight)) {
+ ALOGW("Either video width or video height missing, reporting 0x0!");
+ notifyListener(MEDIA_SET_VIDEO_SIZE, 0, 0);
+ return;
+ }
ALOGV("Video input format %d x %d", displayWidth, displayHeight);
}
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 19e51fd..4e378d4 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -6052,6 +6052,10 @@
mErrorLog.clear();
}
+ if (android::media::codec::provider_->set_state_early()) {
+ mState = newState;
+ }
+
if (newState == UNINITIALIZED) {
// return any straggling buffers, e.g. if we got here on an error
returnBuffersToCodec();
@@ -6062,7 +6066,9 @@
mFlags &= ~kFlagSawMediaServerDie;
}
- mState = newState;
+ if (!android::media::codec::provider_->set_state_early()) {
+ mState = newState;
+ }
if (mBatteryChecker != nullptr) {
mBatteryChecker->setExecuting(isExecuting());
diff --git a/media/libstagefright/data/media_codecs_sw.xml b/media/libstagefright/data/media_codecs_sw.xml
index 0e89521..b3be24b 100644
--- a/media/libstagefright/data/media_codecs_sw.xml
+++ b/media/libstagefright/data/media_codecs_sw.xml
@@ -216,6 +216,7 @@
<Limit name="bitrate" range="1-5000000" />
</Variant>
<Feature name="adaptive-playback" />
+ <Feature name="low-latency" />
<Attribute name="software-codec" />
</MediaCodec>
<MediaCodec name="c2.android.av1-dav1d.decoder" type="video/av01" variant="slow-cpu,!slow-cpu" rank="1024">
@@ -234,6 +235,7 @@
<Limit name="bitrate" range="1-5000000" />
</Variant>
<Feature name="adaptive-playback" />
+ <Feature name="low-latency" />
<Attribute name="software-codec" />
</MediaCodec>
<MediaCodec name="c2.android.mpeg2.decoder" type="video/mpeg2" domain="tv">
diff --git a/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp b/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp
index 4218d2d..3f850c2 100644
--- a/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp
+++ b/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp
@@ -24,61 +24,64 @@
namespace android {
-#define MAX_MEDIA_BUFFER_SIZE 2048
+static const android_pixel_format_t kColorFormats[] = {
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ HAL_PIXEL_FORMAT_RGB_565,
+ HAL_PIXEL_FORMAT_BGRA_8888,
+ HAL_PIXEL_FORMAT_RGBA_1010102,
+ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, /* To cover the default case */
+};
-// Fuzzer entry point.
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
- // Init our wrapper
+static const MediaSource::ReadOptions::SeekMode kSeekModes[] = {
+ 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,
+};
+
+static const std::string kComponentNames[] = {
+ "c2.android.avc.decoder", "c2.android.hevc.decoder", "c2.android.vp8.decoder",
+ "c2.android.vp9.decoder", "c2.android.av1.decoder", "c2.android.mpeg4.decoder",
+ "c2.android.h263.decoder",
+};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
FuzzedDataProvider fdp(data, size);
+ std::string component = fdp.PickValueInArray(kComponentNames);
+ AString componentName(component.c_str());
+ sp<MetaData> trackMeta = generateMetaData(&fdp, component);
+ sp<IMediaSource> source = sp<IMediaSourceFuzzImpl>::make(&fdp, gMaxMediaBufferSize);
- std::string name = fdp.ConsumeRandomLengthString(fdp.remaining_bytes());
- AString componentName(name.c_str());
- sp<MetaData> trackMeta = generateMetaData(&fdp);
- sp<IMediaSource> source = new IMediaSourceFuzzImpl(&fdp, MAX_MEDIA_BUFFER_SIZE);
-
- // Image or video Decoder?
- sp<FrameDecoder> decoder;
- bool isVideoDecoder = fdp.ConsumeBool();
- if (isVideoDecoder) {
- decoder = new VideoFrameDecoder(componentName, trackMeta, source);
+ sp<FrameDecoder> decoder = nullptr;
+ if (fdp.ConsumeBool()) {
+ decoder = sp<MediaImageDecoder>::make(componentName, trackMeta, source);
} else {
- decoder = new MediaImageDecoder(componentName, trackMeta, source);
+ decoder = sp<VideoFrameDecoder>::make(componentName, trackMeta, source);
}
- while (fdp.remaining_bytes()) {
- uint8_t switchCase = fdp.ConsumeIntegralInRange<uint8_t>(0, 3);
- switch (switchCase) {
- case 0: {
- int64_t frameTimeUs = fdp.ConsumeIntegral<int64_t>();
- int option = fdp.ConsumeIntegral<int>();
- int colorFormat = fdp.ConsumeIntegral<int>();
- decoder->init(frameTimeUs, option, colorFormat);
- break;
- }
- case 1:
- decoder->extractFrame();
- break;
- case 2: {
- FrameRect rect;
- rect.left = fdp.ConsumeIntegral<int32_t>();
- rect.top = fdp.ConsumeIntegral<int32_t>();
- rect.right = fdp.ConsumeIntegral<int32_t>();
- rect.bottom = fdp.ConsumeIntegral<int32_t>();
- decoder->extractFrame(&rect);
- break;
- }
- case 3: {
- sp<MetaData> trackMeta = generateMetaData(&fdp);
- decoder->getMetadataOnly(trackMeta,
- /*colorFormat*/ fdp.ConsumeIntegral<int>(),
- /*thumbnail*/ fdp.ConsumeBool());
- break;
- }
- }
+ if (decoder.get() &&
+ decoder->init(fdp.ConsumeIntegral<uint64_t>() /* frameTimeUs */,
+ fdp.PickValueInArray(kSeekModes) /* option */,
+ fdp.PickValueInArray(kColorFormats) /* colorFormat */) == OK) {
+ auto frameDecoderAPI = fdp.PickValueInArray<const std::function<void()>>({
+ [&]() { decoder->extractFrame(); },
+ [&]() {
+ FrameRect rect(fdp.ConsumeIntegral<int32_t>() /* left */,
+ fdp.ConsumeIntegral<int32_t>() /* top */,
+ fdp.ConsumeIntegral<int32_t>() /* right */,
+ fdp.ConsumeIntegral<int32_t>() /* bottom */
+ );
+ decoder->extractFrame(&rect);
+ },
+ [&]() {
+ FrameDecoder::getMetadataOnly(
+ trackMeta, fdp.PickValueInArray(kColorFormats) /* colorFormat */,
+ fdp.ConsumeBool() /* thumbnail */);
+ },
+ });
+ frameDecoderAPI();
}
-
- generated_mime_types.clear();
-
return 0;
}
diff --git a/media/libstagefright/tests/fuzzers/FrameDecoderHelpers.h b/media/libstagefright/tests/fuzzers/FrameDecoderHelpers.h
index 228c04a..5430530 100644
--- a/media/libstagefright/tests/fuzzers/FrameDecoderHelpers.h
+++ b/media/libstagefright/tests/fuzzers/FrameDecoderHelpers.h
@@ -20,69 +20,100 @@
#include <media/stagefright/MetaData.h>
#include "MediaMimeTypes.h"
-#define MAX_METADATA_BUF_SIZE 512
-
namespace android {
std::vector<std::shared_ptr<char>> generated_mime_types;
+constexpr uint8_t kMinKeyHeight = 32;
+constexpr uint8_t kMinKeyWidth = 32;
+constexpr uint16_t kMaxKeyHeight = 2160;
+constexpr uint16_t kMaxKeyWidth = 3840;
+size_t gMaxMediaBufferSize = 0;
-sp<MetaData> generateMetaData(FuzzedDataProvider *fdp) {
- sp<MetaData> newMeta = new MetaData();
+sp<MetaData> generateMetaData(FuzzedDataProvider* fdp, std::string componentName = std::string()) {
+ sp<MetaData> newMeta = sp<MetaData>::make();
- // random MIME Type
- const char *mime_type;
- size_t index = fdp->ConsumeIntegralInRange<size_t>(0, kMimeTypes.size());
- // Let there be a chance of a true random string
- if (index == kMimeTypes.size()) {
- std::string mime_str = fdp->ConsumeRandomLengthString(64);
- std::shared_ptr<char> mime_cstr(new char[mime_str.length()+1]);
- generated_mime_types.push_back(mime_cstr);
- strncpy(mime_cstr.get(), mime_str.c_str(), mime_str.length()+1);
- mime_type = mime_cstr.get();
- } else {
- mime_type = kMimeTypes[index];
+ const char* mime;
+ if(!componentName.empty())
+ {
+ auto it = decoderToMediaType.find(componentName);
+ mime = it->second;
}
- newMeta->setCString(kKeyMIMEType, mime_type);
+ else{
+ size_t index = fdp->ConsumeIntegralInRange<size_t>(0, kMimeTypes.size());
+ // Let there be a chance of a true random string
+ if (index == kMimeTypes.size()) {
+ std::string mime_str = fdp->ConsumeRandomLengthString(64);
+ std::shared_ptr<char> mime_cstr(new char[mime_str.length()+1]);
+ generated_mime_types.push_back(mime_cstr);
+ strncpy(mime_cstr.get(), mime_str.c_str(), mime_str.length()+1);
+ mime = mime_cstr.get();
+ } else {
+ mime = kMimeTypes[index];
+ }
+ }
+ newMeta->setCString(kKeyMIMEType, mime);
- // Thumbnail time
- newMeta->setInt64(kKeyThumbnailTime, fdp->ConsumeIntegral<int64_t>());
+ auto height = fdp->ConsumeIntegralInRange<uint16_t>(kMinKeyHeight, kMaxKeyHeight);
+ auto width = fdp->ConsumeIntegralInRange<uint16_t>(kMinKeyWidth, kMaxKeyWidth);
+ newMeta->setInt32(kKeyHeight, height);
+ newMeta->setInt32(kKeyWidth, width);
- // Values used by allocVideoFrame
- newMeta->setInt32(kKeyRotation, fdp->ConsumeIntegral<int32_t>());
- size_t profile_size =
- fdp->ConsumeIntegralInRange<size_t>(0, MAX_METADATA_BUF_SIZE);
- std::vector<uint8_t> profile_bytes =
- fdp->ConsumeBytes<uint8_t>(profile_size);
- newMeta->setData(kKeyIccProfile,
- fdp->ConsumeIntegral<int32_t>(),
- profile_bytes.empty() ? nullptr : profile_bytes.data(),
- profile_bytes.size());
- newMeta->setInt32(kKeySARWidth, fdp->ConsumeIntegral<int32_t>());
- newMeta->setInt32(kKeySARHeight, fdp->ConsumeIntegral<int32_t>());
- newMeta->setInt32(kKeyDisplayWidth, fdp->ConsumeIntegral<int32_t>());
- newMeta->setInt32(kKeyDisplayHeight, fdp->ConsumeIntegral<int32_t>());
+ gMaxMediaBufferSize = height * width;
- // Values used by findThumbnailInfo
- newMeta->setInt32(kKeyThumbnailWidth, fdp->ConsumeIntegral<int32_t>());
- newMeta->setInt32(kKeyThumbnailHeight, fdp->ConsumeIntegral<int32_t>());
- size_t thumbnail_size =
- fdp->ConsumeIntegralInRange<size_t>(0, MAX_METADATA_BUF_SIZE);
- std::vector<uint8_t> thumb_bytes =
- fdp->ConsumeBytes<uint8_t>(thumbnail_size);
- newMeta->setData(kKeyThumbnailHVCC,
- fdp->ConsumeIntegral<int32_t>(),
- thumb_bytes.empty() ? nullptr : thumb_bytes.data(),
- thumb_bytes.size());
+ if (fdp->ConsumeBool()) {
+ newMeta->setInt32(kKeyTileHeight,
+ fdp->ConsumeIntegralInRange<uint16_t>(kMinKeyHeight, height));
+ newMeta->setInt32(kKeyTileWidth,
+ fdp->ConsumeIntegralInRange<uint16_t>(kMinKeyWidth, width));
+ newMeta->setInt32(kKeyGridRows, fdp->ConsumeIntegral<uint8_t>());
+ newMeta->setInt32(kKeyGridCols, fdp->ConsumeIntegral<uint8_t>());
+ }
- // Values used by findGridInfo
- newMeta->setInt32(kKeyTileWidth, fdp->ConsumeIntegral<int32_t>());
- newMeta->setInt32(kKeyTileHeight, fdp->ConsumeIntegral<int32_t>());
- newMeta->setInt32(kKeyGridRows, fdp->ConsumeIntegral<int32_t>());
- newMeta->setInt32(kKeyGridCols, fdp->ConsumeIntegral<int32_t>());
+ if (fdp->ConsumeBool()) {
+ newMeta->setInt32(kKeySARHeight, fdp->ConsumeIntegral<uint8_t>());
+ newMeta->setInt32(kKeySARWidth, fdp->ConsumeIntegral<uint8_t>());
+ }
- // A few functions perform a CHECK() that height/width are set
- newMeta->setInt32(kKeyHeight, fdp->ConsumeIntegral<int32_t>());
- newMeta->setInt32(kKeyWidth, fdp->ConsumeIntegral<int32_t>());
+ if (fdp->ConsumeBool()) {
+ newMeta->setInt32(kKeyDisplayHeight,
+ fdp->ConsumeIntegralInRange<uint16_t>(height, UINT16_MAX));
+ newMeta->setInt32(kKeyDisplayWidth,
+ fdp->ConsumeIntegralInRange<uint16_t>(width, UINT16_MAX));
+ }
+
+ if (fdp->ConsumeBool()) {
+ newMeta->setRect(kKeyCropRect, fdp->ConsumeIntegral<int32_t>() /* left */,
+ fdp->ConsumeIntegral<int32_t>() /* top */,
+ fdp->ConsumeIntegral<int32_t>() /* right */,
+ fdp->ConsumeIntegral<int32_t>() /* bottom */);
+ }
+
+ if (fdp->ConsumeBool()) {
+ newMeta->setInt32(kKeyRotation, fdp->ConsumeIntegralInRange<uint8_t>(0, 3) * 90);
+ }
+
+ if (fdp->ConsumeBool()) {
+ newMeta->setInt64(kKeyThumbnailTime, fdp->ConsumeIntegral<uint64_t>());
+ newMeta->setInt32(kKeyThumbnailHeight, fdp->ConsumeIntegral<uint8_t>());
+ newMeta->setInt32(kKeyThumbnailWidth, fdp->ConsumeIntegral<uint8_t>());
+
+ size_t thumbnailSize = fdp->ConsumeIntegral<size_t>();
+ std::vector<uint8_t> thumbnailData = fdp->ConsumeBytes<uint8_t>(thumbnailSize);
+ if (mime == MEDIA_MIMETYPE_VIDEO_AV1) {
+ newMeta->setData(kKeyThumbnailAV1C, fdp->ConsumeIntegral<int32_t>() /* type */,
+ thumbnailData.data(), thumbnailData.size());
+ } else {
+ newMeta->setData(kKeyThumbnailHVCC, fdp->ConsumeIntegral<int32_t>() /* type */,
+ thumbnailData.data(), thumbnailData.size());
+ }
+ }
+
+ if (fdp->ConsumeBool()) {
+ size_t profileSize = fdp->ConsumeIntegral<size_t>();
+ std::vector<uint8_t> profileData = fdp->ConsumeBytes<uint8_t>(profileSize);
+ newMeta->setData(kKeyIccProfile, fdp->ConsumeIntegral<int32_t>() /* type */,
+ profileData.data(), profileData.size());
+ }
return newMeta;
}
diff --git a/media/libstagefright/tests/fuzzers/IMediaSourceFuzzImpl.h b/media/libstagefright/tests/fuzzers/IMediaSourceFuzzImpl.h
index e769950..7e6f662 100644
--- a/media/libstagefright/tests/fuzzers/IMediaSourceFuzzImpl.h
+++ b/media/libstagefright/tests/fuzzers/IMediaSourceFuzzImpl.h
@@ -19,31 +19,33 @@
#include <media/stagefright/MediaSource.h>
+#define MAX_FRAMES 5
+
namespace android {
class IMediaSourceFuzzImpl : public IMediaSource {
public:
- IMediaSourceFuzzImpl(FuzzedDataProvider *_fdp, size_t _max_buffer_size) :
- fdp(_fdp),
- max_buffer_size(_max_buffer_size) {}
- status_t start(MetaData*) override { return 0; }
- status_t stop() override { return 0; }
- sp<MetaData> getFormat() override { return nullptr; }
- status_t read(MediaBufferBase**,
- const MediaSource::ReadOptions*) override;
- status_t readMultiple(Vector<MediaBufferBase*>*, uint32_t,
- const MediaSource::ReadOptions*) override;
- bool supportReadMultiple() override { return true; }
- bool supportNonblockingRead() override { return true; }
- status_t pause() override { return 0; }
+ IMediaSourceFuzzImpl(FuzzedDataProvider* _fdp, size_t _max_buffer_size)
+ : frames_read(0), fdp(_fdp), min_buffer_size(32 * 32), max_buffer_size(_max_buffer_size) {}
+ status_t start(MetaData*) override { return 0; }
+ status_t stop() override { return 0; }
+ sp<MetaData> getFormat() override { return nullptr; }
+ status_t read(MediaBufferBase**, const MediaSource::ReadOptions*) override;
+ status_t readMultiple(Vector<MediaBufferBase*>*, uint32_t,
+ const MediaSource::ReadOptions*) override;
+ bool supportReadMultiple() override { return true; }
+ bool supportNonblockingRead() override { return true; }
+ status_t pause() override { return 0; }
protected:
IBinder* onAsBinder() { return nullptr; }
private:
- FuzzedDataProvider *fdp;
- std::vector<std::shared_ptr<MediaBufferBase>> buffer_bases;
- const size_t max_buffer_size;
+ uint8_t frames_read;
+ FuzzedDataProvider* fdp;
+ const size_t min_buffer_size;
+ const size_t max_buffer_size;
+ std::vector<uint8_t> buf;
};
// This class is simply to expose the destructor
@@ -53,32 +55,41 @@
~MediaBufferFuzzImpl() {}
};
-status_t IMediaSourceFuzzImpl::read(MediaBufferBase **buffer,
- const MediaSource::ReadOptions *options) {
+status_t IMediaSourceFuzzImpl::read(MediaBufferBase** buffer, const MediaSource::ReadOptions*) {
Vector<MediaBufferBase*> buffers;
- status_t ret = readMultiple(&buffers, 1, options);
+ status_t ret = readMultiple(&buffers, 1, nullptr);
*buffer = buffers.empty() ? nullptr : buffers[0];
return ret;
}
-status_t IMediaSourceFuzzImpl::readMultiple(Vector<MediaBufferBase*>* buffers,
- uint32_t maxNumBuffers, const MediaSource::ReadOptions*) {
- uint32_t num_buffers =
- fdp->ConsumeIntegralInRange<uint32_t>(0, maxNumBuffers);
- for(uint32_t i = 0; i < num_buffers; i++) {
- std::vector<uint8_t> buf = fdp->ConsumeBytes<uint8_t>(
- fdp->ConsumeIntegralInRange<size_t>(0, max_buffer_size));
+status_t IMediaSourceFuzzImpl::readMultiple(Vector<MediaBufferBase*>* buffers, uint32_t,
+ const MediaSource::ReadOptions*) {
+ if (++frames_read == MAX_FRAMES) {
+ auto size = fdp->ConsumeIntegralInRange<size_t>(min_buffer_size, max_buffer_size);
+ buf = fdp->ConsumeBytes<uint8_t>(size);
+ if (buf.size() < size) {
+ buf.resize(size, 0);
+ }
- std::shared_ptr<MediaBufferBase> mbb(
- new MediaBufferFuzzImpl(buf.data(), buf.size()));
+ MediaBufferBase* mbb = new MediaBufferFuzzImpl(buf.data(), buf.size());
+ mbb->meta_data().setInt64(kKeyTime, fdp->ConsumeIntegral<uint64_t>());
+ buffers->push_back(mbb);
- buffer_bases.push_back(mbb);
- buffers->push_back(mbb.get());
+ return ERROR_END_OF_STREAM;
}
- // STATUS_OK
- return 0;
+ auto size = fdp->ConsumeIntegralInRange<size_t>(min_buffer_size, max_buffer_size);
+ buf = fdp->ConsumeBytes<uint8_t>(size);
+ if (buf.size() < size) {
+ buf.resize(size, 0);
+ }
+
+ MediaBufferBase* mbb = new MediaBufferFuzzImpl(buf.data(), buf.size());
+ mbb->meta_data().setInt64(kKeyTime, fdp->ConsumeIntegral<uint64_t>());
+ buffers->push_back(mbb);
+
+ return OK;
}
} // namespace android
diff --git a/media/libstagefright/tests/fuzzers/MediaMimeTypes.h b/media/libstagefright/tests/fuzzers/MediaMimeTypes.h
index 9f337ac..de7814e 100644
--- a/media/libstagefright/tests/fuzzers/MediaMimeTypes.h
+++ b/media/libstagefright/tests/fuzzers/MediaMimeTypes.h
@@ -18,6 +18,7 @@
#define FUZZER_MEDIAMIMETYPES_H_
#include <media/stagefright/foundation/MediaDefs.h>
+#include <unordered_map>
namespace android {
@@ -80,6 +81,15 @@
MEDIA_MIMETYPE_DATA_TIMED_ID3
};
+static const std::unordered_map<std::string, const char*> decoderToMediaType = {
+ {"c2.android.vp8.decoder", MEDIA_MIMETYPE_VIDEO_VP8},
+ {"c2.android.vp9.decoder", MEDIA_MIMETYPE_VIDEO_VP9},
+ {"c2.android.av1.decoder", MEDIA_MIMETYPE_VIDEO_AV1},
+ {"c2.android.avc.decoder", MEDIA_MIMETYPE_VIDEO_AVC},
+ {"c2.android.hevc.decoder", MEDIA_MIMETYPE_VIDEO_HEVC},
+ {"c2.android.mpeg4.decoder", MEDIA_MIMETYPE_VIDEO_MPEG4},
+ {"c2.android.h263.decoder", MEDIA_MIMETYPE_VIDEO_H263}};
+
} // namespace android
#endif // FUZZER_MEDIAMIMETYPES_H_
diff --git a/media/libstagefright/tests/fuzzers/corpus/0ef67b8a074fed50b8875df345ab2e62175c34c9 b/media/libstagefright/tests/fuzzers/corpus/0ef67b8a074fed50b8875df345ab2e62175c34c9
new file mode 100644
index 0000000..652581f
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/corpus/0ef67b8a074fed50b8875df345ab2e62175c34c9
Binary files differ
diff --git a/media/libstagefright/tests/fuzzers/corpus/60eb43c963545c0b2676dad3e4c38cfe87136bbc b/media/libstagefright/tests/fuzzers/corpus/60eb43c963545c0b2676dad3e4c38cfe87136bbc
new file mode 100644
index 0000000..60ca169
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/corpus/60eb43c963545c0b2676dad3e4c38cfe87136bbc
Binary files differ
diff --git a/media/libstagefright/tests/fuzzers/corpus/8c7cb9439f81a8e00b651b3658fe24116f37df7e b/media/libstagefright/tests/fuzzers/corpus/8c7cb9439f81a8e00b651b3658fe24116f37df7e
new file mode 100644
index 0000000..c03bcad
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/corpus/8c7cb9439f81a8e00b651b3658fe24116f37df7e
Binary files differ
diff --git a/media/libstagefright/tests/fuzzers/corpus/c624e73c16c59dfbc3c563416cfc962e3c3a96a0 b/media/libstagefright/tests/fuzzers/corpus/c624e73c16c59dfbc3c563416cfc962e3c3a96a0
new file mode 100644
index 0000000..52f2d5a
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/corpus/c624e73c16c59dfbc3c563416cfc962e3c3a96a0
Binary files differ
diff --git a/media/libstagefright/tests/fuzzers/corpus/c6aff0d7ccaf58a1964a6bcc51777bf1786503ca b/media/libstagefright/tests/fuzzers/corpus/c6aff0d7ccaf58a1964a6bcc51777bf1786503ca
new file mode 100644
index 0000000..83c522f
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/corpus/c6aff0d7ccaf58a1964a6bcc51777bf1786503ca
Binary files differ
diff --git a/media/libstagefright/tests/fuzzers/corpus/ec6bd6069f74a2f6e92442f88efb29288ad6f456 b/media/libstagefright/tests/fuzzers/corpus/ec6bd6069f74a2f6e92442f88efb29288ad6f456
new file mode 100644
index 0000000..62d259b
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/corpus/ec6bd6069f74a2f6e92442f88efb29288ad6f456
Binary files differ
diff --git a/media/libstagefright/tests/fuzzers/corpus/fbf47d9a9173df0a39285c94d89fcbc767d5e774 b/media/libstagefright/tests/fuzzers/corpus/fbf47d9a9173df0a39285c94d89fcbc767d5e774
new file mode 100644
index 0000000..db78b75
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/corpus/fbf47d9a9173df0a39285c94d89fcbc767d5e774
Binary files differ
diff --git a/services/audiopolicy/fuzzer/aidl/audiopolicy_aidl_fuzzer.cpp b/services/audiopolicy/fuzzer/aidl/audiopolicy_aidl_fuzzer.cpp
index d582062..f5e72f5 100644
--- a/services/audiopolicy/fuzzer/aidl/audiopolicy_aidl_fuzzer.cpp
+++ b/services/audiopolicy/fuzzer/aidl/audiopolicy_aidl_fuzzer.cpp
@@ -38,6 +38,7 @@
[[clang::no_destroy]] static std::once_flag gSmOnce;
sp<FakeServiceManager> gFakeServiceManager;
+sp<AudioPolicyService> gAudioPolicyService;
bool addService(const String16& serviceName, const sp<FakeServiceManager>& fakeServiceManager,
FuzzedDataProvider& fdp) {
@@ -49,22 +50,10 @@
return true;
}
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- FuzzedDataProvider fdp(data, size);
-
- std::call_once(gSmOnce, [&] {
- /* Create a FakeServiceManager instance and add required services */
- gFakeServiceManager = sp<FakeServiceManager>::make();
- setDefaultServiceManager(gFakeServiceManager);
- });
- gFakeServiceManager->clear();
-
- for (const char* service : {"activity", "sensor_privacy", "permission", "scheduling_policy",
- "batterystats", "media.metrics"}) {
- if (!addService(String16(service), gFakeServiceManager, fdp)) {
- return 0;
- }
- }
+extern "C" int LLVMFuzzerInitialize(int* /*argc*/, char*** /*argv*/) {
+ /* Create a FakeServiceManager instance and add required services */
+ gFakeServiceManager = sp<FakeServiceManager>::make();
+ setDefaultServiceManager(gFakeServiceManager);
auto configService = ndk::SharedRefBase::make<ConfigMock>();
CHECK_EQ(NO_ERROR, AServiceManager_addService(configService.get()->asBinder().get(),
@@ -82,22 +71,37 @@
// Disable creating thread pool for fuzzer instance of audio flinger and audio policy services
AudioSystem::disableThreadPool();
- const auto audioFlinger = sp<AudioFlinger>::make();
- const auto afAdapter = sp<AudioFlingerServerAdapter>::make(audioFlinger);
+ return 0;
+}
- CHECK_EQ(NO_ERROR,
- gFakeServiceManager->addService(
- String16(IAudioFlinger::DEFAULT_SERVICE_NAME), IInterface::asBinder(afAdapter),
- false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
- const auto audioPolicyService = sp<AudioPolicyService>::make();
+ for (const char* service : {"activity", "sensor_privacy", "permission", "scheduling_policy",
+ "batterystats", "media.metrics"}) {
+ if (!addService(String16(service), gFakeServiceManager, fdp)) {
+ return 0;
+ }
+ }
- CHECK_EQ(NO_ERROR,
- gFakeServiceManager->addService(String16("media.audio_policy"), audioPolicyService,
- false /* allowIsolated */,
- IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
+ // TODO(330882064) : Initialise Audio Flinger and Audio Policy services every time
+ std::call_once(gSmOnce, [&] {
+ const auto audioFlinger = sp<AudioFlinger>::make();
+ const auto audioFlingerServerAdapter = sp<AudioFlingerServerAdapter>::make(audioFlinger);
+ CHECK_EQ(NO_ERROR,
+ gFakeServiceManager->addService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME),
+ IInterface::asBinder(audioFlingerServerAdapter),
+ false /* allowIsolated */,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
- fuzzService(media::IAudioPolicyService::asBinder(audioPolicyService), std::move(fdp));
+ gAudioPolicyService = sp<AudioPolicyService>::make();
+ CHECK_EQ(NO_ERROR,
+ gFakeServiceManager->addService(String16("media.audio_policy"),
+ gAudioPolicyService, false /* allowIsolated */,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
+ });
+
+ fuzzService(media::IAudioPolicyService::asBinder(gAudioPolicyService), std::move(fdp));
return 0;
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 42afa1e..315e08d 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -123,8 +123,8 @@
device->toAudioPort(&devicePort);
if (status_t status = mpClientInterface->setDeviceConnectedState(&devicePort, state);
status != OK) {
- ALOGE("Error %d while setting connected state for device %s",
- static_cast<int>(state),
+ ALOGE("Error %d while setting connected state %d for device %s",
+ status, static_cast<int>(state),
device->getDeviceTypeAddr().toString(false).c_str());
}
}
@@ -212,9 +212,9 @@
if (checkOutputsForDevice(device, state, outputs) != NO_ERROR) {
mAvailableOutputDevices.remove(device);
- mHwModules.cleanUpForDevice(device);
-
broadcastDeviceConnectionState(device, media::DeviceConnectedState::DISCONNECTED);
+
+ mHwModules.cleanUpForDevice(device);
return INVALID_OPERATION;
}
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 74d3474..8642fd4 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -2373,6 +2373,116 @@
)
);
+namespace {
+
+class AudioPolicyManagerTestClientOpenFails : public AudioPolicyManagerTestClient {
+ public:
+ status_t openOutput(audio_module_handle_t module,
+ audio_io_handle_t *output,
+ audio_config_t * halConfig,
+ audio_config_base_t * mixerConfig,
+ const sp<DeviceDescriptorBase>& device,
+ uint32_t * latencyMs,
+ audio_output_flags_t flags) override {
+ return mSimulateFailure ? BAD_VALUE :
+ AudioPolicyManagerTestClient::openOutput(
+ module, output, halConfig, mixerConfig, device, latencyMs, flags);
+ }
+
+ status_t openInput(audio_module_handle_t module,
+ audio_io_handle_t *input,
+ audio_config_t * config,
+ audio_devices_t * device,
+ const String8 & address,
+ audio_source_t source,
+ audio_input_flags_t flags) override {
+ return mSimulateFailure ? BAD_VALUE :
+ AudioPolicyManagerTestClient::openInput(
+ module, input, config, device, address, source, flags);
+ }
+
+ void setSimulateFailure(bool simulateFailure) { mSimulateFailure = simulateFailure; }
+
+ private:
+ bool mSimulateFailure = false;
+};
+
+} // namespace
+
+using DeviceConnectionWithFormatTestParams =
+ std::tuple<audio_devices_t /*type*/, std::string /*name*/, std::string /*address*/,
+ audio_format_t /*format*/>;
+
+class AudioPolicyManagerTestDeviceConnectionFailed :
+ public AudioPolicyManagerTestWithConfigurationFile,
+ public testing::WithParamInterface<DeviceConnectionWithFormatTestParams> {
+ protected:
+ std::string getConfigFile() override { return sBluetoothConfig; }
+ AudioPolicyManagerTestClient* getClient() override {
+ mFullClient = new AudioPolicyManagerTestClientOpenFails;
+ return mFullClient;
+ }
+ void setSimulateOpenFailure(bool simulateFailure) {
+ mFullClient->setSimulateFailure(simulateFailure); }
+
+ static const std::string sBluetoothConfig;
+
+ private:
+ AudioPolicyManagerTestClientOpenFails* mFullClient;
+};
+
+const std::string AudioPolicyManagerTestDeviceConnectionFailed::sBluetoothConfig =
+ AudioPolicyManagerTestDeviceConnectionFailed::sExecutableDir +
+ "test_audio_policy_configuration_bluetooth.xml";
+
+TEST_P(AudioPolicyManagerTestDeviceConnectionFailed, SetDeviceConnectedStateHasAddress) {
+ const audio_devices_t type = std::get<0>(GetParam());
+ const std::string name = std::get<1>(GetParam());
+ const std::string address = std::get<2>(GetParam());
+ const audio_format_t format = std::get<3>(GetParam());
+
+ EXPECT_EQ(0, mClient->getConnectedDevicePortCount());
+ EXPECT_EQ(0, mClient->getDisconnectedDevicePortCount());
+
+ setSimulateOpenFailure(true);
+ ASSERT_EQ(INVALID_OPERATION, mManager->setDeviceConnectionState(
+ type, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ address.c_str(), name.c_str(), format));
+
+ // Since the failure happens when opening input/output, the device must be connected
+ // first and then disconnected.
+ EXPECT_EQ(1, mClient->getConnectedDevicePortCount());
+ EXPECT_EQ(1, mClient->getDisconnectedDevicePortCount());
+
+ if (mClient->getConnectedDevicePortCount() > 0) {
+ auto port = mClient->getLastConnectedDevicePort();
+ EXPECT_EQ(type, port->ext.device.type);
+ EXPECT_EQ(0, strncmp(port->ext.device.address, address.c_str(),
+ AUDIO_DEVICE_MAX_ADDRESS_LEN)) << "\"" << port->ext.device.address << "\"";
+ }
+ if (mClient->getDisconnectedDevicePortCount() > 0) {
+ auto port = mClient->getLastDisconnectedDevicePort();
+ EXPECT_EQ(type, port->ext.device.type);
+ EXPECT_EQ(0, strncmp(port->ext.device.address, address.c_str(),
+ AUDIO_DEVICE_MAX_ADDRESS_LEN)) << "\"" << port->ext.device.address << "\"";
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(
+ DeviceConnectionFailure,
+ AudioPolicyManagerTestDeviceConnectionFailed,
+ testing::Values(
+ DeviceConnectionWithFormatTestParams({AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
+ "bt_hfp_in", "00:11:22:33:44:55", AUDIO_FORMAT_DEFAULT}),
+ DeviceConnectionWithFormatTestParams({AUDIO_DEVICE_OUT_BLUETOOTH_SCO,
+ "bt_hfp_out", "00:11:22:33:44:55", AUDIO_FORMAT_DEFAULT}),
+ DeviceConnectionWithFormatTestParams({AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
+ "bt_a2dp_out", "00:11:22:33:44:55", AUDIO_FORMAT_DEFAULT}),
+ DeviceConnectionWithFormatTestParams({AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
+ "bt_a2dp_out", "00:11:22:33:44:66", AUDIO_FORMAT_LDAC})
+ )
+ );
+
class AudioPolicyManagerCarTest : public AudioPolicyManagerTestDynamicPolicy {
protected:
std::string getConfigFile() override { return sCarConfig; }
@@ -3283,4 +3393,4 @@
// unregister effect should succeed since effect shall have been restore on the client session
ASSERT_EQ(NO_ERROR, mManager->unregisterEffect(effectId));
-}
\ No newline at end of file
+}
diff --git a/services/audiopolicy/tests/resources/Android.bp b/services/audiopolicy/tests/resources/Android.bp
index 3f6a6e3..535dd7a 100644
--- a/services/audiopolicy/tests/resources/Android.bp
+++ b/services/audiopolicy/tests/resources/Android.bp
@@ -11,6 +11,7 @@
name: "audiopolicytest_configuration_files",
srcs: [
"test_audio_policy_configuration.xml",
+ "test_audio_policy_configuration_bluetooth.xml",
"test_audio_policy_primary_only_configuration.xml",
"test_car_ap_atmos_offload_configuration.xml",
"test_invalid_audio_policy_configuration.xml",
diff --git a/services/audiopolicy/tests/resources/test_audio_policy_configuration_bluetooth.xml b/services/audiopolicy/tests/resources/test_audio_policy_configuration_bluetooth.xml
new file mode 100644
index 0000000..0cf1688
--- /dev/null
+++ b/services/audiopolicy/tests/resources/test_audio_policy_configuration_bluetooth.xml
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<audioPolicyConfiguration version="7.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <globalConfiguration speaker_drc_enabled="true"/>
+
+ <modules>
+ <!-- Primary module -->
+ <module name="primary" halVersion="2.0">
+ <attachedDevices>
+ <item>Speaker</item>
+ <item>Built-In Mic</item>
+ </attachedDevices>
+ <defaultOutputDevice>Speaker</defaultOutputDevice>
+ <mixPorts>
+ <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="primary input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000"
+ channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ <mixPort name="mixport_bt_hfp_output" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="mixport_bt_hfp_input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000 11025 16000 44100 48000"
+ channelMasks="AUDIO_CHANNEL_IN_STEREO AUDIO_CHANNEL_IN_MONO"/>
+ </mixPort>
+ <mixPort name="voip_tx" role="sink"
+ flags="AUDIO_INPUT_FLAG_VOIP_TX">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000 16000 32000 48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+ </mixPort>
+ <mixPort name="voip_rx" role="source"
+ flags="AUDIO_OUTPUT_FLAG_VOIP_RX">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000 16000 32000 48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
+ </devicePort>
+ <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
+ </devicePort>
+ <devicePort tagName="Hdmi" type="AUDIO_DEVICE_OUT_HDMI" role="sink"
+ encodedFormats="AUDIO_FORMAT_AC3">
+ </devicePort>
+ <devicePort tagName="Hdmi-In Mic" type="AUDIO_DEVICE_IN_HDMI" role="source">
+ </devicePort>
+ <devicePort tagName="BT SCO" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO" role="sink" />
+ <devicePort tagName="BT SCO Headset Mic" type="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"
+ role="source" />
+ <devicePort tagName="BT A2DP Out" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP" role="sink"
+ encodedFormats="AUDIO_FORMAT_SBC">
+ <profile name="" format="AUDIO_FORMAT_PCM_8_BIT"
+ samplingRates="44100 48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="USB Device Out" type="AUDIO_DEVICE_OUT_USB_DEVICE" role="sink">
+ </devicePort>
+ <devicePort tagName="USB Device In" type="AUDIO_DEVICE_IN_USB_DEVICE" role="source">
+ </devicePort>
+ </devicePorts>
+ <routes>
+ <route type="mix" sink="Speaker"
+ sources="primary output,voip_rx"/>
+ <route type="mix" sink="primary input"
+ sources="Built-In Mic,Hdmi-In Mic,USB Device In"/>
+ <route type="mix" sink="voip_tx"
+ sources="Built-In Mic"/>
+ <route type="mix" sink="Hdmi"
+ sources="primary output"/>
+ <route type="mix" sink="BT SCO"
+ sources="mixport_bt_hfp_output"/>
+ <route type="mix" sink="mixport_bt_hfp_input"
+ sources="BT SCO Headset Mic"/>
+ <route type="mix" sink="BT A2DP Out"
+ sources="primary output"/>
+ <route type="mix" sink="USB Device Out"
+ sources="primary output"/>
+ </routes>
+ </module>
+
+ <!-- Remote Submix module -->
+ <module name="r_submix" halVersion="2.0">
+ <attachedDevices>
+ <item>Remote Submix In</item>
+ </attachedDevices>
+ <mixPorts>
+ <mixPort name="r_submix output" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="r_submix input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <devicePort tagName="Remote Submix Out" type="AUDIO_DEVICE_OUT_REMOTE_SUBMIX" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="Remote Submix In" type="AUDIO_DEVICE_IN_REMOTE_SUBMIX" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </devicePort>
+ </devicePorts>
+ <routes>
+ <route type="mix" sink="Remote Submix Out"
+ sources="r_submix output"/>
+ <route type="mix" sink="r_submix input"
+ sources="Remote Submix In"/>
+ </routes>
+ </module>
+
+ <!-- Software Bluetooth Module -->
+ <module name="bluetooth" halVersion="2.0">
+ <mixPorts>
+ <mixPort name="a2dp_sw_output" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100 48000 88200 96000"
+ channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <devicePort tagName="BTS A2DP Out" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100 48000 88200 96000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ </devicePorts>
+ <routes>
+ <route type="mix" sink="BTS A2DP Out"
+ sources="a2dp_sw_output"/>
+ </routes>
+ </module>
+
+ </modules>
+</audioPolicyConfiguration>
diff --git a/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp b/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
index 433332c..c6793a9 100644
--- a/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
+++ b/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
@@ -33,6 +33,8 @@
constexpr size_t kLogItemsLowWater = 1;
// high water mark
constexpr size_t kLogItemsHighWater = 2;
+constexpr size_t kMaxItemLength = 16;
+constexpr size_t kMaxApis = 64;
class MediaMetricsServiceFuzzer {
public:
@@ -304,10 +306,11 @@
}
FuzzedDataProvider fdp2 = FuzzedDataProvider(data, size);
-
- while (fdp2.remaining_bytes()) {
+ size_t apiCount = 0;
+ while (fdp2.remaining_bytes() && ++apiCount <= kMaxApis) {
// make a test item
- auto item = std::make_shared<mediametrics::Item>(fdp2.ConsumeRandomLengthString().c_str());
+ auto item = std::make_shared<mediametrics::Item>(
+ fdp2.ConsumeRandomLengthString(kMaxItemLength).c_str());
(*item).set("event", fdp2.ConsumeRandomLengthString().c_str());
// get the actions and execute them