diff --git a/codec2/C2FFMPEGVideoDecodeComponent.cpp b/codec2/C2FFMPEGVideoDecodeComponent.cpp index 59d33f6..4fb2b6e 100644 --- a/codec2/C2FFMPEGVideoDecodeComponent.cpp +++ b/codec2/C2FFMPEGVideoDecodeComponent.cpp @@ -62,6 +62,98 @@ typedef struct { namespace android { +static C2Color::range_t convertFFMPEGColorRange(enum AVColorRange range) { + switch (range) { + case AVCOL_RANGE_JPEG: + return C2Color::RANGE_FULL; + case AVCOL_RANGE_MPEG: + case AVCOL_RANGE_UNSPECIFIED: + default: + return C2Color::RANGE_LIMITED; + } +} + +static C2Color::primaries_t convertFFMPEGColorPrimaries(enum AVColorPrimaries primaries) { + switch (primaries) { + case AVCOL_PRI_BT709: + return C2Color::PRIMARIES_BT709; + case AVCOL_PRI_BT470M: + return C2Color::PRIMARIES_BT470_M; + case AVCOL_PRI_BT470BG: + return C2Color::PRIMARIES_BT601_625; + case AVCOL_PRI_SMPTE170M: + case AVCOL_PRI_SMPTE240M: + return C2Color::PRIMARIES_BT601_525; + case AVCOL_PRI_FILM: + return C2Color::PRIMARIES_GENERIC_FILM; + case AVCOL_PRI_BT2020: + return C2Color::PRIMARIES_BT2020; + case AVCOL_PRI_SMPTE431: + return C2Color::PRIMARIES_RP431; + case AVCOL_PRI_SMPTE432: + return C2Color::PRIMARIES_EG432; + case AVCOL_PRI_UNSPECIFIED: + default: + return C2Color::PRIMARIES_UNSPECIFIED; + } +} + +static C2Color::transfer_t convertFFMPEGColorTransfer(enum AVColorTransferCharacteristic transfer) { + switch (transfer) { + case AVCOL_TRC_BT709: + case AVCOL_TRC_SMPTE170M: + case AVCOL_TRC_BT2020_10: + case AVCOL_TRC_BT2020_12: + return C2Color::TRANSFER_170M; + case AVCOL_TRC_GAMMA22: + return C2Color::TRANSFER_GAMMA22; + case AVCOL_TRC_GAMMA28: + return C2Color::TRANSFER_GAMMA28; + case AVCOL_TRC_LINEAR: + return C2Color::TRANSFER_LINEAR; + case AVCOL_TRC_SMPTE240M: + return C2Color::TRANSFER_240M; + case AVCOL_TRC_IEC61966_2_4: + return C2Color::TRANSFER_XVYCC; + case AVCOL_TRC_BT1361_ECG: + return C2Color::TRANSFER_BT1361; + case AVCOL_TRC_IEC61966_2_1: + return C2Color::TRANSFER_SRGB; + case AVCOL_TRC_SMPTE2084: + return C2Color::TRANSFER_ST2084; + case AVCOL_TRC_SMPTE428: + return C2Color::TRANSFER_ST428; + case AVCOL_TRC_ARIB_STD_B67: + return C2Color::TRANSFER_HLG; + case AVCOL_TRC_UNSPECIFIED: + default: + return C2Color::TRANSFER_UNSPECIFIED; + } +} + +static C2Color::matrix_t convertFFMPEGColorMatrix(enum AVColorSpace colorspace) { + switch (colorspace) { + case AVCOL_SPC_BT709: + return C2Color::MATRIX_BT709; + case AVCOL_SPC_FCC: + return C2Color::MATRIX_FCC47_73_682; + case AVCOL_SPC_BT470BG: + case AVCOL_SPC_SMPTE170M: + return C2Color::MATRIX_BT601; + case AVCOL_SPC_SMPTE240M: + return C2Color::MATRIX_240M; + case AVCOL_SPC_BT2020_NCL: + return C2Color::MATRIX_BT2020; + case AVCOL_SPC_BT2020_CL: + return C2Color::MATRIX_BT2020_CONSTANT; + case AVCOL_SPC_RGB: + return C2Color::MATRIX_OTHER; + case AVCOL_SPC_UNSPECIFIED: + default: + return C2Color::MATRIX_UNSPECIFIED; + } +} + static int getDeinterlaceMode() { std::string prop = base::GetProperty("debug.ffmpeg-codec2.deinterlace", "auto"); @@ -92,6 +184,10 @@ C2FFMPEGVideoDecodeComponent::C2FFMPEGVideoDecodeComponent( mCodecAlreadyOpened(false), mExtradataReady(false), mEOSSignalled(false), + mFrameColorAspects(C2Color::RANGE_UNSPECIFIED, + C2Color::PRIMARIES_UNSPECIFIED, + C2Color::TRANSFER_UNSPECIFIED, + C2Color::MATRIX_UNSPECIFIED), mUtils(std::make_unique()) { ALOGD("C2FFMPEGVideoDecodeComponent: mediaType = %s", componentInfo->mediaType); #if CONFIG_VAAPI @@ -350,11 +446,12 @@ c2_status_t C2FFMPEGVideoDecodeComponent::sendInputBuffer( av_packet_unref(mPacket); if (err < 0) { + int packetSize = inBuffer ? inBuffer->capacity() : 0; ALOGE("sendInputBuffer: failed to send data (%d) to decoder: %s (%08x)", - inBuffer->capacity(), av_err2str(err), err); + packetSize, av_err2str(err), err); if (err == AVERROR(EAGAIN)) { // Frames must be read first, notify main decoding loop. - ALOGD("sendInputBuffer: returning C2_BAD_STATE"); + ALOGD("sendInputBuffer: decoder needs output drain before accepting more input"); return C2_BAD_STATE; } else if (err == AVERROR(ENOSYS) && mCtx->codec_id == AV_CODEC_ID_AV1 && mCtx->hw_device_ctx) { // AV1 HW decoding not supported, re-initialize decoder without VA-API @@ -871,6 +968,93 @@ c2_status_t C2FFMPEGVideoDecodeComponent::downloadFrame(bool forceSw) { return C2_OK; } +bool C2FFMPEGVideoDecodeComponent::updateColorAspects( + std::vector>& configUpdate) { + if (!mFrame) { + return false; + } + + C2StreamColorAspectsInfo::input codedAspects(0u); + codedAspects.range = convertFFMPEGColorRange(mFrame->color_range); + codedAspects.primaries = convertFFMPEGColorPrimaries(mFrame->color_primaries); + codedAspects.transfer = convertFFMPEGColorTransfer(mFrame->color_trc); + codedAspects.matrix = convertFFMPEGColorMatrix(mFrame->colorspace); + + const bool changed = codedAspects.range != mFrameColorAspects.range + || codedAspects.primaries != mFrameColorAspects.primaries + || codedAspects.transfer != mFrameColorAspects.transfer + || codedAspects.matrix != mFrameColorAspects.matrix; + if (!changed) { + return false; + } + + std::vector> failures; + c2_status_t err = mIntf->config({ &codedAspects }, C2_MAY_BLOCK, &failures); + if (err != C2_OK) { + ALOGW("updateColorAspects: config update failed err = %d", err); + return false; + } + + mFrameColorAspects = codedAspects; + configUpdate.push_back(C2Param::Copy(codedAspects)); + configUpdate.push_back(C2Param::Copy(*mIntf->getColorAspectsInfo())); + + ALOGD("updateColorAspects: range=%u primaries=%u transfer=%u matrix=%u " + "from ffmpeg range=%d primaries=%d trc=%d colorspace=%d", + codedAspects.range, codedAspects.primaries, codedAspects.transfer, codedAspects.matrix, + mFrame->color_range, mFrame->color_primaries, mFrame->color_trc, mFrame->colorspace); + + return true; +} + +bool C2FFMPEGVideoDecodeComponent::shouldUseP010Output(const AVHWFramesContext* hwfc) const { +#if CONFIG_VAAPI + if (hwfc && hwfc->sw_format == AV_PIX_FMT_P010) { + return true; + } +#else + (void)hwfc; +#endif + return mUtils->getPixelFormatType() == PixelFormatType::YUV_420_P010; +} + +uint32_t C2FFMPEGVideoDecodeComponent::getActivePixelFormat(bool flexible, const AVHWFramesContext* hwfc) const { + if (shouldUseP010Output(hwfc)) { + return HAL_PIXEL_FORMAT_YCBCR_P010; + } + return mUtils->getPixelFormat(flexible); +} + +#if CONFIG_VAAPI +uint32_t C2FFMPEGVideoDecodeComponent::getActiveVAFormat(const AVHWFramesContext* hwfc) const { + if (shouldUseP010Output(hwfc)) { + return VA_RT_FORMAT_YUV420_10BPP; + } + return mUtils->getVAFormat(); +} + +uint32_t C2FFMPEGVideoDecodeComponent::getActiveVAFOURCCFormat(const AVHWFramesContext* hwfc) const { + if (shouldUseP010Output(hwfc)) { + return VA_FOURCC_P010; + } + return mUtils->getVAFOURCCFormat(); +} +#endif + +uint32_t C2FFMPEGVideoDecodeComponent::getActiveDRMFOURCCFormat(const AVHWFramesContext* hwfc) const { + if (shouldUseP010Output(hwfc)) { + return DRM_FORMAT_P010; + } + return mUtils->getDRMFOURCCFormat(); +} + +enum AVPixelFormat C2FFMPEGVideoDecodeComponent::getActiveAVFormat(const AVHWFramesContext* hwfc) const { + if (shouldUseP010Output(hwfc)) { + return AV_PIX_FMT_P010; + } + return mUtils->getAVFormat(); +} + std::shared_ptr C2FFMPEGVideoDecodeComponent::getOutputBuffer(const std::shared_ptr& pool) { #if CONFIG_VAAPI if (mFrame->format == AV_PIX_FMT_VAAPI) { @@ -881,11 +1065,11 @@ std::shared_ptr C2FFMPEGVideoDecodeComponent::getOutputBuffer(const st std::shared_ptr block; c2_status_t err; - err = pool->fetchGraphicBlock(ALIGN(mFrame->width, 16), ALIGN(mFrame->height, 2), mUtils->getPixelFormat(false), + err = pool->fetchGraphicBlock(ALIGN(mFrame->width, 16), ALIGN(mFrame->height, 2), getActivePixelFormat(false), { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, &block); if (err != C2_OK) { ALOGE("getOutputBuffer: failed to fetch graphic block %d x %d (%#x) err = %d", - mFrame->width, mFrame->height, mUtils->getPixelFormat(false), err); + mFrame->width, mFrame->height, getActivePixelFormat(false), err); return NULL; } @@ -902,7 +1086,14 @@ std::shared_ptr C2FFMPEGVideoDecodeComponent::getOutputBuffer(const st C2PlanarLayout layout = wView.layout(); struct SwsContext* currentImgConvertCtx = mImgConvertCtx; - if (mUtils->getPixelFormat(false) == HAL_PIXEL_FORMAT_YV12) { + if (getActivePixelFormat(false) == HAL_PIXEL_FORMAT_YCBCR_P010) { + data[0] = wView.data()[C2PlanarLayout::PLANE_Y]; + data[1] = wView.data()[C2PlanarLayout::PLANE_U]; + data[2] = data[3] = nullptr; + linesize[0] = layout.planes[C2PlanarLayout::PLANE_Y].rowInc; + linesize[1] = layout.planes[C2PlanarLayout::PLANE_U].rowInc; + linesize[2] = linesize[3] = 0; + } else if (mUtils->getPixelFormat(false) == HAL_PIXEL_FORMAT_YV12) { data[0] = wView.data()[C2PlanarLayout::PLANE_Y]; data[1] = wView.data()[C2PlanarLayout::PLANE_U]; data[2] = wView.data()[C2PlanarLayout::PLANE_V]; @@ -923,11 +1114,11 @@ std::shared_ptr C2FFMPEGVideoDecodeComponent::getOutputBuffer(const st mImgConvertCtx = sws_getCachedContext(currentImgConvertCtx, mFrame->width, mFrame->height, (AVPixelFormat)mFrame->format, - mFrame->width, mFrame->height, mUtils->getAVFormat(), + mFrame->width, mFrame->height, getActiveAVFormat(), SWS_BICUBIC, NULL, NULL, NULL); if (mImgConvertCtx && mImgConvertCtx != currentImgConvertCtx) { ALOGD("getOutputBuffer: created video converter - %s => %s", - av_get_pix_fmt_name((AVPixelFormat)mFrame->format), av_get_pix_fmt_name(mUtils->getAVFormat())); + av_get_pix_fmt_name((AVPixelFormat)mFrame->format), av_get_pix_fmt_name(getActiveAVFormat())); } else if (! mImgConvertCtx) { ALOGE("getOutputBuffer: cannot initialize the conversion context"); return NULL; @@ -1117,16 +1308,23 @@ c2_status_t C2FFMPEGVideoDecodeComponent::outputFrame( } } + updateColorAspects(configUpdate); + #if CONFIG_VAAPI - if (mFrame->format == AV_PIX_FMT_VAAPI && mIntf->getPixelFormat() != mUtils->getPixelFormat(true)) { - ALOGD("outputFrame: pixel format changed - %#x", mUtils->getPixelFormat(true)); + AVHWFramesContext* hwfc = mFrame->hw_frames_ctx ? (AVHWFramesContext*)mFrame->hw_frames_ctx->data : nullptr; + if (mFrame->format == AV_PIX_FMT_VAAPI && mIntf->getPixelFormat() != getActivePixelFormat(true, hwfc)) { + ALOGD("outputFrame: pixel format changed - %#x", getActivePixelFormat(true, hwfc)); - C2StreamPixelFormatInfo::output format(0u, mUtils->getPixelFormat(true)); + C2StreamPixelFormatInfo::output format(0u, getActivePixelFormat(true, hwfc)); std::vector> failures; err = mIntf->config({ &format }, C2_MAY_BLOCK, &failures); if (err == C2_OK) { configUpdate.push_back(C2Param::Copy(format)); + // C2_PARAMKEY_CODED_COLOR_INFO is exposed as a const value by the + // component interface, so it cannot be reconfigured after the + // stream starts. The active output pixel format is enough for the + // graphic buffer allocation path to switch to P010. } else { ALOGE("outputFrame: config update failed err = %d", err); return C2_CORRUPTED; @@ -1144,6 +1342,7 @@ c2_status_t C2FFMPEGVideoDecodeComponent::outputFrame( std::shared_ptr buffer = getOutputBuffer(pool); if (buffer) { buffer->setInfo(mIntf->getPixelFormatInfo()); + buffer->setInfo(mIntf->getColorAspectsInfo()); } if (work && c2_cntr64_t(mFrame->best_effort_timestamp) == work->input.ordinal.frameIndex) { @@ -1267,7 +1466,13 @@ void C2FFMPEGVideoDecodeComponent::process( inputConsumed = true; outputAvailable = true; work->input.buffers.clear(); - } else if (err != C2_BAD_STATE) { + } else if (err == C2_BAD_STATE) { + // avcodec_send_packet() returned EAGAIN. The decoder still owns the + // input-side backpressure, so receive pending frames before retrying + // this same input buffer. Without this, one EAGAIN after outputAvailable + // became false spins on avcodec_send_packet() and playback stalls. + outputAvailable = true; + } else { work->workletsProcessed = 1u; work->result = err; return; @@ -1412,7 +1617,7 @@ int C2FFMPEGVideoDecodeComponent::getBufferVAAPI(AVHWFramesContext* hwfc, AVFram // If we are in VPP mode, and the decoder asks for other formats, // we MUST return ENOSYS to let FFmpeg use its internal YUV pool for decoding. - if (!(forceAllocator || mUtils->getAVFormat() == hwfc->sw_format)) { + if (!(forceAllocator || getActiveAVFormat(hwfc) == hwfc->sw_format)) { ALOGV("getBufferVAAPI: Rejecting request with non-matching pixel format in VPP mode."); return AVERROR(ENOSYS); } @@ -1444,11 +1649,11 @@ int C2FFMPEGVideoDecodeComponent::getBufferVAAPI(AVHWFramesContext* hwfc, AVFram while (!block) { if (mAvailableSurfaces.empty()) { - err = mBlockPool->fetchGraphicBlock(mSurfaceWidth, mSurfaceHeight, mUtils->getPixelFormat(true), + err = mBlockPool->fetchGraphicBlock(mSurfaceWidth, mSurfaceHeight, getActivePixelFormat(true, hwfc), { mIntf->getConsumerUsage(), (uint64_t)BufferUsage::VIDEO_DECODER }, &block); if (err != C2_OK) { ALOGE("getBufferVAAPI[%p]: failed to fetch graphic block %d x %d (%#x) err = %d", - hwfc, mSurfaceWidth, mSurfaceHeight, mUtils->getPixelFormat(true), err); + hwfc, mSurfaceWidth, mSurfaceHeight, getActivePixelFormat(true, hwfc), err); return AVERROR(ENOMEM); } desc.set(block); @@ -1527,7 +1732,7 @@ int C2FFMPEGVideoDecodeComponent::getBufferVAAPI(AVHWFramesContext* hwfc, AVFram } }; - descriptor.fourcc = mUtils->getVAFOURCCFormat(); + descriptor.fourcc = getActiveVAFOURCCFormat(hwfc); descriptor.width = mSurfaceWidth; descriptor.height = mSurfaceHeight; descriptor.num_objects = 1; @@ -1550,7 +1755,7 @@ int C2FFMPEGVideoDecodeComponent::getBufferVAAPI(AVHWFramesContext* hwfc, AVFram } else { // Determine Bytes Per Pixel (BPP) int bpp = 1; - uint32_t currentPixelFormat = mUtils->getPixelFormat(false); + uint32_t currentPixelFormat = getActivePixelFormat(false, hwfc); if (currentPixelFormat == HAL_PIXEL_FORMAT_RGBX_8888 || currentPixelFormat == HAL_PIXEL_FORMAT_BGRA_8888) { @@ -1568,7 +1773,7 @@ int C2FFMPEGVideoDecodeComponent::getBufferVAAPI(AVHWFramesContext* hwfc, AVFram descriptor.layers[0].offset[1] + desc.stride * ALIGN(desc.height / 2, 32) : desc.stride * desc.height * bpp; // Multiply by bpp - descriptor.layers[0].drm_format = mUtils->getDRMFOURCCFormat(); + descriptor.layers[0].drm_format = getActiveDRMFOURCCFormat(hwfc); descriptor.layers[0].num_planes = isYUV ? 2 : 1; descriptor.layers[0].pitch[0] = desc.stride * bpp; @@ -1581,7 +1786,7 @@ int C2FFMPEGVideoDecodeComponent::getBufferVAAPI(AVHWFramesContext* hwfc, AVFram descriptor.layers[0].offset[3] = 0; } - vas = vaCreateSurfaces(hwctx->display, mUtils->getVAFormat(), + vas = vaCreateSurfaces(hwctx->display, getActiveVAFormat(hwfc), mSurfaceWidth, mSurfaceHeight, &surfaceId, 1, attributes, 2); if (vas != VA_STATUS_SUCCESS) { diff --git a/codec2/C2FFMPEGVideoDecodeComponent.h b/codec2/C2FFMPEGVideoDecodeComponent.h index ce38b9b..a71c88e 100644 --- a/codec2/C2FFMPEGVideoDecodeComponent.h +++ b/codec2/C2FFMPEGVideoDecodeComponent.h @@ -74,7 +74,16 @@ class C2FFMPEGVideoDecodeComponent : public SimpleC2Component { const std::unique_ptr &work, const std::shared_ptr &pool); c2_status_t downloadFrame(bool forceSw); + bool updateColorAspects(std::vector>& configUpdate); c2_status_t reconfigureOutputDelay(std::vector>& configUpdate); + bool shouldUseP010Output(const AVHWFramesContext* hwfc = nullptr) const; + uint32_t getActivePixelFormat(bool flexible, const AVHWFramesContext* hwfc = nullptr) const; +#if CONFIG_VAAPI + uint32_t getActiveVAFormat(const AVHWFramesContext* hwfc = nullptr) const; + uint32_t getActiveVAFOURCCFormat(const AVHWFramesContext* hwfc = nullptr) const; +#endif + uint32_t getActiveDRMFOURCCFormat(const AVHWFramesContext* hwfc = nullptr) const; + enum AVPixelFormat getActiveAVFormat(const AVHWFramesContext* hwfc = nullptr) const; void pushPendingWork(const std::unique_ptr& work); void popPendingWork(const std::unique_ptr& work); @@ -114,6 +123,7 @@ class C2FFMPEGVideoDecodeComponent : public SimpleC2Component { bool mExtradataReady; bool mEOSSignalled; bool mFilterInitialized; + C2ColorAspectsStruct mFrameColorAspects; int mDeinterlaceMode; int mDeinterlaceIndicator; std::deque mPendingWorkQueue; diff --git a/codec2/C2FFMPEGVideoDecodeInterface.cpp b/codec2/C2FFMPEGVideoDecodeInterface.cpp index b390017..c4dc214 100644 --- a/codec2/C2FFMPEGVideoDecodeInterface.cpp +++ b/codec2/C2FFMPEGVideoDecodeInterface.cpp @@ -127,10 +127,11 @@ C2FFMPEGVideoDecodeInterface::C2FFMPEGVideoDecodeInterface( addParameter( DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL) .withDefault(new C2StreamProfileLevelInfo::input(0u, - C2Config::PROFILE_HEVC_MAIN, C2Config::LEVEL_HEVC_MAIN_5_1)) + C2Config::PROFILE_HEVC_MAIN_10, C2Config::LEVEL_HEVC_MAIN_5_1)) .withFields({ C2F(mProfileLevel, profile).oneOf({ C2Config::PROFILE_HEVC_MAIN, + C2Config::PROFILE_HEVC_MAIN_10, C2Config::PROFILE_HEVC_MAIN_STILL}), C2F(mProfileLevel, level).oneOf({ C2Config::LEVEL_HEVC_MAIN_1, @@ -218,21 +219,23 @@ C2FFMPEGVideoDecodeInterface::C2FFMPEGVideoDecodeInterface( std::shared_ptr defaultColorInfo = nullptr; + const uint32_t defaultBitDepth = mUtils->getBitDepth(); + if (mUtils->isPixelFormatYUV420()) { C2ChromaOffsetStruct locations[1] = { C2ChromaOffsetStruct::ITU_YUV_420_0() }; defaultColorInfo = C2StreamColorInfo::output::AllocShared( - 1u, 0u, 8u /* bitDepth */, C2Color::YUV_420); + 1u, 0u, defaultBitDepth, C2Color::YUV_420); memcpy(defaultColorInfo->m.locations, locations, sizeof(locations)); defaultColorInfo = C2StreamColorInfo::output::AllocShared( { C2ChromaOffsetStruct::ITU_YUV_420_0() }, - 0u, 8u /* bitDepth */, C2Color::YUV_420); + 0u, defaultBitDepth, C2Color::YUV_420); } else { defaultColorInfo = C2StreamColorInfo::output::AllocShared( - 0u, 0u, 8u /* bitDepth */, C2Color::RGB); + 0u, 0u, defaultBitDepth, C2Color::RGB); helper->addStructDescriptors(); } @@ -241,6 +244,60 @@ C2FFMPEGVideoDecodeInterface::C2FFMPEGVideoDecodeInterface( .withConstValue(defaultColorInfo) .build()); + addParameter( + DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS) + .withDefault(new C2StreamColorAspectsTuning::output( + 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED, + C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED)) + .withFields({ + C2F(mDefaultColorAspects, range).inRange( + C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER), + C2F(mDefaultColorAspects, primaries).inRange( + C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER), + C2F(mDefaultColorAspects, transfer).inRange( + C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER), + C2F(mDefaultColorAspects, matrix).inRange( + C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER), + }) + .withSetter(DefaultColorAspectsSetter) + .build()); + + addParameter( + DefineParam(mCodedColorAspects, C2_PARAMKEY_VUI_COLOR_ASPECTS) + .withDefault(new C2StreamColorAspectsInfo::input( + 0u, C2Color::RANGE_LIMITED, C2Color::PRIMARIES_UNSPECIFIED, + C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED)) + .withFields({ + C2F(mCodedColorAspects, range).inRange( + C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER), + C2F(mCodedColorAspects, primaries).inRange( + C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER), + C2F(mCodedColorAspects, transfer).inRange( + C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER), + C2F(mCodedColorAspects, matrix).inRange( + C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER), + }) + .withSetter(CodedColorAspectsSetter) + .build()); + + addParameter( + DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS) + .withDefault(new C2StreamColorAspectsInfo::output( + 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED, + C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED)) + .withFields({ + C2F(mColorAspects, range).inRange( + C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER), + C2F(mColorAspects, primaries).inRange( + C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER), + C2F(mColorAspects, transfer).inRange( + C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER), + C2F(mColorAspects, matrix).inRange( + C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER), + }) + .withSetter(ColorAspectsSetter, mDefaultColorAspects, mCodedColorAspects) + .build()); + addParameter( DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT) .withDefault(new C2StreamPixelFormatInfo::output( @@ -290,6 +347,56 @@ C2R C2FFMPEGVideoDecodeInterface::ProfileLevelSetter( return C2R::Ok(); } +C2R C2FFMPEGVideoDecodeInterface::DefaultColorAspectsSetter( + bool mayBlock __unused, C2P& me) { + if (me.v.range > C2Color::RANGE_OTHER) { + me.set().range = C2Color::RANGE_OTHER; + } + if (me.v.primaries > C2Color::PRIMARIES_OTHER) { + me.set().primaries = C2Color::PRIMARIES_OTHER; + } + if (me.v.transfer > C2Color::TRANSFER_OTHER) { + me.set().transfer = C2Color::TRANSFER_OTHER; + } + if (me.v.matrix > C2Color::MATRIX_OTHER) { + me.set().matrix = C2Color::MATRIX_OTHER; + } + return C2R::Ok(); +} + +C2R C2FFMPEGVideoDecodeInterface::CodedColorAspectsSetter( + bool mayBlock __unused, C2P& me) { + if (me.v.range > C2Color::RANGE_OTHER) { + me.set().range = C2Color::RANGE_OTHER; + } + if (me.v.primaries > C2Color::PRIMARIES_OTHER) { + me.set().primaries = C2Color::PRIMARIES_OTHER; + } + if (me.v.transfer > C2Color::TRANSFER_OTHER) { + me.set().transfer = C2Color::TRANSFER_OTHER; + } + if (me.v.matrix > C2Color::MATRIX_OTHER) { + me.set().matrix = C2Color::MATRIX_OTHER; + } + return C2R::Ok(); +} + +C2R C2FFMPEGVideoDecodeInterface::ColorAspectsSetter( + bool mayBlock __unused, + C2P& me, + const C2P& def, + const C2P& coded) { + me.set().range = coded.v.range == C2Color::RANGE_UNSPECIFIED + ? def.v.range : coded.v.range; + me.set().primaries = coded.v.primaries == C2Color::PRIMARIES_UNSPECIFIED + ? def.v.primaries : coded.v.primaries; + me.set().transfer = coded.v.transfer == C2Color::TRANSFER_UNSPECIFIED + ? def.v.transfer : coded.v.transfer; + me.set().matrix = coded.v.matrix == C2Color::MATRIX_UNSPECIFIED + ? def.v.matrix : coded.v.matrix; + return C2R::Ok(); +} + C2R C2FFMPEGVideoDecodeInterface::CodecSetter( bool mayBlock __unused, C2P& me __unused) { return C2R::Ok(); diff --git a/codec2/C2FFMPEGVideoDecodeInterface.h b/codec2/C2FFMPEGVideoDecodeInterface.h index c09d61f..5eb0e6d 100644 --- a/codec2/C2FFMPEGVideoDecodeInterface.h +++ b/codec2/C2FFMPEGVideoDecodeInterface.h @@ -36,8 +36,11 @@ class C2FFMPEGVideoDecodeInterface : public SimpleInterface::BaseParams { uint64_t getConsumerUsage() const { return mConsumerUsage->value; } const std::shared_ptr& getPixelFormatInfo() const { return mPixelFormat; } + const std::shared_ptr& + getColorAspectsInfo() const { return mColorAspects; } uint32_t getPixelFormat() const { return mPixelFormat->value; } uint32_t getOutputDelay() const { return mActualOutputDelay->value; } + uint32_t getBitDepth() const { return mUtils->getBitDepth(); } private: static C2R SizeSetter( @@ -48,6 +51,15 @@ class C2FFMPEGVideoDecodeInterface : public SimpleInterface::BaseParams { bool mayBlock, C2P &me, const C2P &size); + static C2R DefaultColorAspectsSetter( + bool mayBlock, C2P &me); + static C2R CodedColorAspectsSetter( + bool mayBlock, C2P &me); + static C2R ColorAspectsSetter( + bool mayBlock, + C2P &me, + const C2P &def, + const C2P &coded); static C2R CodecSetter( bool mayBlock, C2P& me); @@ -55,6 +67,9 @@ class C2FFMPEGVideoDecodeInterface : public SimpleInterface::BaseParams { std::shared_ptr mSize; std::shared_ptr mProfileLevel; std::shared_ptr mColorInfo; + std::shared_ptr mDefaultColorAspects; + std::shared_ptr mCodedColorAspects; + std::shared_ptr mColorAspects; std::shared_ptr mPixelFormat; std::shared_ptr mRawCodecData; std::shared_ptr mConsumerUsage; diff --git a/codec2/C2FFMPEGVideoUtils.cpp b/codec2/C2FFMPEGVideoUtils.cpp index 23a9c0e..ebafdfb 100644 --- a/codec2/C2FFMPEGVideoUtils.cpp +++ b/codec2/C2FFMPEGVideoUtils.cpp @@ -62,6 +62,7 @@ bool C2FFMPEGVideoUtils::shouldEnableCodec(const std::string codec, bool hwonly) bool C2FFMPEGVideoUtils::isPixelFormatYUV420() const { switch (getPixelFormatType()) { case PixelFormatType::YUV_420: + case PixelFormatType::YUV_420_P010: case PixelFormatType::YUV_420_PLANER: return true; default: @@ -72,7 +73,23 @@ bool C2FFMPEGVideoUtils::isPixelFormatYUV420() const { } bool C2FFMPEGVideoUtils::isVPPMode() const { - return (mUseDrmPrime && getPixelFormatType() != PixelFormatType::YUV_420); + return (mUseDrmPrime && getPixelFormatType() != PixelFormatType::YUV_420 + && getPixelFormatType() != PixelFormatType::YUV_420_P010); +} + +uint32_t C2FFMPEGVideoUtils::getBitDepth() const { + switch (getPixelFormatType()) { + case PixelFormatType::YUV_420_P010: + return 10; + case PixelFormatType::YUV_420: + case PixelFormatType::YUV_420_PLANER: + case PixelFormatType::RGB_565: + case PixelFormatType::RGBX_8888: + case PixelFormatType::BGRA_8888: + case PixelFormatType::UNKNOWN: + default: + return 8; + } } PixelFormatType C2FFMPEGVideoUtils::getPixelFormatType() const { @@ -88,6 +105,8 @@ uint32_t C2FFMPEGVideoUtils::getPixelFormat(bool flexible) const { } else { return HAL_PIXEL_FORMAT_YV12; } + case PixelFormatType::YUV_420_P010: + return HAL_PIXEL_FORMAT_YCBCR_P010; case PixelFormatType::YUV_420_PLANER: return HAL_PIXEL_FORMAT_YV12; case PixelFormatType::RGB_565: @@ -109,6 +128,8 @@ uint32_t C2FFMPEGVideoUtils::getVAFormat() const { case PixelFormatType::YUV_420: case PixelFormatType::YUV_420_PLANER: return VA_RT_FORMAT_YUV420; + case PixelFormatType::YUV_420_P010: + return VA_RT_FORMAT_YUV420_10BPP; case PixelFormatType::RGB_565: return VA_RT_FORMAT_RGB16; case PixelFormatType::BGRA_8888: @@ -125,6 +146,8 @@ uint32_t C2FFMPEGVideoUtils::getVAFOURCCFormat() const { switch (getPixelFormatType()) { case PixelFormatType::YUV_420: return VA_FOURCC_NV12; + case PixelFormatType::YUV_420_P010: + return VA_FOURCC_P010; case PixelFormatType::YUV_420_PLANER: return VA_FOURCC_YV12; case PixelFormatType::RGB_565: @@ -145,6 +168,8 @@ uint32_t C2FFMPEGVideoUtils::getDRMFOURCCFormat() const { switch (getPixelFormatType()) { case PixelFormatType::YUV_420: return mUseDrmPrime ? DRM_FORMAT_NV12 : DRM_FORMAT_YVU420; + case PixelFormatType::YUV_420_P010: + return DRM_FORMAT_P010; case PixelFormatType::YUV_420_PLANER: return DRM_FORMAT_YVU420; case PixelFormatType::RGB_565: @@ -164,6 +189,8 @@ enum AVPixelFormat C2FFMPEGVideoUtils::getAVFormat() const { switch (getPixelFormatType()) { case PixelFormatType::YUV_420: return mUseDrmPrime ? AV_PIX_FMT_NV12 : AV_PIX_FMT_YUV420P; + case PixelFormatType::YUV_420_P010: + return AV_PIX_FMT_P010; case PixelFormatType::YUV_420_PLANER: return AV_PIX_FMT_YUV420P; case PixelFormatType::RGB_565: diff --git a/codec2/C2FFMPEGVideoUtils.h b/codec2/C2FFMPEGVideoUtils.h index be542cc..7a6577b 100644 --- a/codec2/C2FFMPEGVideoUtils.h +++ b/codec2/C2FFMPEGVideoUtils.h @@ -32,6 +32,7 @@ namespace android { enum class PixelFormatType { YUV_420, + YUV_420_P010, YUV_420_PLANER, RGB_565, RGBX_8888, @@ -48,6 +49,7 @@ class C2FFMPEGVideoUtils { bool shouldEnableCodec(const std::string codec, bool hwonly) const; bool isPixelFormatYUV420() const; bool isVPPMode() const; + uint32_t getBitDepth() const; uint32_t getPixelFormat(bool flexible) const; #if CONFIG_VAAPI uint32_t getVAFormat() const; @@ -62,6 +64,7 @@ class C2FFMPEGVideoUtils { private: const std::map mPixelFormatMap = { { "YUV_420", PixelFormatType::YUV_420 }, + { "YUV_420_P010", PixelFormatType::YUV_420_P010 }, { "YUV_420_PLANER", PixelFormatType::YUV_420_PLANER }, { "RGB_565", PixelFormatType::RGB_565 }, { "RGBX_8888", PixelFormatType::RGBX_8888 }, diff --git a/codec2/media_codecs_ffmpeg_c2.xml b/codec2/media_codecs_ffmpeg_c2.xml index 8748f45..fa55d10 100644 --- a/codec2/media_codecs_ffmpeg_c2.xml +++ b/codec2/media_codecs_ffmpeg_c2.xml @@ -95,8 +95,13 @@ - + + + + + + diff --git a/utils/ffmpeg_hwaccel.c b/utils/ffmpeg_hwaccel.c index 6deaada..4d68ba0 100644 --- a/utils/ffmpeg_hwaccel.c +++ b/utils/ffmpeg_hwaccel.c @@ -6,6 +6,7 @@ #include "config.h" #include "ffmpeg_hwaccel.h" #include "libavutil/opt.h" +#include "libavutil/hwcontext.h" int ffmpeg_hwaccel_init(AVCodecContext *avctx) { if (!property_get_bool("media.sf.hwaccel", 0)) @@ -75,6 +76,12 @@ int ffmpeg_hwaccel_get_frame(AVCodecContext *avctx __unused, AVFrame *frame) { return 0; } + enum AVPixelFormat sw_format = AV_PIX_FMT_YUV420P; + AVHWFramesContext *hwfc = (AVHWFramesContext *)frame->hw_frames_ctx->data; + if (hwfc && hwfc->sw_format == AV_PIX_FMT_P010) { + sw_format = AV_PIX_FMT_P010; + } + AVFrame* output; int err; @@ -97,9 +104,9 @@ int ffmpeg_hwaccel_get_frame(AVCodecContext *avctx __unused, AVFrame *frame) { // would be successful (and if it fails, then method 3 will also // likely fail). - // YUV420P mapping (slower) + // Software frame mapping (slower) - output->format = AV_PIX_FMT_YUV420P; + output->format = sw_format; err = av_hwframe_map(output, frame, AV_HWFRAME_MAP_READ); if (err == 0) { @@ -109,7 +116,7 @@ int ffmpeg_hwaccel_get_frame(AVCodecContext *avctx __unused, AVFrame *frame) { // HW frame download (slowest) - output->format = AV_PIX_FMT_YUV420P; + output->format = sw_format; err = av_hwframe_transfer_data(output, frame, 0); if (err < 0) {