1/* 2 * DXVA2 HW acceleration. 3 * 4 * copyright (c) 2010 Laurent Aimar 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 "dxva2_internal.h" 24 25void *ff_dxva2_get_surface(const Picture *picture) 26{ 27 return picture->data[3]; 28} 29 30unsigned ff_dxva2_get_surface_index(const struct dxva_context *ctx, 31 const Picture *picture) 32{ 33 void *surface = ff_dxva2_get_surface(picture); 34 unsigned i; 35 36 for (i = 0; i < ctx->surface_count; i++) 37 if (ctx->surface[i] == surface) 38 return i; 39 40 assert(0); 41 return 0; 42} 43 44int ff_dxva2_commit_buffer(AVCodecContext *avctx, 45 struct dxva_context *ctx, 46 DXVA2_DecodeBufferDesc *dsc, 47 unsigned type, const void *data, unsigned size, 48 unsigned mb_count) 49{ 50 void *dxva_data; 51 unsigned dxva_size; 52 int result; 53 54 if (FAILED(IDirectXVideoDecoder_GetBuffer(ctx->decoder, type, 55 &dxva_data, &dxva_size))) { 56 av_log(avctx, AV_LOG_ERROR, "Failed to get a buffer for %d\n", type); 57 return -1; 58 } 59 if (size <= dxva_size) { 60 memcpy(dxva_data, data, size); 61 62 memset(dsc, 0, sizeof(*dsc)); 63 dsc->CompressedBufferType = type; 64 dsc->DataSize = size; 65 dsc->NumMBsInBuffer = mb_count; 66 67 result = 0; 68 } else { 69 av_log(avctx, AV_LOG_ERROR, "Buffer for type %d was too small\n", type); 70 result = -1; 71 } 72 if (FAILED(IDirectXVideoDecoder_ReleaseBuffer(ctx->decoder, type))) { 73 av_log(avctx, AV_LOG_ERROR, "Failed to release buffer type %d\n", type); 74 result = -1; 75 } 76 return result; 77} 78 79int ff_dxva2_common_end_frame(AVCodecContext *avctx, MpegEncContext *s, 80 const void *pp, unsigned pp_size, 81 const void *qm, unsigned qm_size, 82 int (*commit_bs_si)(AVCodecContext *, 83 DXVA2_DecodeBufferDesc *bs, 84 DXVA2_DecodeBufferDesc *slice)) 85{ 86 struct dxva_context *ctx = avctx->hwaccel_context; 87 unsigned buffer_count = 0; 88 DXVA2_DecodeBufferDesc buffer[4]; 89 DXVA2_DecodeExecuteParams exec; 90 int result; 91 92 if (FAILED(IDirectXVideoDecoder_BeginFrame(ctx->decoder, 93 ff_dxva2_get_surface(s->current_picture_ptr), 94 NULL))) { 95 av_log(avctx, AV_LOG_ERROR, "Failed to begin frame\n"); 96 return -1; 97 } 98 99 result = ff_dxva2_commit_buffer(avctx, ctx, &buffer[buffer_count], 100 DXVA2_PictureParametersBufferType, 101 pp, pp_size, 0); 102 if (result) { 103 av_log(avctx, AV_LOG_ERROR, 104 "Failed to add picture parameter buffer\n"); 105 goto end; 106 } 107 buffer_count++; 108 109 if (qm_size > 0) { 110 result = ff_dxva2_commit_buffer(avctx, ctx, &buffer[buffer_count], 111 DXVA2_InverseQuantizationMatrixBufferType, 112 qm, qm_size, 0); 113 if (result) { 114 av_log(avctx, AV_LOG_ERROR, 115 "Failed to add inverse quantization matrix buffer\n"); 116 goto end; 117 } 118 buffer_count++; 119 } 120 121 result = commit_bs_si(avctx, 122 &buffer[buffer_count + 0], 123 &buffer[buffer_count + 1]); 124 if (result) { 125 av_log(avctx, AV_LOG_ERROR, 126 "Failed to add bitstream or slice control buffer\n"); 127 goto end; 128 } 129 buffer_count += 2; 130 131 /* TODO Film Grain when possible */ 132 133 assert(buffer_count == 1 + (qm_size > 0) + 2); 134 135 memset(&exec, 0, sizeof(exec)); 136 exec.NumCompBuffers = buffer_count; 137 exec.pCompressedBuffers = buffer; 138 exec.pExtensionData = NULL; 139 if (FAILED(IDirectXVideoDecoder_Execute(ctx->decoder, &exec))) { 140 av_log(avctx, AV_LOG_ERROR, "Failed to execute\n"); 141 result = -1; 142 } 143 144end: 145 if (FAILED(IDirectXVideoDecoder_EndFrame(ctx->decoder, NULL))) { 146 av_log(avctx, AV_LOG_ERROR, "Failed to end frame\n"); 147 result = -1; 148 } 149 150 if (!result) 151 ff_draw_horiz_band(s, 0, s->avctx->height); 152 return result; 153} 154 155