1/*
2 * MPEG-1/2 HW decode acceleration through NVDEC
3 *
4 * Copyright (c) 2017 Philip Langdale
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include "config_components.h"
24
25#include "avcodec.h"
26#include "internal.h"
27#include "mpegvideo.h"
28#include "nvdec.h"
29#include "decode.h"
30
31static int nvdec_mpeg12_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)
32{
33    MpegEncContext *s = avctx->priv_data;
34
35    NVDECContext      *ctx = avctx->internal->hwaccel_priv_data;
36    CUVIDPICPARAMS     *pp = &ctx->pic_params;
37    CUVIDMPEG2PICPARAMS *ppc = &pp->CodecSpecific.mpeg2;
38    FrameDecodeData *fdd;
39    NVDECFrame *cf;
40    AVFrame *cur_frame = s->current_picture.f;
41
42    int ret, i;
43
44    ret = ff_nvdec_start_frame(avctx, cur_frame);
45    if (ret < 0)
46        return ret;
47
48    fdd = (FrameDecodeData*)cur_frame->private_ref->data;
49    cf  = (NVDECFrame*)fdd->hwaccel_priv;
50
51    *pp = (CUVIDPICPARAMS) {
52        .PicWidthInMbs     = (cur_frame->width  + 15) / 16,
53        .FrameHeightInMbs  = (cur_frame->height + 15) / 16,
54        .CurrPicIdx        = cf->idx,
55
56        .field_pic_flag    = s->picture_structure != PICT_FRAME,
57        .bottom_field_flag = s->picture_structure == PICT_BOTTOM_FIELD,
58        .second_field      = s->picture_structure != PICT_FRAME && !s->first_field,
59
60        .intra_pic_flag    = s->pict_type == AV_PICTURE_TYPE_I,
61        .ref_pic_flag      = s->pict_type == AV_PICTURE_TYPE_I ||
62                             s->pict_type == AV_PICTURE_TYPE_P,
63
64        .CodecSpecific.mpeg2 = {
65            .ForwardRefIdx     = ff_nvdec_get_ref_idx(s->last_picture.f),
66            .BackwardRefIdx    = ff_nvdec_get_ref_idx(s->next_picture.f),
67
68            .picture_coding_type        = s->pict_type,
69            .full_pel_forward_vector    = s->full_pel[0],
70            .full_pel_backward_vector   = s->full_pel[1],
71            .f_code                     = { { s->mpeg_f_code[0][0],
72                                              s->mpeg_f_code[0][1] },
73                                            { s->mpeg_f_code[1][0],
74                                              s->mpeg_f_code[1][1] } },
75            .intra_dc_precision         = s->intra_dc_precision,
76            .frame_pred_frame_dct       = s->frame_pred_frame_dct,
77            .concealment_motion_vectors = s->concealment_motion_vectors,
78            .q_scale_type               = s->q_scale_type,
79            .intra_vlc_format           = s->intra_vlc_format,
80            .alternate_scan             = s->alternate_scan,
81            .top_field_first            = s->top_field_first,
82        }
83    };
84
85    for (i = 0; i < 64; ++i) {
86        int n = s->idsp.idct_permutation[i];
87        ppc->QuantMatrixIntra[i] = s->intra_matrix[n];
88        ppc->QuantMatrixInter[i] = s->inter_matrix[n];
89    }
90
91    return 0;
92}
93
94static int nvdec_mpeg12_frame_params(AVCodecContext *avctx,
95                                  AVBufferRef *hw_frames_ctx)
96{
97    // Each frame can at most have one P and one B reference
98    return ff_nvdec_frame_params(avctx, hw_frames_ctx, 2, 0);
99}
100
101#if CONFIG_MPEG2_NVDEC_HWACCEL
102const AVHWAccel ff_mpeg2_nvdec_hwaccel = {
103    .name                 = "mpeg2_nvdec",
104    .type                 = AVMEDIA_TYPE_VIDEO,
105    .id                   = AV_CODEC_ID_MPEG2VIDEO,
106    .pix_fmt              = AV_PIX_FMT_CUDA,
107    .start_frame          = nvdec_mpeg12_start_frame,
108    .end_frame            = ff_nvdec_simple_end_frame,
109    .decode_slice         = ff_nvdec_simple_decode_slice,
110    .frame_params         = nvdec_mpeg12_frame_params,
111    .init                 = ff_nvdec_decode_init,
112    .uninit               = ff_nvdec_decode_uninit,
113    .priv_data_size       = sizeof(NVDECContext),
114};
115#endif
116
117#if CONFIG_MPEG1_NVDEC_HWACCEL
118const AVHWAccel ff_mpeg1_nvdec_hwaccel = {
119    .name                 = "mpeg1_nvdec",
120    .type                 = AVMEDIA_TYPE_VIDEO,
121    .id                   = AV_CODEC_ID_MPEG1VIDEO,
122    .pix_fmt              = AV_PIX_FMT_CUDA,
123    .start_frame          = nvdec_mpeg12_start_frame,
124    .end_frame            = ff_nvdec_simple_end_frame,
125    .decode_slice         = ff_nvdec_simple_decode_slice,
126    .frame_params         = nvdec_mpeg12_frame_params,
127    .init                 = ff_nvdec_decode_init,
128    .uninit               = ff_nvdec_decode_uninit,
129    .priv_data_size       = sizeof(NVDECContext),
130};
131#endif
132