[automerger skipped] Merge changes from topic "am-21ce8922bf5e498bb030b1c2a53f476d" into android12L-tests-dev am: e37b15ad16 -s ours am: 71720334f7 -s ours am: 3a7fe554a2 -s ours
am skip reason: Merged-In I3707d883d0daa4ffd2baa9bd69aebf4bf9ddef4e with SHA-1 82fa481114 is already in history
Original change: https://android-review.googlesource.com/c/platform/frameworks/av/+/2066387
Change-Id: Ife4cf001c8c82820c12fc57701972f86e1723d16
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/apex/manifest.json b/apex/manifest.json
index 4b75b04..5b235cd 100644
--- a/apex/manifest.json
+++ b/apex/manifest.json
@@ -1,6 +1,10 @@
{
"name": "com.android.media",
- "version": 339990000,
+
+ // Placeholder module version to be replaced during build.
+ // Do not change!
+ "version": 0,
+
"requireNativeLibs": [
"libandroid.so",
"libbinder_ndk.so",
diff --git a/apex/manifest_codec.json b/apex/manifest_codec.json
index fbcbb69..f2b8b36 100644
--- a/apex/manifest_codec.json
+++ b/apex/manifest_codec.json
@@ -1,6 +1,10 @@
{
"name": "com.android.media.swcodec",
- "version": 339990000,
+
+ // Placeholder module version to be replaced during build.
+ // Do not change!
+ "version": 0,
+
"requireNativeLibs": [
":sphal"
]
diff --git a/media/codec2/components/aac/C2SoftAacDec.cpp b/media/codec2/components/aac/C2SoftAacDec.cpp
index 4e4a9a1..d1b08bd 100644
--- a/media/codec2/components/aac/C2SoftAacDec.cpp
+++ b/media/codec2/components/aac/C2SoftAacDec.cpp
@@ -275,7 +275,8 @@
mStreamInfo(nullptr),
mSignalledError(false),
mOutputPortDelay(kDefaultOutputPortDelay),
- mOutputDelayRingBuffer(nullptr) {
+ mOutputDelayRingBuffer(nullptr),
+ mDeviceApiLevel(android_get_device_api_level()) {
}
C2SoftAacDec::~C2SoftAacDec() {
@@ -891,7 +892,7 @@
work->worklets.front()->output.configUpdate.push_back(
C2Param::Copy(currentBoostFactor));
- if (android_get_device_api_level() < __ANDROID_API_S__) {
+ if (mDeviceApiLevel < __ANDROID_API_S__) {
// We used to report DRC compression mode in the output format
// in Q and R, but stopped doing that in S
C2StreamDrcCompressionModeTuning::input currentCompressMode(0u,
diff --git a/media/codec2/components/aac/C2SoftAacDec.h b/media/codec2/components/aac/C2SoftAacDec.h
index b45f148..f85d45f 100644
--- a/media/codec2/components/aac/C2SoftAacDec.h
+++ b/media/codec2/components/aac/C2SoftAacDec.h
@@ -97,6 +97,7 @@
int32_t mOutputDelayRingBufferWritePos;
int32_t mOutputDelayRingBufferReadPos;
int32_t mOutputDelayRingBufferFilled;
+ int mDeviceApiLevel;
bool outputDelayRingBufferPutSamples(INT_PCM *samples, int numSamples);
int32_t outputDelayRingBufferGetSamples(INT_PCM *samples, int numSamples);
int32_t outputDelayRingBufferSamplesAvailable();
diff --git a/media/codec2/components/aom/C2SoftAomDec.cpp b/media/codec2/components/aom/C2SoftAomDec.cpp
index 96b81d7..0eb47f4 100644
--- a/media/codec2/components/aom/C2SoftAomDec.cpp
+++ b/media/codec2/components/aom/C2SoftAomDec.cpp
@@ -578,7 +578,8 @@
size_t srcVStride = img->stride[AOM_PLANE_V];
C2PlanarLayout layout = wView.layout();
size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
- size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
+ size_t dstUStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
+ size_t dstVStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc;
if (img->fmt == AOM_IMG_FMT_I42016) {
const uint16_t *srcY = (const uint16_t *)img->planes[AOM_PLANE_Y];
@@ -592,7 +593,7 @@
std::static_pointer_cast<const C2ColorAspectsStruct>(defaultColorAspects));
} else {
convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride / 2,
- srcUStride / 2, srcVStride / 2, dstYStride, dstUVStride,
+ srcUStride / 2, srcVStride / 2, dstYStride, dstUStride,
mWidth, mHeight);
}
} else {
@@ -600,7 +601,7 @@
const uint8_t *srcU = (const uint8_t *)img->planes[AOM_PLANE_U];
const uint8_t *srcV = (const uint8_t *)img->planes[AOM_PLANE_V];
convertYUV420Planar8ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
- srcVStride, dstYStride, dstUVStride, mWidth, mHeight);
+ srcVStride, dstYStride, dstUStride, dstVStride, mWidth, mHeight);
}
finishWork(*(int64_t*)img->user_priv, work, std::move(block));
block = nullptr;
diff --git a/media/codec2/components/avc/C2SoftAvcDec.cpp b/media/codec2/components/avc/C2SoftAvcDec.cpp
index 953afc5..96a4c4a 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.cpp
+++ b/media/codec2/components/avc/C2SoftAvcDec.cpp
@@ -671,6 +671,9 @@
void C2SoftAvcDec::resetPlugin() {
mSignalledOutputEos = false;
mTimeStart = mTimeEnd = systemTime();
+ if (mOutBlock) {
+ mOutBlock.reset();
+ }
}
status_t C2SoftAvcDec::deleteDecoder() {
diff --git a/media/codec2/components/base/SimpleC2Component.cpp b/media/codec2/components/base/SimpleC2Component.cpp
index 9d4f049..c252613 100644
--- a/media/codec2/components/base/SimpleC2Component.cpp
+++ b/media/codec2/components/base/SimpleC2Component.cpp
@@ -38,8 +38,8 @@
void convertYUV420Planar8ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint8_t *srcY,
const uint8_t *srcU, const uint8_t *srcV, size_t srcYStride,
size_t srcUStride, size_t srcVStride, size_t dstYStride,
- size_t dstUVStride, uint32_t width, uint32_t height,
- bool isMonochrome) {
+ size_t dstUStride, size_t dstVStride, uint32_t width,
+ uint32_t height, bool isMonochrome) {
for (size_t i = 0; i < height; ++i) {
memcpy(dstY, srcY, width);
srcY += srcYStride;
@@ -51,8 +51,8 @@
for (size_t i = 0; i < (height + 1) / 2; ++i) {
memset(dstV, kNeutralUVBitDepth8, (width + 1) / 2);
memset(dstU, kNeutralUVBitDepth8, (width + 1) / 2);
- dstV += dstUVStride;
- dstU += dstUVStride;
+ dstV += dstVStride;
+ dstU += dstUStride;
}
return;
}
@@ -60,13 +60,13 @@
for (size_t i = 0; i < (height + 1) / 2; ++i) {
memcpy(dstV, srcV, (width + 1) / 2);
srcV += srcVStride;
- dstV += dstUVStride;
+ dstV += dstVStride;
}
for (size_t i = 0; i < (height + 1) / 2; ++i) {
memcpy(dstU, srcU, (width + 1) / 2);
srcU += srcUStride;
- dstU += dstUVStride;
+ dstU += dstUStride;
}
}
@@ -190,7 +190,7 @@
// matrix conversion coefficients
// (see media/libstagefright/colorconverter/ColorConverter.cpp for more details)
struct Coeffs {
- int32_t _y, _b_u, _g_u, _g_v, _r_v, _c16;
+ int32_t _y, _r_v, _g_u, _g_v, _b_u, _c16;
};
static const struct Coeffs GetCoeffsForAspects(const C2ColorAspectsStruct &aspects) {
diff --git a/media/codec2/components/base/include/SimpleC2Component.h b/media/codec2/components/base/include/SimpleC2Component.h
index 7600c5b..83c4991 100644
--- a/media/codec2/components/base/include/SimpleC2Component.h
+++ b/media/codec2/components/base/include/SimpleC2Component.h
@@ -33,8 +33,8 @@
void convertYUV420Planar8ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint8_t *srcY,
const uint8_t *srcU, const uint8_t *srcV, size_t srcYStride,
size_t srcUStride, size_t srcVStride, size_t dstYStride,
- size_t dstUVStride, uint32_t width, uint32_t height,
- bool isMonochrome = false);
+ size_t dstUStride, size_t dstVStride, uint32_t width,
+ uint32_t height, bool isMonochrome = false);
void convertYUV420Planar16ToY410OrRGBA1010102(
uint32_t *dst, const uint16_t *srcY,
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.cpp b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
index 4dec57f..9c5ce9f 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.cpp
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
@@ -102,6 +102,29 @@
.withSetter(Hdr10PlusInfoOutputSetter)
.build());
+ // default static info
+ C2HdrStaticMetadataStruct defaultStaticInfo{};
+ helper->addStructDescriptors<C2MasteringDisplayColorVolumeStruct, C2ColorXyStruct>();
+ addParameter(
+ DefineParam(mHdrStaticInfo, C2_PARAMKEY_HDR_STATIC_INFO)
+ .withDefault(new C2StreamHdrStaticInfo::output(0u, defaultStaticInfo))
+ .withFields({
+ C2F(mHdrStaticInfo, mastering.red.x).inRange(0, 1),
+ C2F(mHdrStaticInfo, mastering.red.y).inRange(0, 1),
+ C2F(mHdrStaticInfo, mastering.green.x).inRange(0, 1),
+ C2F(mHdrStaticInfo, mastering.green.y).inRange(0, 1),
+ C2F(mHdrStaticInfo, mastering.blue.x).inRange(0, 1),
+ C2F(mHdrStaticInfo, mastering.blue.y).inRange(0, 1),
+ C2F(mHdrStaticInfo, mastering.white.x).inRange(0, 1),
+ C2F(mHdrStaticInfo, mastering.white.x).inRange(0, 1),
+ C2F(mHdrStaticInfo, mastering.maxLuminance).inRange(0, 65535),
+ C2F(mHdrStaticInfo, mastering.minLuminance).inRange(0, 6.5535),
+ C2F(mHdrStaticInfo, maxCll).inRange(0, 0XFFFF),
+ C2F(mHdrStaticInfo, maxFall).inRange(0, 0XFFFF)
+ })
+ .withSetter(HdrStaticInfoSetter)
+ .build());
+
addParameter(
DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
.withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 320, 240))
@@ -331,6 +354,47 @@
// unsafe getters
std::shared_ptr<C2StreamPixelFormatInfo::output> getPixelFormat_l() const { return mPixelFormat; }
+ static C2R HdrStaticInfoSetter(bool mayBlock, C2P<C2StreamHdrStaticInfo::output> &me) {
+ (void)mayBlock;
+ if (me.v.mastering.red.x > 1) {
+ me.set().mastering.red.x = 1;
+ }
+ if (me.v.mastering.red.y > 1) {
+ me.set().mastering.red.y = 1;
+ }
+ if (me.v.mastering.green.x > 1) {
+ me.set().mastering.green.x = 1;
+ }
+ if (me.v.mastering.green.y > 1) {
+ me.set().mastering.green.y = 1;
+ }
+ if (me.v.mastering.blue.x > 1) {
+ me.set().mastering.blue.x = 1;
+ }
+ if (me.v.mastering.blue.y > 1) {
+ me.set().mastering.blue.y = 1;
+ }
+ if (me.v.mastering.white.x > 1) {
+ me.set().mastering.white.x = 1;
+ }
+ if (me.v.mastering.white.y > 1) {
+ me.set().mastering.white.y = 1;
+ }
+ if (me.v.mastering.maxLuminance > 65535.0) {
+ me.set().mastering.maxLuminance = 65535.0;
+ }
+ if (me.v.mastering.minLuminance > 6.5535) {
+ me.set().mastering.minLuminance = 6.5535;
+ }
+ if (me.v.maxCll > 65535.0) {
+ me.set().maxCll = 65535.0;
+ }
+ if (me.v.maxFall > 65535.0) {
+ me.set().maxFall = 65535.0;
+ }
+ return C2R::Ok();
+ }
+
private:
std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
@@ -343,6 +407,7 @@
std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects;
std::shared_ptr<C2StreamHdr10PlusInfo::input> mHdr10PlusInfoInput;
std::shared_ptr<C2StreamHdr10PlusInfo::output> mHdr10PlusInfoOutput;
+ std::shared_ptr<C2StreamHdrStaticInfo::output> mHdrStaticInfo;
};
C2SoftGav1Dec::C2SoftGav1Dec(const char *name, c2_node_id_t id,
@@ -558,6 +623,76 @@
}
}
+void C2SoftGav1Dec::getHDRStaticParams(const libgav1::DecoderBuffer *buffer,
+ const std::unique_ptr<C2Work> &work) {
+ C2StreamHdrStaticMetadataInfo::output hdrStaticMetadataInfo{};
+ bool infoPresent = false;
+ if (buffer->has_hdr_mdcv) {
+ // hdr_mdcv.primary_chromaticity_* values are in 0.16 fixed-point format.
+ hdrStaticMetadataInfo.mastering.red.x = buffer->hdr_mdcv.primary_chromaticity_x[0] / 65536.0;
+ hdrStaticMetadataInfo.mastering.red.y = buffer->hdr_mdcv.primary_chromaticity_y[0] / 65536.0;
+
+ hdrStaticMetadataInfo.mastering.green.x = buffer->hdr_mdcv.primary_chromaticity_x[1] / 65536.0;
+ hdrStaticMetadataInfo.mastering.green.y = buffer->hdr_mdcv.primary_chromaticity_y[1] / 65536.0;
+
+ hdrStaticMetadataInfo.mastering.blue.x = buffer->hdr_mdcv.primary_chromaticity_x[2] / 65536.0;
+ hdrStaticMetadataInfo.mastering.blue.y = buffer->hdr_mdcv.primary_chromaticity_y[2] / 65536.0;
+
+ // hdr_mdcv.white_point_chromaticity_* values are in 0.16 fixed-point format.
+ hdrStaticMetadataInfo.mastering.white.x = buffer->hdr_mdcv.white_point_chromaticity_x / 65536.0;
+ hdrStaticMetadataInfo.mastering.white.y = buffer->hdr_mdcv.white_point_chromaticity_y / 65536.0;
+
+ // hdr_mdcv.luminance_max is in 24.8 fixed-point format.
+ hdrStaticMetadataInfo.mastering.maxLuminance = buffer->hdr_mdcv.luminance_max / 256.0;
+ // hdr_mdcv.luminance_min is in 18.14 format.
+ hdrStaticMetadataInfo.mastering.minLuminance = buffer->hdr_mdcv.luminance_min / 16384.0;
+ infoPresent = true;
+ }
+
+ if (buffer->has_hdr_cll) {
+ hdrStaticMetadataInfo.maxCll = buffer->hdr_cll.max_cll;
+ hdrStaticMetadataInfo.maxFall = buffer->hdr_cll.max_fall;
+ infoPresent = true;
+ }
+ // config if static info has changed
+ if (infoPresent && !(hdrStaticMetadataInfo == mHdrStaticMetadataInfo)) {
+ mHdrStaticMetadataInfo = hdrStaticMetadataInfo;
+ work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(mHdrStaticMetadataInfo));
+ }
+}
+
+void C2SoftGav1Dec::getHDR10PlusInfoData(const libgav1::DecoderBuffer *buffer,
+ const std::unique_ptr<C2Work> &work) {
+ if (buffer->has_itut_t35) {
+ std::vector<uint8_t> payload;
+ size_t payloadSize = buffer->itut_t35.payload_size;
+ if (payloadSize > 0) {
+ payload.push_back(buffer->itut_t35.country_code);
+ if (buffer->itut_t35.country_code == 0xFF) {
+ payload.push_back(buffer->itut_t35.country_code_extension_byte);
+ }
+ payload.insert(payload.end(), buffer->itut_t35.payload_bytes,
+ buffer->itut_t35.payload_bytes + buffer->itut_t35.payload_size);
+ }
+
+ std::unique_ptr<C2StreamHdr10PlusInfo::output> hdr10PlusInfo =
+ C2StreamHdr10PlusInfo::output::AllocUnique(payload.size());
+ if (!hdr10PlusInfo) {
+ ALOGE("Hdr10PlusInfo allocation failed");
+ mSignalledError = true;
+ work->result = C2_NO_MEMORY;
+ return;
+ }
+ memcpy(hdr10PlusInfo->m.value, payload.data(), payload.size());
+
+ // config if hdr10Plus info has changed
+ if (nullptr == mHdr10PlusInfo || !(*hdr10PlusInfo == *mHdr10PlusInfo)) {
+ mHdr10PlusInfo = std::move(hdr10PlusInfo);
+ work->worklets.front()->output.configUpdate.push_back(std::move(mHdr10PlusInfo));
+ }
+ }
+}
+
void C2SoftGav1Dec::getVuiParams(const libgav1::DecoderBuffer *buffer) {
VuiColorAspects vuiColorAspects;
vuiColorAspects.primaries = buffer->color_primary;
@@ -633,6 +768,9 @@
}
getVuiParams(buffer);
+ getHDRStaticParams(buffer, work);
+ getHDR10PlusInfoData(buffer, work);
+
if (!(buffer->image_format == libgav1::kImageFormatYuv420 ||
buffer->image_format == libgav1::kImageFormatMonochrome400)) {
ALOGE("image_format %d not supported", buffer->image_format);
@@ -719,7 +857,8 @@
C2PlanarLayout layout = wView.layout();
size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
- size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
+ size_t dstUStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
+ size_t dstVStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc;
if (buffer->bitdepth == 10) {
const uint16_t *srcY = (const uint16_t *)buffer->plane[0];
@@ -735,10 +874,10 @@
} else if (format == HAL_PIXEL_FORMAT_YCBCR_P010) {
convertYUV420Planar16ToP010((uint16_t *)dstY, (uint16_t *)dstU, srcY, srcU, srcV,
srcYStride / 2, srcUStride / 2, srcVStride / 2, dstYStride / 2,
- dstUVStride / 2, mWidth, mHeight, isMonochrome);
+ dstUStride / 2, mWidth, mHeight, isMonochrome);
} else {
convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride / 2,
- srcUStride / 2, srcVStride / 2, dstYStride, dstUVStride, mWidth,
+ srcUStride / 2, srcVStride / 2, dstYStride, dstUStride, mWidth,
mHeight, isMonochrome);
}
} else {
@@ -746,7 +885,8 @@
const uint8_t *srcU = (const uint8_t *)buffer->plane[1];
const uint8_t *srcV = (const uint8_t *)buffer->plane[2];
convertYUV420Planar8ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
- srcVStride, dstYStride, dstUVStride, mWidth, mHeight, isMonochrome);
+ srcVStride, dstYStride, dstUStride, dstVStride, mWidth, mHeight,
+ isMonochrome);
}
finishWork(buffer->user_private_data, work, std::move(block));
block = nullptr;
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.h b/media/codec2/components/gav1/C2SoftGav1Dec.h
index 3d4db55..e51c511 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.h
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.h
@@ -61,6 +61,9 @@
bool mSignalledOutputEos;
bool mSignalledError;
+ C2StreamHdrStaticMetadataInfo::output mHdrStaticMetadataInfo;
+ std::unique_ptr<C2StreamHdr10PlusInfo::output> mHdr10PlusInfo = nullptr;
+
// Color aspects. These are ISO values and are meant to detect changes in aspects to avoid
// converting them to C2 values for each frame
struct VuiColorAspects {
@@ -86,6 +89,10 @@
nsecs_t mTimeEnd = 0; // Time at the end of decode()
bool initDecoder();
+ void getHDRStaticParams(const libgav1::DecoderBuffer *buffer,
+ const std::unique_ptr<C2Work> &work);
+ void getHDR10PlusInfoData(const libgav1::DecoderBuffer *buffer,
+ const std::unique_ptr<C2Work> &work);
void getVuiParams(const libgav1::DecoderBuffer *buffer);
void destroyDecoder();
void finishWork(uint64_t index, const std::unique_ptr<C2Work>& work,
diff --git a/media/codec2/components/hevc/C2SoftHevcDec.cpp b/media/codec2/components/hevc/C2SoftHevcDec.cpp
index 5a660c5..15d6dcd 100644
--- a/media/codec2/components/hevc/C2SoftHevcDec.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcDec.cpp
@@ -664,6 +664,9 @@
void C2SoftHevcDec::resetPlugin() {
mSignalledOutputEos = false;
mTimeStart = mTimeEnd = systemTime();
+ if (mOutBlock) {
+ mOutBlock.reset();
+ }
}
status_t C2SoftHevcDec::deleteDecoder() {
@@ -917,7 +920,8 @@
if (0 < ps_decode_op->u4_pic_wd && 0 < ps_decode_op->u4_pic_ht) {
if (mHeaderDecoded == false) {
mHeaderDecoded = true;
- setParams(ALIGN128(ps_decode_op->u4_pic_wd), IVD_DECODE_FRAME);
+ mStride = ALIGN128(ps_decode_op->u4_pic_wd);
+ setParams(mStride, IVD_DECODE_FRAME);
}
if (ps_decode_op->u4_pic_wd != mWidth || ps_decode_op->u4_pic_ht != mHeight) {
mWidth = ps_decode_op->u4_pic_wd;
diff --git a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
index 9a41910..439323c 100644
--- a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
+++ b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
@@ -732,6 +732,9 @@
void C2SoftMpeg2Dec::resetPlugin() {
mSignalledOutputEos = false;
mTimeStart = mTimeEnd = systemTime();
+ if (mOutBlock) {
+ mOutBlock.reset();
+ }
}
status_t C2SoftMpeg2Dec::deleteDecoder() {
diff --git a/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp b/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp
index 54a1d0e..2137964 100644
--- a/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp
+++ b/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp
@@ -256,7 +256,9 @@
mFramesConfigured = false;
mSignalledOutputEos = false;
mSignalledError = false;
-
+ if (mOutBlock) {
+ mOutBlock.reset();
+ }
return C2_OK;
}
@@ -601,7 +603,8 @@
C2PlanarLayout layout = wView.layout();
size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
- size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
+ size_t dstUStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
+ size_t dstVStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc;
size_t srcYStride = align(mWidth, 16);
size_t srcUStride = srcYStride / 2;
size_t srcVStride = srcYStride / 2;
@@ -611,8 +614,8 @@
const uint8_t *srcV = (const uint8_t *)srcY + vStride * srcYStride * 5 / 4;
convertYUV420Planar8ToYV12(outputBufferY, outputBufferU, outputBufferV, srcY, srcU, srcV,
- srcYStride, srcUStride, srcVStride, dstYStride, dstUVStride,
- mWidth, mHeight);
+ srcYStride, srcUStride, srcVStride, dstYStride, dstUStride,
+ dstVStride, mWidth, mHeight);
inPos += inSize - (size_t)tmpInSize;
finishWork(workIndex, work);
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.cpp b/media/codec2/components/vpx/C2SoftVpxDec.cpp
index 8087396..dab7b89 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxDec.cpp
@@ -69,8 +69,8 @@
DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
.withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
.withFields({
- C2F(mSize, width).inRange(2, 2048, 2),
- C2F(mSize, height).inRange(2, 2048, 2),
+ C2F(mSize, width).inRange(2, 2048),
+ C2F(mSize, height).inRange(2, 2048),
})
.withSetter(SizeSetter)
.build());
@@ -734,7 +734,12 @@
}
C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16), mHeight, format, usage, &block);
+ // We always create a graphic block that is width aligned to 16 and height
+ // aligned to 2. We set the correct "crop" value of the image in the call to
+ // createGraphicBuffer() by setting the correct image dimensions.
+ c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16),
+ align(mHeight, 2), format, usage,
+ &block);
if (err != C2_OK) {
ALOGE("fetchGraphicBlock for Output failed with status %d", err);
work->result = err;
@@ -761,7 +766,8 @@
size_t srcVStride = img->stride[VPX_PLANE_V];
C2PlanarLayout layout = wView.layout();
size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
- size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
+ size_t dstUStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
+ size_t dstVStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc;
if (img->fmt == VPX_IMG_FMT_I42016) {
const uint16_t *srcY = (const uint16_t *)img->planes[VPX_PLANE_Y];
@@ -799,10 +805,10 @@
} else if (format == HAL_PIXEL_FORMAT_YCBCR_P010) {
convertYUV420Planar16ToP010((uint16_t *)dstY, (uint16_t *)dstU, srcY, srcU, srcV,
srcYStride / 2, srcUStride / 2, srcVStride / 2,
- dstYStride / 2, dstUVStride / 2, mWidth, mHeight);
+ dstYStride / 2, dstUStride / 2, mWidth, mHeight);
} else {
convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride / 2,
- srcUStride / 2, srcVStride / 2, dstYStride, dstUVStride,
+ srcUStride / 2, srcVStride / 2, dstYStride, dstUStride,
mWidth, mHeight);
}
} else {
@@ -811,7 +817,7 @@
const uint8_t *srcV = (const uint8_t *)img->planes[VPX_PLANE_V];
convertYUV420Planar8ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
- srcVStride, dstYStride, dstUVStride, mWidth, mHeight);
+ srcVStride, dstYStride, dstVStride, dstVStride, mWidth, mHeight);
}
finishWork(((c2_cntr64_t *)img->user_priv)->peekull(), work, std::move(block));
return OK;
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.cpp b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
index f99ee24..daf7a61 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
@@ -59,7 +59,7 @@
addParameter(
DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
- .withDefault(new C2StreamPictureSizeInfo::input(0u, 320, 240))
+ .withDefault(new C2StreamPictureSizeInfo::input(0u, 64, 64))
.withFields({
C2F(mSize, width).inRange(2, 2048, 2),
C2F(mSize, height).inRange(2, 2048, 2),
@@ -81,7 +81,7 @@
addParameter(
DefineParam(mFrameRate, C2_PARAMKEY_FRAME_RATE)
- .withDefault(new C2StreamFrameRateInfo::output(0u, 30.))
+ .withDefault(new C2StreamFrameRateInfo::output(0u, 1.))
// TODO: More restriction?
.withFields({C2F(mFrameRate, value).greaterThan(0.)})
.withSetter(
@@ -127,10 +127,18 @@
C2F(mProfileLevel, profile).equalTo(
PROFILE_VP9_0
),
- C2F(mProfileLevel, level).equalTo(
- LEVEL_VP9_4_1),
+ C2F(mProfileLevel, level).oneOf({
+ C2Config::LEVEL_VP9_1,
+ C2Config::LEVEL_VP9_1_1,
+ C2Config::LEVEL_VP9_2,
+ C2Config::LEVEL_VP9_2_1,
+ C2Config::LEVEL_VP9_3,
+ C2Config::LEVEL_VP9_3_1,
+ C2Config::LEVEL_VP9_4,
+ C2Config::LEVEL_VP9_4_1,
+ }),
})
- .withSetter(ProfileLevelSetter)
+ .withSetter(ProfileLevelSetter, mSize, mFrameRate, mBitrate)
.build());
#else
addParameter(
@@ -144,7 +152,7 @@
C2F(mProfileLevel, level).equalTo(
LEVEL_UNUSED),
})
- .withSetter(ProfileLevelSetter)
+ .withSetter(ProfileLevelSetter, mSize, mFrameRate, mBitrate)
.build());
#endif
addParameter(
@@ -217,14 +225,81 @@
}
C2R C2SoftVpxEnc::IntfImpl::ProfileLevelSetter(bool mayBlock,
- C2P<C2StreamProfileLevelInfo::output>& me) {
+ C2P<C2StreamProfileLevelInfo::output>& me,
+ const C2P<C2StreamPictureSizeInfo::input>& size,
+ const C2P<C2StreamFrameRateInfo::output>& frameRate,
+ const C2P<C2StreamBitrateInfo::output>& bitrate) {
(void)mayBlock;
+#ifdef VP9
if (!me.F(me.v.profile).supportsAtAll(me.v.profile)) {
me.set().profile = PROFILE_VP9_0;
}
- if (!me.F(me.v.level).supportsAtAll(me.v.level)) {
+ struct LevelLimits {
+ C2Config::level_t level;
+ float samplesPerSec;
+ uint64_t samples;
+ uint32_t bitrate;
+ size_t dimension;
+ };
+ constexpr LevelLimits kLimits[] = {
+ {LEVEL_VP9_1, 829440, 36864, 200000, 512},
+ {LEVEL_VP9_1_1, 2764800, 73728, 800000, 768},
+ {LEVEL_VP9_2, 4608000, 122880, 1800000, 960},
+ {LEVEL_VP9_2_1, 9216000, 245760, 3600000, 1344},
+ {LEVEL_VP9_3, 20736000, 552960, 7200000, 2048},
+ {LEVEL_VP9_3_1, 36864000, 983040, 12000000, 2752},
+ {LEVEL_VP9_4, 83558400, 2228224, 18000000, 4160},
+ {LEVEL_VP9_4_1, 160432128, 2228224, 30000000, 4160},
+ };
+
+ uint64_t samples = size.v.width * size.v.height;
+ float samplesPerSec = float(samples) * frameRate.v.value;
+ size_t dimension = std::max(size.v.width, size.v.height);
+
+ // Check if the supplied level meets the samples / bitrate requirements.
+ // If not, update the level with the lowest level meeting the requirements.
+ bool found = false;
+
+ // By default needsUpdate = false in case the supplied level does meet
+ // the requirements.
+ bool needsUpdate = false;
+ for (const LevelLimits& limit : kLimits) {
+ if (samples <= limit.samples && samplesPerSec <= limit.samplesPerSec &&
+ bitrate.v.value <= limit.bitrate && dimension <= limit.dimension) {
+ // This is the lowest level that meets the requirements, and if
+ // we haven't seen the supplied level yet, that means we don't
+ // need the update.
+ if (needsUpdate) {
+ ALOGD("Given level %x does not cover current configuration: "
+ "adjusting to %x",
+ me.v.level, limit.level);
+ me.set().level = limit.level;
+ }
+ found = true;
+ break;
+ }
+ if (me.v.level == limit.level) {
+ // We break out of the loop when the lowest feasible level is
+ // found. The fact that we're here means that our level doesn't
+ // meet the requirement and needs to be updated.
+ needsUpdate = true;
+ }
+ }
+ if (!found) {
+ // We set to the highest supported level.
me.set().level = LEVEL_VP9_4_1;
}
+#else
+ (void)size;
+ (void)frameRate;
+ (void)bitrate;
+ if (!me.F(me.v.profile).supportsAtAll(me.v.profile)) {
+ me.set().profile = PROFILE_VP8_0;
+ }
+ if (!me.F(me.v.level).supportsAtAll(me.v.level)) {
+ me.set().level = LEVEL_UNUSED;
+ }
+#endif
return C2R::Ok();
}
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.h b/media/codec2/components/vpx/C2SoftVpxEnc.h
index 714fadb..bfb4444 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.h
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.h
@@ -243,9 +243,10 @@
static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::input> &oldMe,
C2P<C2StreamPictureSizeInfo::input> &me);
- static C2R ProfileLevelSetter(
- bool mayBlock,
- C2P<C2StreamProfileLevelInfo::output> &me);
+ static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::output>& me,
+ const C2P<C2StreamPictureSizeInfo::input>& size,
+ const C2P<C2StreamFrameRateInfo::output>& frameRate,
+ const C2P<C2StreamBitrateInfo::output>& bitrate);
static C2R LayeringSetter(bool mayBlock, C2P<C2StreamTemporalLayeringTuning::output>& me);
diff --git a/media/codec2/hidl/1.0/utils/types.cpp b/media/codec2/hidl/1.0/utils/types.cpp
index 5c24bd7..319ba62 100644
--- a/media/codec2/hidl/1.0/utils/types.cpp
+++ b/media/codec2/hidl/1.0/utils/types.cpp
@@ -1447,6 +1447,10 @@
bool objcpy(C2BaseBlock* d, const BaseBlock& s) {
switch (s.getDiscriminator()) {
case BaseBlock::hidl_discriminator::nativeBlock: {
+ if (s.nativeBlock() == nullptr) {
+ LOG(ERROR) << "Null BaseBlock::nativeBlock handle";
+ return false;
+ }
native_handle_t* sHandle =
native_handle_clone(s.nativeBlock());
if (sHandle == nullptr) {
@@ -1609,6 +1613,7 @@
// assuming blob is const here
size_t size = blob.size();
size_t ix = 0;
+ size_t old_ix = 0;
const uint8_t *data = blob.data();
C2Param *p = nullptr;
@@ -1616,8 +1621,13 @@
p = C2ParamUtils::ParseFirst(data + ix, size - ix);
if (p) {
params->emplace_back(p);
+ old_ix = ix;
ix += p->size();
ix = align(ix, PARAMS_ALIGNMENT);
+ if (ix <= old_ix || ix > size) {
+ android_errorWriteLog(0x534e4554, "238083570");
+ break;
+ }
}
} while (p);
diff --git a/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp b/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp
index ef5800d..332d3ac 100644
--- a/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp
+++ b/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp
@@ -38,7 +38,7 @@
!strcmp(deviceCodeName, "Tiramisu");
}
-bool isVendorApiOrFirstApiAtLeastT() {
+static bool isP010Allowed() {
// The first SDK the device shipped with.
static const int32_t kProductFirstApiLevel =
base::GetIntProperty<int32_t>("ro.product.first_api_level", 0);
@@ -47,6 +47,17 @@
// to signal which VSR requirements they conform to even if the first device SDK was higher.
static const int32_t kBoardFirstApiLevel =
base::GetIntProperty<int32_t>("ro.board.first_api_level", 0);
+
+ // Some devices that launched prior to Android S may not support P010 correctly, even
+ // though they may advertise it as supported.
+ if (kProductFirstApiLevel != 0 && kProductFirstApiLevel < __ANDROID_API_S__) {
+ return false;
+ }
+
+ if (kBoardFirstApiLevel != 0 && kBoardFirstApiLevel < __ANDROID_API_S__) {
+ return false;
+ }
+
static const int32_t kBoardApiLevel =
base::GetIntProperty<int32_t>("ro.board.api_level", 0);
@@ -67,7 +78,7 @@
// API alone. For now limit P010 to devices that launched with Android T or known to conform
// to Android T VSR (as opposed to simply limiting to a T vendor image).
if (format == (AHardwareBuffer_Format)HAL_PIXEL_FORMAT_YCBCR_P010 &&
- !isVendorApiOrFirstApiAtLeastT()) {
+ !isP010Allowed()) {
return false;
}
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index bc4053d..f272499 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -54,6 +54,10 @@
static_assert((~C2MemoryUsage::PLATFORM_MASK & PASSTHROUGH_USAGE_MASK) == 0, "");
} // unnamed
+static bool isAtLeastT() {
+ return android_get_device_api_level() >= __ANDROID_API_T__;
+}
+
C2MemoryUsage C2AndroidMemoryUsage::FromGrallocUsage(uint64_t usage) {
// gralloc does not support WRITE_PROTECTED
return C2MemoryUsage(
@@ -702,6 +706,14 @@
}
case static_cast<uint32_t>(PixelFormat4::YCBCR_P010): {
+ // In Android T, P010 is relaxed to allow arbitrary stride for the Y and UV planes,
+ // try locking with the gralloc4 mapper first.
+ c2_status_t status = Gralloc4Mapper_lock(
+ const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, layout, addr);
+ if (status == C2_OK) {
+ break;
+ }
+
void *pointer = nullptr;
status_t err = GraphicBufferMapper::get().lock(
const_cast<native_handle_t *>(mBuffer), grallocUsage, rect, &pointer);
@@ -760,10 +772,12 @@
default: {
// We don't know what it is, let's try to lock it with gralloc4
android_ycbcr ycbcrLayout;
- c2_status_t status = Gralloc4Mapper_lock(
- const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, layout, addr);
- if (status == C2_OK) {
- break;
+ if (isAtLeastT()) {
+ c2_status_t status = Gralloc4Mapper_lock(
+ const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, layout, addr);
+ if (status == C2_OK) {
+ break;
+ }
}
// fallback to lockYCbCr
diff --git a/media/codec2/vndk/include/C2SurfaceSyncObj.h b/media/codec2/vndk/include/C2SurfaceSyncObj.h
index ac87fe4..d858f27 100644
--- a/media/codec2/vndk/include/C2SurfaceSyncObj.h
+++ b/media/codec2/vndk/include/C2SurfaceSyncObj.h
@@ -72,12 +72,13 @@
/**
* Notify a buffer is queued. Return whether the upcoming dequeue operation
* is not blocked. if it's blocked and waitId is non-null, waitId is returned
- * to be used for waiting.
+ * to be used for waiting. Notify(wake-up) waitors only when 'notify' is
+ * true.
*
* \retval false dequeue operation is blocked now.
* \retval true dequeue operation is possible.
*/
- bool notifyQueuedLocked(uint32_t *waitId = nullptr);
+ bool notifyQueuedLocked(uint32_t *waitId = nullptr, bool notify = true);
/**
* Notify a buffer is dequeued.
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index e67e42f..f2cd585 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -432,12 +432,16 @@
if (fence) {
static constexpr int kFenceWaitTimeMs = 10;
+ if (bufferNeedsReallocation) {
+ mBuffers[slot].clear();
+ }
+
status_t status = fence->wait(kFenceWaitTimeMs);
if (status == -ETIME) {
// fence is not signalled yet.
if (syncVar) {
- syncVar->lock();
(void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+ syncVar->lock();
dequeueable = syncVar->notifyQueuedLocked(&waitId);
syncVar->unlock();
if (c2Fence) {
@@ -452,8 +456,8 @@
if (status != android::NO_ERROR) {
ALOGD("buffer fence wait error %d", status);
if (syncVar) {
- syncVar->lock();
(void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+ syncVar->lock();
syncVar->notifyQueuedLocked();
syncVar->unlock();
if (c2Fence) {
@@ -502,8 +506,8 @@
} else if (status != android::NO_ERROR) {
slotBuffer.clear();
if (syncVar) {
- syncVar->lock();
(void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+ syncVar->lock();
syncVar->notifyQueuedLocked();
syncVar->unlock();
if (c2Fence) {
@@ -550,8 +554,8 @@
// Block was not created. call requestBuffer# again next time.
slotBuffer.clear();
if (syncVar) {
- syncVar->lock();
(void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+ syncVar->lock();
syncVar->notifyQueuedLocked();
syncVar->unlock();
if (c2Fence) {
@@ -813,11 +817,10 @@
if (mGeneration == mCurrentGeneration && mBqId == mCurrentBqId && !mOwner.expired()) {
C2SyncVariables *syncVar = mSyncMem ? mSyncMem->mem() : nullptr;
if (syncVar) {
+ mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
syncVar->lock();
- if (syncVar->getSyncStatusLocked() == C2SyncVariables::STATUS_ACTIVE) {
- mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
- syncVar->notifyQueuedLocked();
- }
+ syncVar->notifyQueuedLocked(nullptr,
+ syncVar->getSyncStatusLocked() == C2SyncVariables::STATUS_ACTIVE);
syncVar->unlock();
} else {
mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
@@ -826,11 +829,10 @@
} else if (!mOwner.expired()) {
C2SyncVariables *syncVar = mSyncMem ? mSyncMem->mem() : nullptr;
if (syncVar) {
+ mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
syncVar->lock();
- if (syncVar->getSyncStatusLocked() != C2SyncVariables::STATUS_SWITCHING) {
- mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
- syncVar->notifyQueuedLocked();
- }
+ syncVar->notifyQueuedLocked(nullptr,
+ syncVar->getSyncStatusLocked() != C2SyncVariables::STATUS_SWITCHING);
syncVar->unlock();
} else {
mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
diff --git a/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
index 6be4d09..bf4ca32 100644
--- a/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
+++ b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
@@ -182,12 +182,14 @@
return true;
}
-bool C2SyncVariables::notifyQueuedLocked(uint32_t *waitId) {
+bool C2SyncVariables::notifyQueuedLocked(uint32_t *waitId, bool notify) {
// Note. thundering herds may occur. Edge trigged signalling.
// But one waiter will guarantee to dequeue. others may wait again.
// Minimize futex syscall(trap) for the main use case(one waiter case).
if (mMaxDequeueCount == mCurDequeueCount--) {
- broadcast();
+ if (notify) {
+ broadcast();
+ }
return true;
}
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 7f97ddc..a026153 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -1969,26 +1969,8 @@
}
if (chunk_type == FOURCC("fLaC")) {
-
- // From https://github.com/xiph/flac/blob/master/doc/isoflac.txt
- // 4 for mime, 4 for blockType and BlockLen, 34 for metadata
- uint8_t flacInfo[4 + 4 + 34];
- // skipping dFla, version
- data_offset += sizeof(buffer) + 12;
- size_t flacOffset = 4;
- // Add flaC header mime type to CSD
- strncpy((char *)flacInfo, "fLaC", 4);
- if (mDataSource->readAt(
- data_offset, flacInfo + flacOffset, sizeof(flacInfo) - flacOffset) <
- (ssize_t)sizeof(flacInfo) - flacOffset) {
- return ERROR_IO;
- }
- data_offset += sizeof(flacInfo) - flacOffset;
-
- AMediaFormat_setBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_0, flacInfo,
- sizeof(flacInfo));
+ data_offset += sizeof(buffer);
*offset = data_offset;
- CHECK_EQ(*offset, stop_offset);
}
while (*offset < stop_offset) {
@@ -2521,6 +2503,35 @@
break;
}
+ case FOURCC("dfLa"):
+ {
+ *offset += chunk_size;
+
+ // From https://github.com/xiph/flac/blob/master/doc/isoflac.txt
+ // 4 for mediaType, 4 for blockType and BlockLen, 34 for metadata
+ uint8_t flacInfo[4 + 4 + 34];
+
+ if (chunk_data_size != sizeof(flacInfo)) {
+ return ERROR_MALFORMED;
+ }
+
+ data_offset += 4;
+ size_t flacOffset = 4;
+ // Add flaC header mediaType to CSD
+ strncpy((char *)flacInfo, "fLaC", 4);
+
+ ssize_t bytesToRead = sizeof(flacInfo) - flacOffset;
+ if (mDataSource->readAt(
+ data_offset, flacInfo + flacOffset, bytesToRead) < bytesToRead) {
+ return ERROR_IO;
+ }
+
+ data_offset += bytesToRead;
+ AMediaFormat_setBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_0, flacInfo,
+ sizeof(flacInfo));
+ break;
+ }
+
case FOURCC("avcC"):
{
*offset += chunk_size;
@@ -5897,12 +5908,18 @@
return -EINVAL;
}
- int32_t dataOffsetDelta;
- if (!mDataSource->getUInt32(offset, (uint32_t*)&dataOffsetDelta)) {
+ uint32_t dataOffsetDelta;
+ if (!mDataSource->getUInt32(offset, &dataOffsetDelta)) {
return ERROR_MALFORMED;
}
- dataOffset = mTrackFragmentHeaderInfo.mBaseDataOffset + dataOffsetDelta;
+ if (__builtin_add_overflow(
+ mTrackFragmentHeaderInfo.mBaseDataOffset, dataOffsetDelta, &dataOffset)) {
+ ALOGW("b/232242894 mBaseDataOffset(%" PRIu64 ") + dataOffsetDelta(%u) overflows uint64",
+ mTrackFragmentHeaderInfo.mBaseDataOffset, dataOffsetDelta);
+ android_errorWriteLog(0x534e4554, "232242894");
+ return ERROR_MALFORMED;
+ }
offset += 4;
size -= 4;
@@ -6036,7 +6053,12 @@
return NO_MEMORY;
}
- dataOffset += sampleSize;
+ if (__builtin_add_overflow(dataOffset, sampleSize, &dataOffset)) {
+ ALOGW("b/232242894 dataOffset(%" PRIu64 ") + sampleSize(%u) overflows uint64",
+ dataOffset, sampleSize);
+ android_errorWriteLog(0x534e4554, "232242894");
+ return ERROR_MALFORMED;
+ }
}
mTrackFragmentHeaderInfo.mDataOffset = dataOffset;
@@ -6701,7 +6723,7 @@
const Sample *smpl = &mCurrentSamples[mCurrentSampleIndex];
offset = smpl->offset;
size = smpl->size;
- cts = mCurrentTime + smpl->compositionOffset;
+ cts = (int64_t)mCurrentTime + (int64_t)smpl->compositionOffset;
if (mElstInitialEmptyEditTicks > 0) {
cts += mElstInitialEmptyEditTicks;
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index eb2246d..11f93b5 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -34,6 +34,9 @@
#include <system/audio.h>
#include <utils/String8.h>
+#include <inttypes.h>
+#include <stdint.h>
+
extern "C" {
#include <Tremolo/codec_internal.h>
@@ -346,66 +349,118 @@
off64_t startOffset, off64_t *pageOffset) {
*pageOffset = startOffset;
- for (;;) {
- char signature[4];
- ssize_t n = mSource->readAt(*pageOffset, &signature, 4);
+ // balance between larger reads and reducing how much we over-read.
+ const int FIND_BUF_SIZE = 2048;
+ const int lenOggS = strlen("OggS");
+ while(1) {
- if (n < 4) {
+ // work with big buffers to amortize readAt() costs
+ char signatureBuffer[FIND_BUF_SIZE];
+ ssize_t n = mSource->readAt(*pageOffset, &signatureBuffer, sizeof(signatureBuffer));
+
+ if (n < lenOggS) {
*pageOffset = 0;
-
return (n < 0) ? n : (status_t)ERROR_END_OF_STREAM;
}
- if (!memcmp(signature, "OggS", 4)) {
- if (*pageOffset > startOffset) {
- ALOGV("skipped %lld bytes of junk to reach next frame",
- (long long)(*pageOffset - startOffset));
- }
-
- return OK;
- }
-
- // see how far ahead to skip; avoid some fruitless comparisons
- unsigned int i;
- for (i = 1; i < 4 ; i++) {
- if (signature[i] == 'O')
+ for(int i = 0; i < n - (lenOggS - 1) ; i++) {
+ // fast scan for 1st character in a signature
+ char *p = (char *)memchr(&signatureBuffer[i], 'O', n - (lenOggS - 1) - i);
+ if (p == NULL) {
+ // no signature start in the rest of this buffer.
break;
+ }
+ int jump = (p-&signatureBuffer[i]);
+ i += jump;
+ if (memcmp("OggS", &signatureBuffer[i], lenOggS) == 0) {
+ *pageOffset += i;
+ if (*pageOffset > startOffset) {
+ ALOGD("skipped %" PRIu64 " bytes of junk to reach next frame",
+ (*pageOffset - startOffset));
+ }
+ return OK;
+ }
}
- *pageOffset += i;
+
+ // on to next block. buffer didn't end with "OggS", but could end with "Ogg".
+ // overlap enough to detect this. n >= lenOggS, so this always advances.
+ *pageOffset += n - (lenOggS - 1);
}
+ return (status_t)ERROR_END_OF_STREAM;
}
// Given the offset of the "current" page, find the page immediately preceding
// it (if any) and return its granule position.
// To do this we back up from the "current" page's offset until we find any
// page preceding it and then scan forward to just before the current page.
+//
status_t MyOggExtractor::findPrevGranulePosition(
off64_t pageOffset, uint64_t *granulePos) {
*granulePos = 0;
- off64_t prevPageOffset = 0;
- off64_t prevGuess = pageOffset;
- for (;;) {
- if (prevGuess >= 5000) {
- prevGuess -= 5000;
+ const int FIND_BUF_SIZE = 2048;
+ const int lenOggS = strlen("OggS");
+
+ if (pageOffset == 0) {
+ ALOGV("no page before the first page");
+ return UNKNOWN_ERROR;
+ }
+
+ off64_t prevPageOffset = pageOffset;
+
+ // we start our search on the byte immediately in front of pageOffset
+ // which could mean "O" immediately before and "ggS" starting at pageOffset
+ //
+ // if there was an "OggS" at pageOffset, we'll have scanned a few extra bytes
+ // but if pageOffset was chosen by a seek operation, we don't know that it
+ // reflects the beginning of a page. By choosing to scan 3 possibly unneeded
+ // bytes at the start we cover both cases.
+ //
+ off64_t firstAfter = pageOffset + lenOggS - 1; // NOT within our buffer
+ off64_t nextOffset = pageOffset;
+
+ while(prevPageOffset == pageOffset) {
+ // work with big buffers to amortize readAt() costs
+ char signatureBuffer[FIND_BUF_SIZE];
+
+ ssize_t desired = sizeof(signatureBuffer);
+ if (firstAfter >= desired) {
+ nextOffset = firstAfter - desired;
} else {
- prevGuess = 0;
+ nextOffset = 0;
+ desired = firstAfter;
}
+ ssize_t n = mSource->readAt(nextOffset, &signatureBuffer, desired);
- ALOGV("backing up %lld bytes", (long long)(pageOffset - prevGuess));
-
- status_t err = findNextPage(prevGuess, &prevPageOffset);
- if (err == ERROR_END_OF_STREAM) {
- // We are at the last page and didn't back off enough;
- // back off 5000 bytes more and try again.
- continue;
- } else if (err != OK) {
- return err;
- }
-
- if (prevPageOffset < pageOffset || prevGuess == 0) {
+ if (n < lenOggS) {
+ ALOGD("short read, get out");
break;
}
+
+ // work backwards
+ // loop control ok for n >= 0
+ for(int i = n - lenOggS; i >= 0 ; i--) {
+ // fast scan for 1st character in the signature
+ char *p = (char *)memrchr(&signatureBuffer[0], 'O', i);
+ if (p == NULL) {
+ // no signature start in the rest of this buffer.
+ break;
+ }
+ i = (p-&signatureBuffer[0]);
+ // loop start chosen to ensure we will always have lenOggS bytes
+ if (memcmp("OggS", &signatureBuffer[i], lenOggS) == 0) {
+ prevPageOffset = nextOffset + i;
+ break;
+ }
+ }
+
+ // back up for next read; make sure we catch overlaps
+ if (nextOffset == 0) {
+ // can't back up any further
+ break;
+ }
+ // current buffer might start with "ggS", include those bytes in the next iteration
+ firstAfter = nextOffset + lenOggS - 1;
}
if (prevPageOffset == pageOffset) {
@@ -413,8 +468,8 @@
return UNKNOWN_ERROR;
}
- ALOGV("prevPageOffset at %lld, pageOffset at %lld",
- (long long)prevPageOffset, (long long)pageOffset);
+ ALOGV("prevPageOffset at %" PRIu64 ", pageOffset at %" PRIu64,
+ prevPageOffset, pageOffset);
uint8_t flag = 0;
for (;;) {
Page prevPage;
diff --git a/media/libmedia/tests/codeclist/Android.bp b/media/libmedia/tests/codeclist/Android.bp
index 2ed3126..6f3010c 100644
--- a/media/libmedia/tests/codeclist/Android.bp
+++ b/media/libmedia/tests/codeclist/Android.bp
@@ -25,7 +25,7 @@
cc_test {
name: "CodecListTest",
- test_suites: ["device-tests", "mts"],
+ test_suites: ["device-tests"],
gtest: true,
// Support multilib variants (using different suffix per sub-architecture), which is needed on
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index d71faa7..e63e574 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -5584,6 +5584,9 @@
}
status_t MediaCodec::onSetParameters(const sp<AMessage> ¶ms) {
+ if (mState == UNINITIALIZED || mState == INITIALIZING) {
+ return NO_INIT;
+ }
updateLowLatency(params);
mapFormat(mComponentName, params, nullptr, false);
updateTunnelPeek(params);
diff --git a/media/libstagefright/data/media_codecs_google_c2_video.xml b/media/libstagefright/data/media_codecs_google_c2_video.xml
index 3509ef8..03d8b78 100644
--- a/media/libstagefright/data/media_codecs_google_c2_video.xml
+++ b/media/libstagefright/data/media_codecs_google_c2_video.xml
@@ -60,7 +60,7 @@
<MediaCodec name="c2.android.vp8.decoder" type="video/x-vnd.on2.vp8">
<Alias name="OMX.google.vp8.decoder" />
<Limit name="size" min="2x2" max="2048x2048" />
- <Limit name="alignment" value="2x2" />
+ <Limit name="alignment" value="1x1" />
<Limit name="block-size" value="16x16" />
<Limit name="block-count" range="1-16384" />
<Limit name="blocks-per-second" range="1-1000000" />
@@ -70,7 +70,7 @@
<MediaCodec name="c2.android.vp9.decoder" type="video/x-vnd.on2.vp9">
<Alias name="OMX.google.vp9.decoder" />
<Limit name="size" min="2x2" max="2048x2048" />
- <Limit name="alignment" value="2x2" />
+ <Limit name="alignment" value="1x1" />
<Limit name="block-size" value="16x16" />
<Limit name="block-count" range="1-16384" />
<Limit name="blocks-per-second" range="1-500000" />
diff --git a/media/libstagefright/data/media_codecs_sw.xml b/media/libstagefright/data/media_codecs_sw.xml
index d7e2d18..fb4f9a0 100644
--- a/media/libstagefright/data/media_codecs_sw.xml
+++ b/media/libstagefright/data/media_codecs_sw.xml
@@ -150,7 +150,7 @@
<MediaCodec name="c2.android.vp8.decoder" type="video/x-vnd.on2.vp8" variant="slow-cpu,!slow-cpu">
<Alias name="OMX.google.vp8.decoder" />
<Limit name="size" min="2x2" max="2048x2048" />
- <Limit name="alignment" value="2x2" />
+ <Limit name="alignment" value="1x1" />
<Limit name="block-size" value="16x16" />
<Variant name="!slow-cpu">
<Limit name="block-count" range="1-16384" />
@@ -166,7 +166,7 @@
</MediaCodec>
<MediaCodec name="c2.android.vp9.decoder" type="video/x-vnd.on2.vp9" variant="slow-cpu,!slow-cpu">
<Alias name="OMX.google.vp9.decoder" />
- <Limit name="alignment" value="2x2" />
+ <Limit name="alignment" value="1x1" />
<Limit name="block-size" value="16x16" />
<Variant name="!slow-cpu">
<Limit name="size" min="2x2" max="2048x2048" />