int ff_dxva2_commit_buffer(AVCodecContext *avctx, AVDXVAContext *ctx, DECODER_BUFFER_DESC *dsc, unsigned type, const void *data, unsigned size, unsigned mb_count) { void *dxva_data; unsigned dxva_size; int result; HRESULT hr = 0; #if CONFIG_D3D11VA if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) hr = ID3D11VideoContext_GetDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder, type, &dxva_size, &dxva_data); #endif #if CONFIG_DXVA2 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) hr = IDirectXVideoDecoder_GetBuffer(DXVA2_CONTEXT(ctx)->decoder, type, &dxva_data, &dxva_size); #endif if (FAILED(hr)) { av_log(avctx, AV_LOG_ERROR, "Failed to get a buffer for %u: 0x%lx\n", type, hr); return -1; } if (size <= dxva_size) { memcpy(dxva_data, data, size); #if CONFIG_D3D11VA if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) { D3D11_VIDEO_DECODER_BUFFER_DESC *dsc11 = dsc; memset(dsc11, 0, sizeof(*dsc11)); dsc11->BufferType = type; dsc11->DataSize = size; dsc11->NumMBsInBuffer = mb_count; } #endif #if CONFIG_DXVA2 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) { DXVA2_DecodeBufferDesc *dsc2 = dsc; memset(dsc2, 0, sizeof(*dsc2)); dsc2->CompressedBufferType = type; dsc2->DataSize = size; dsc2->NumMBsInBuffer = mb_count; } #endif result = 0; } else { av_log(avctx, AV_LOG_ERROR, "Buffer for type %u was too small\n", type); result = -1; } #if CONFIG_D3D11VA if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) hr = ID3D11VideoContext_ReleaseDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder, type); #endif #if CONFIG_DXVA2 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) hr = IDirectXVideoDecoder_ReleaseBuffer(DXVA2_CONTEXT(ctx)->decoder, type); #endif if (FAILED(hr)) { av_log(avctx, AV_LOG_ERROR, "Failed to release buffer type %u: 0x%lx\n", type, hr); result = -1; } return result; }
static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, DECODER_BUFFER_DESC *bs, DECODER_BUFFER_DESC *sc) { const H264Context *h = avctx->priv_data; const unsigned mb_count = h->mb_width * h->mb_height; AVDXVAContext *ctx = avctx->hwaccel_context; const H264Picture *current_picture = h->cur_pic_ptr; struct dxva2_picture_context *ctx_pic = current_picture->hwaccel_picture_private; DXVA_Slice_H264_Short *slice = NULL; void *dxva_data_ptr = NULL; uint8_t *dxva_data, *current, *end; unsigned dxva_size = 0; void *slice_data; unsigned slice_size; unsigned padding; unsigned i; unsigned type; /* Create an annex B bitstream buffer with only slice NAL and finalize slice */ #if CONFIG_D3D11VA if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) { type = D3D11_VIDEO_DECODER_BUFFER_BITSTREAM; if (FAILED(ID3D11VideoContext_GetDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder, type, &dxva_size, &dxva_data_ptr))) return -1; } #endif #if CONFIG_DXVA2 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) { type = DXVA2_BitStreamDateBufferType; if (FAILED(IDirectXVideoDecoder_GetBuffer(DXVA2_CONTEXT(ctx)->decoder, type, &dxva_data_ptr, &dxva_size))) return -1; } #endif dxva_data = dxva_data_ptr; current = dxva_data; end = dxva_data + dxva_size; for (i = 0; i < ctx_pic->slice_count; i++) { static const uint8_t start_code[] = { 0, 0, 1 }; static const unsigned start_code_size = sizeof(start_code); unsigned position, size; assert(offsetof(DXVA_Slice_H264_Short, BSNALunitDataLocation) == offsetof(DXVA_Slice_H264_Long, BSNALunitDataLocation)); assert(offsetof(DXVA_Slice_H264_Short, SliceBytesInBuffer) == offsetof(DXVA_Slice_H264_Long, SliceBytesInBuffer)); if (is_slice_short(avctx, ctx)) slice = &ctx_pic->slice_short[i]; else slice = (DXVA_Slice_H264_Short*)&ctx_pic->slice_long[i]; position = slice->BSNALunitDataLocation; size = slice->SliceBytesInBuffer; if (start_code_size + size > end - current) { av_log(avctx, AV_LOG_ERROR, "Failed to build bitstream"); break; } slice->BSNALunitDataLocation = current - dxva_data; slice->SliceBytesInBuffer = start_code_size + size; if (!is_slice_short(avctx, ctx)) { DXVA_Slice_H264_Long *slice_long = (DXVA_Slice_H264_Long*)slice; if (i < ctx_pic->slice_count - 1) slice_long->NumMbsForSlice = slice_long[1].first_mb_in_slice - slice_long[0].first_mb_in_slice; else slice_long->NumMbsForSlice = mb_count - slice_long->first_mb_in_slice; } memcpy(current, start_code, start_code_size); current += start_code_size; memcpy(current, &ctx_pic->bitstream[position], size); current += size; } padding = FFMIN(128 - ((current - dxva_data) & 127), end - current); if (slice && padding > 0) { memset(current, 0, padding); current += padding; slice->SliceBytesInBuffer += padding; } #if CONFIG_D3D11VA if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) if (FAILED(ID3D11VideoContext_ReleaseDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder, type))) return -1; #endif #if CONFIG_DXVA2 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) if (FAILED(IDirectXVideoDecoder_ReleaseBuffer(DXVA2_CONTEXT(ctx)->decoder, type))) return -1; #endif if (i < ctx_pic->slice_count) return -1; #if CONFIG_D3D11VA if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) { D3D11_VIDEO_DECODER_BUFFER_DESC *dsc11 = bs; memset(dsc11, 0, sizeof(*dsc11)); dsc11->BufferType = type; dsc11->DataSize = current - dxva_data; dsc11->NumMBsInBuffer = mb_count; type = D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL; av_assert0((dsc11->DataSize & 127) == 0); } #endif #if CONFIG_DXVA2 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) { DXVA2_DecodeBufferDesc *dsc2 = bs; memset(dsc2, 0, sizeof(*dsc2)); dsc2->CompressedBufferType = type; dsc2->DataSize = current - dxva_data; dsc2->NumMBsInBuffer = mb_count; type = DXVA2_SliceControlBufferType; av_assert0((dsc2->DataSize & 127) == 0); } #endif if (is_slice_short(avctx, ctx)) { slice_data = ctx_pic->slice_short; slice_size = ctx_pic->slice_count * sizeof(*ctx_pic->slice_short); } else { slice_data = ctx_pic->slice_long; slice_size = ctx_pic->slice_count * sizeof(*ctx_pic->slice_long); } return ff_dxva2_commit_buffer(avctx, ctx, sc, type, slice_data, slice_size, mb_count); }
int ff_dxva2_common_end_frame(AVCodecContext *avctx, AVFrame *frame, const void *pp, unsigned pp_size, const void *qm, unsigned qm_size, int (*commit_bs_si)(AVCodecContext *, DECODER_BUFFER_DESC *bs, DECODER_BUFFER_DESC *slice)) { AVDXVAContext *ctx = avctx->hwaccel_context; unsigned buffer_count = 0; #if CONFIG_D3D11VA D3D11_VIDEO_DECODER_BUFFER_DESC buffer11[4]; #endif #if CONFIG_DXVA2 DXVA2_DecodeBufferDesc buffer2[4]; #endif DECODER_BUFFER_DESC *buffer = NULL, *buffer_slice = NULL; int result, runs = 0; HRESULT hr; unsigned type; do { #if CONFIG_D3D11VA if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) hr = ID3D11VideoContext_DecoderBeginFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder, ff_dxva2_get_surface(frame), 0, NULL); #endif #if CONFIG_DXVA2 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) hr = IDirectXVideoDecoder_BeginFrame(DXVA2_CONTEXT(ctx)->decoder, ff_dxva2_get_surface(frame), NULL); #endif if (hr == E_PENDING) av_usleep(2000); } while (hr == E_PENDING && ++runs < 50); if (FAILED(hr)) { av_log(avctx, AV_LOG_ERROR, "Failed to begin frame: 0x%lx\n", hr); return -1; } #if CONFIG_D3D11VA if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) { buffer = &buffer11[buffer_count]; type = D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS; } #endif #if CONFIG_DXVA2 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) { buffer = &buffer2[buffer_count]; type = DXVA2_PictureParametersBufferType; } #endif result = ff_dxva2_commit_buffer(avctx, ctx, buffer, type, 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) { #if CONFIG_D3D11VA if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) { buffer = &buffer11[buffer_count]; type = D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX; } #endif #if CONFIG_DXVA2 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) { buffer = &buffer2[buffer_count]; type = DXVA2_InverseQuantizationMatrixBufferType; } #endif result = ff_dxva2_commit_buffer(avctx, ctx, buffer, type, qm, qm_size, 0); if (result) { av_log(avctx, AV_LOG_ERROR, "Failed to add inverse quantization matrix buffer\n"); goto end; } buffer_count++; } #if CONFIG_D3D11VA if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) { buffer = &buffer11[buffer_count + 0]; buffer_slice = &buffer11[buffer_count + 1]; } #endif #if CONFIG_DXVA2 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) { buffer = &buffer2[buffer_count + 0]; buffer_slice = &buffer2[buffer_count + 1]; } #endif result = commit_bs_si(avctx, buffer, buffer_slice); 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); #if CONFIG_D3D11VA if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) hr = ID3D11VideoContext_SubmitDecoderBuffers(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder, buffer_count, buffer11); #endif #if CONFIG_DXVA2 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) { DXVA2_DecodeExecuteParams exec = { .NumCompBuffers = buffer_count, .pCompressedBuffers = buffer2, .pExtensionData = NULL, }; hr = IDirectXVideoDecoder_Execute(DXVA2_CONTEXT(ctx)->decoder, &exec); }