diff --git a/packages/multimedia/ffmpeg/patches/rpi/ffmpeg-001-rpi.patch b/packages/multimedia/ffmpeg/patches/rpi/ffmpeg-001-rpi.patch index 87a16f85db..998d86ff6c 100644 --- a/packages/multimedia/ffmpeg/patches/rpi/ffmpeg-001-rpi.patch +++ b/packages/multimedia/ffmpeg/patches/rpi/ffmpeg-001-rpi.patch @@ -1,5 +1,5 @@ diff --git a/configure b/configure -index d7a3f507e8..83383b0317 100755 +index 4ba72bf84b..f2fc33e89b 100755 --- a/configure +++ b/configure @@ -207,6 +207,7 @@ External library support: @@ -104,7 +104,7 @@ index d7a3f507e8..83383b0317 100755 huffyuv_decoder_select="bswapdsp huffyuvdsp llviddsp" huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp llvidencdsp" hymt_decoder_select="huffyuv_decoder" -@@ -2919,6 +2941,7 @@ d3d11va_deps="dxva_h ID3D11VideoDecoder ID3D11VideoContext" +@@ -2920,6 +2942,7 @@ d3d11va_deps="dxva_h ID3D11VideoDecoder ID3D11VideoContext" dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode ole32 user32" ffnvcodec_deps_any="libdl LoadLibrary" nvdec_deps="ffnvcodec" @@ -112,7 +112,7 @@ index d7a3f507e8..83383b0317 100755 vaapi_x11_deps="xlib" videotoolbox_hwaccel_deps="videotoolbox pthreads" videotoolbox_hwaccel_extralibs="-framework QuartzCore" -@@ -2960,6 +2983,12 @@ hevc_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_HEVC" +@@ -2961,6 +2984,12 @@ hevc_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_HEVC" hevc_dxva2_hwaccel_select="hevc_decoder" hevc_nvdec_hwaccel_deps="nvdec" hevc_nvdec_hwaccel_select="hevc_decoder" @@ -125,7 +125,7 @@ index d7a3f507e8..83383b0317 100755 hevc_vaapi_hwaccel_deps="vaapi VAPictureParameterBufferHEVC" hevc_vaapi_hwaccel_select="hevc_decoder" hevc_vdpau_hwaccel_deps="vdpau VdpPictureInfoHEVC" -@@ -3437,8 +3466,13 @@ sndio_indev_deps="sndio" +@@ -3438,8 +3467,13 @@ sndio_indev_deps="sndio" sndio_outdev_deps="sndio" v4l2_indev_deps_any="linux_videodev2_h sys_videoio_h" v4l2_indev_suggest="libv4l2" @@ -139,7 +139,7 @@ index d7a3f507e8..83383b0317 100755 vfwcap_indev_deps="vfw32 vfwcap_defines" xcbgrab_indev_deps="libxcb" xcbgrab_indev_suggest="libxcb_shm libxcb_shape libxcb_xfixes" -@@ -3657,6 +3691,7 @@ tonemap_vaapi_filter_deps="vaapi VAProcFilterParameterBufferHDRToneMapping" +@@ -3658,6 +3692,7 @@ tonemap_vaapi_filter_deps="vaapi VAProcFilterParameterBufferHDRToneMapping" tonemap_opencl_filter_deps="opencl const_nan" transpose_opencl_filter_deps="opencl" transpose_vaapi_filter_deps="vaapi VAProcPipelineCaps_rotation_flags" @@ -147,7 +147,7 @@ index d7a3f507e8..83383b0317 100755 unsharp_opencl_filter_deps="opencl" uspp_filter_deps="gpl avcodec" vaguedenoiser_filter_deps="gpl" -@@ -6154,6 +6189,12 @@ check_func_headers glob.h glob +@@ -6155,6 +6190,12 @@ check_func_headers glob.h glob enabled xlib && check_lib xlib "X11/Xlib.h X11/extensions/Xvlib.h" XvGetPortAttribute -lXv -lX11 -lXext @@ -160,7 +160,7 @@ index d7a3f507e8..83383b0317 100755 check_headers direct.h check_headers dirent.h check_headers dxgidebug.h -@@ -6491,11 +6532,12 @@ enabled mbedtls && { check_pkg_config mbedtls mbedtls mbedtls/x509_crt +@@ -6492,11 +6533,12 @@ enabled mbedtls && { check_pkg_config mbedtls mbedtls mbedtls/x509_crt check_lib mbedtls mbedtls/ssl.h mbedtls_ssl_init -lmbedtls -lmbedx509 -lmbedcrypto || die "ERROR: mbedTLS not found"; } enabled mediacodec && { enabled jni || die "ERROR: mediacodec requires --enable-jni"; } @@ -175,7 +175,7 @@ index d7a3f507e8..83383b0317 100755 die "ERROR: mmal not found" && check_func_headers interface/mmal/mmal.h "MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS"; } enabled openal && { { for al_extralibs in "${OPENAL_LIBS}" "-lopenal" "-lOpenAL32"; do -@@ -6536,8 +6578,16 @@ enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/r +@@ -6537,8 +6579,16 @@ enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/r { enabled libdrm || die "ERROR: rkmpp requires --enable-libdrm"; } } @@ -192,7 +192,7 @@ index d7a3f507e8..83383b0317 100755 if enabled gcrypt; then GCRYPT_CONFIG="${cross_prefix}libgcrypt-config" -@@ -6617,6 +6667,10 @@ if enabled v4l2_m2m; then +@@ -6618,6 +6668,10 @@ if enabled v4l2_m2m; then check_cc vp9_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_VP9;" fi @@ -203,7 +203,7 @@ index d7a3f507e8..83383b0317 100755 check_headers sys/videoio.h test_code cc sys/videoio.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_sanitized struct_v4l2_frmivalenum_discrete -@@ -7104,6 +7158,9 @@ check_deps $CONFIG_LIST \ +@@ -7105,6 +7159,9 @@ check_deps $CONFIG_LIST \ enabled threads && ! enabled pthreads && ! enabled atomics_native && die "non pthread threading without atomics not supported, try adding --enable-pthreads or --cpu=i486 or higher if you are on x86" enabled avresample && warn "Building with deprecated library libavresample" @@ -214,10 +214,10 @@ index d7a3f507e8..83383b0317 100755 haiku) disable memalign diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c -index 46bb014de8..0502ff71b8 100644 +index dec012a299..8aa13007f9 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c -@@ -2186,8 +2186,8 @@ static int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame) +@@ -2189,8 +2189,8 @@ static int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame) ifilter->channel_layout != frame->channel_layout; break; case AVMEDIA_TYPE_VIDEO: @@ -228,7 +228,7 @@ index 46bb014de8..0502ff71b8 100644 break; } -@@ -2198,6 +2198,9 @@ static int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame) +@@ -2201,6 +2201,9 @@ static int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame) (ifilter->hw_frames_ctx && ifilter->hw_frames_ctx->data != frame->hw_frames_ctx->data)) need_reinit = 1; @@ -238,7 +238,7 @@ index 46bb014de8..0502ff71b8 100644 if (need_reinit) { ret = ifilter_parameters_from_frame(ifilter, frame); if (ret < 0) -@@ -2466,8 +2469,7 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output, int64_ +@@ -2469,8 +2472,7 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output, int64_ decoded_frame->top_field_first = ist->top_field_first; ist->frames_decoded++; @@ -248,7 +248,7 @@ index 46bb014de8..0502ff71b8 100644 err = ist->hwaccel_retrieve_data(ist->dec_ctx, decoded_frame); if (err < 0) goto fail; -@@ -2671,7 +2673,12 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo +@@ -2674,7 +2676,12 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo case AVMEDIA_TYPE_VIDEO: ret = decode_video (ist, repeating ? NULL : avpkt, &got_output, &duration_pts, !pkt, &decode_failed); @@ -262,7 +262,7 @@ index 46bb014de8..0502ff71b8 100644 if (pkt && pkt->duration) { duration_dts = av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q); } else if(ist->dec_ctx->framerate.num != 0 && ist->dec_ctx->framerate.den != 0) { -@@ -2895,6 +2902,16 @@ static enum AVPixelFormat get_format(AVCodecContext *s, const enum AVPixelFormat +@@ -2898,6 +2905,16 @@ static enum AVPixelFormat get_format(AVCodecContext *s, const enum AVPixelFormat } else { const HWAccel *hwaccel = NULL; int i; @@ -279,7 +279,7 @@ index 46bb014de8..0502ff71b8 100644 for (i = 0; hwaccels[i].name; i++) { if (hwaccels[i].pix_fmt == *p) { hwaccel = &hwaccels[i]; -@@ -2990,6 +3007,15 @@ static int init_input_stream(int ist_index, char *error, int error_len) +@@ -2993,6 +3010,15 @@ static int init_input_stream(int ist_index, char *error, int error_len) return ret; } @@ -53003,11 +53003,15 @@ index b67b216331..ded1478a49 100644 + #endif /* AVCODEC_V4L2_M2M_H */ diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c -index ab07c0a24a..2bd113facb 100644 +index ab07c0a24a..4c5ad55547 100644 --- a/libavcodec/v4l2_m2m_dec.c +++ b/libavcodec/v4l2_m2m_dec.c -@@ -23,6 +23,10 @@ +@@ -21,8 +21,14 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ ++#include "config.h" ++ #include #include + @@ -53017,7 +53021,7 @@ index ab07c0a24a..2bd113facb 100644 #include "libavutil/pixfmt.h" #include "libavutil/pixdesc.h" #include "libavutil/opt.h" -@@ -30,75 +34,267 @@ +@@ -30,75 +36,274 @@ #include "libavcodec/decode.h" #include "libavcodec/internal.h" @@ -53031,6 +53035,13 @@ index ab07c0a24a..2bd113facb 100644 +#include "v4l2_req_dmabufs.h" -static int v4l2_try_start(AVCodecContext *avctx) ++#if CONFIG_H264_DECODER ++#include "h264_parse.h" ++#endif ++#if CONFIG_HEVC_DECODER ++#include "hevc_parse.h" ++#endif ++ +// Pick 64 for max last count - that is >1sec at 60fps +#define STATS_LAST_COUNT_MAX 64 +#define STATS_INTERVAL_MAX (1 << 30) @@ -53090,13 +53101,13 @@ index ab07c0a24a..2bd113facb 100644 + for (i = 0; i != 8; ++i) { + *s++ = ' '; + s = len > i + offset ? hex2(s, *m++) : dash2(s); - } ++ } + *s++ = ' '; + *s++ = ':'; + for (; i != 16; ++i) { + *s++ = ' '; + s = len > i + offset ? hex2(s, *m++) : dash2(s); -+ } + } + *s++ = 0; +} @@ -53333,7 +53344,7 @@ index ab07c0a24a..2bd113facb 100644 return 0; } -@@ -133,58 +329,548 @@ static int v4l2_prepare_decoder(V4L2m2mContext *s) +@@ -133,58 +338,742 @@ static int v4l2_prepare_decoder(V4L2m2mContext *s) return 0; } @@ -53541,23 +53552,23 @@ index ab07c0a24a..2bd113facb 100644 + } + return NQ_DRAINING; + } ++ ++ if (!s->buf_pkt.size) ++ return NQ_NONE; ++ ++ if ((ret = check_output_streamon(avctx, s)) != 0) ++ return ret; - ret = ff_v4l2_context_enqueue_packet(output, &s->buf_pkt); - if (ret < 0 && ret != AVERROR(EAGAIN)) - goto fail; -+ if (!s->buf_pkt.size) -+ return NQ_NONE; - -- /* if EAGAIN don't unref packet and try to enqueue in the next iteration */ -- if (ret != AVERROR(EAGAIN)) -+ if ((ret = check_output_streamon(avctx, s)) != 0) -+ return ret; -+ + if (s->extdata_sent) + ret = ff_v4l2_context_enqueue_packet(&s->output, &s->buf_pkt, NULL, 0); + else + ret = ff_v4l2_context_enqueue_packet(&s->output, &s->buf_pkt, s->extdata_data, s->extdata_size); -+ + +- /* if EAGAIN don't unref packet and try to enqueue in the next iteration */ +- if (ret != AVERROR(EAGAIN)) + if (ret == AVERROR(EAGAIN)) { + // Out of input buffers - keep packet + ret = NQ_Q_FULL; @@ -53576,15 +53587,6 @@ index ab07c0a24a..2bd113facb 100644 - goto fail; + av_log(avctx, AV_LOG_ERROR, "Packet enqueue failure: err=%d\n", ret); + return ret; -+ } -+ } -+ -+ // Start if we haven't -+ { -+ const int ret2 = v4l2_try_start(avctx); -+ if (ret2) { -+ av_log(avctx, AV_LOG_DEBUG, "Start failure: err=%d\n", ret2); -+ ret = (ret2 == AVERROR(ENOMEM)) ? ret2 : NQ_DEAD; } } @@ -53592,9 +53594,18 @@ index ab07c0a24a..2bd113facb 100644 - return ff_v4l2_context_dequeue_frame(capture, frame, -1); -fail: - av_packet_unref(&s->buf_pkt); - return ret; - } - ++ // Start if we haven't ++ { ++ const int ret2 = v4l2_try_start(avctx); ++ if (ret2) { ++ av_log(avctx, AV_LOG_DEBUG, "Start failure: err=%d\n", ret2); ++ ret = (ret2 == AVERROR(ENOMEM)) ? ret2 : NQ_DEAD; ++ } ++ } ++ ++ return ret; ++} ++ +static int qbuf_wait(AVCodecContext * const avctx, V4L2Context * const ctx) +{ + int rv = 0; @@ -53751,10 +53762,131 @@ index ab07c0a24a..2bd113facb 100644 + ret = v4l2_receive_frame2(avctx, frame); + done = us_time(); + av_log(avctx, AV_LOG_TRACE, ">>> %s: rx time=%" PRId64 ", rv=%d\n", __func__, done - now, ret); -+ return ret; -+} + return ret; + } +#endif + ++static uint32_t ++avprofile_to_v4l2(const enum AVCodecID codec_id, const int avprofile) ++{ ++ switch (codec_id) { ++ case AV_CODEC_ID_H264: ++ switch (avprofile) { ++ case FF_PROFILE_H264_BASELINE: ++ return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; ++ case FF_PROFILE_H264_CONSTRAINED_BASELINE: ++ return V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE; ++ case FF_PROFILE_H264_MAIN: ++ return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN; ++ case FF_PROFILE_H264_EXTENDED: ++ return V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED; ++ case FF_PROFILE_H264_HIGH: ++ return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; ++ case FF_PROFILE_H264_HIGH_10: ++ return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10; ++ case FF_PROFILE_H264_HIGH_10_INTRA: ++ return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA; ++ case FF_PROFILE_H264_MULTIVIEW_HIGH: ++ case FF_PROFILE_H264_HIGH_422: ++ return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422; ++ case FF_PROFILE_H264_HIGH_422_INTRA: ++ return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA; ++ case FF_PROFILE_H264_STEREO_HIGH: ++ return V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH; ++ case FF_PROFILE_H264_HIGH_444_PREDICTIVE: ++ return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE; ++ case FF_PROFILE_H264_HIGH_444_INTRA: ++ return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA; ++ case FF_PROFILE_H264_CAVLC_444: ++ return V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA; ++ case FF_PROFILE_H264_HIGH_444: ++ default: ++ break; ++// V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE = 12, ++// V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH = 13, ++// V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA = 14, ++// V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH = 16, ++// V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH = 17, ++ } ++ break; ++ case AV_CODEC_ID_MPEG2VIDEO: ++ case AV_CODEC_ID_MPEG4: ++ case AV_CODEC_ID_VC1: ++ case AV_CODEC_ID_VP8: ++ case AV_CODEC_ID_VP9: ++ case AV_CODEC_ID_AV1: ++ // Most profiles are a simple number that matches the V4L2 enum ++ return avprofile; ++ default: ++ break; ++ } ++ return ~(uint32_t)0; ++} ++ ++// This check mirrors Chrome's profile check by testing to see if the profile ++// exists as a possible value for the V4L2 profile control ++static int ++check_profile(AVCodecContext *const avctx, V4L2m2mContext *const s) ++{ ++ struct v4l2_queryctrl query_ctrl; ++ struct v4l2_querymenu query_menu; ++ uint32_t profile_id; ++ ++ // An unset profile is almost certainly zero or -99 - do not reject ++ if (avctx->profile <= 0) { ++ av_log(avctx, AV_LOG_VERBOSE, "Profile <= 0 - check skipped\n"); ++ return 0; ++ } ++ ++ memset(&query_ctrl, 0, sizeof(query_ctrl)); ++ switch (avctx->codec_id) { ++ case AV_CODEC_ID_MPEG2VIDEO: ++ profile_id = V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE; ++ break; ++ case AV_CODEC_ID_MPEG4: ++ profile_id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE; ++ break; ++ case AV_CODEC_ID_H264: ++ profile_id = V4L2_CID_MPEG_VIDEO_H264_PROFILE; ++ break; ++ case AV_CODEC_ID_VP8: ++ profile_id = V4L2_CID_MPEG_VIDEO_VP8_PROFILE; ++ break; ++ case AV_CODEC_ID_VP9: ++ profile_id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE; ++ break; ++#ifdef V4L2_CID_MPEG_VIDEO_AV1_PROFILE ++ case AV_CODEC_ID_AV1: ++ profile_id = V4L2_CID_MPEG_VIDEO_AV1_PROFILE; ++ break; ++#endif ++ default: ++ av_log(avctx, AV_LOG_VERBOSE, "Can't map profile for codec id %d; profile check skipped\n", avctx->codec_id); ++ return 0; ++ } ++ ++ query_ctrl = (struct v4l2_queryctrl){.id = profile_id}; ++ if (ioctl(s->fd, VIDIOC_QUERYCTRL, &query_ctrl) != 0) { ++ av_log(avctx, AV_LOG_VERBOSE, "Query profile ctrl (%#x) not supported: assume OK\n", query_ctrl.id); ++ } ++ else { ++ av_log(avctx, AV_LOG_DEBUG, "%s: Control supported: %#x\n", __func__, query_ctrl.id); ++ ++ query_menu = (struct v4l2_querymenu){ ++ .id = query_ctrl.id, ++ .index = avprofile_to_v4l2(avctx->codec_id, avctx->profile), ++ }; ++ ++ if (query_menu.index > query_ctrl.maximum || ++ query_menu.index < query_ctrl.minimum || ++ ioctl(s->fd, VIDIOC_QUERYMENU, &query_menu) != 0) { ++ return AVERROR(ENOENT); ++ } ++ } ++ ++ return 0; ++}; ++ +static int +check_size(AVCodecContext * const avctx, V4L2m2mContext * const s) +{ @@ -53875,6 +54007,78 @@ index ab07c0a24a..2bd113facb 100644 + return size + (1 << 16); +} + ++static void ++parse_extradata(AVCodecContext *avctx) ++{ ++ if (!avctx->extradata || !avctx->extradata_size) ++ return; ++ ++ switch (avctx->codec_id) { ++#if CONFIG_H264_DECODER ++ case AV_CODEC_ID_H264: ++ { ++ H264ParamSets ps = {{NULL}}; ++ int is_avc = 0; ++ int nal_length_size = 0; ++ int ret; ++ ++ ret = ff_h264_decode_extradata(avctx->extradata, avctx->extradata_size, ++ &ps, &is_avc, &nal_length_size, ++ avctx->err_recognition, avctx); ++ if (ret > 0) { ++ const SPS * sps = NULL; ++ unsigned int i; ++ for (i = 0; i != MAX_SPS_COUNT; ++i) { ++ if (ps.sps_list[i]) { ++ sps = (const SPS *)ps.sps_list[i]->data; ++ break; ++ } ++ } ++ if (sps) { ++ avctx->profile = ff_h264_get_profile(sps); ++ avctx->level = sps->level_idc; ++ } ++ } ++ ff_h264_ps_uninit(&ps); ++ break; ++ } ++#endif ++#if CONFIG_HEVC_DECODER ++ case AV_CODEC_ID_HEVC: ++ { ++ HEVCParamSets ps = {{NULL}}; ++ HEVCSEI sei = {{{{0}}}}; ++ int is_nalff = 0; ++ int nal_length_size = 0; ++ int ret; ++ ++ ret = ff_hevc_decode_extradata(avctx->extradata, avctx->extradata_size, ++ &ps, &sei, &is_nalff, &nal_length_size, ++ avctx->err_recognition, 0, avctx); ++ if (ret > 0) { ++ const HEVCSPS * sps = NULL; ++ unsigned int i; ++ for (i = 0; i != HEVC_MAX_SPS_COUNT; ++i) { ++ if (ps.sps_list[i]) { ++ sps = (const HEVCSPS *)ps.sps_list[i]->data; ++ break; ++ } ++ } ++ if (sps) { ++ avctx->profile = sps->ptl.general_ptl.profile_idc; ++ avctx->level = sps->ptl.general_ptl.level_idc; ++ } ++ } ++ ff_hevc_ps_uninit(&ps); ++ ff_hevc_reset_sei(&sei); ++ break; ++ } ++#endif ++ default: ++ break; ++ } ++} + static av_cold int v4l2_decode_init(AVCodecContext *avctx) { V4L2Context *capture, *output; @@ -53895,7 +54099,8 @@ index ab07c0a24a..2bd113facb 100644 + avctx->ticks_per_frame = 2; + } + -+ av_log(avctx, AV_LOG_INFO, "level=%d\n", avctx->level); ++ parse_extradata(avctx); ++ ret = ff_v4l2_m2m_create_context(priv, &s); if (ret < 0) return ret; @@ -53906,7 +54111,7 @@ index ab07c0a24a..2bd113facb 100644 capture = &s->capture; output = &s->output; -@@ -192,14 +878,65 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx) +@@ -192,14 +1081,65 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx) * by the v4l2 driver; this event will trigger a full pipeline reconfig and * the proper values will be retrieved from the kernel driver. */ @@ -53974,7 +54179,7 @@ index ab07c0a24a..2bd113facb 100644 s->avctx = avctx; ret = ff_v4l2_m2m_codec_init(priv); -@@ -208,12 +945,84 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx) +@@ -208,12 +1148,88 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx) return ret; } @@ -53997,6 +54202,10 @@ index ab07c0a24a..2bd113facb 100644 + if ((ret = check_size(avctx, s)) != 0) + return ret; + ++ if ((ret = check_profile(avctx, s)) != 0) { ++ av_log(avctx, AV_LOG_WARNING, "Profile %d not supported by decode\n", avctx->profile); ++ return ret; ++ } + return 0; } @@ -54061,7 +54270,7 @@ index ab07c0a24a..2bd113facb 100644 } #define OFFSET(x) offsetof(V4L2m2mPriv, x) -@@ -222,10 +1031,17 @@ static av_cold int v4l2_decode_close(AVCodecContext *avctx) +@@ -222,10 +1238,17 @@ static av_cold int v4l2_decode_close(AVCodecContext *avctx) static const AVOption options[] = { V4L_M2M_DEFAULT_OPTS, { "num_capture_buffers", "Number of buffers in the capture context", @@ -54080,7 +54289,7 @@ index ab07c0a24a..2bd113facb 100644 #define M2MDEC_CLASS(NAME) \ static const AVClass v4l2_m2m_ ## NAME ## _dec_class = { \ .class_name = #NAME "_v4l2m2m_decoder", \ -@@ -246,9 +1062,15 @@ static const AVOption options[] = { +@@ -246,9 +1269,15 @@ static const AVOption options[] = { .init = v4l2_decode_init, \ .receive_frame = v4l2_receive_frame, \ .close = v4l2_decode_close, \ @@ -59855,7 +60064,7 @@ index 0000000000..99c90064ea + +#endif diff --git a/libavcodec/vc1dec.c b/libavcodec/vc1dec.c -index ea93e11588..a9e0c6323e 100644 +index d4ceb60791..fb7f839c5e 100644 --- a/libavcodec/vc1dec.c +++ b/libavcodec/vc1dec.c @@ -486,7 +486,7 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx) @@ -62325,6 +62534,67 @@ index f6b572b3de..44fe8b679c 100644 if (ret < 0) return ret; av_log(log_ctx, AV_LOG_ERROR, +diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c +index 15d897cff6..c134759bbf 100644 +--- a/libavfilter/buffersink.c ++++ b/libavfilter/buffersink.c +@@ -58,6 +58,11 @@ typedef struct BufferSinkContext { + int sample_rates_size; + + AVFrame *peeked_frame; ++ ++ union { ++ av_buffersink_alloc_video_frame * video; ++ } alloc_cb; ++ void * alloc_v; + } BufferSinkContext; + + #define NB_ITEMS(list) (list ## _size / sizeof(*list)) +@@ -148,6 +153,22 @@ int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx, + return get_frame_internal(ctx, frame, 0, nb_samples); + } + ++static AVFrame * alloc_video_buffer(AVFilterLink *link, int w, int h) ++{ ++ AVFilterContext * const ctx = link->dst; ++ BufferSinkContext * const bs = ctx->priv; ++ return bs->alloc_cb.video ? bs->alloc_cb.video(ctx, bs->alloc_v, w, h) : ++ ff_default_get_video_buffer(link, w, h); ++} ++ ++int av_buffersink_set_alloc_video_frame(AVFilterContext *ctx, av_buffersink_alloc_video_frame * cb, void * v) ++{ ++ BufferSinkContext * const bs = ctx->priv; ++ bs->alloc_cb.video = cb; ++ bs->alloc_v = v; ++ return 0; ++} ++ + #if FF_API_BUFFERSINK_ALLOC + AVBufferSinkParams *av_buffersink_params_alloc(void) + { +@@ -331,6 +352,7 @@ static const AVFilterPad avfilter_vsink_buffer_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, ++ .get_video_buffer = alloc_video_buffer, + }, + { NULL } + }; +diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h +index 69ed0f29a8..a3aa6fcb3c 100644 +--- a/libavfilter/buffersink.h ++++ b/libavfilter/buffersink.h +@@ -198,6 +198,9 @@ int av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame); + */ + int av_buffersink_get_samples(AVFilterContext *ctx, AVFrame *frame, int nb_samples); + ++typedef AVFrame * av_buffersink_alloc_video_frame(AVFilterContext * ctx, void * v, int w, int h); ++int av_buffersink_set_alloc_video_frame(AVFilterContext *ctx, av_buffersink_alloc_video_frame * cb, void * v); ++ + /** + * @} + */ diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c index da1cf9941e..c588ed23cb 100644 --- a/libavfilter/buffersrc.c @@ -64695,7 +64965,7 @@ index 0000000000..61c03a385c +}; + diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c -index bbf231f2a4..22571c89a3 100644 +index b4284a8778..692265593c 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -58,6 +58,9 @@ @@ -64723,7 +64993,7 @@ index bbf231f2a4..22571c89a3 100644 case AV_CODEC_ID_HEVC: return ff_isom_write_hvcc(dyn_cp, par->extradata, par->extradata_size, 0); -@@ -2258,7 +2265,9 @@ static int mkv_check_new_extra_data(AVFormatContext *s, const AVPacket *pkt) +@@ -2259,7 +2266,9 @@ static int mkv_check_new_extra_data(AVFormatContext *s, const AVPacket *pkt) break; // FIXME: Remove the following once libaom starts propagating extradata during init() // See https://bugs.chromium.org/p/aomedia/issues/detail?id=2012 @@ -64733,7 +65003,7 @@ index bbf231f2a4..22571c89a3 100644 if (side_data_size && mkv->track.bc && !par->extradata_size) { AVIOContext *dyn_cp; uint8_t *codecpriv; -@@ -2266,7 +2275,10 @@ static int mkv_check_new_extra_data(AVFormatContext *s, const AVPacket *pkt) +@@ -2267,7 +2276,10 @@ static int mkv_check_new_extra_data(AVFormatContext *s, const AVPacket *pkt) ret = avio_open_dyn_buf(&dyn_cp); if (ret < 0) return ret; @@ -64745,7 +65015,7 @@ index bbf231f2a4..22571c89a3 100644 codecpriv_size = avio_get_dyn_buf(dyn_cp, &codecpriv); if ((ret = dyn_cp->error) < 0 || !codecpriv_size && (ret = AVERROR_INVALIDDATA)) { -@@ -2274,8 +2286,25 @@ static int mkv_check_new_extra_data(AVFormatContext *s, const AVPacket *pkt) +@@ -2275,8 +2287,25 @@ static int mkv_check_new_extra_data(AVFormatContext *s, const AVPacket *pkt) return ret; } avio_seek(mkv->track.bc, track->codecpriv_offset, SEEK_SET); @@ -64774,10 +65044,10 @@ index bbf231f2a4..22571c89a3 100644 ret = ff_alloc_extradata(par, side_data_size); if (ret < 0) diff --git a/libavformat/movenc.c b/libavformat/movenc.c -index bade57dcea..d23101b23f 100644 +index 2cd5773dc5..0cbbc094de 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c -@@ -5913,6 +5913,7 @@ static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt) +@@ -5926,6 +5926,7 @@ static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt) if (trk->par->codec_id == AV_CODEC_ID_MP4ALS || trk->par->codec_id == AV_CODEC_ID_AAC || trk->par->codec_id == AV_CODEC_ID_AV1 || @@ -64786,10 +65056,10 @@ index bade57dcea..d23101b23f 100644 buffer_size_t side_size; uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size); diff --git a/libavformat/utils.c b/libavformat/utils.c -index 1384b56771..27479e3c40 100644 +index 75e5350a27..e10b493dae 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c -@@ -3011,6 +3011,40 @@ static int has_codec_parameters(AVStream *st, const char **errmsg_ptr) +@@ -3013,6 +3013,40 @@ static int has_codec_parameters(AVStream *st, const char **errmsg_ptr) return 1; } @@ -64830,7 +65100,7 @@ index 1384b56771..27479e3c40 100644 /* returns 1 or 0 if or if not decoded data was returned, or a negative error */ static int try_decode_frame(AVFormatContext *s, AVStream *st, const AVPacket *avpkt, AVDictionary **options) -@@ -3049,7 +3083,11 @@ static int try_decode_frame(AVFormatContext *s, AVStream *st, +@@ -3051,7 +3085,11 @@ static int try_decode_frame(AVFormatContext *s, AVStream *st, av_dict_set(options ? options : &thread_opt, "lowres", "0", 0); if (s->codec_whitelist) av_dict_set(options ? options : &thread_opt, "codec_whitelist", s->codec_whitelist, 0); @@ -64843,7 +65113,7 @@ index 1384b56771..27479e3c40 100644 if (!options) av_dict_free(&thread_opt); if (ret < 0) { -@@ -3080,6 +3118,14 @@ static int try_decode_frame(AVFormatContext *s, AVStream *st, +@@ -3082,6 +3120,14 @@ static int try_decode_frame(AVFormatContext *s, AVStream *st, if (avctx->codec_type == AVMEDIA_TYPE_VIDEO || avctx->codec_type == AVMEDIA_TYPE_AUDIO) { ret = avcodec_send_packet(avctx, &pkt); @@ -64858,7 +65128,7 @@ index 1384b56771..27479e3c40 100644 if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) break; if (ret >= 0) -@@ -3708,9 +3754,20 @@ FF_ENABLE_DEPRECATION_WARNINGS +@@ -3710,9 +3756,20 @@ FF_ENABLE_DEPRECATION_WARNINGS // Try to just open decoders, in case this is enough to get parameters. if (!has_codec_parameters(st, NULL) && st->internal->request_probe <= 0) { if (codec && !avctx->codec) diff --git a/projects/RPi/patches/kodi/0001-CDVDVideoCodecDRMPRIME-Also-support-YUV420-buffers.patch b/projects/RPi/patches/kodi/0001-CDVDVideoCodecDRMPRIME-Also-support-YUV420-buffers.patch index 0f2c93f4c2..c4b3d66cb3 100644 --- a/projects/RPi/patches/kodi/0001-CDVDVideoCodecDRMPRIME-Also-support-YUV420-buffers.patch +++ b/projects/RPi/patches/kodi/0001-CDVDVideoCodecDRMPRIME-Also-support-YUV420-buffers.patch @@ -1,7 +1,7 @@ From 97d39a46091b65e4355ce7e545bdec46ff2f87de Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sat, 11 Sep 2021 14:03:05 +0100 -Subject: [PATCH 1/4] CDVDVideoCodecDRMPRIME: Also support YUV420 buffers +Subject: [PATCH 1/7] CDVDVideoCodecDRMPRIME: Also support YUV420 buffers CDVDVideoCodecDRMPRIME: Add support for deinterlace of sw decoded buffers @@ -50,5 +50,5 @@ index 20a5c24f53..a36107c515 100644 if (ret < 0) { -- -2.39.0 +2.39.2 diff --git a/projects/RPi/patches/kodi/0002-gbm-Set-max-bpc-for-high-bit-depth-videos.patch b/projects/RPi/patches/kodi/0002-gbm-Set-max-bpc-for-high-bit-depth-videos.patch index b0abba97ed..6e4b0e8da5 100644 --- a/projects/RPi/patches/kodi/0002-gbm-Set-max-bpc-for-high-bit-depth-videos.patch +++ b/projects/RPi/patches/kodi/0002-gbm-Set-max-bpc-for-high-bit-depth-videos.patch @@ -1,7 +1,7 @@ From 42b30508bfe5451d4dc2884acfde9e0ec2d58c92 Mon Sep 17 00:00:00 2001 From: Dom Cobley Date: Fri, 3 Dec 2021 16:00:50 +0000 -Subject: [PATCH 2/4] gbm: Set max bpc for high bit depth videos +Subject: [PATCH 2/7] gbm: Set max bpc for high bit depth videos --- .../HwDecRender/VideoLayerBridgeDRMPRIME.cpp | 16 ++++++++++++++++ @@ -42,5 +42,5 @@ index 4b8ee5afbb..bd6623e8d1 100644 void CVideoLayerBridgeDRMPRIME::SetVideoPlane(CVideoBufferDRMPRIME* buffer, const CRect& destRect) -- -2.39.0 +2.39.2 diff --git a/projects/RPi/patches/kodi/0003-CVideoLayerBridgeDRMPRIME-add-colourspace-connector-.patch b/projects/RPi/patches/kodi/0003-CVideoLayerBridgeDRMPRIME-add-colourspace-connector-.patch index 7fe34c3654..12b7d57cf4 100644 --- a/projects/RPi/patches/kodi/0003-CVideoLayerBridgeDRMPRIME-add-colourspace-connector-.patch +++ b/projects/RPi/patches/kodi/0003-CVideoLayerBridgeDRMPRIME-add-colourspace-connector-.patch @@ -1,7 +1,7 @@ From 0b9b204c6560f3aff39697f92616b48102840dfe Mon Sep 17 00:00:00 2001 From: Lukas Rusak Date: Mon, 29 Apr 2019 18:48:45 -0700 -Subject: [PATCH 3/4] CVideoLayerBridgeDRMPRIME add colourspace connector +Subject: [PATCH 3/7] CVideoLayerBridgeDRMPRIME add colourspace connector property --- @@ -83,5 +83,5 @@ index bd6623e8d1..a1342595c6 100644 void CVideoLayerBridgeDRMPRIME::SetVideoPlane(CVideoBufferDRMPRIME* buffer, const CRect& destRect) -- -2.39.0 +2.39.2 diff --git a/projects/RPi/patches/kodi/0004-CDVDVideoCodecDRMPRIME-Adjust-av-formats-to-match-re.patch b/projects/RPi/patches/kodi/0004-CDVDVideoCodecDRMPRIME-Adjust-av-formats-to-match-re.patch index 94e221e1a6..c996f21873 100644 --- a/projects/RPi/patches/kodi/0004-CDVDVideoCodecDRMPRIME-Adjust-av-formats-to-match-re.patch +++ b/projects/RPi/patches/kodi/0004-CDVDVideoCodecDRMPRIME-Adjust-av-formats-to-match-re.patch @@ -1,7 +1,7 @@ From 518d8487d090af854fb72a7d0e5efc075d97228c Mon Sep 17 00:00:00 2001 From: Dom Cobley Date: Wed, 18 Jan 2023 16:41:00 +0000 -Subject: [PATCH 4/4] CDVDVideoCodecDRMPRIME: Adjust av formats to match recent +Subject: [PATCH 4/7] CDVDVideoCodecDRMPRIME: Adjust av formats to match recent ffmpeg changes --- @@ -45,5 +45,5 @@ index a36107c515..d5b3289680 100644 if (ret < 0) { -- -2.39.0 +2.39.2 diff --git a/projects/RPi/patches/kodi/0005-DVDVideoCodecDRMPRIME-Support-YUV422-and-YUV444-form.patch b/projects/RPi/patches/kodi/0005-DVDVideoCodecDRMPRIME-Support-YUV422-and-YUV444-form.patch new file mode 100644 index 0000000000..b36915dbd4 --- /dev/null +++ b/projects/RPi/patches/kodi/0005-DVDVideoCodecDRMPRIME-Support-YUV422-and-YUV444-form.patch @@ -0,0 +1,93 @@ +From a11461db2d442e0648ebb9255a2399a647d8f5be Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Wed, 25 Jan 2023 18:42:24 +0000 +Subject: [PATCH 5/7] DVDVideoCodecDRMPRIME: Support YUV422 and YUV444 formats + +See: https://github.com/xbmc/xbmc/issues/20017 + +We currently can't play YUV422 and YUV444 videos with drm +but they can be made to work with straightforward plumbing +--- + .../Buffers/VideoBufferPoolDMA.cpp | 6 +++++ + .../DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp | 27 +++++++++++++++---- + 2 files changed, 28 insertions(+), 5 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/Buffers/VideoBufferPoolDMA.cpp b/xbmc/cores/VideoPlayer/Buffers/VideoBufferPoolDMA.cpp +index fb2dfc6c78..e6b071117e 100644 +--- a/xbmc/cores/VideoPlayer/Buffers/VideoBufferPoolDMA.cpp ++++ b/xbmc/cores/VideoPlayer/Buffers/VideoBufferPoolDMA.cpp +@@ -123,6 +123,12 @@ uint32_t CVideoBufferPoolDMA::TranslateFormat(AVPixelFormat format) + case AV_PIX_FMT_YUV420P: + case AV_PIX_FMT_YUVJ420P: + return DRM_FORMAT_YUV420; ++ case AV_PIX_FMT_YUV422P: ++ case AV_PIX_FMT_YUVJ422P: ++ return DRM_FORMAT_YUV422; ++ case AV_PIX_FMT_YUV444P: ++ case AV_PIX_FMT_YUVJ444P: ++ return DRM_FORMAT_YUV444; + default: + return 0; + } +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +index d5b3289680..4af903ecf5 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +@@ -142,7 +142,8 @@ static bool IsSupportedHwFormat(const enum AVPixelFormat fmt) + + static bool IsSupportedSwFormat(const enum AVPixelFormat fmt) + { +- return fmt == AV_PIX_FMT_YUV420P || fmt == AV_PIX_FMT_YUVJ420P; ++ return fmt == AV_PIX_FMT_YUV420P || fmt == AV_PIX_FMT_YUVJ420P || fmt == AV_PIX_FMT_YUV422P || ++ fmt == AV_PIX_FMT_YUVJ422P || fmt == AV_PIX_FMT_YUV444P || fmt == AV_PIX_FMT_YUVJ444P; + } + + static const AVCodecHWConfig* FindHWConfig(const AVCodec* codec) +@@ -206,7 +207,14 @@ enum AVPixelFormat CDVDVideoCodecDRMPRIME::GetFormat(struct AVCodecContext* avct + } + } + +- CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::{} - unsupported pixel format", __FUNCTION__); ++ std::vector formats; ++ for (int n = 0; fmt[n] != AV_PIX_FMT_NONE; n++) ++ { ++ formats.emplace_back(av_get_pix_fmt_name(fmt[n])); ++ } ++ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::{} - no supported pixel formats: {}", __FUNCTION__, ++ StringUtils::Join(formats, ", ")); ++ + return AV_PIX_FMT_NONE; + } + +@@ -226,6 +234,14 @@ int CDVDVideoCodecDRMPRIME::GetBuffer(struct AVCodecContext* avctx, AVFrame* fra + case AV_PIX_FMT_YUVJ420P: + size = width * height * 3 / 2; + break; ++ case AV_PIX_FMT_YUV422P: ++ case AV_PIX_FMT_YUVJ422P: ++ size = width * height * 2; ++ break; ++ case AV_PIX_FMT_YUV444P: ++ case AV_PIX_FMT_YUVJ444P: ++ size = width * height * 3; ++ break; + default: + return -1; + } +@@ -512,9 +528,10 @@ bool CDVDVideoCodecDRMPRIME::SetPictureParams(VideoPicture* pVideoPicture) + (static_cast(lrint(pVideoPicture->iWidth / aspect_ratio))) & -3; + } + +- pVideoPicture->color_range = m_pFrame->color_range == AVCOL_RANGE_JPEG || +- m_pFrame->format == AV_PIX_FMT_YUVJ420P || +- m_hints.colorRange == AVCOL_RANGE_JPEG; ++ pVideoPicture->color_range = ++ m_pFrame->color_range == AVCOL_RANGE_JPEG || m_pFrame->format == AV_PIX_FMT_YUVJ420P || ++ m_pFrame->format == AV_PIX_FMT_YUVJ422P || m_pFrame->format == AV_PIX_FMT_YUVJ444P || ++ m_hints.colorRange == AVCOL_RANGE_JPEG; + pVideoPicture->color_primaries = m_pFrame->color_primaries == AVCOL_PRI_UNSPECIFIED + ? m_hints.colorPrimaries + : m_pFrame->color_primaries; +-- +2.39.2 + diff --git a/projects/RPi/patches/kodi/0006-VideoBufferDMA-Support-exporting-YCbCr444-buffers.patch b/projects/RPi/patches/kodi/0006-VideoBufferDMA-Support-exporting-YCbCr444-buffers.patch new file mode 100644 index 0000000000..a76667adef --- /dev/null +++ b/projects/RPi/patches/kodi/0006-VideoBufferDMA-Support-exporting-YCbCr444-buffers.patch @@ -0,0 +1,55 @@ +From 7b820fa6812e8389613238c6ab3a12fc1dee0276 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Tue, 31 Jan 2023 14:13:00 +0000 +Subject: [PATCH 6/7] VideoBufferDMA: Support exporting YCbCr444 buffers + +The current code assumes chroma is decimated by two, but that is not necessarily the case. +DRMPRIME decode with EGL rendering of YCbCr444 video will have corrupted colours. + +Ask ffmpeg what the chroma decimation is. +--- + .../VideoPlayer/Buffers/VideoBufferDMA.cpp | 21 ++++++++++++------- + 1 file changed, 14 insertions(+), 7 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/Buffers/VideoBufferDMA.cpp b/xbmc/cores/VideoPlayer/Buffers/VideoBufferDMA.cpp +index 2dd7c1341d..3e6bf0dc7a 100644 +--- a/xbmc/cores/VideoPlayer/Buffers/VideoBufferDMA.cpp ++++ b/xbmc/cores/VideoPlayer/Buffers/VideoBufferDMA.cpp +@@ -119,20 +119,27 @@ bool CVideoBufferDMA::Alloc() + + void CVideoBufferDMA::Export(AVFrame* frame, uint32_t width, uint32_t height) + { +- m_planes = av_pix_fmt_count_planes(static_cast(frame->format)); ++ AVPixelFormat pix_fmt = static_cast(frame->format); ++ m_planes = av_pix_fmt_count_planes(pix_fmt); ++ int h_shift; ++ int v_shift; + +- if (m_planes < 2) +- throw std::runtime_error( +- "non-planar formats not supported: " + +- std::string(av_get_pix_fmt_name(static_cast(frame->format)))); ++ if (av_pix_fmt_get_chroma_sub_sample(pix_fmt, &h_shift, &v_shift)) ++ throw std::runtime_error("unable to determine chroma_sub_sample: " + ++ std::string(av_get_pix_fmt_name(pix_fmt))); ++ ++ if (m_planes < 2 || m_planes > 3) ++ throw std::runtime_error("only 2 or 3 plane formats supported: " + ++ std::string(av_get_pix_fmt_name(pix_fmt))); + + for (uint32_t plane = 0; plane < m_planes; plane++) + { + m_strides[plane] = + av_image_get_linesize(static_cast(frame->format), width, plane); +- m_offsets[plane] = +- plane == 0 ? 0 : (m_offsets[plane - 1] + m_strides[plane - 1] * (height >> (plane - 1))); + } ++ m_offsets[0] = 0; ++ m_offsets[1] = m_strides[0] * height; ++ m_offsets[2] = m_offsets[1] + (m_strides[1] * height >> v_shift); + + if (CServiceBroker::GetLogging().CanLogComponent(LOGVIDEO)) + { +-- +2.39.2 + diff --git a/projects/RPi/patches/kodi/0007-DVDVideoCodecDRMPRIME-Add-support-for-arbitrary-outp.patch b/projects/RPi/patches/kodi/0007-DVDVideoCodecDRMPRIME-Add-support-for-arbitrary-outp.patch new file mode 100644 index 0000000000..219c7f5974 --- /dev/null +++ b/projects/RPi/patches/kodi/0007-DVDVideoCodecDRMPRIME-Add-support-for-arbitrary-outp.patch @@ -0,0 +1,332 @@ +From ae91030c1a84693fd0d34b919f9f8434b08e00c9 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Mon, 6 Feb 2023 15:19:51 +0000 +Subject: [PATCH 7/7] DVDVideoCodecDRMPRIME: Add support for arbitrary output + pixel formats + +This enables any ffmpeg pixel formats to be supported by DRMPRIME decoder +by creating a scale ffmpeg filter to convert it to a supported format. + +This allows formats like h264 Hi10P and hevc 12-bit 444 to be software decoded, +converted and displayed through DRM. + +This will be a cheaper path than disabling DRMPRIME, which is also +software decode, convert, but then needs convert to texture and display through GL. + +And it happens automatically without requiring user video settings +--- + .../DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp | 124 +++++++++++------- + .../DVDCodecs/Video/DVDVideoCodecDRMPRIME.h | 3 +- + 2 files changed, 77 insertions(+), 50 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +index 4af903ecf5..92a182608d 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +@@ -199,7 +199,7 @@ enum AVPixelFormat CDVDVideoCodecDRMPRIME::GetFormat(struct AVCodecContext* avct + { + for (int n = 0; fmt[n] != AV_PIX_FMT_NONE; n++) + { +- if (IsSupportedHwFormat(fmt[n]) || IsSupportedSwFormat(fmt[n])) ++ //if (IsSupportedHwFormat(fmt[n]) || IsSupportedSwFormat(fmt[n])) + { + CDVDVideoCodecDRMPRIME* ctx = static_cast(avctx->opaque); + ctx->UpdateProcessInfo(avctx, fmt[n]); +@@ -220,7 +220,8 @@ enum AVPixelFormat CDVDVideoCodecDRMPRIME::GetFormat(struct AVCodecContext* avct + + int CDVDVideoCodecDRMPRIME::GetBuffer(struct AVCodecContext* avctx, AVFrame* frame, int flags) + { +- if (IsSupportedSwFormat(static_cast(frame->format))) ++ AVPixelFormat pix_fmt = static_cast(frame->format); ++ if (IsSupportedSwFormat(pix_fmt)) + { + int width = frame->width; + int height = frame->height; +@@ -228,7 +229,7 @@ int CDVDVideoCodecDRMPRIME::GetBuffer(struct AVCodecContext* avctx, AVFrame* fra + AlignedSize(avctx, width, height); + + int size; +- switch (avctx->pix_fmt) ++ switch (pix_fmt) + { + case AV_PIX_FMT_YUV420P: + case AV_PIX_FMT_YUVJ420P: +@@ -248,13 +249,12 @@ int CDVDVideoCodecDRMPRIME::GetBuffer(struct AVCodecContext* avctx, AVFrame* fra + + CDVDVideoCodecDRMPRIME* ctx = static_cast(avctx->opaque); + auto buffer = dynamic_cast( +- ctx->m_processInfo.GetVideoBufferManager().Get(avctx->pix_fmt, size, nullptr)); ++ ctx->m_processInfo.GetVideoBufferManager().Get(pix_fmt, size, nullptr)); + if (!buffer) + return -1; + +- frame->opaque = static_cast(buffer); + frame->opaque_ref = +- av_buffer_create(nullptr, 0, ReleaseBuffer, frame->opaque, AV_BUFFER_FLAG_READONLY); ++ av_buffer_create(nullptr, 0, ReleaseBuffer, static_cast(buffer), AV_BUFFER_FLAG_READONLY); + + buffer->Export(frame, width, height); + buffer->SyncStart(); +@@ -608,9 +608,9 @@ bool CDVDVideoCodecDRMPRIME::SetPictureParams(VideoPicture* pVideoPicture) + buffer->SetRef(m_pFrame); + pVideoPicture->videoBuffer = buffer; + } +- else if (m_pFrame->opaque) ++ else if (IsSupportedSwFormat(static_cast(m_pFrame->format))) + { +- CVideoBufferDMA* buffer = static_cast(m_pFrame->opaque); ++ CVideoBufferDMA* buffer = static_cast(av_buffer_get_opaque(m_pFrame->buf[0])); + buffer->SetPictureParams(*pVideoPicture); + buffer->Acquire(); + buffer->SyncEnd(); +@@ -644,13 +644,13 @@ void CDVDVideoCodecDRMPRIME::FilterTest() + + if (name.find("deinterlace") != std::string::npos) + { +- if (FilterOpen(name, true)) ++ bool ret = FilterOpen(name, false, true); ++ FilterClose(); ++ if (ret) + { + m_deintFilterName = name; +- + CLog::Log(LOGDEBUG, "CDVDVideoCodecDRMPRIME::{} - found deinterlacing filter {}", + __FUNCTION__, name); +- + return; + } + } +@@ -660,14 +660,31 @@ void CDVDVideoCodecDRMPRIME::FilterTest() + __FUNCTION__); + } + +-bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test) ++AVFrame *CDVDVideoCodecDRMPRIME::alloc_filter_frame(AVFilterContext * ctx, void * v, int w, int h) ++{ ++ int result; ++ CDVDVideoCodecDRMPRIME* me = static_cast(v); ++ AVFrame *frame = av_frame_alloc(); ++ frame->width = w; ++ frame->height = h; ++ frame->format = AV_PIX_FMT_YUV420P; ++ ++ if ((result = CDVDVideoCodecDRMPRIME::GetBuffer(me->m_pCodecContext, frame, 0)) < 0) ++ { ++ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::alloc_filter_frame - failed to GetBuffer ({})", result); ++ return nullptr; ++ } ++ return frame; ++} ++ ++bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool scale, bool test) + { + int result; + + if (m_pFilterGraph) + FilterClose(); + +- if (filters.empty()) ++ if (filters.empty() && !scale) + return true; + + if (!(m_pFilterGraph = avfilter_graph_alloc())) +@@ -678,13 +695,13 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test) + + const AVFilter* srcFilter = avfilter_get_by_name("buffer"); + const AVFilter* outFilter = avfilter_get_by_name("buffersink"); +- enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_DRM_PRIME, AV_PIX_FMT_NONE }; ++ enum AVPixelFormat pix_fmts[] = { scale ? AV_PIX_FMT_YUV420P : AV_PIX_FMT_DRM_PRIME, AV_PIX_FMT_NONE }; + + std::string args = StringUtils::Format("video_size={}x{}:pix_fmt={}:time_base={}/{}:" + "pixel_aspect={}/{}", + m_pCodecContext->width, + m_pCodecContext->height, +- AV_PIX_FMT_DRM_PRIME, ++ scale ? m_pCodecContext->pix_fmt : AV_PIX_FMT_DRM_PRIME, + m_pCodecContext->time_base.num ? + m_pCodecContext->time_base.num : 1, + m_pCodecContext->time_base.num ? +@@ -703,7 +720,6 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test) + CLog::Log(LOGERROR, + "CDVDVideoCodecDRMPRIME::FilterOpen - avfilter_graph_create_filter: src: {} ({})", + err, result); +- FilterClose(); + return false; + } + +@@ -711,7 +727,6 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test) + if (!par) + { + CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - unable to alloc buffersrc"); +- FilterClose(); + return false; + } + +@@ -727,7 +742,6 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test) + CLog::Log(LOGERROR, + "CDVDVideoCodecDRMPRIME::FilterOpen - av_buffersrc_parameters_set: {} ({})", + err, result); +- FilterClose(); + return false; + } + av_freep(&par); +@@ -741,7 +755,6 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test) + CLog::Log(LOGERROR, + "CDVDVideoCodecDRMPRIME::FilterOpen - avfilter_graph_create_filter: out: {} ({})", + err, result); +- FilterClose(); + return false; + } + +@@ -750,32 +763,46 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test) + if (result < 0) + { + CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - failed settings pix formats"); +- FilterClose(); + return false; + } + +- AVFilterInOut* outputs = avfilter_inout_alloc(); +- AVFilterInOut* inputs = avfilter_inout_alloc(); ++ if (!filters.empty()) ++ { ++ AVFilterInOut* outputs = avfilter_inout_alloc(); ++ AVFilterInOut* inputs = avfilter_inout_alloc(); + +- outputs->name = av_strdup("in"); +- outputs->filter_ctx = m_pFilterIn; +- outputs->pad_idx = 0; +- outputs->next = nullptr; ++ outputs->name = av_strdup("in"); ++ outputs->filter_ctx = m_pFilterIn; ++ outputs->pad_idx = 0; ++ outputs->next = nullptr; + +- inputs->name = av_strdup("out"); +- inputs->filter_ctx = m_pFilterOut; +- inputs->pad_idx = 0; +- inputs->next = nullptr; ++ inputs->name = av_strdup("out"); ++ inputs->filter_ctx = m_pFilterOut; ++ inputs->pad_idx = 0; ++ inputs->next = nullptr; + +- result = avfilter_graph_parse_ptr(m_pFilterGraph, filters.c_str(), &inputs, &outputs, NULL); +- avfilter_inout_free(&outputs); +- avfilter_inout_free(&inputs); ++ result = avfilter_graph_parse_ptr(m_pFilterGraph, filters.c_str(), &inputs, &outputs, NULL); ++ avfilter_inout_free(&outputs); ++ avfilter_inout_free(&inputs); + +- if (result < 0) ++ if (result < 0) ++ { ++ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - avfilter_graph_parse"); ++ return false; ++ } ++ } ++ else + { +- CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - avfilter_graph_parse"); +- FilterClose(); +- return false; ++ if ((result = av_buffersink_set_alloc_video_frame(m_pFilterOut, alloc_filter_frame, static_cast(this))) < 0) ++ { ++ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - av_buffersink_set_alloc_video_frame = {}", result); ++ return result; ++ } ++ if ((result = avfilter_link(m_pFilterIn, 0, m_pFilterOut, 0)) < 0) ++ { ++ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - avfilter_link"); ++ return false; ++ } + } + + if ((result = avfilter_graph_config(m_pFilterGraph, nullptr)) < 0) +@@ -784,15 +811,11 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test) + av_strerror(result, err, AV_ERROR_MAX_STRING_SIZE); + CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - avfilter_graph_config: {} ({})", + err, result); +- FilterClose(); + return false; + } + + if (test) +- { +- FilterClose(); + return true; +- } + + m_processInfo.SetVideoDeintMethod(filters); + +@@ -827,16 +850,16 @@ void CDVDVideoCodecDRMPRIME::FilterClose() + CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::ProcessFilterIn() + { + // sw decoded buffers need cache flush and for descripter to be set +- if (!IsSupportedHwFormat(static_cast(m_pFrame->format)) && m_pFrame->opaque != nullptr) ++ if (!IsSupportedHwFormat(static_cast(m_pFrame->format)) && IsSupportedSwFormat(static_cast(m_pFrame->format))) + { +- CVideoBufferDMA* buffer = static_cast(m_pFrame->opaque); ++ CVideoBufferDMA* buffer = static_cast(av_buffer_get_opaque(m_pFrame->buf[0])); + buffer->SetDimensions(m_pFrame->width, m_pFrame->height); + buffer->SyncEnd(); + auto descriptor = buffer->GetDescriptor(); + m_pFrame->data[0] = reinterpret_cast(descriptor); ++ m_pFrame->format = AV_PIX_FMT_DRM_PRIME; + } + +- m_pFrame->format = AV_PIX_FMT_DRM_PRIME; + int ret = av_buffersrc_add_frame(m_pFilterIn, m_pFrame); + if (ret < 0) + { +@@ -929,25 +952,28 @@ CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::GetPicture(VideoPicture* pVideo + return VC_ERROR; + } + ++ // we need to scale if the buffer isn't in DRM_PRIME format ++ bool need_scale = !IsSupportedSwFormat(static_cast(m_pFrame->format)) && !IsSupportedHwFormat(static_cast(m_pFrame->format)); ++ + if (!m_processInfo.GetVideoInterlaced() && m_pFrame->interlaced_frame) + m_processInfo.SetVideoInterlaced(true); + + std::string filterChain = GetFilterChain(m_pFrame->interlaced_frame); +- if (!filterChain.empty()) ++ if (!filterChain.empty() || need_scale) + { + bool reopenFilter = false; + if (m_filters != filterChain) + reopenFilter = true; + + if (m_pFilterGraph && +- (m_pFilterIn->outputs[0]->w != m_pCodecContext->width || +- m_pFilterIn->outputs[0]->h != m_pCodecContext->height)) ++ (m_pFilterIn->outputs[0]->w != m_pFrame->width || ++ m_pFilterIn->outputs[0]->h != m_pFrame->height)) + reopenFilter = true; + +- if (reopenFilter) ++ if (reopenFilter || (need_scale && m_pFilterGraph == nullptr)) + { + m_filters = filterChain; +- if (!FilterOpen(filterChain, false)) ++ if (!FilterOpen(filterChain, need_scale, false)) + FilterClose(); + } + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h +index fab3431d40..bb88fde1f9 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h +@@ -44,7 +44,8 @@ protected: + CDVDVideoCodec::VCReturn ProcessFilterOut(); + static enum AVPixelFormat GetFormat(struct AVCodecContext* avctx, const enum AVPixelFormat* fmt); + static int GetBuffer(struct AVCodecContext* avctx, AVFrame* frame, int flags); +- bool FilterOpen(const std::string& filters, bool test); ++ static AVFrame *alloc_filter_frame(AVFilterContext * ctx, void * v, int w, int h); ++ bool FilterOpen(const std::string& filters, bool scale, bool test); + void FilterClose(); + void FilterTest(); + std::string GetFilterChain(bool interlaced); +-- +2.39.2 + diff --git a/tools/ffmpeg/gen-patches.sh b/tools/ffmpeg/gen-patches.sh index 1d786f2bda..c78c0a09b4 100755 --- a/tools/ffmpeg/gen-patches.sh +++ b/tools/ffmpeg/gen-patches.sh @@ -46,7 +46,7 @@ create_patch() { ;; rpi) REPO="https://github.com/jc-kynesim/rpi-ffmpeg" - REFSPEC="dev/4.4/rpi_import_1" + REFSPEC="test/4.4.1/main" PATCH_CREATE_DIFF="yes" ;; kodi)