yading@10: /* yading@10: * DXVA2 HW acceleration. yading@10: * yading@10: * copyright (c) 2010 Laurent Aimar yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: #include "dxva2_internal.h" yading@10: yading@10: void *ff_dxva2_get_surface(const Picture *picture) yading@10: { yading@10: return picture->f.data[3]; yading@10: } yading@10: yading@10: unsigned ff_dxva2_get_surface_index(const struct dxva_context *ctx, yading@10: const Picture *picture) yading@10: { yading@10: void *surface = ff_dxva2_get_surface(picture); yading@10: unsigned i; yading@10: yading@10: for (i = 0; i < ctx->surface_count; i++) yading@10: if (ctx->surface[i] == surface) yading@10: return i; yading@10: yading@10: assert(0); yading@10: return 0; yading@10: } yading@10: yading@10: int ff_dxva2_commit_buffer(AVCodecContext *avctx, yading@10: struct dxva_context *ctx, yading@10: DXVA2_DecodeBufferDesc *dsc, yading@10: unsigned type, const void *data, unsigned size, yading@10: unsigned mb_count) yading@10: { yading@10: void *dxva_data; yading@10: unsigned dxva_size; yading@10: int result; yading@10: yading@10: if (FAILED(IDirectXVideoDecoder_GetBuffer(ctx->decoder, type, yading@10: &dxva_data, &dxva_size))) { yading@10: av_log(avctx, AV_LOG_ERROR, "Failed to get a buffer for %d\n", type); yading@10: return -1; yading@10: } yading@10: if (size <= dxva_size) { yading@10: memcpy(dxva_data, data, size); yading@10: yading@10: memset(dsc, 0, sizeof(*dsc)); yading@10: dsc->CompressedBufferType = type; yading@10: dsc->DataSize = size; yading@10: dsc->NumMBsInBuffer = mb_count; yading@10: yading@10: result = 0; yading@10: } else { yading@10: av_log(avctx, AV_LOG_ERROR, "Buffer for type %d was too small\n", type); yading@10: result = -1; yading@10: } yading@10: if (FAILED(IDirectXVideoDecoder_ReleaseBuffer(ctx->decoder, type))) { yading@10: av_log(avctx, AV_LOG_ERROR, "Failed to release buffer type %d\n", type); yading@10: result = -1; yading@10: } yading@10: return result; yading@10: } yading@10: yading@10: int ff_dxva2_common_end_frame(AVCodecContext *avctx, Picture *pic, yading@10: const void *pp, unsigned pp_size, yading@10: const void *qm, unsigned qm_size, yading@10: int (*commit_bs_si)(AVCodecContext *, yading@10: DXVA2_DecodeBufferDesc *bs, yading@10: DXVA2_DecodeBufferDesc *slice)) yading@10: { yading@10: struct dxva_context *ctx = avctx->hwaccel_context; yading@10: unsigned buffer_count = 0; yading@10: DXVA2_DecodeBufferDesc buffer[4]; yading@10: DXVA2_DecodeExecuteParams exec = { 0 }; yading@10: int result; yading@10: yading@10: if (FAILED(IDirectXVideoDecoder_BeginFrame(ctx->decoder, yading@10: ff_dxva2_get_surface(pic), yading@10: NULL))) { yading@10: av_log(avctx, AV_LOG_ERROR, "Failed to begin frame\n"); yading@10: return -1; yading@10: } yading@10: yading@10: result = ff_dxva2_commit_buffer(avctx, ctx, &buffer[buffer_count], yading@10: DXVA2_PictureParametersBufferType, yading@10: pp, pp_size, 0); yading@10: if (result) { yading@10: av_log(avctx, AV_LOG_ERROR, yading@10: "Failed to add picture parameter buffer\n"); yading@10: goto end; yading@10: } yading@10: buffer_count++; yading@10: yading@10: if (qm_size > 0) { yading@10: result = ff_dxva2_commit_buffer(avctx, ctx, &buffer[buffer_count], yading@10: DXVA2_InverseQuantizationMatrixBufferType, yading@10: qm, qm_size, 0); yading@10: if (result) { yading@10: av_log(avctx, AV_LOG_ERROR, yading@10: "Failed to add inverse quantization matrix buffer\n"); yading@10: goto end; yading@10: } yading@10: buffer_count++; yading@10: } yading@10: yading@10: result = commit_bs_si(avctx, yading@10: &buffer[buffer_count + 0], yading@10: &buffer[buffer_count + 1]); yading@10: if (result) { yading@10: av_log(avctx, AV_LOG_ERROR, yading@10: "Failed to add bitstream or slice control buffer\n"); yading@10: goto end; yading@10: } yading@10: buffer_count += 2; yading@10: yading@10: /* TODO Film Grain when possible */ yading@10: yading@10: assert(buffer_count == 1 + (qm_size > 0) + 2); yading@10: yading@10: exec.NumCompBuffers = buffer_count; yading@10: exec.pCompressedBuffers = buffer; yading@10: exec.pExtensionData = NULL; yading@10: if (FAILED(IDirectXVideoDecoder_Execute(ctx->decoder, &exec))) { yading@10: av_log(avctx, AV_LOG_ERROR, "Failed to execute\n"); yading@10: result = -1; yading@10: } yading@10: yading@10: end: yading@10: if (FAILED(IDirectXVideoDecoder_EndFrame(ctx->decoder, NULL))) { yading@10: av_log(avctx, AV_LOG_ERROR, "Failed to end frame\n"); yading@10: result = -1; yading@10: } yading@10: yading@10: return result; yading@10: }