Merge pull request #7689 from HiassofT/le11-rpi-h264-hi10-fix

[le11] RPi: fix playback of 10bit H264 files
This commit is contained in:
CvH 2023-03-27 10:57:13 +02:00 committed by GitHub
commit 08665f1c32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 822 additions and 72 deletions

View File

@ -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 <linux/videodev2.h>
#include <sys/ioctl.h>
+
@ -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)

View File

@ -1,7 +1,7 @@
From 97d39a46091b65e4355ce7e545bdec46ff2f87de Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
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

View File

@ -1,7 +1,7 @@
From 42b30508bfe5451d4dc2884acfde9e0ec2d58c92 Mon Sep 17 00:00:00 2001
From: Dom Cobley <popcornmix@gmail.com>
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

View File

@ -1,7 +1,7 @@
From 0b9b204c6560f3aff39697f92616b48102840dfe Mon Sep 17 00:00:00 2001
From: Lukas Rusak <lorusak@gmail.com>
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

View File

@ -1,7 +1,7 @@
From 518d8487d090af854fb72a7d0e5efc075d97228c Mon Sep 17 00:00:00 2001
From: Dom Cobley <popcornmix@gmail.com>
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

View File

@ -0,0 +1,93 @@
From a11461db2d442e0648ebb9255a2399a647d8f5be Mon Sep 17 00:00:00 2001
From: Dom Cobley <popcornmix@gmail.com>
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<std::string> 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<int>(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

View File

@ -0,0 +1,55 @@
From 7b820fa6812e8389613238c6ab3a12fc1dee0276 Mon Sep 17 00:00:00 2001
From: Dom Cobley <popcornmix@gmail.com>
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<AVPixelFormat>(frame->format));
+ AVPixelFormat pix_fmt = static_cast<AVPixelFormat>(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<AVPixelFormat>(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<AVPixelFormat>(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

View File

@ -0,0 +1,332 @@
From ae91030c1a84693fd0d34b919f9f8434b08e00c9 Mon Sep 17 00:00:00 2001
From: Dom Cobley <popcornmix@gmail.com>
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<CDVDVideoCodecDRMPRIME*>(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<AVPixelFormat>(frame->format)))
+ AVPixelFormat pix_fmt = static_cast<AVPixelFormat>(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<CDVDVideoCodecDRMPRIME*>(avctx->opaque);
auto buffer = dynamic_cast<CVideoBufferDMA*>(
- 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<void*>(buffer);
frame->opaque_ref =
- av_buffer_create(nullptr, 0, ReleaseBuffer, frame->opaque, AV_BUFFER_FLAG_READONLY);
+ av_buffer_create(nullptr, 0, ReleaseBuffer, static_cast<void*>(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<AVPixelFormat>(m_pFrame->format)))
{
- CVideoBufferDMA* buffer = static_cast<CVideoBufferDMA*>(m_pFrame->opaque);
+ CVideoBufferDMA* buffer = static_cast<CVideoBufferDMA*>(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<CDVDVideoCodecDRMPRIME*>(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<void*>(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<AVPixelFormat>(m_pFrame->format)) && m_pFrame->opaque != nullptr)
+ if (!IsSupportedHwFormat(static_cast<AVPixelFormat>(m_pFrame->format)) && IsSupportedSwFormat(static_cast<AVPixelFormat>(m_pFrame->format)))
{
- CVideoBufferDMA* buffer = static_cast<CVideoBufferDMA*>(m_pFrame->opaque);
+ CVideoBufferDMA* buffer = static_cast<CVideoBufferDMA*>(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<uint8_t*>(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<AVPixelFormat>(m_pFrame->format)) && !IsSupportedHwFormat(static_cast<AVPixelFormat>(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

View File

@ -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)