1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * MPEG-4 Part 10 / AVC / H.264 HW decode acceleration through VDPAU
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * Copyright (c) 2008 NVIDIA
5cabdff1aSopenharmony_ci * Copyright (c) 2013 Rémi Denis-Courmont
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * This file is part of FFmpeg.
8cabdff1aSopenharmony_ci *
9cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
10cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
11cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
12cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
13cabdff1aSopenharmony_ci *
14cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
15cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
16cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17cabdff1aSopenharmony_ci * Lesser General Public License for more details.
18cabdff1aSopenharmony_ci *
19cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
20cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software Foundation,
21cabdff1aSopenharmony_ci * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22cabdff1aSopenharmony_ci */
23cabdff1aSopenharmony_ci
24cabdff1aSopenharmony_ci#include <vdpau/vdpau.h>
25cabdff1aSopenharmony_ci
26cabdff1aSopenharmony_ci#include "avcodec.h"
27cabdff1aSopenharmony_ci#include "h264dec.h"
28cabdff1aSopenharmony_ci#include "h264_ps.h"
29cabdff1aSopenharmony_ci#include "hwconfig.h"
30cabdff1aSopenharmony_ci#include "mpegutils.h"
31cabdff1aSopenharmony_ci#include "vdpau.h"
32cabdff1aSopenharmony_ci#include "vdpau_internal.h"
33cabdff1aSopenharmony_ci
34cabdff1aSopenharmony_cistatic int32_t h264_foc(int foc)
35cabdff1aSopenharmony_ci{
36cabdff1aSopenharmony_ci    if (foc == INT_MAX)
37cabdff1aSopenharmony_ci        foc = 0;
38cabdff1aSopenharmony_ci    return foc;
39cabdff1aSopenharmony_ci}
40cabdff1aSopenharmony_ci
41cabdff1aSopenharmony_cistatic void vdpau_h264_clear_rf(VdpReferenceFrameH264 *rf)
42cabdff1aSopenharmony_ci{
43cabdff1aSopenharmony_ci    rf->surface             = VDP_INVALID_HANDLE;
44cabdff1aSopenharmony_ci    rf->is_long_term        = VDP_FALSE;
45cabdff1aSopenharmony_ci    rf->top_is_reference    = VDP_FALSE;
46cabdff1aSopenharmony_ci    rf->bottom_is_reference = VDP_FALSE;
47cabdff1aSopenharmony_ci    rf->field_order_cnt[0]  = 0;
48cabdff1aSopenharmony_ci    rf->field_order_cnt[1]  = 0;
49cabdff1aSopenharmony_ci    rf->frame_idx           = 0;
50cabdff1aSopenharmony_ci}
51cabdff1aSopenharmony_ci
52cabdff1aSopenharmony_cistatic void vdpau_h264_set_rf(VdpReferenceFrameH264 *rf, H264Picture *pic,
53cabdff1aSopenharmony_ci                              int pic_structure)
54cabdff1aSopenharmony_ci{
55cabdff1aSopenharmony_ci    VdpVideoSurface surface = ff_vdpau_get_surface_id(pic->f);
56cabdff1aSopenharmony_ci
57cabdff1aSopenharmony_ci    if (pic_structure == 0)
58cabdff1aSopenharmony_ci        pic_structure = pic->reference;
59cabdff1aSopenharmony_ci
60cabdff1aSopenharmony_ci    rf->surface             = surface;
61cabdff1aSopenharmony_ci    rf->is_long_term        = pic->reference && pic->long_ref;
62cabdff1aSopenharmony_ci    rf->top_is_reference    = (pic_structure & PICT_TOP_FIELD)    != 0;
63cabdff1aSopenharmony_ci    rf->bottom_is_reference = (pic_structure & PICT_BOTTOM_FIELD) != 0;
64cabdff1aSopenharmony_ci    rf->field_order_cnt[0]  = h264_foc(pic->field_poc[0]);
65cabdff1aSopenharmony_ci    rf->field_order_cnt[1]  = h264_foc(pic->field_poc[1]);
66cabdff1aSopenharmony_ci    rf->frame_idx           = pic->long_ref ? pic->pic_id : pic->frame_num;
67cabdff1aSopenharmony_ci}
68cabdff1aSopenharmony_ci
69cabdff1aSopenharmony_cistatic void vdpau_h264_set_reference_frames(AVCodecContext *avctx)
70cabdff1aSopenharmony_ci{
71cabdff1aSopenharmony_ci    H264Context * const h = avctx->priv_data;
72cabdff1aSopenharmony_ci    struct vdpau_picture_context *pic_ctx = h->cur_pic_ptr->hwaccel_picture_private;
73cabdff1aSopenharmony_ci    VdpPictureInfoH264 *info = &pic_ctx->info.h264;
74cabdff1aSopenharmony_ci    int list;
75cabdff1aSopenharmony_ci
76cabdff1aSopenharmony_ci    VdpReferenceFrameH264 *rf = &info->referenceFrames[0];
77cabdff1aSopenharmony_ci#define H264_RF_COUNT FF_ARRAY_ELEMS(info->referenceFrames)
78cabdff1aSopenharmony_ci
79cabdff1aSopenharmony_ci    for (list = 0; list < 2; ++list) {
80cabdff1aSopenharmony_ci        H264Picture **lp = list ? h->long_ref : h->short_ref;
81cabdff1aSopenharmony_ci        int i, ls    = list ? 16          : h->short_ref_count;
82cabdff1aSopenharmony_ci
83cabdff1aSopenharmony_ci        for (i = 0; i < ls; ++i) {
84cabdff1aSopenharmony_ci            H264Picture *pic = lp[i];
85cabdff1aSopenharmony_ci            VdpReferenceFrameH264 *rf2;
86cabdff1aSopenharmony_ci            VdpVideoSurface surface_ref;
87cabdff1aSopenharmony_ci            int pic_frame_idx;
88cabdff1aSopenharmony_ci
89cabdff1aSopenharmony_ci            if (!pic || !pic->reference)
90cabdff1aSopenharmony_ci                continue;
91cabdff1aSopenharmony_ci            pic_frame_idx = pic->long_ref ? pic->pic_id : pic->frame_num;
92cabdff1aSopenharmony_ci            surface_ref = ff_vdpau_get_surface_id(pic->f);
93cabdff1aSopenharmony_ci
94cabdff1aSopenharmony_ci            rf2 = &info->referenceFrames[0];
95cabdff1aSopenharmony_ci            while (rf2 != rf) {
96cabdff1aSopenharmony_ci                if ((rf2->surface      == surface_ref)   &&
97cabdff1aSopenharmony_ci                    (rf2->is_long_term == pic->long_ref) &&
98cabdff1aSopenharmony_ci                    (rf2->frame_idx    == pic_frame_idx))
99cabdff1aSopenharmony_ci                    break;
100cabdff1aSopenharmony_ci                ++rf2;
101cabdff1aSopenharmony_ci            }
102cabdff1aSopenharmony_ci            if (rf2 != rf) {
103cabdff1aSopenharmony_ci                rf2->top_is_reference    |= (pic->reference & PICT_TOP_FIELD)    ? VDP_TRUE : VDP_FALSE;
104cabdff1aSopenharmony_ci                rf2->bottom_is_reference |= (pic->reference & PICT_BOTTOM_FIELD) ? VDP_TRUE : VDP_FALSE;
105cabdff1aSopenharmony_ci                continue;
106cabdff1aSopenharmony_ci            }
107cabdff1aSopenharmony_ci
108cabdff1aSopenharmony_ci            if (rf >= &info->referenceFrames[H264_RF_COUNT])
109cabdff1aSopenharmony_ci                continue;
110cabdff1aSopenharmony_ci
111cabdff1aSopenharmony_ci            vdpau_h264_set_rf(rf, pic, pic->reference);
112cabdff1aSopenharmony_ci            ++rf;
113cabdff1aSopenharmony_ci        }
114cabdff1aSopenharmony_ci    }
115cabdff1aSopenharmony_ci
116cabdff1aSopenharmony_ci    for (; rf < &info->referenceFrames[H264_RF_COUNT]; ++rf)
117cabdff1aSopenharmony_ci        vdpau_h264_clear_rf(rf);
118cabdff1aSopenharmony_ci}
119cabdff1aSopenharmony_ci
120cabdff1aSopenharmony_cistatic int vdpau_h264_start_frame(AVCodecContext *avctx,
121cabdff1aSopenharmony_ci                                  const uint8_t *buffer, uint32_t size)
122cabdff1aSopenharmony_ci{
123cabdff1aSopenharmony_ci    H264Context * const h = avctx->priv_data;
124cabdff1aSopenharmony_ci    const PPS *pps = h->ps.pps;
125cabdff1aSopenharmony_ci    const SPS *sps = h->ps.sps;
126cabdff1aSopenharmony_ci    H264Picture *pic = h->cur_pic_ptr;
127cabdff1aSopenharmony_ci    struct vdpau_picture_context *pic_ctx = pic->hwaccel_picture_private;
128cabdff1aSopenharmony_ci    VdpPictureInfoH264 *info = &pic_ctx->info.h264;
129cabdff1aSopenharmony_ci#ifdef VDP_DECODER_PROFILE_H264_HIGH_444_PREDICTIVE
130cabdff1aSopenharmony_ci    VdpPictureInfoH264Predictive *info2 = &pic_ctx->info.h264_predictive;
131cabdff1aSopenharmony_ci#endif
132cabdff1aSopenharmony_ci
133cabdff1aSopenharmony_ci    /* init VdpPictureInfoH264 */
134cabdff1aSopenharmony_ci    info->slice_count                            = 0;
135cabdff1aSopenharmony_ci    info->field_order_cnt[0]                     = h264_foc(pic->field_poc[0]);
136cabdff1aSopenharmony_ci    info->field_order_cnt[1]                     = h264_foc(pic->field_poc[1]);
137cabdff1aSopenharmony_ci    info->is_reference                           = h->nal_ref_idc != 0;
138cabdff1aSopenharmony_ci    info->frame_num                              = h->poc.frame_num;
139cabdff1aSopenharmony_ci    info->field_pic_flag                         = h->picture_structure != PICT_FRAME;
140cabdff1aSopenharmony_ci    info->bottom_field_flag                      = h->picture_structure == PICT_BOTTOM_FIELD;
141cabdff1aSopenharmony_ci    info->num_ref_frames                         = sps->ref_frame_count;
142cabdff1aSopenharmony_ci    info->mb_adaptive_frame_field_flag           = sps->mb_aff && !info->field_pic_flag;
143cabdff1aSopenharmony_ci    info->constrained_intra_pred_flag            = pps->constrained_intra_pred;
144cabdff1aSopenharmony_ci    info->weighted_pred_flag                     = pps->weighted_pred;
145cabdff1aSopenharmony_ci    info->weighted_bipred_idc                    = pps->weighted_bipred_idc;
146cabdff1aSopenharmony_ci    info->frame_mbs_only_flag                    = sps->frame_mbs_only_flag;
147cabdff1aSopenharmony_ci    info->transform_8x8_mode_flag                = pps->transform_8x8_mode;
148cabdff1aSopenharmony_ci    info->chroma_qp_index_offset                 = pps->chroma_qp_index_offset[0];
149cabdff1aSopenharmony_ci    info->second_chroma_qp_index_offset          = pps->chroma_qp_index_offset[1];
150cabdff1aSopenharmony_ci    info->pic_init_qp_minus26                    = pps->init_qp - 26;
151cabdff1aSopenharmony_ci    info->num_ref_idx_l0_active_minus1           = pps->ref_count[0] - 1;
152cabdff1aSopenharmony_ci    info->num_ref_idx_l1_active_minus1           = pps->ref_count[1] - 1;
153cabdff1aSopenharmony_ci    info->log2_max_frame_num_minus4              = sps->log2_max_frame_num - 4;
154cabdff1aSopenharmony_ci    info->pic_order_cnt_type                     = sps->poc_type;
155cabdff1aSopenharmony_ci    info->log2_max_pic_order_cnt_lsb_minus4      = sps->poc_type ? 0 : sps->log2_max_poc_lsb - 4;
156cabdff1aSopenharmony_ci    info->delta_pic_order_always_zero_flag       = sps->delta_pic_order_always_zero_flag;
157cabdff1aSopenharmony_ci    info->direct_8x8_inference_flag              = sps->direct_8x8_inference_flag;
158cabdff1aSopenharmony_ci#ifdef VDP_DECODER_PROFILE_H264_HIGH_444_PREDICTIVE
159cabdff1aSopenharmony_ci    info2->qpprime_y_zero_transform_bypass_flag  = sps->transform_bypass;
160cabdff1aSopenharmony_ci    info2->separate_colour_plane_flag            = sps->residual_color_transform_flag;
161cabdff1aSopenharmony_ci#endif
162cabdff1aSopenharmony_ci    info->entropy_coding_mode_flag               = pps->cabac;
163cabdff1aSopenharmony_ci    info->pic_order_present_flag                 = pps->pic_order_present;
164cabdff1aSopenharmony_ci    info->deblocking_filter_control_present_flag = pps->deblocking_filter_parameters_present;
165cabdff1aSopenharmony_ci    info->redundant_pic_cnt_present_flag         = pps->redundant_pic_cnt_present;
166cabdff1aSopenharmony_ci
167cabdff1aSopenharmony_ci    memcpy(info->scaling_lists_4x4, pps->scaling_matrix4,
168cabdff1aSopenharmony_ci           sizeof(info->scaling_lists_4x4));
169cabdff1aSopenharmony_ci    memcpy(info->scaling_lists_8x8[0], pps->scaling_matrix8[0],
170cabdff1aSopenharmony_ci           sizeof(info->scaling_lists_8x8[0]));
171cabdff1aSopenharmony_ci    memcpy(info->scaling_lists_8x8[1], pps->scaling_matrix8[3],
172cabdff1aSopenharmony_ci           sizeof(info->scaling_lists_8x8[1]));
173cabdff1aSopenharmony_ci
174cabdff1aSopenharmony_ci    vdpau_h264_set_reference_frames(avctx);
175cabdff1aSopenharmony_ci
176cabdff1aSopenharmony_ci    return ff_vdpau_common_start_frame(pic_ctx, buffer, size);
177cabdff1aSopenharmony_ci}
178cabdff1aSopenharmony_ci
179cabdff1aSopenharmony_cistatic const uint8_t start_code_prefix[3] = { 0x00, 0x00, 0x01 };
180cabdff1aSopenharmony_ci
181cabdff1aSopenharmony_cistatic int vdpau_h264_decode_slice(AVCodecContext *avctx,
182cabdff1aSopenharmony_ci                                   const uint8_t *buffer, uint32_t size)
183cabdff1aSopenharmony_ci{
184cabdff1aSopenharmony_ci    H264Context *h = avctx->priv_data;
185cabdff1aSopenharmony_ci    H264Picture *pic = h->cur_pic_ptr;
186cabdff1aSopenharmony_ci    struct vdpau_picture_context *pic_ctx = pic->hwaccel_picture_private;
187cabdff1aSopenharmony_ci    int val;
188cabdff1aSopenharmony_ci
189cabdff1aSopenharmony_ci    val = ff_vdpau_add_buffer(pic_ctx, start_code_prefix, 3);
190cabdff1aSopenharmony_ci    if (val)
191cabdff1aSopenharmony_ci        return val;
192cabdff1aSopenharmony_ci
193cabdff1aSopenharmony_ci    val = ff_vdpau_add_buffer(pic_ctx, buffer, size);
194cabdff1aSopenharmony_ci    if (val)
195cabdff1aSopenharmony_ci        return val;
196cabdff1aSopenharmony_ci
197cabdff1aSopenharmony_ci    pic_ctx->info.h264.slice_count++;
198cabdff1aSopenharmony_ci    return 0;
199cabdff1aSopenharmony_ci}
200cabdff1aSopenharmony_ci
201cabdff1aSopenharmony_cistatic int vdpau_h264_end_frame(AVCodecContext *avctx)
202cabdff1aSopenharmony_ci{
203cabdff1aSopenharmony_ci    H264Context *h = avctx->priv_data;
204cabdff1aSopenharmony_ci    H264SliceContext *sl = &h->slice_ctx[0];
205cabdff1aSopenharmony_ci    H264Picture *pic = h->cur_pic_ptr;
206cabdff1aSopenharmony_ci    struct vdpau_picture_context *pic_ctx = pic->hwaccel_picture_private;
207cabdff1aSopenharmony_ci    int val;
208cabdff1aSopenharmony_ci
209cabdff1aSopenharmony_ci    val = ff_vdpau_common_end_frame(avctx, pic->f, pic_ctx);
210cabdff1aSopenharmony_ci    if (val < 0)
211cabdff1aSopenharmony_ci        return val;
212cabdff1aSopenharmony_ci
213cabdff1aSopenharmony_ci    ff_h264_draw_horiz_band(h, sl, 0, h->avctx->height);
214cabdff1aSopenharmony_ci    return 0;
215cabdff1aSopenharmony_ci}
216cabdff1aSopenharmony_ci
217cabdff1aSopenharmony_cistatic int vdpau_h264_init(AVCodecContext *avctx)
218cabdff1aSopenharmony_ci{
219cabdff1aSopenharmony_ci    VdpDecoderProfile profile;
220cabdff1aSopenharmony_ci    uint32_t level = avctx->level;
221cabdff1aSopenharmony_ci
222cabdff1aSopenharmony_ci    switch (avctx->profile & ~FF_PROFILE_H264_INTRA) {
223cabdff1aSopenharmony_ci    case FF_PROFILE_H264_BASELINE:
224cabdff1aSopenharmony_ci        profile = VDP_DECODER_PROFILE_H264_BASELINE;
225cabdff1aSopenharmony_ci        break;
226cabdff1aSopenharmony_ci    case FF_PROFILE_H264_CONSTRAINED_BASELINE:
227cabdff1aSopenharmony_ci#ifdef VDP_DECODER_PROFILE_H264_CONSTRAINED_BASELINE
228cabdff1aSopenharmony_ci        profile = VDP_DECODER_PROFILE_H264_CONSTRAINED_BASELINE;
229cabdff1aSopenharmony_ci        break;
230cabdff1aSopenharmony_ci#endif
231cabdff1aSopenharmony_ci    case FF_PROFILE_H264_MAIN:
232cabdff1aSopenharmony_ci        profile = VDP_DECODER_PROFILE_H264_MAIN;
233cabdff1aSopenharmony_ci        break;
234cabdff1aSopenharmony_ci    case FF_PROFILE_H264_HIGH:
235cabdff1aSopenharmony_ci        profile = VDP_DECODER_PROFILE_H264_HIGH;
236cabdff1aSopenharmony_ci        break;
237cabdff1aSopenharmony_ci#ifdef VDP_DECODER_PROFILE_H264_EXTENDED
238cabdff1aSopenharmony_ci    case FF_PROFILE_H264_EXTENDED:
239cabdff1aSopenharmony_ci        profile = VDP_DECODER_PROFILE_H264_EXTENDED;
240cabdff1aSopenharmony_ci        break;
241cabdff1aSopenharmony_ci#endif
242cabdff1aSopenharmony_ci    case FF_PROFILE_H264_HIGH_10:
243cabdff1aSopenharmony_ci        /* XXX: High 10 can be treated as High so long as only 8 bits per
244cabdff1aSopenharmony_ci         * format are supported. */
245cabdff1aSopenharmony_ci        profile = VDP_DECODER_PROFILE_H264_HIGH;
246cabdff1aSopenharmony_ci        break;
247cabdff1aSopenharmony_ci#ifdef VDP_DECODER_PROFILE_H264_HIGH_444_PREDICTIVE
248cabdff1aSopenharmony_ci    case FF_PROFILE_H264_HIGH_422:
249cabdff1aSopenharmony_ci    case FF_PROFILE_H264_HIGH_444_PREDICTIVE:
250cabdff1aSopenharmony_ci    case FF_PROFILE_H264_CAVLC_444:
251cabdff1aSopenharmony_ci        profile = VDP_DECODER_PROFILE_H264_HIGH_444_PREDICTIVE;
252cabdff1aSopenharmony_ci        break;
253cabdff1aSopenharmony_ci#endif
254cabdff1aSopenharmony_ci    default:
255cabdff1aSopenharmony_ci        return AVERROR(ENOTSUP);
256cabdff1aSopenharmony_ci    }
257cabdff1aSopenharmony_ci
258cabdff1aSopenharmony_ci    if ((avctx->profile & FF_PROFILE_H264_INTRA) && avctx->level == 11)
259cabdff1aSopenharmony_ci        level = VDP_DECODER_LEVEL_H264_1b;
260cabdff1aSopenharmony_ci
261cabdff1aSopenharmony_ci    return ff_vdpau_common_init(avctx, profile, level);
262cabdff1aSopenharmony_ci}
263cabdff1aSopenharmony_ci
264cabdff1aSopenharmony_ciconst AVHWAccel ff_h264_vdpau_hwaccel = {
265cabdff1aSopenharmony_ci    .name           = "h264_vdpau",
266cabdff1aSopenharmony_ci    .type           = AVMEDIA_TYPE_VIDEO,
267cabdff1aSopenharmony_ci    .id             = AV_CODEC_ID_H264,
268cabdff1aSopenharmony_ci    .pix_fmt        = AV_PIX_FMT_VDPAU,
269cabdff1aSopenharmony_ci    .start_frame    = vdpau_h264_start_frame,
270cabdff1aSopenharmony_ci    .end_frame      = vdpau_h264_end_frame,
271cabdff1aSopenharmony_ci    .decode_slice   = vdpau_h264_decode_slice,
272cabdff1aSopenharmony_ci    .frame_priv_data_size = sizeof(struct vdpau_picture_context),
273cabdff1aSopenharmony_ci    .init           = vdpau_h264_init,
274cabdff1aSopenharmony_ci    .uninit         = ff_vdpau_common_uninit,
275cabdff1aSopenharmony_ci    .frame_params   = ff_vdpau_common_frame_params,
276cabdff1aSopenharmony_ci    .priv_data_size = sizeof(VDPAUContext),
277cabdff1aSopenharmony_ci    .caps_internal  = HWACCEL_CAP_ASYNC_SAFE,
278cabdff1aSopenharmony_ci};
279