Browse code

avcodec: Implement mpeg2 nvdec hwaccel

This is mostly straight-forward. The weird part is that it should
just work for mpeg1, but I see corruption in my test cases, so I'm
going to try and fix that separately.

Philip Langdale authored on 2017/11/17 00:35:17
Showing 8 changed files
... ...
@@ -13,7 +13,7 @@ version <next>:
13 13
 - PCE support for extended channel layouts in the AAC encoder
14 14
 - native aptX encoder and decoder
15 15
 - Raw aptX muxer and demuxer
16
-- NVIDIA NVDEC-accelerated H.264, HEVC, VC1 and VP9 hwaccel decoding
16
+- NVIDIA NVDEC-accelerated H.264, HEVC, MPEG-2, VC1 and VP9 hwaccel decoding
17 17
 - Intel QSV-accelerated overlay filter
18 18
 - mcompand audio filter
19 19
 
... ...
@@ -2713,6 +2713,8 @@ mpeg2_dxva2_hwaccel_deps="dxva2"
2713 2713
 mpeg2_dxva2_hwaccel_select="mpeg2video_decoder"
2714 2714
 mpeg2_mediacodec_hwaccel_deps="mediacodec"
2715 2715
 mpeg2_mmal_hwaccel_deps="mmal"
2716
+mpeg2_nvdec_hwaccel_deps="nvdec"
2717
+mpeg2_nvdec_hwaccel_select="mpeg2video_decoder"
2716 2718
 mpeg2_qsv_hwaccel_deps="libmfx"
2717 2719
 mpeg2_vaapi_hwaccel_deps="vaapi"
2718 2720
 mpeg2_vaapi_hwaccel_select="mpeg2video_decoder"
... ...
@@ -854,6 +854,7 @@ OBJS-$(CONFIG_MPEG1_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o
854 854
 OBJS-$(CONFIG_MPEG1_XVMC_HWACCEL)         += mpegvideo_xvmc.o
855 855
 OBJS-$(CONFIG_MPEG2_D3D11VA_HWACCEL)      += dxva2_mpeg2.o
856 856
 OBJS-$(CONFIG_MPEG2_DXVA2_HWACCEL)        += dxva2_mpeg2.o
857
+OBJS-$(CONFIG_MPEG2_NVDEC_HWACCEL)        += nvdec_mpeg12.o
857 858
 OBJS-$(CONFIG_MPEG2_QSV_HWACCEL)          += qsvdec_other.o
858 859
 OBJS-$(CONFIG_MPEG2_VAAPI_HWACCEL)        += vaapi_mpeg2.o
859 860
 OBJS-$(CONFIG_MPEG2_VDPAU_HWACCEL)        += vdpau_mpeg12.o
... ...
@@ -96,6 +96,7 @@ static void register_all(void)
96 96
     REGISTER_HWACCEL(MPEG2_D3D11VA2,    mpeg2_d3d11va2);
97 97
     REGISTER_HWACCEL(MPEG2_DXVA2,       mpeg2_dxva2);
98 98
     REGISTER_HWACCEL(MPEG2_MMAL,        mpeg2_mmal);
99
+    REGISTER_HWACCEL(MPEG2_NVDEC,       mpeg2_nvdec);
99 100
     REGISTER_HWACCEL(MPEG2_QSV,         mpeg2_qsv);
100 101
     REGISTER_HWACCEL(MPEG2_VAAPI,       mpeg2_vaapi);
101 102
     REGISTER_HWACCEL(MPEG2_VDPAU,       mpeg2_vdpau);
... ...
@@ -1141,6 +1141,9 @@ static const enum AVPixelFormat mpeg1_hwaccel_pixfmt_list_420[] = {
1141 1141
 };
1142 1142
 
1143 1143
 static const enum AVPixelFormat mpeg2_hwaccel_pixfmt_list_420[] = {
1144
+#if CONFIG_MPEG2_NVDEC_HWACCEL
1145
+    AV_PIX_FMT_CUDA,
1146
+#endif
1144 1147
 #if CONFIG_MPEG2_XVMC_HWACCEL
1145 1148
     AV_PIX_FMT_XVMC,
1146 1149
 #endif
... ...
@@ -52,11 +52,12 @@ typedef struct NVDECFramePool {
52 52
 static int map_avcodec_id(enum AVCodecID id)
53 53
 {
54 54
     switch (id) {
55
-    case AV_CODEC_ID_H264: return cudaVideoCodec_H264;
56
-    case AV_CODEC_ID_HEVC: return cudaVideoCodec_HEVC;
57
-    case AV_CODEC_ID_VC1:  return cudaVideoCodec_VC1;
58
-    case AV_CODEC_ID_VP9:  return cudaVideoCodec_VP9;
59
-    case AV_CODEC_ID_WMV3:  return cudaVideoCodec_VC1;
55
+    case AV_CODEC_ID_H264:       return cudaVideoCodec_H264;
56
+    case AV_CODEC_ID_HEVC:       return cudaVideoCodec_HEVC;
57
+    case AV_CODEC_ID_MPEG2VIDEO: return cudaVideoCodec_MPEG2;
58
+    case AV_CODEC_ID_VC1:        return cudaVideoCodec_VC1;
59
+    case AV_CODEC_ID_VP9:        return cudaVideoCodec_VP9;
60
+    case AV_CODEC_ID_WMV3:       return cudaVideoCodec_VC1;
60 61
     }
61 62
     return -1;
62 63
 }
63 64
new file mode 100644
... ...
@@ -0,0 +1,152 @@
0
+/*
1
+ * MPEG-2 HW decode acceleration through NVDEC
2
+ *
3
+ * Copyright (c) 2017 Philip Langdale
4
+ *
5
+ * This file is part of FFmpeg.
6
+ *
7
+ * FFmpeg is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * FFmpeg is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with FFmpeg; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ */
21
+
22
+#include "avcodec.h"
23
+#include "mpegvideo.h"
24
+#include "nvdec.h"
25
+#include "decode.h"
26
+
27
+static int get_ref_idx(AVFrame *frame)
28
+{
29
+    FrameDecodeData *fdd;
30
+    NVDECFrame *cf;
31
+
32
+    if (!frame || !frame->private_ref)
33
+        return -1;
34
+
35
+    fdd = (FrameDecodeData*)frame->private_ref->data;
36
+    cf  = (NVDECFrame*)fdd->hwaccel_priv;
37
+    if (!cf)
38
+        return -1;
39
+
40
+    return cf->idx;
41
+}
42
+
43
+static int nvdec_mpeg12_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)
44
+{
45
+    MpegEncContext *s = avctx->priv_data;
46
+
47
+    NVDECContext      *ctx = avctx->internal->hwaccel_priv_data;
48
+    CUVIDPICPARAMS     *pp = &ctx->pic_params;
49
+    CUVIDMPEG2PICPARAMS *ppc = &pp->CodecSpecific.mpeg2;
50
+    FrameDecodeData *fdd;
51
+    NVDECFrame *cf;
52
+    AVFrame *cur_frame = s->current_picture.f;
53
+
54
+    int ret, i;
55
+
56
+    ret = ff_nvdec_start_frame(avctx, cur_frame);
57
+    if (ret < 0)
58
+        return ret;
59
+
60
+    fdd = (FrameDecodeData*)cur_frame->private_ref->data;
61
+    cf  = (NVDECFrame*)fdd->hwaccel_priv;
62
+
63
+    *pp = (CUVIDPICPARAMS) {
64
+        .PicWidthInMbs     = (cur_frame->width  + 15) / 16,
65
+        .FrameHeightInMbs  = (cur_frame->height + 15) / 16,
66
+        .CurrPicIdx        = cf->idx,
67
+
68
+        .intra_pic_flag    = s->pict_type == AV_PICTURE_TYPE_I,
69
+        .ref_pic_flag      = s->pict_type == AV_PICTURE_TYPE_I ||
70
+                             s->pict_type == AV_PICTURE_TYPE_P,
71
+
72
+        .CodecSpecific.mpeg2 = {
73
+            .ForwardRefIdx     = get_ref_idx(s->last_picture.f),
74
+            .BackwardRefIdx    = get_ref_idx(s->next_picture.f),
75
+
76
+            .picture_coding_type        = s->pict_type,
77
+            .full_pel_forward_vector    = s->full_pel[0],
78
+            .full_pel_backward_vector   = s->full_pel[1],
79
+            .f_code                     = { { s->mpeg_f_code[0][0],
80
+                                              s->mpeg_f_code[0][1] },
81
+                                            { s->mpeg_f_code[1][0],
82
+                                              s->mpeg_f_code[1][1] } },
83
+            .intra_dc_precision         = s->intra_dc_precision,
84
+            .frame_pred_frame_dct       = s->frame_pred_frame_dct,
85
+            .concealment_motion_vectors = s->concealment_motion_vectors,
86
+            .q_scale_type               = s->q_scale_type,
87
+            .intra_vlc_format           = s->intra_vlc_format,
88
+            .alternate_scan             = s->alternate_scan,
89
+            .top_field_first            = s->top_field_first,
90
+        }
91
+    };
92
+
93
+    for (i = 0; i < 64; ++i) {
94
+        ppc->QuantMatrixIntra[i] = s->intra_matrix[i];
95
+        ppc->QuantMatrixInter[i] = s->inter_matrix[i];
96
+    }
97
+
98
+    return 0;
99
+}
100
+
101
+static int nvdec_mpeg12_end_frame(AVCodecContext *avctx)
102
+{
103
+    NVDECContext *ctx = avctx->internal->hwaccel_priv_data;
104
+    int ret = ff_nvdec_end_frame(avctx);
105
+    ctx->bitstream = NULL;
106
+    return ret;
107
+}
108
+
109
+static int nvdec_mpeg12_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)
110
+{
111
+    NVDECContext *ctx = avctx->internal->hwaccel_priv_data;
112
+    void *tmp;
113
+
114
+    tmp = av_fast_realloc(ctx->slice_offsets, &ctx->slice_offsets_allocated,
115
+                          (ctx->nb_slices + 1) * sizeof(*ctx->slice_offsets));
116
+    if (!tmp)
117
+        return AVERROR(ENOMEM);
118
+    ctx->slice_offsets = tmp;
119
+
120
+    if (!ctx->bitstream)
121
+        ctx->bitstream = (uint8_t*)buffer;
122
+
123
+    ctx->slice_offsets[ctx->nb_slices] = buffer - ctx->bitstream;
124
+    ctx->bitstream_len += size;
125
+    ctx->nb_slices++;
126
+
127
+    return 0;
128
+}
129
+
130
+static int nvdec_mpeg12_frame_params(AVCodecContext *avctx,
131
+                                  AVBufferRef *hw_frames_ctx)
132
+{
133
+    // Each frame can at most have one P and one B reference
134
+    return ff_nvdec_frame_params(avctx, hw_frames_ctx, 2);
135
+}
136
+
137
+#if CONFIG_MPEG2_NVDEC_HWACCEL
138
+AVHWAccel ff_mpeg2_nvdec_hwaccel = {
139
+    .name                 = "mpeg2_nvdec",
140
+    .type                 = AVMEDIA_TYPE_VIDEO,
141
+    .id                   = AV_CODEC_ID_MPEG2VIDEO,
142
+    .pix_fmt              = AV_PIX_FMT_CUDA,
143
+    .start_frame          = nvdec_mpeg12_start_frame,
144
+    .end_frame            = nvdec_mpeg12_end_frame,
145
+    .decode_slice         = nvdec_mpeg12_decode_slice,
146
+    .frame_params         = nvdec_mpeg12_frame_params,
147
+    .init                 = ff_nvdec_decode_init,
148
+    .uninit               = ff_nvdec_decode_uninit,
149
+    .priv_data_size       = sizeof(NVDECContext),
150
+};
151
+#endif
... ...
@@ -29,7 +29,7 @@
29 29
 
30 30
 #define LIBAVCODEC_VERSION_MAJOR  58
31 31
 #define LIBAVCODEC_VERSION_MINOR   3
32
-#define LIBAVCODEC_VERSION_MICRO 102
32
+#define LIBAVCODEC_VERSION_MICRO 103
33 33
 
34 34
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
35 35
                                                LIBAVCODEC_VERSION_MINOR, \