[FFmpeg-devel] [PATCH v2 5/8] avcodec: Add V4L2 Request API mpeg2 hwaccel

Jonas Karlman jonas at kwiboo.se
Tue Aug 6 12:06:04 EEST 2024


Add a V4L2 Request API hwaccel for MPEG2.

Support for MPEG2 is enabled when Linux kernel headers declare the
control id V4L2_CID_STATELESS_MPEG2_SEQUENCE, added in v5.14.

This also change v4l2_request hwaccel to use autodetect in configure.

Signed-off-by: Jonas Karlman <jonas at kwiboo.se>
---
 configure                       |   7 +-
 libavcodec/Makefile             |   1 +
 libavcodec/hwaccels.h           |   1 +
 libavcodec/mpeg12dec.c          |   6 ++
 libavcodec/v4l2_request_mpeg2.c | 176 ++++++++++++++++++++++++++++++++
 5 files changed, 189 insertions(+), 2 deletions(-)
 create mode 100644 libavcodec/v4l2_request_mpeg2.c

diff --git a/configure b/configure
index af6d12f7bb..35e33a8409 100755
--- a/configure
+++ b/configure
@@ -358,7 +358,7 @@ External library support:
   --enable-omx-rpi         enable OpenMAX IL code for Raspberry Pi [no]
   --enable-rkmpp           enable Rockchip Media Process Platform code [no]
   --disable-v4l2-m2m       disable V4L2 mem2mem code [autodetect]
-  --enable-v4l2-request    enable V4L2 Request API code [no]
+  --disable-v4l2-request   disable V4L2 Request API code [autodetect]
   --disable-vaapi          disable Video Acceleration API (mainly Unix/Intel) code [autodetect]
   --disable-vdpau          disable Nvidia Video Decode and Presentation API for Unix code [autodetect]
   --disable-videotoolbox   disable VideoToolbox code [autodetect]
@@ -2004,6 +2004,7 @@ HWACCEL_AUTODETECT_LIBRARY_LIST="
     videotoolbox
     vulkan
     v4l2_m2m
+    v4l2_request
 "
 
 # catchall list of things that require external libs to link
@@ -2025,7 +2026,6 @@ HWACCEL_LIBRARY_LIST="
     mmal
     omx
     opencl
-    v4l2_request
 "
 
 DOCUMENT_LIST="
@@ -3234,6 +3234,8 @@ mpeg2_dxva2_hwaccel_deps="dxva2"
 mpeg2_dxva2_hwaccel_select="mpeg2video_decoder"
 mpeg2_nvdec_hwaccel_deps="nvdec"
 mpeg2_nvdec_hwaccel_select="mpeg2video_decoder"
+mpeg2_v4l2request_hwaccel_deps="v4l2_request mpeg2_v4l2_request"
+mpeg2_v4l2request_hwaccel_select="mpeg2video_decoder"
 mpeg2_vaapi_hwaccel_deps="vaapi"
 mpeg2_vaapi_hwaccel_select="mpeg2video_decoder"
 mpeg2_vdpau_hwaccel_deps="vdpau"
@@ -7177,6 +7179,7 @@ if enabled v4l2_m2m; then
 fi
 
 if enabled v4l2_request; then
+    check_cc mpeg2_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_MPEG2_SEQUENCE"
     check_cc v4l2_m2m_hold_capture_buf linux/videodev2.h "int i = V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF"
     check_func_headers "linux/media.h linux/videodev2.h" v4l2_timeval_to_ns
     check_pkg_config libudev libudev libudev.h udev_new
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 590d2e3bc2..5c51818d0d 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1031,6 +1031,7 @@ OBJS-$(CONFIG_MPEG2_DXVA2_HWACCEL)        += dxva2_mpeg2.o
 OBJS-$(CONFIG_MPEG2_D3D12VA_HWACCEL)      += dxva2_mpeg2.o d3d12va_mpeg2.o
 OBJS-$(CONFIG_MPEG2_NVDEC_HWACCEL)        += nvdec_mpeg12.o
 OBJS-$(CONFIG_MPEG2_QSV_HWACCEL)          += qsvdec.o
+OBJS-$(CONFIG_MPEG2_V4L2REQUEST_HWACCEL)  += v4l2_request_mpeg2.o
 OBJS-$(CONFIG_MPEG2_VAAPI_HWACCEL)        += vaapi_mpeg2.o
 OBJS-$(CONFIG_MPEG2_VDPAU_HWACCEL)        += vdpau_mpeg12.o
 OBJS-$(CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o
diff --git a/libavcodec/hwaccels.h b/libavcodec/hwaccels.h
index 5171e4c7d7..0cba7c71be 100644
--- a/libavcodec/hwaccels.h
+++ b/libavcodec/hwaccels.h
@@ -57,6 +57,7 @@ extern const struct FFHWAccel ff_mpeg2_d3d11va2_hwaccel;
 extern const struct FFHWAccel ff_mpeg2_d3d12va_hwaccel;
 extern const struct FFHWAccel ff_mpeg2_dxva2_hwaccel;
 extern const struct FFHWAccel ff_mpeg2_nvdec_hwaccel;
+extern const struct FFHWAccel ff_mpeg2_v4l2request_hwaccel;
 extern const struct FFHWAccel ff_mpeg2_vaapi_hwaccel;
 extern const struct FFHWAccel ff_mpeg2_vdpau_hwaccel;
 extern const struct FFHWAccel ff_mpeg2_videotoolbox_hwaccel;
diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c
index 4f784611de..af8ffa5976 100644
--- a/libavcodec/mpeg12dec.c
+++ b/libavcodec/mpeg12dec.c
@@ -839,6 +839,9 @@ static const enum AVPixelFormat mpeg2_hwaccel_pixfmt_list_420[] = {
 #endif
 #if CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL
     AV_PIX_FMT_VIDEOTOOLBOX,
+#endif
+#if CONFIG_MPEG2_V4L2REQUEST_HWACCEL
+    AV_PIX_FMT_DRM_PRIME,
 #endif
     AV_PIX_FMT_YUV420P,
     AV_PIX_FMT_NONE
@@ -2681,6 +2684,9 @@ const FFCodec ff_mpeg2video_decoder = {
 #endif
 #if CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL
                         HWACCEL_VIDEOTOOLBOX(mpeg2),
+#endif
+#if CONFIG_MPEG2_V4L2REQUEST_HWACCEL
+                        HWACCEL_V4L2REQUEST(mpeg2),
 #endif
                         NULL
                     },
diff --git a/libavcodec/v4l2_request_mpeg2.c b/libavcodec/v4l2_request_mpeg2.c
new file mode 100644
index 0000000000..998c91355a
--- /dev/null
+++ b/libavcodec/v4l2_request_mpeg2.c
@@ -0,0 +1,176 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include "hwaccel_internal.h"
+#include "hwconfig.h"
+#include "mpegvideo.h"
+#include "v4l2_request.h"
+
+typedef struct V4L2RequestControlsMPEG2 {
+    V4L2RequestPictureContext pic;
+    struct v4l2_ctrl_mpeg2_sequence sequence;
+    struct v4l2_ctrl_mpeg2_picture picture;
+    struct v4l2_ctrl_mpeg2_quantisation quantisation;
+} V4L2RequestControlsMPEG2;
+
+static int v4l2_request_mpeg2_start_frame(AVCodecContext *avctx,
+                                          av_unused const uint8_t *buffer,
+                                          av_unused uint32_t size)
+{
+    const MpegEncContext *s = avctx->priv_data;
+    V4L2RequestControlsMPEG2 *controls = s->cur_pic.ptr->hwaccel_picture_private;
+    int ret;
+
+    ret = ff_v4l2_request_start_frame(avctx, &controls->pic, s->cur_pic.ptr->f);
+    if (ret)
+        return ret;
+
+    controls->sequence = (struct v4l2_ctrl_mpeg2_sequence) {
+        /* ISO/IEC 13818-2, ITU-T Rec. H.262: Sequence header */
+        .horizontal_size = s->width,
+        .vertical_size = s->height,
+        .vbv_buffer_size = controls->pic.output->size,
+
+        /* ISO/IEC 13818-2, ITU-T Rec. H.262: Sequence extension */
+        .profile_and_level_indication = 0,
+        .chroma_format = s->chroma_format,
+    };
+
+    if (s->progressive_sequence)
+        controls->sequence.flags |= V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE;
+
+    controls->picture = (struct v4l2_ctrl_mpeg2_picture) {
+        /* ISO/IEC 13818-2, ITU-T Rec. H.262: Picture header */
+        .picture_coding_type = s->pict_type,
+
+        /* ISO/IEC 13818-2, ITU-T Rec. H.262: Picture coding extension */
+        .f_code[0][0] = s->mpeg_f_code[0][0],
+        .f_code[0][1] = s->mpeg_f_code[0][1],
+        .f_code[1][0] = s->mpeg_f_code[1][0],
+        .f_code[1][1] = s->mpeg_f_code[1][1],
+        .picture_structure = s->picture_structure,
+        .intra_dc_precision = s->intra_dc_precision,
+    };
+
+    if (s->top_field_first)
+        controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST;
+
+    if (s->frame_pred_frame_dct)
+        controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT;
+
+    if (s->concealment_motion_vectors)
+        controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV;
+
+    if (s->intra_vlc_format)
+        controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_INTRA_VLC;
+
+    if (s->q_scale_type)
+        controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE;
+
+    if (s->alternate_scan)
+        controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_ALT_SCAN;
+
+    if (s->repeat_first_field)
+        controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_REPEAT_FIRST;
+
+    if (s->progressive_frame)
+        controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_PROGRESSIVE;
+
+    switch (s->pict_type) {
+    case AV_PICTURE_TYPE_B:
+        if (s->next_pic.ptr)
+            controls->picture.backward_ref_ts =
+                ff_v4l2_request_get_capture_timestamp(s->next_pic.ptr->f);
+        // fall-through
+    case AV_PICTURE_TYPE_P:
+        if (s->last_pic.ptr)
+            controls->picture.forward_ref_ts =
+                ff_v4l2_request_get_capture_timestamp(s->last_pic.ptr->f);
+    }
+
+    for (int i = 0; i < 64; i++) {
+        int n = s->idsp.idct_permutation[ff_zigzag_direct[i]];
+        controls->quantisation.intra_quantiser_matrix[i] = s->intra_matrix[n];
+        controls->quantisation.non_intra_quantiser_matrix[i] = s->inter_matrix[n];
+        controls->quantisation.chroma_intra_quantiser_matrix[i] = s->chroma_intra_matrix[n];
+        controls->quantisation.chroma_non_intra_quantiser_matrix[i] = s->chroma_inter_matrix[n];
+    }
+
+    return 0;
+}
+
+static int v4l2_request_mpeg2_decode_slice(AVCodecContext *avctx,
+                                           const uint8_t *buffer, uint32_t size)
+{
+    const MpegEncContext *s = avctx->priv_data;
+    V4L2RequestControlsMPEG2 *controls = s->cur_pic.ptr->hwaccel_picture_private;
+
+    return ff_v4l2_request_append_output(avctx, &controls->pic, buffer, size);
+}
+
+static int v4l2_request_mpeg2_end_frame(AVCodecContext *avctx)
+{
+    const MpegEncContext *s = avctx->priv_data;
+    V4L2RequestControlsMPEG2 *controls = s->cur_pic.ptr->hwaccel_picture_private;
+
+    struct v4l2_ext_control control[] = {
+        {
+            .id = V4L2_CID_STATELESS_MPEG2_SEQUENCE,
+            .ptr = &controls->sequence,
+            .size = sizeof(controls->sequence),
+        },
+        {
+            .id = V4L2_CID_STATELESS_MPEG2_PICTURE,
+            .ptr = &controls->picture,
+            .size = sizeof(controls->picture),
+        },
+        {
+            .id = V4L2_CID_STATELESS_MPEG2_QUANTISATION,
+            .ptr = &controls->quantisation,
+            .size = sizeof(controls->quantisation),
+        },
+    };
+
+    return ff_v4l2_request_decode_frame(avctx, &controls->pic,
+                                        control, FF_ARRAY_ELEMS(control));
+}
+
+static int v4l2_request_mpeg2_init(AVCodecContext *avctx)
+{
+    return ff_v4l2_request_init(avctx, V4L2_PIX_FMT_MPEG2_SLICE,
+                                1024 * 1024,
+                                NULL, 0);
+}
+
+const FFHWAccel ff_mpeg2_v4l2request_hwaccel = {
+    .p.name             = "mpeg2_v4l2request",
+    .p.type             = AVMEDIA_TYPE_VIDEO,
+    .p.id               = AV_CODEC_ID_MPEG2VIDEO,
+    .p.pix_fmt          = AV_PIX_FMT_DRM_PRIME,
+    .start_frame        = v4l2_request_mpeg2_start_frame,
+    .decode_slice       = v4l2_request_mpeg2_decode_slice,
+    .end_frame          = v4l2_request_mpeg2_end_frame,
+    .flush              = ff_v4l2_request_flush,
+    .frame_priv_data_size = sizeof(V4L2RequestControlsMPEG2),
+    .init               = v4l2_request_mpeg2_init,
+    .uninit             = ff_v4l2_request_uninit,
+    .priv_data_size     = sizeof(V4L2RequestContext),
+    .frame_params       = ff_v4l2_request_frame_params,
+};
-- 
2.45.2



More information about the ffmpeg-devel mailing list