Loading media/codec2/components/hevc/C2SoftHevcEnc.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -86,8 +86,8 @@ class C2SoftHevcEnc::IntfImpl : public SimpleInterface<void>::BaseParams { DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE) .withDefault(new C2StreamPictureSizeInfo::input(0u, 320, 240)) .withFields({ C2F(mSize, width).inRange(320, 1920, 2), C2F(mSize, height).inRange(128, 1088, 2), C2F(mSize, width).inRange(2, 1920, 2), C2F(mSize, height).inRange(2, 1088, 2), }) .withSetter(SizeSetter) .build()); Loading media/codec2/components/vpx/C2SoftVpxDec.cpp +88 −9 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ #define LOG_TAG "C2SoftVpxDec" #include <log/log.h> #include <algorithm> #include <media/stagefright/foundation/AUtils.h> #include <media/stagefright/foundation/MediaDefs.h> Loading Loading @@ -303,13 +305,43 @@ private: #endif }; C2SoftVpxDec::ConverterThread::ConverterThread( const std::shared_ptr<Mutexed<ConversionQueue>> &queue) : Thread(false), mQueue(queue) {} bool C2SoftVpxDec::ConverterThread::threadLoop() { Mutexed<ConversionQueue>::Locked queue(*mQueue); if (queue->entries.empty()) { queue.waitForCondition(queue->cond); if (queue->entries.empty()) { return true; } } std::function<void()> convert = queue->entries.front(); queue->entries.pop_front(); if (!queue->entries.empty()) { queue->cond.signal(); } queue.unlock(); convert(); queue.lock(); if (--queue->numPending == 0u) { queue->cond.broadcast(); } return true; } C2SoftVpxDec::C2SoftVpxDec( const char *name, c2_node_id_t id, const std::shared_ptr<IntfImpl> &intfImpl) : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)), mIntf(intfImpl), mCodecCtx(nullptr) { mCodecCtx(nullptr), mCoreCount(1), mQueue(new Mutexed<ConversionQueue>) { } C2SoftVpxDec::~C2SoftVpxDec() { Loading Loading @@ -399,7 +431,7 @@ status_t C2SoftVpxDec::initDecoder() { vpx_codec_dec_cfg_t cfg; memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t)); cfg.threads = GetCPUCoreCount(); cfg.threads = mCoreCount = GetCPUCoreCount(); vpx_codec_flags_t flags; memset(&flags, 0, sizeof(vpx_codec_flags_t)); Loading @@ -413,6 +445,18 @@ status_t C2SoftVpxDec::initDecoder() { return UNKNOWN_ERROR; } if (mMode == MODE_VP9) { using namespace std::string_literals; for (int i = 0; i < mCoreCount; ++i) { sp<ConverterThread> thread(new ConverterThread(mQueue)); mConverterThreads.push_back(thread); if (thread->run(("vp9conv #"s + std::to_string(i)).c_str(), ANDROID_PRIORITY_AUDIO) != OK) { return UNKNOWN_ERROR; } } } return OK; } Loading @@ -422,6 +466,21 @@ status_t C2SoftVpxDec::destroyDecoder() { delete mCodecCtx; mCodecCtx = nullptr; } bool running = true; for (const sp<ConverterThread> &thread : mConverterThreads) { thread->requestExit(); } while (running) { mQueue->lock()->cond.broadcast(); running = false; for (const sp<ConverterThread> &thread : mConverterThreads) { if (thread->isRunning()) { running = true; break; } } } mConverterThreads.clear(); return OK; } Loading Loading @@ -759,10 +818,30 @@ bool C2SoftVpxDec::outputBuffer( const uint16_t *srcV = (const uint16_t *)img->planes[VPX_PLANE_V]; if (format == HAL_PIXEL_FORMAT_RGBA_1010102) { convertYUV420Planar16ToY410((uint32_t *)dst, srcY, srcU, srcV, srcYStride / 2, srcUStride / 2, srcVStride / 2, dstYStride / sizeof(uint32_t), mWidth, mHeight); Mutexed<ConversionQueue>::Locked queue(*mQueue); size_t i = 0; constexpr size_t kHeight = 64; for (; i < mHeight; i += kHeight) { queue->entries.push_back( [dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride, dstYStride, width = mWidth, height = std::min(mHeight - i, kHeight)] { convertYUV420Planar16ToY410( (uint32_t *)dst, srcY, srcU, srcV, srcYStride / 2, srcUStride / 2, srcVStride / 2, dstYStride / sizeof(uint32_t), width, height); }); srcY += srcYStride / 2 * kHeight; srcU += srcUStride / 2 * (kHeight / 2); srcV += srcVStride / 2 * (kHeight / 2); dst += dstYStride * kHeight; } CHECK_EQ(0u, queue->numPending); queue->numPending = queue->entries.size(); while (queue->numPending > 0) { queue->cond.signal(); queue.waitForCondition(queue->cond); } } else { convertYUV420Planar16ToYUV420Planar(dst, srcY, srcU, srcV, srcYStride / 2, srcUStride / 2, srcVStride / 2, Loading media/codec2/components/vpx/C2SoftVpxDec.h +22 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,19 @@ struct C2SoftVpxDec : public SimpleC2Component { MODE_VP9, } mMode; struct ConversionQueue; class ConverterThread : public Thread { public: explicit ConverterThread( const std::shared_ptr<Mutexed<ConversionQueue>> &queue); ~ConverterThread() override = default; bool threadLoop() override; private: std::shared_ptr<Mutexed<ConversionQueue>> mQueue; }; std::shared_ptr<IntfImpl> mIntf; vpx_codec_ctx_t *mCodecCtx; bool mFrameParallelMode; // Frame parallel is only supported by VP9 decoder. Loading @@ -59,6 +72,15 @@ struct C2SoftVpxDec : public SimpleC2Component { bool mSignalledOutputEos; bool mSignalledError; int mCoreCount; struct ConversionQueue { std::list<std::function<void()>> entries; Condition cond; size_t numPending{0u}; }; std::shared_ptr<Mutexed<ConversionQueue>> mQueue; std::vector<sp<ConverterThread>> mConverterThreads; status_t initDecoder(); status_t destroyDecoder(); void finishWork(uint64_t index, const std::unique_ptr<C2Work> &work, Loading media/extractors/mkv/MatroskaExtractor.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -1993,6 +1993,12 @@ void MatroskaExtractor::addTracks() { } } else if (!strcmp("V_AV1", codecID)) { AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AV1); if (codecPrivateSize > 0) { // 'csd-0' for AV1 is the Blob of Codec Private data as // specified in https://aomediacodec.github.io/av1-isobmff/. AMediaFormat_setBuffer( meta, AMEDIAFORMAT_KEY_CSD_0, codecPrivate, codecPrivateSize); } } else if (!strcmp("V_MPEG2", codecID) || !strcmp("V_MPEG1", codecID)) { AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_MPEG2); Loading media/libstagefright/Utils.cpp +64 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ #include <media/stagefright/foundation/ByteUtils.h> #include <media/stagefright/foundation/OpusHeader.h> #include <media/stagefright/MetaData.h> #include <media/stagefright/MediaCodecConstants.h> #include <media/stagefright/MediaDefs.h> #include <media/AudioSystem.h> #include <media/MediaPlayerInterface.h> Loading Loading @@ -573,6 +574,68 @@ static void parseVp9ProfileLevelFromCsd(const sp<ABuffer> &csd, sp<AMessage> &fo } } static void parseAV1ProfileLevelFromCsd(const sp<ABuffer> &csd, sp<AMessage> &format) { // Parse CSD structure to extract profile level information // https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox const uint8_t *data = csd->data(); size_t remaining = csd->size(); if (remaining < 4 || data[0] != 0x81) { // configurationVersion == 1 return; } uint8_t profileData = (data[1] & 0xE0) >> 5; uint8_t levelData = data[1] & 0x1F; uint8_t highBitDepth = (data[2] & 0x40) >> 6; const static ALookup<std::pair<uint8_t, uint8_t>, int32_t> profiles { { { 0, 0 }, AV1ProfileMain8 }, { { 1, 0 }, AV1ProfileMain10 }, }; int32_t profile; if (profiles.map(std::make_pair(highBitDepth, profileData), &profile)) { // bump to HDR profile if (isHdr(format) && profile == AV1ProfileMain10) { if (format->contains("hdr10-plus-info")) { profile = AV1ProfileMain10HDR10Plus; } else { profile = AV1ProfileMain10HDR10; } } format->setInt32("profile", profile); } const static ALookup<uint8_t, int32_t> levels { { 0, AV1Level2 }, { 1, AV1Level21 }, { 2, AV1Level22 }, { 3, AV1Level23 }, { 4, AV1Level3 }, { 5, AV1Level31 }, { 6, AV1Level32 }, { 7, AV1Level33 }, { 8, AV1Level4 }, { 9, AV1Level41 }, { 10, AV1Level42 }, { 11, AV1Level43 }, { 12, AV1Level5 }, { 13, AV1Level51 }, { 14, AV1Level52 }, { 15, AV1Level53 }, { 16, AV1Level6 }, { 17, AV1Level61 }, { 18, AV1Level62 }, { 19, AV1Level63 }, { 20, AV1Level7 }, { 21, AV1Level71 }, { 22, AV1Level72 }, { 23, AV1Level73 }, }; int32_t level; if (levels.map(levelData, &level)) { format->setInt32("level", level); } } static std::vector<std::pair<const char *, uint32_t>> stringMappings { { Loading Loading @@ -1234,6 +1297,7 @@ status_t convertMetaDataToMessage( buffer->meta()->setInt32("csd", true); buffer->meta()->setInt64("timeUs", 0); msg->setBuffer("csd-0", buffer); parseAV1ProfileLevelFromCsd(buffer, msg); } else if (meta->findData(kKeyESDS, &type, &data, &size)) { ESDS esds((const char *)data, size); if (esds.InitCheck() != (status_t)OK) { Loading Loading
media/codec2/components/hevc/C2SoftHevcEnc.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -86,8 +86,8 @@ class C2SoftHevcEnc::IntfImpl : public SimpleInterface<void>::BaseParams { DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE) .withDefault(new C2StreamPictureSizeInfo::input(0u, 320, 240)) .withFields({ C2F(mSize, width).inRange(320, 1920, 2), C2F(mSize, height).inRange(128, 1088, 2), C2F(mSize, width).inRange(2, 1920, 2), C2F(mSize, height).inRange(2, 1088, 2), }) .withSetter(SizeSetter) .build()); Loading
media/codec2/components/vpx/C2SoftVpxDec.cpp +88 −9 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ #define LOG_TAG "C2SoftVpxDec" #include <log/log.h> #include <algorithm> #include <media/stagefright/foundation/AUtils.h> #include <media/stagefright/foundation/MediaDefs.h> Loading Loading @@ -303,13 +305,43 @@ private: #endif }; C2SoftVpxDec::ConverterThread::ConverterThread( const std::shared_ptr<Mutexed<ConversionQueue>> &queue) : Thread(false), mQueue(queue) {} bool C2SoftVpxDec::ConverterThread::threadLoop() { Mutexed<ConversionQueue>::Locked queue(*mQueue); if (queue->entries.empty()) { queue.waitForCondition(queue->cond); if (queue->entries.empty()) { return true; } } std::function<void()> convert = queue->entries.front(); queue->entries.pop_front(); if (!queue->entries.empty()) { queue->cond.signal(); } queue.unlock(); convert(); queue.lock(); if (--queue->numPending == 0u) { queue->cond.broadcast(); } return true; } C2SoftVpxDec::C2SoftVpxDec( const char *name, c2_node_id_t id, const std::shared_ptr<IntfImpl> &intfImpl) : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)), mIntf(intfImpl), mCodecCtx(nullptr) { mCodecCtx(nullptr), mCoreCount(1), mQueue(new Mutexed<ConversionQueue>) { } C2SoftVpxDec::~C2SoftVpxDec() { Loading Loading @@ -399,7 +431,7 @@ status_t C2SoftVpxDec::initDecoder() { vpx_codec_dec_cfg_t cfg; memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t)); cfg.threads = GetCPUCoreCount(); cfg.threads = mCoreCount = GetCPUCoreCount(); vpx_codec_flags_t flags; memset(&flags, 0, sizeof(vpx_codec_flags_t)); Loading @@ -413,6 +445,18 @@ status_t C2SoftVpxDec::initDecoder() { return UNKNOWN_ERROR; } if (mMode == MODE_VP9) { using namespace std::string_literals; for (int i = 0; i < mCoreCount; ++i) { sp<ConverterThread> thread(new ConverterThread(mQueue)); mConverterThreads.push_back(thread); if (thread->run(("vp9conv #"s + std::to_string(i)).c_str(), ANDROID_PRIORITY_AUDIO) != OK) { return UNKNOWN_ERROR; } } } return OK; } Loading @@ -422,6 +466,21 @@ status_t C2SoftVpxDec::destroyDecoder() { delete mCodecCtx; mCodecCtx = nullptr; } bool running = true; for (const sp<ConverterThread> &thread : mConverterThreads) { thread->requestExit(); } while (running) { mQueue->lock()->cond.broadcast(); running = false; for (const sp<ConverterThread> &thread : mConverterThreads) { if (thread->isRunning()) { running = true; break; } } } mConverterThreads.clear(); return OK; } Loading Loading @@ -759,10 +818,30 @@ bool C2SoftVpxDec::outputBuffer( const uint16_t *srcV = (const uint16_t *)img->planes[VPX_PLANE_V]; if (format == HAL_PIXEL_FORMAT_RGBA_1010102) { convertYUV420Planar16ToY410((uint32_t *)dst, srcY, srcU, srcV, srcYStride / 2, srcUStride / 2, srcVStride / 2, dstYStride / sizeof(uint32_t), mWidth, mHeight); Mutexed<ConversionQueue>::Locked queue(*mQueue); size_t i = 0; constexpr size_t kHeight = 64; for (; i < mHeight; i += kHeight) { queue->entries.push_back( [dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride, dstYStride, width = mWidth, height = std::min(mHeight - i, kHeight)] { convertYUV420Planar16ToY410( (uint32_t *)dst, srcY, srcU, srcV, srcYStride / 2, srcUStride / 2, srcVStride / 2, dstYStride / sizeof(uint32_t), width, height); }); srcY += srcYStride / 2 * kHeight; srcU += srcUStride / 2 * (kHeight / 2); srcV += srcVStride / 2 * (kHeight / 2); dst += dstYStride * kHeight; } CHECK_EQ(0u, queue->numPending); queue->numPending = queue->entries.size(); while (queue->numPending > 0) { queue->cond.signal(); queue.waitForCondition(queue->cond); } } else { convertYUV420Planar16ToYUV420Planar(dst, srcY, srcU, srcV, srcYStride / 2, srcUStride / 2, srcVStride / 2, Loading
media/codec2/components/vpx/C2SoftVpxDec.h +22 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,19 @@ struct C2SoftVpxDec : public SimpleC2Component { MODE_VP9, } mMode; struct ConversionQueue; class ConverterThread : public Thread { public: explicit ConverterThread( const std::shared_ptr<Mutexed<ConversionQueue>> &queue); ~ConverterThread() override = default; bool threadLoop() override; private: std::shared_ptr<Mutexed<ConversionQueue>> mQueue; }; std::shared_ptr<IntfImpl> mIntf; vpx_codec_ctx_t *mCodecCtx; bool mFrameParallelMode; // Frame parallel is only supported by VP9 decoder. Loading @@ -59,6 +72,15 @@ struct C2SoftVpxDec : public SimpleC2Component { bool mSignalledOutputEos; bool mSignalledError; int mCoreCount; struct ConversionQueue { std::list<std::function<void()>> entries; Condition cond; size_t numPending{0u}; }; std::shared_ptr<Mutexed<ConversionQueue>> mQueue; std::vector<sp<ConverterThread>> mConverterThreads; status_t initDecoder(); status_t destroyDecoder(); void finishWork(uint64_t index, const std::unique_ptr<C2Work> &work, Loading
media/extractors/mkv/MatroskaExtractor.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -1993,6 +1993,12 @@ void MatroskaExtractor::addTracks() { } } else if (!strcmp("V_AV1", codecID)) { AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AV1); if (codecPrivateSize > 0) { // 'csd-0' for AV1 is the Blob of Codec Private data as // specified in https://aomediacodec.github.io/av1-isobmff/. AMediaFormat_setBuffer( meta, AMEDIAFORMAT_KEY_CSD_0, codecPrivate, codecPrivateSize); } } else if (!strcmp("V_MPEG2", codecID) || !strcmp("V_MPEG1", codecID)) { AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_MPEG2); Loading
media/libstagefright/Utils.cpp +64 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ #include <media/stagefright/foundation/ByteUtils.h> #include <media/stagefright/foundation/OpusHeader.h> #include <media/stagefright/MetaData.h> #include <media/stagefright/MediaCodecConstants.h> #include <media/stagefright/MediaDefs.h> #include <media/AudioSystem.h> #include <media/MediaPlayerInterface.h> Loading Loading @@ -573,6 +574,68 @@ static void parseVp9ProfileLevelFromCsd(const sp<ABuffer> &csd, sp<AMessage> &fo } } static void parseAV1ProfileLevelFromCsd(const sp<ABuffer> &csd, sp<AMessage> &format) { // Parse CSD structure to extract profile level information // https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox const uint8_t *data = csd->data(); size_t remaining = csd->size(); if (remaining < 4 || data[0] != 0x81) { // configurationVersion == 1 return; } uint8_t profileData = (data[1] & 0xE0) >> 5; uint8_t levelData = data[1] & 0x1F; uint8_t highBitDepth = (data[2] & 0x40) >> 6; const static ALookup<std::pair<uint8_t, uint8_t>, int32_t> profiles { { { 0, 0 }, AV1ProfileMain8 }, { { 1, 0 }, AV1ProfileMain10 }, }; int32_t profile; if (profiles.map(std::make_pair(highBitDepth, profileData), &profile)) { // bump to HDR profile if (isHdr(format) && profile == AV1ProfileMain10) { if (format->contains("hdr10-plus-info")) { profile = AV1ProfileMain10HDR10Plus; } else { profile = AV1ProfileMain10HDR10; } } format->setInt32("profile", profile); } const static ALookup<uint8_t, int32_t> levels { { 0, AV1Level2 }, { 1, AV1Level21 }, { 2, AV1Level22 }, { 3, AV1Level23 }, { 4, AV1Level3 }, { 5, AV1Level31 }, { 6, AV1Level32 }, { 7, AV1Level33 }, { 8, AV1Level4 }, { 9, AV1Level41 }, { 10, AV1Level42 }, { 11, AV1Level43 }, { 12, AV1Level5 }, { 13, AV1Level51 }, { 14, AV1Level52 }, { 15, AV1Level53 }, { 16, AV1Level6 }, { 17, AV1Level61 }, { 18, AV1Level62 }, { 19, AV1Level63 }, { 20, AV1Level7 }, { 21, AV1Level71 }, { 22, AV1Level72 }, { 23, AV1Level73 }, }; int32_t level; if (levels.map(levelData, &level)) { format->setInt32("level", level); } } static std::vector<std::pair<const char *, uint32_t>> stringMappings { { Loading Loading @@ -1234,6 +1297,7 @@ status_t convertMetaDataToMessage( buffer->meta()->setInt32("csd", true); buffer->meta()->setInt64("timeUs", 0); msg->setBuffer("csd-0", buffer); parseAV1ProfileLevelFromCsd(buffer, msg); } else if (meta->findData(kKeyESDS, &type, &data, &size)) { ESDS esds((const char *)data, size); if (esds.InitCheck() != (status_t)OK) { Loading