X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fdxva2_h264.c;h=7009d6ceca94f37514db994c64020fa4bcec0de5;hb=09031b4639667273354d6bcd1705d9f24fc9bdd4;hp=827ab6890de68e93832957a3a6ed5d1ac72831ff;hpb=8db7ee09c3e2952f04e5e43020755c9d65aba699;p=ffmpeg diff --git a/libavcodec/dxva2_h264.c b/libavcodec/dxva2_h264.c index 827ab6890de..7009d6ceca9 100644 --- a/libavcodec/dxva2_h264.c +++ b/libavcodec/dxva2_h264.c @@ -3,27 +3,24 @@ * * copyright (c) 2009 Laurent Aimar * - * This file is part of FFmpeg. + * This file is part of Libav. * - * FFmpeg is free software; you can redistribute it and/or + * Libav 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, + * Libav 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 + * License along with Libav; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "dxva2.h" -#include "avcodec.h" - -#include "mpegvideo.h" +#include "dxva2_internal.h" #include "h264.h" #include "h264data.h" @@ -37,24 +34,6 @@ struct dxva2_picture_context { unsigned bitstream_size; }; -static void *get_surface(const Picture *picture) -{ - return picture->data[3]; -} -static unsigned get_surface_index(const struct dxva_context *ctx, - const Picture *picture) -{ - void *surface = get_surface(picture); - unsigned i; - - for (i = 0; i < ctx->surface_count; i++) - if (ctx->surface[i] == surface) - return i; - - assert(0); - return 0; -} - static void fill_picture_entry(DXVA_PicEntry_H264 *pic, unsigned index, unsigned flag) { @@ -65,41 +44,40 @@ static void fill_picture_entry(DXVA_PicEntry_H264 *pic, static void fill_picture_parameters(struct dxva_context *ctx, const H264Context *h, DXVA_PicParams_H264 *pp) { - const MpegEncContext *s = &h->s; - const Picture *current_picture = s->current_picture_ptr; - int i; + const Picture *current_picture = h->cur_pic_ptr; + int i, j; memset(pp, 0, sizeof(*pp)); /* Configure current picture */ fill_picture_entry(&pp->CurrPic, - get_surface_index(ctx, current_picture), - s->picture_structure == PICT_BOTTOM_FIELD); + ff_dxva2_get_surface_index(ctx, current_picture), + h->picture_structure == PICT_BOTTOM_FIELD); /* Configure the set of references */ pp->UsedForReferenceFlags = 0; pp->NonExistingFrameFlags = 0; - for (i = 0; i < FF_ARRAY_ELEMS(pp->RefFrameList); i++) { - if (i < h->short_ref_count + h->long_ref_count) { - const Picture *r; - if (i < h->short_ref_count) { - r = h->short_ref[i]; - assert(!r->long_ref); - } else { - r = h->long_ref[i - h->short_ref_count]; - assert(r->long_ref); - } + for (i = 0, j = 0; i < FF_ARRAY_ELEMS(pp->RefFrameList); i++) { + const Picture *r; + if (j < h->short_ref_count) { + r = h->short_ref[j++]; + } else { + r = NULL; + while (!r && j < h->short_ref_count + 16) + r = h->long_ref[j++ - h->short_ref_count]; + } + if (r) { fill_picture_entry(&pp->RefFrameList[i], - get_surface_index(ctx, r), + ff_dxva2_get_surface_index(ctx, r), r->long_ref != 0); - if ((r->reference & PICT_TOP_FIELD) && r->field_poc[0] != INT_MAX) + if ((r->f.reference & PICT_TOP_FIELD) && r->field_poc[0] != INT_MAX) pp->FieldOrderCntList[i][0] = r->field_poc[0]; - if ((r->reference & PICT_BOTTOM_FIELD) && r->field_poc[1] != INT_MAX) + if ((r->f.reference & PICT_BOTTOM_FIELD) && r->field_poc[1] != INT_MAX) pp->FieldOrderCntList[i][1] = r->field_poc[1]; pp->FrameNumList[i] = r->long_ref ? r->pic_id : r->frame_num; - if (r->reference & PICT_TOP_FIELD) + if (r->f.reference & PICT_TOP_FIELD) pp->UsedForReferenceFlags |= 1 << (2*i + 0); - if (r->reference & PICT_BOTTOM_FIELD) + if (r->f.reference & PICT_BOTTOM_FIELD) pp->UsedForReferenceFlags |= 1 << (2*i + 1); } else { pp->RefFrameList[i].bPicEntry = 0xff; @@ -109,14 +87,15 @@ static void fill_picture_parameters(struct dxva_context *ctx, const H264Context } } - pp->wFrameWidthInMbsMinus1 = s->mb_width - 1; - pp->wFrameHeightInMbsMinus1 = s->mb_height - 1; + pp->wFrameWidthInMbsMinus1 = h->mb_width - 1; + pp->wFrameHeightInMbsMinus1 = h->mb_height - 1; pp->num_ref_frames = h->sps.ref_frame_count; - pp->wBitFields = ((s->picture_structure != PICT_FRAME) << 0) | - (h->sps.mb_aff << 1) | + pp->wBitFields = ((h->picture_structure != PICT_FRAME) << 0) | + ((h->sps.mb_aff && + (h->picture_structure == PICT_FRAME)) << 1) | (h->sps.residual_color_transform_flag << 2) | - /* sp_for_switch_flag (not implemented by FFmpeg) */ + /* sp_for_switch_flag (not implemented by Libav) */ (0 << 3) | (h->sps.chroma_format_idc << 4) | ((h->nal_ref_idc != 0) << 6) | @@ -134,14 +113,17 @@ static void fill_picture_parameters(struct dxva_context *ctx, const H264Context pp->bit_depth_luma_minus8 = h->sps.bit_depth_luma - 8; pp->bit_depth_chroma_minus8 = h->sps.bit_depth_chroma - 8; - pp->Reserved16Bits = 3; /* FIXME is there a way to detect the right mode ? */ + if (ctx->workaround & FF_DXVA2_WORKAROUND_SCALING_LIST_ZIGZAG) + pp->Reserved16Bits = 0; + else + pp->Reserved16Bits = 3; /* FIXME is there a way to detect the right mode ? */ pp->StatusReportFeedbackNumber = 1 + ctx->report_id++; pp->CurrFieldOrderCnt[0] = 0; - if ((s->picture_structure & PICT_TOP_FIELD) && + if ((h->picture_structure & PICT_TOP_FIELD) && current_picture->field_poc[0] != INT_MAX) pp->CurrFieldOrderCnt[0] = current_picture->field_poc[0]; pp->CurrFieldOrderCnt[1] = 0; - if ((s->picture_structure & PICT_BOTTOM_FIELD) && + if ((h->picture_structure & PICT_BOTTOM_FIELD) && current_picture->field_poc[1] != INT_MAX) pp->CurrFieldOrderCnt[1] = current_picture->field_poc[1]; pp->pic_init_qs_minus26 = h->pps.init_qs - 26; @@ -167,21 +149,33 @@ static void fill_picture_parameters(struct dxva_context *ctx, const H264Context pp->deblocking_filter_control_present_flag = h->pps.deblocking_filter_parameters_present; pp->redundant_pic_cnt_present_flag= h->pps.redundant_pic_cnt_present; pp->Reserved8BitsB = 0; - pp->slice_group_change_rate_minus1= 0; /* XXX not implemented by FFmpeg */ - //pp->SliceGroupMap[810]; /* XXX not implemented by FFmpeg */ + pp->slice_group_change_rate_minus1= 0; /* XXX not implemented by Libav */ + //pp->SliceGroupMap[810]; /* XXX not implemented by Libav */ } -static void fill_scaling_lists(const H264Context *h, DXVA_Qmatrix_H264 *qm) +static void fill_scaling_lists(struct dxva_context *ctx, const H264Context *h, DXVA_Qmatrix_H264 *qm) { unsigned i, j; memset(qm, 0, sizeof(*qm)); - for (i = 0; i < 6; i++) - for (j = 0; j < 16; j++) - qm->bScalingLists4x4[i][j] = h->pps.scaling_matrix4[i][zigzag_scan[j]]; + if (ctx->workaround & FF_DXVA2_WORKAROUND_SCALING_LIST_ZIGZAG) { + for (i = 0; i < 6; i++) + for (j = 0; j < 16; j++) + qm->bScalingLists4x4[i][j] = h->pps.scaling_matrix4[i][j]; + + for (i = 0; i < 64; i++) { + qm->bScalingLists8x8[0][i] = h->pps.scaling_matrix8[0][i]; + qm->bScalingLists8x8[1][i] = h->pps.scaling_matrix8[3][i]; + } + } else { + for (i = 0; i < 6; i++) + for (j = 0; j < 16; j++) + qm->bScalingLists4x4[i][j] = h->pps.scaling_matrix4[i][zigzag_scan[j]]; - for (i = 0; i < 2; i++) - for (j = 0; j < 64; j++) - qm->bScalingLists8x8[i][j] = h->pps.scaling_matrix8[i][ff_zigzag_direct[j]]; + for (i = 0; i < 64; i++) { + qm->bScalingLists8x8[0][i] = h->pps.scaling_matrix8[0][ff_zigzag_direct[i]]; + qm->bScalingLists8x8[1][i] = h->pps.scaling_matrix8[3][ff_zigzag_direct[i]]; + } + } } static int is_slice_short(struct dxva_context *ctx) @@ -203,9 +197,8 @@ static void fill_slice_short(DXVA_Slice_H264_Short *slice, static void fill_slice_long(AVCodecContext *avctx, DXVA_Slice_H264_Long *slice, unsigned position, unsigned size) { - H264Context *h = avctx->priv_data; /* FIXME Can't use const because of get_bits_count */ + const H264Context *h = avctx->priv_data; struct dxva_context *ctx = avctx->hwaccel_context; - MpegEncContext *s = &h->s; unsigned list; memset(slice, 0, sizeof(*slice)); @@ -213,9 +206,9 @@ static void fill_slice_long(AVCodecContext *avctx, DXVA_Slice_H264_Long *slice, slice->SliceBytesInBuffer = size; slice->wBadSliceChopping = 0; - slice->first_mb_in_slice = (s->mb_y >> FIELD_OR_MBAFF_PICTURE) * s->mb_width + s->mb_x; + slice->first_mb_in_slice = (h->mb_y >> FIELD_OR_MBAFF_PICTURE) * h->mb_width + h->mb_x; slice->NumMbsForSlice = 0; /* XXX it is set once we have all slices */ - slice->BitOffsetToSliceData = get_bits_count(&s->gb) + 8; + slice->BitOffsetToSliceData = get_bits_count(&h->gb); slice->slice_type = ff_h264_get_slice_type(h); if (h->slice_type_fixed) slice->slice_type += 5; @@ -225,8 +218,8 @@ static void fill_slice_long(AVCodecContext *avctx, DXVA_Slice_H264_Long *slice, slice->num_ref_idx_l0_active_minus1 = h->ref_count[0] - 1; if (h->list_count > 1) slice->num_ref_idx_l1_active_minus1 = h->ref_count[1] - 1; - slice->slice_alpha_c0_offset_div2 = h->slice_alpha_c0_offset / 2; - slice->slice_beta_offset_div2 = h->slice_beta_offset / 2; + slice->slice_alpha_c0_offset_div2 = h->slice_alpha_c0_offset / 2 - 26; + slice->slice_beta_offset_div2 = h->slice_beta_offset / 2 - 26; slice->Reserved8Bits = 0; for (list = 0; list < 2; list++) { @@ -236,16 +229,16 @@ static void fill_slice_long(AVCodecContext *avctx, DXVA_Slice_H264_Long *slice, const Picture *r = &h->ref_list[list][i]; unsigned plane; fill_picture_entry(&slice->RefPicList[list][i], - get_surface_index(ctx, r), - r->reference == PICT_BOTTOM_FIELD); + ff_dxva2_get_surface_index(ctx, r), + r->f.reference == PICT_BOTTOM_FIELD); for (plane = 0; plane < 3; plane++) { int w, o; if (plane == 0 && h->luma_weight_flag[list]) { - w = h->luma_weight[list][i]; - o = h->luma_offset[list][i]; + w = h->luma_weight[i][list][0]; + o = h->luma_weight[i][list][1]; } else if (plane >= 1 && h->chroma_weight_flag[list]) { - w = h->chroma_weight[list][i][plane-1]; - o = h->chroma_offset[list][i][plane-1]; + w = h->chroma_weight[i][list][plane-1][0]; + o = h->chroma_weight[i][list][plane-1][1]; } else { w = 1 << (plane == 0 ? h->luma_log2_weight_denom : h->chroma_log2_weight_denom); @@ -264,10 +257,10 @@ static void fill_slice_long(AVCodecContext *avctx, DXVA_Slice_H264_Long *slice, } } } - slice->slice_qs_delta = 0; /* XXX not implemented by FFmpeg */ - slice->slice_qp_delta = s->qscale - h->pps.init_qp; + slice->slice_qs_delta = 0; /* XXX not implemented by Libav */ + slice->slice_qp_delta = h->qscale - h->pps.init_qp; slice->redundant_pic_cnt = h->redundant_pic_count; - if (h->slice_type == FF_B_TYPE) + if (h->slice_type == AV_PICTURE_TYPE_B) slice->direct_spatial_mv_pred_flag = h->direct_spatial_mv_pred; slice->cabac_init_idc = h->pps.cabac ? h->cabac_init_idc : 0; if (h->deblocking_filter < 2) @@ -277,51 +270,15 @@ static void fill_slice_long(AVCodecContext *avctx, DXVA_Slice_H264_Long *slice, slice->slice_id = h->current_slice - 1; } -static int commit_buffer(AVCodecContext *avctx, - struct dxva_context *ctx, - DXVA2_DecodeBufferDesc *dsc, - unsigned type, const void *data, unsigned size, - unsigned mb_count) -{ - void *dxva_data; - unsigned dxva_size; - int result; - - if (FAILED(IDirectXVideoDecoder_GetBuffer(ctx->decoder, type, - &dxva_data, &dxva_size))) { - av_log(avctx, AV_LOG_ERROR, "Failed to get a buffer for %d\n", type); - return -1; - } - if (size <= dxva_size) { - memcpy(dxva_data, data, size); - - memset(dsc, 0, sizeof(*dsc)); - dsc->CompressedBufferType = type; - dsc->DataSize = size; - dsc->NumMBsInBuffer = mb_count; - - result = 0; - } else { - av_log(avctx, AV_LOG_ERROR, "Buffer for type %d was too small\n", type); - result = -1; - } - if (FAILED(IDirectXVideoDecoder_ReleaseBuffer(ctx->decoder, type))) { - av_log(avctx, AV_LOG_ERROR, "Failed to release buffer type %d\n", type); - result = -1; - } - return result; -} - static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, DXVA2_DecodeBufferDesc *bs, DXVA2_DecodeBufferDesc *sc) { - H264Context *h = avctx->priv_data; - MpegEncContext *s = &h->s; - const unsigned mb_count = s->mb_width * s->mb_height; + const H264Context *h = avctx->priv_data; + const unsigned mb_count = h->mb_width * h->mb_height; struct dxva_context *ctx = avctx->hwaccel_context; - const Picture *current_picture = h->s.current_picture_ptr; - struct dxva2_picture_context *ctx_pic = current_picture->hwaccel_picture_private; + const Picture *current_picture = h->cur_pic_ptr; + struct dxva2_picture_context *ctx_pic = current_picture->f.hwaccel_picture_private; DXVA_Slice_H264_Short *slice = NULL; uint8_t *dxva_data, *current, *end; unsigned dxva_size; @@ -404,9 +361,9 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, slice_size = ctx_pic->slice_count * sizeof(*ctx_pic->slice_long); } assert((bs->DataSize & 127) == 0); - return commit_buffer(avctx, ctx, sc, - DXVA2_SliceControlBufferType, - slice_data, slice_size, mb_count); + return ff_dxva2_commit_buffer(avctx, ctx, sc, + DXVA2_SliceControlBufferType, + slice_data, slice_size, mb_count); } @@ -416,7 +373,7 @@ static int start_frame(AVCodecContext *avctx, { const H264Context *h = avctx->priv_data; struct dxva_context *ctx = avctx->hwaccel_context; - struct dxva2_picture_context *ctx_pic = h->s.current_picture_ptr->hwaccel_picture_private; + struct dxva2_picture_context *ctx_pic = h->cur_pic_ptr->f.hwaccel_picture_private; if (!ctx->decoder || !ctx->cfg || ctx->surface_count <= 0) return -1; @@ -426,7 +383,7 @@ static int start_frame(AVCodecContext *avctx, fill_picture_parameters(ctx, h, &ctx_pic->pp); /* Fill up DXVA_Qmatrix_H264 */ - fill_scaling_lists(h, &ctx_pic->qm); + fill_scaling_lists(ctx, h, &ctx_pic->qm); ctx_pic->slice_count = 0; ctx_pic->bitstream_size = 0; @@ -437,10 +394,10 @@ static int start_frame(AVCodecContext *avctx, static int decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) { - H264Context *h = avctx->priv_data; /* FIXME Can't use const because of get_bits_count */ + const H264Context *h = avctx->priv_data; struct dxva_context *ctx = avctx->hwaccel_context; - const Picture *current_picture = h->s.current_picture_ptr; - struct dxva2_picture_context *ctx_pic = current_picture->hwaccel_picture_private; + const Picture *current_picture = h->cur_pic_ptr; + struct dxva2_picture_context *ctx_pic = current_picture->f.hwaccel_picture_private; unsigned position; if (ctx_pic->slice_count >= MAX_SLICES) @@ -459,111 +416,36 @@ static int decode_slice(AVCodecContext *avctx, position, size); ctx_pic->slice_count++; - if (h->slice_type != FF_I_TYPE && h->slice_type != FF_SI_TYPE) + if (h->slice_type != AV_PICTURE_TYPE_I && h->slice_type != AV_PICTURE_TYPE_SI) ctx_pic->pp.wBitFields &= ~(1 << 15); /* Set IntraPicFlag to 0 */ return 0; } -static int ff_dxva2_common_end_frame(AVCodecContext *avctx, MpegEncContext *s, - const void *pp, unsigned pp_size, - const void *qm, unsigned qm_size, - int (*commit_bs_si)(AVCodecContext *, - DXVA2_DecodeBufferDesc *bs, - DXVA2_DecodeBufferDesc *slice)) -{ - struct dxva_context *ctx = avctx->hwaccel_context; - unsigned buffer_count = 0; - DXVA2_DecodeBufferDesc buffer[4]; - DXVA2_DecodeExecuteParams exec; - int result; - - if (FAILED(IDirectXVideoDecoder_BeginFrame(ctx->decoder, - get_surface(s->current_picture_ptr), - NULL))) { - av_log(avctx, AV_LOG_ERROR, "Failed to begin frame\n"); - return -1; - } - - result = commit_buffer(avctx, ctx, &buffer[buffer_count], - DXVA2_PictureParametersBufferType, - pp, pp_size, 0); - if (result) { - av_log(avctx, AV_LOG_ERROR, - "Failed to add picture parameter buffer\n"); - goto end; - } - buffer_count++; - - if (qm_size > 0) { - result = commit_buffer(avctx, ctx, &buffer[buffer_count], - DXVA2_InverseQuantizationMatrixBufferType, - qm, qm_size, 0); - if (result) { - av_log(avctx, AV_LOG_ERROR, - "Failed to add inverse quantization matrix buffer\n"); - goto end; - } - buffer_count++; - } - - result = commit_bs_si(avctx, - &buffer[buffer_count + 0], - &buffer[buffer_count + 1]); - if (result) { - av_log(avctx, AV_LOG_ERROR, - "Failed to add bitstream or slice control buffer\n"); - goto end; - } - buffer_count += 2; - - /* TODO Film Grain when possible */ - - assert(buffer_count == 1 + (qm_size > 0) + 2); - - memset(&exec, 0, sizeof(exec)); - exec.NumCompBuffers = buffer_count; - exec.pCompressedBuffers = buffer; - exec.pExtensionData = NULL; - if (FAILED(IDirectXVideoDecoder_Execute(ctx->decoder, &exec))) { - av_log(avctx, AV_LOG_ERROR, "Failed to execute\n"); - result = -1; - } - -end: - if (FAILED(IDirectXVideoDecoder_EndFrame(ctx->decoder, NULL))) { - av_log(avctx, AV_LOG_ERROR, "Failed to end frame\n"); - result = -1; - } - - if (!result) - ff_draw_horiz_band(s, 0, s->avctx->height); - return result; -} - static int end_frame(AVCodecContext *avctx) { H264Context *h = avctx->priv_data; - MpegEncContext *s = &h->s; struct dxva2_picture_context *ctx_pic = - h->s.current_picture_ptr->hwaccel_picture_private; + h->cur_pic_ptr->f.hwaccel_picture_private; + int ret; if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0) return -1; - return ff_dxva2_common_end_frame(avctx, s, - &ctx_pic->pp, sizeof(ctx_pic->pp), - &ctx_pic->qm, sizeof(ctx_pic->qm), - commit_bitstream_and_slice_buffer); + ret = ff_dxva2_common_end_frame(avctx, h->cur_pic_ptr, + &ctx_pic->pp, sizeof(ctx_pic->pp), + &ctx_pic->qm, sizeof(ctx_pic->qm), + commit_bitstream_and_slice_buffer); + if (!ret) + ff_h264_draw_horiz_band(h, 0, h->avctx->height); + return ret; } -AVHWAccel h264_dxva2_hwaccel = { +AVHWAccel ff_h264_dxva2_hwaccel = { .name = "h264_dxva2", - .type = CODEC_TYPE_VIDEO, - .id = CODEC_ID_H264, - .pix_fmt = PIX_FMT_DXVA2_VLD, - .capabilities = 0, + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_H264, + .pix_fmt = AV_PIX_FMT_DXVA2_VLD, .start_frame = start_frame, .decode_slice = decode_slice, .end_frame = end_frame, .priv_data_size = sizeof(struct dxva2_picture_context), }; -