Loading media/module/extractors/Android.bp +5 −0 Original line number Original line Diff line number Diff line Loading @@ -28,6 +28,10 @@ cc_defaults { "liblog", "liblog", ], ], static_libs: [ "libstagefright_metadatautils", ], // extractors are expected to run on Q(29) // extractors are expected to run on Q(29) min_sdk_version: "29", min_sdk_version: "29", apex_available: [ apex_available: [ Loading Loading @@ -56,6 +60,7 @@ cc_defaults { "libutils", "libutils", "libmediandk_format", "libmediandk_format", "libmedia_ndkformatpriv", "libmedia_ndkformatpriv", "libstagefright_metadatautils", ], ], }, }, }, }, Loading media/module/extractors/fuzzers/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -131,6 +131,7 @@ cc_fuzz { "libstagefright_id3", "libstagefright_id3", "libstagefright_esds", "libstagefright_esds", "libmp4extractor", "libmp4extractor", "libstagefright_metadatautils", ], ], dictionary: "mp4_extractor_fuzzer.dict", dictionary: "mp4_extractor_fuzzer.dict", Loading media/module/extractors/mkv/MatroskaExtractor.cpp +1 −1 Original line number Original line Diff line number Diff line Loading @@ -1787,7 +1787,7 @@ status_t MatroskaExtractor::synthesizeVP9(TrackInfo* trackInfo, size_t index) { return ERROR_MALFORMED; return ERROR_MALFORMED; } } if (!MakeVP9CodecSpecificData(trackInfo->mMeta, tmpData.get(), frame.len)) { if (!MakeVP9CodecSpecificDataFromFirstFrame(trackInfo->mMeta, tmpData.get(), frame.len)) { return ERROR_MALFORMED; return ERROR_MALFORMED; } } Loading media/module/extractors/mp4/MPEG4Extractor.cpp +26 −1 Original line number Original line Diff line number Diff line Loading @@ -51,6 +51,7 @@ #include <media/stagefright/MediaBufferGroup.h> #include <media/stagefright/MediaBufferGroup.h> #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MetaDataBase.h> #include <media/stagefright/MetaDataBase.h> #include <media/stagefright/MetaDataUtils.h> #include <utils/String8.h> #include <utils/String8.h> #include <byteswap.h> #include <byteswap.h> Loading Loading @@ -2596,8 +2597,32 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { *offset += chunk_size; *offset += chunk_size; break; break; } } case FOURCC("vpcC"): case FOURCC("vpcC"): { if (mLastTrack == NULL) { return ERROR_MALFORMED; } auto buffer = heapbuffer<uint8_t>(chunk_data_size); if (buffer.get() == NULL) { ALOGE("b/28471206"); return NO_MEMORY; } if (mDataSource->readAt(data_offset, buffer.get(), chunk_data_size) < chunk_data_size) { return ERROR_IO; } if (!MakeVP9CodecPrivateFromVpcC(mLastTrack->meta, buffer.get(), chunk_data_size)) { ALOGE("Failed to create VP9 CodecPrivate from vpcC."); return ERROR_MALFORMED; } *offset += chunk_size; break; } case FOURCC("av1C"): case FOURCC("av1C"): { { auto buffer = heapbuffer<uint8_t>(chunk_data_size); auto buffer = heapbuffer<uint8_t>(chunk_data_size); Loading media/module/metadatautils/MetaDataUtils.cpp +64 −20 Original line number Original line Diff line number Diff line Loading @@ -134,10 +134,54 @@ static bool getVp9BitdepthChromaSubSampling(ABitReader &bits, } } return true; return true; } } /** * Build VP9 Codec Feature Metadata (CodecPrivate) to set CSD for VP9 codec. * For reference: * https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate. * * @param meta A pointer to AMediaFormat object. * @param profile The profile value of the VP9 stream. * @param level The VP9 codec level. If the level is unknown, pass -1 to this parameter. * @param bitDepth The bit depth of the luma and color components of the VP9 stream. * @param chromaSubsampling The chroma subsampling of the VP9 stream. If chromaSubsampling is * unknown, pass -1 to this parameter. * @return true if CodecPrivate is set as CSD of AMediaFormat object. * */ static bool MakeVP9CodecPrivate(AMediaFormat* meta, int32_t profile, int32_t level, int32_t bitDepth, int32_t chromaSubsampling) { if (meta == nullptr) { return false; } std::vector<uint8_t> codecPrivate; // Construct CodecPrivate in WebM format (ID | Length | Data). // Helper lambda to add a field to the codec private data auto addField = [&codecPrivate](uint8_t id, uint8_t value) { codecPrivate.push_back(id); codecPrivate.push_back(0x01); // Length is always 1 codecPrivate.push_back(value); }; // Add fields addField(0x01, static_cast<uint8_t>(profile)); if (level >= 0) { addField(0x02, static_cast<uint8_t>(level)); } addField(0x03, static_cast<uint8_t>(bitDepth)); if (chromaSubsampling >= 0) { addField(0x04, static_cast<uint8_t>(chromaSubsampling)); } // Set CSD in the meta format AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, codecPrivate.data(), codecPrivate.size()); return true; } // The param data contains the first frame data, starting with the uncompressed frame // The param data contains the first frame data, starting with the uncompressed frame // header. This uncompressed header (refer section 6.2 of the VP9 bitstream spec) is // header. This uncompressed header (refer section 6.2 of the VP9 bitstream spec) is // used to parse profile, bitdepth and subsampling. // used to parse profile, bitdepth and subsampling. bool MakeVP9CodecSpecificData(AMediaFormat* meta, const uint8_t* data, size_t size) { bool MakeVP9CodecSpecificDataFromFirstFrame(AMediaFormat* meta, const uint8_t* data, size_t size) { if (meta == nullptr || data == nullptr || size == 0) { if (meta == nullptr || data == nullptr || size == 0) { return false; return false; } } Loading Loading @@ -227,29 +271,29 @@ bool MakeVP9CodecSpecificData(AMediaFormat* meta, const uint8_t* data, size_t si if (chromaSubsampling != -1) { if (chromaSubsampling != -1) { csdSize += 3; csdSize += 3; } } // As level is not present in first frame build CodecPrivate without it. return MakeVP9CodecPrivate(meta, profile, -1, bitDepth, chromaSubsampling); } // Create VP9 Codec Feature Metadata (CodecPrivate) that can be parsed bool MakeVP9CodecPrivateFromVpcC(AMediaFormat* meta, const uint8_t* csdData, size_t size) { // https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate if (meta == nullptr || csdData == nullptr || size < 12) { sp<ABuffer> csd = sp<ABuffer>::make(csdSize); return false; uint8_t* csdData = csd->data(); } *csdData++ = 0x01 /* FEATURE PROFILE */; *csdData++ = 0x01 /* length */; *csdData++ = profile; *csdData++ = 0x03 /* FEATURE BITDEPTH */; *csdData++ = 0x01 /* length */; *csdData++ = bitDepth; // csdSize more than 6 means chroma subsampling data was found. // Check the first 4 bytes (VersionAndFlags) if they match the required value. if (csdSize > 6) { if (csdData[0] != 0x01 || csdData[1] != 0x00 || csdData[2] != 0x00 || csdData[3] != 0x00) { *csdData++ = 0x04 /* FEATURE SUBSAMPLING */; return false; *csdData++ = 0x01 /* length */; *csdData++ = chromaSubsampling; } } AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, csd->data(), csd->size()); // Create VP9 Codec Feature Metadata (CodecPrivate) that can be parsed. return true; // https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate const uint8_t* vpcCData = csdData + 4; // Skip the first 4 bytes (VersionAndFlags) int32_t profile = vpcCData[0]; int32_t level = vpcCData[1]; int32_t bitDepth = (vpcCData[2] >> 4) & 0x0F; // Bit Depth (4 bits). int32_t chromaSubsampling = (vpcCData[2] >> 1) & 0x07; // Chroma Subsampling (3 bits). return MakeVP9CodecPrivate(meta, profile, level, bitDepth, chromaSubsampling); } } bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) { bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) { Loading Loading
media/module/extractors/Android.bp +5 −0 Original line number Original line Diff line number Diff line Loading @@ -28,6 +28,10 @@ cc_defaults { "liblog", "liblog", ], ], static_libs: [ "libstagefright_metadatautils", ], // extractors are expected to run on Q(29) // extractors are expected to run on Q(29) min_sdk_version: "29", min_sdk_version: "29", apex_available: [ apex_available: [ Loading Loading @@ -56,6 +60,7 @@ cc_defaults { "libutils", "libutils", "libmediandk_format", "libmediandk_format", "libmedia_ndkformatpriv", "libmedia_ndkformatpriv", "libstagefright_metadatautils", ], ], }, }, }, }, Loading
media/module/extractors/fuzzers/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -131,6 +131,7 @@ cc_fuzz { "libstagefright_id3", "libstagefright_id3", "libstagefright_esds", "libstagefright_esds", "libmp4extractor", "libmp4extractor", "libstagefright_metadatautils", ], ], dictionary: "mp4_extractor_fuzzer.dict", dictionary: "mp4_extractor_fuzzer.dict", Loading
media/module/extractors/mkv/MatroskaExtractor.cpp +1 −1 Original line number Original line Diff line number Diff line Loading @@ -1787,7 +1787,7 @@ status_t MatroskaExtractor::synthesizeVP9(TrackInfo* trackInfo, size_t index) { return ERROR_MALFORMED; return ERROR_MALFORMED; } } if (!MakeVP9CodecSpecificData(trackInfo->mMeta, tmpData.get(), frame.len)) { if (!MakeVP9CodecSpecificDataFromFirstFrame(trackInfo->mMeta, tmpData.get(), frame.len)) { return ERROR_MALFORMED; return ERROR_MALFORMED; } } Loading
media/module/extractors/mp4/MPEG4Extractor.cpp +26 −1 Original line number Original line Diff line number Diff line Loading @@ -51,6 +51,7 @@ #include <media/stagefright/MediaBufferGroup.h> #include <media/stagefright/MediaBufferGroup.h> #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MetaDataBase.h> #include <media/stagefright/MetaDataBase.h> #include <media/stagefright/MetaDataUtils.h> #include <utils/String8.h> #include <utils/String8.h> #include <byteswap.h> #include <byteswap.h> Loading Loading @@ -2596,8 +2597,32 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { *offset += chunk_size; *offset += chunk_size; break; break; } } case FOURCC("vpcC"): case FOURCC("vpcC"): { if (mLastTrack == NULL) { return ERROR_MALFORMED; } auto buffer = heapbuffer<uint8_t>(chunk_data_size); if (buffer.get() == NULL) { ALOGE("b/28471206"); return NO_MEMORY; } if (mDataSource->readAt(data_offset, buffer.get(), chunk_data_size) < chunk_data_size) { return ERROR_IO; } if (!MakeVP9CodecPrivateFromVpcC(mLastTrack->meta, buffer.get(), chunk_data_size)) { ALOGE("Failed to create VP9 CodecPrivate from vpcC."); return ERROR_MALFORMED; } *offset += chunk_size; break; } case FOURCC("av1C"): case FOURCC("av1C"): { { auto buffer = heapbuffer<uint8_t>(chunk_data_size); auto buffer = heapbuffer<uint8_t>(chunk_data_size); Loading
media/module/metadatautils/MetaDataUtils.cpp +64 −20 Original line number Original line Diff line number Diff line Loading @@ -134,10 +134,54 @@ static bool getVp9BitdepthChromaSubSampling(ABitReader &bits, } } return true; return true; } } /** * Build VP9 Codec Feature Metadata (CodecPrivate) to set CSD for VP9 codec. * For reference: * https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate. * * @param meta A pointer to AMediaFormat object. * @param profile The profile value of the VP9 stream. * @param level The VP9 codec level. If the level is unknown, pass -1 to this parameter. * @param bitDepth The bit depth of the luma and color components of the VP9 stream. * @param chromaSubsampling The chroma subsampling of the VP9 stream. If chromaSubsampling is * unknown, pass -1 to this parameter. * @return true if CodecPrivate is set as CSD of AMediaFormat object. * */ static bool MakeVP9CodecPrivate(AMediaFormat* meta, int32_t profile, int32_t level, int32_t bitDepth, int32_t chromaSubsampling) { if (meta == nullptr) { return false; } std::vector<uint8_t> codecPrivate; // Construct CodecPrivate in WebM format (ID | Length | Data). // Helper lambda to add a field to the codec private data auto addField = [&codecPrivate](uint8_t id, uint8_t value) { codecPrivate.push_back(id); codecPrivate.push_back(0x01); // Length is always 1 codecPrivate.push_back(value); }; // Add fields addField(0x01, static_cast<uint8_t>(profile)); if (level >= 0) { addField(0x02, static_cast<uint8_t>(level)); } addField(0x03, static_cast<uint8_t>(bitDepth)); if (chromaSubsampling >= 0) { addField(0x04, static_cast<uint8_t>(chromaSubsampling)); } // Set CSD in the meta format AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, codecPrivate.data(), codecPrivate.size()); return true; } // The param data contains the first frame data, starting with the uncompressed frame // The param data contains the first frame data, starting with the uncompressed frame // header. This uncompressed header (refer section 6.2 of the VP9 bitstream spec) is // header. This uncompressed header (refer section 6.2 of the VP9 bitstream spec) is // used to parse profile, bitdepth and subsampling. // used to parse profile, bitdepth and subsampling. bool MakeVP9CodecSpecificData(AMediaFormat* meta, const uint8_t* data, size_t size) { bool MakeVP9CodecSpecificDataFromFirstFrame(AMediaFormat* meta, const uint8_t* data, size_t size) { if (meta == nullptr || data == nullptr || size == 0) { if (meta == nullptr || data == nullptr || size == 0) { return false; return false; } } Loading Loading @@ -227,29 +271,29 @@ bool MakeVP9CodecSpecificData(AMediaFormat* meta, const uint8_t* data, size_t si if (chromaSubsampling != -1) { if (chromaSubsampling != -1) { csdSize += 3; csdSize += 3; } } // As level is not present in first frame build CodecPrivate without it. return MakeVP9CodecPrivate(meta, profile, -1, bitDepth, chromaSubsampling); } // Create VP9 Codec Feature Metadata (CodecPrivate) that can be parsed bool MakeVP9CodecPrivateFromVpcC(AMediaFormat* meta, const uint8_t* csdData, size_t size) { // https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate if (meta == nullptr || csdData == nullptr || size < 12) { sp<ABuffer> csd = sp<ABuffer>::make(csdSize); return false; uint8_t* csdData = csd->data(); } *csdData++ = 0x01 /* FEATURE PROFILE */; *csdData++ = 0x01 /* length */; *csdData++ = profile; *csdData++ = 0x03 /* FEATURE BITDEPTH */; *csdData++ = 0x01 /* length */; *csdData++ = bitDepth; // csdSize more than 6 means chroma subsampling data was found. // Check the first 4 bytes (VersionAndFlags) if they match the required value. if (csdSize > 6) { if (csdData[0] != 0x01 || csdData[1] != 0x00 || csdData[2] != 0x00 || csdData[3] != 0x00) { *csdData++ = 0x04 /* FEATURE SUBSAMPLING */; return false; *csdData++ = 0x01 /* length */; *csdData++ = chromaSubsampling; } } AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, csd->data(), csd->size()); // Create VP9 Codec Feature Metadata (CodecPrivate) that can be parsed. return true; // https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate const uint8_t* vpcCData = csdData + 4; // Skip the first 4 bytes (VersionAndFlags) int32_t profile = vpcCData[0]; int32_t level = vpcCData[1]; int32_t bitDepth = (vpcCData[2] >> 4) & 0x0F; // Bit Depth (4 bits). int32_t chromaSubsampling = (vpcCData[2] >> 1) & 0x07; // Chroma Subsampling (3 bits). return MakeVP9CodecPrivate(meta, profile, level, bitDepth, chromaSubsampling); } } bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) { bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) { Loading