f0f86627 |
/*
* DXVA2 WMV3/VC-1 HW acceleration.
*
* copyright (c) 2010 Laurent Aimar
*
* This file is part of FFmpeg.
*
* FFmpeg 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,
* 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
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
|
8f144d9e |
#include "dxva2_internal.h" |
e0c16e4e |
#include "mpegutils.h" |
f0f86627 |
#include "vc1.h"
#include "vc1data.h"
|
99ee8ee0 |
#define MAX_SLICES 1024 |
b14761d1 |
|
f0f86627 |
struct dxva2_picture_context {
DXVA_PictureParameters pp; |
99ee8ee0 |
unsigned slice_count;
DXVA_SliceInfo slice[MAX_SLICES]; |
f0f86627 |
const uint8_t *bitstream;
unsigned bitstream_size;
};
static void fill_picture_parameters(AVCodecContext *avctx, |
d8039ef8 |
AVDXVAContext *ctx, const VC1Context *v, |
f0f86627 |
DXVA_PictureParameters *pp)
{
const MpegEncContext *s = &v->s;
const Picture *current_picture = s->current_picture_ptr; |
c5562890 |
int intcomp = 0;
// determine if intensity compensation is needed
if (s->pict_type == AV_PICTURE_TYPE_P) {
if ((v->fcm == ILACE_FRAME && v->intcomp) || (v->fcm != ILACE_FRAME && v->mv_mode == MV_PMODE_INTENSITY_COMP)) { |
930f67b7 |
if (v->lumscale != 32 || v->lumshift != 0 || (s->picture_structure != PICT_FRAME && (v->lumscale2 != 32 || v->lumshift2 != 0))) |
c5562890 |
intcomp = 1;
}
} |
f0f86627 |
memset(pp, 0, sizeof(*pp));
pp->wDecodedPictureIndex = |
d8039ef8 |
pp->wDeblockedPictureIndex = ff_dxva2_get_surface_index(avctx, ctx, current_picture->f); |
a3c5aeff |
if (s->pict_type != AV_PICTURE_TYPE_I && !v->bi_type) |
d8039ef8 |
pp->wForwardRefPictureIndex = ff_dxva2_get_surface_index(avctx, ctx, s->last_picture.f); |
f0f86627 |
else
pp->wForwardRefPictureIndex = 0xffff; |
a3c5aeff |
if (s->pict_type == AV_PICTURE_TYPE_B && !v->bi_type) |
d8039ef8 |
pp->wBackwardRefPictureIndex = ff_dxva2_get_surface_index(avctx, ctx, s->next_picture.f); |
f0f86627 |
else
pp->wBackwardRefPictureIndex = 0xffff;
if (v->profile == PROFILE_ADVANCED) {
/* It is the cropped width/height -1 of the frame */
pp->wPicWidthInMBminus1 = avctx->width - 1;
pp->wPicHeightInMBminus1= avctx->height - 1;
} else {
/* It is the coded width/height in macroblock -1 of the frame */
pp->wPicWidthInMBminus1 = s->mb_width - 1;
pp->wPicHeightInMBminus1= s->mb_height - 1;
}
pp->bMacroblockWidthMinus1 = 15;
pp->bMacroblockHeightMinus1 = 15;
pp->bBlockWidthMinus1 = 7;
pp->bBlockHeightMinus1 = 7;
pp->bBPPminus1 = 7;
if (s->picture_structure & PICT_TOP_FIELD)
pp->bPicStructure |= 0x01;
if (s->picture_structure & PICT_BOTTOM_FIELD)
pp->bPicStructure |= 0x02; |
b87ff344 |
pp->bSecondField = v->interlace && v->fcm == ILACE_FIELD && v->second_field; |
a3c5aeff |
pp->bPicIntra = s->pict_type == AV_PICTURE_TYPE_I || v->bi_type;
pp->bPicBackwardPrediction = s->pict_type == AV_PICTURE_TYPE_B && !v->bi_type; |
f0f86627 |
pp->bBidirectionalAveragingMode = (1 << 7) | |
d8039ef8 |
((DXVA_CONTEXT_CFG_INTRARESID(avctx, ctx) != 0) << 6) |
((DXVA_CONTEXT_CFG_RESIDACCEL(avctx, ctx) != 0) << 5) | |
c5562890 |
(intcomp << 4) | |
f0f86627 |
((v->profile == PROFILE_ADVANCED) << 3);
pp->bMVprecisionAndChromaRelation = ((v->mv_mode == MV_PMODE_1MV_HPEL_BILIN) << 3) |
(1 << 2) |
(0 << 1) |
(!s->quarter_sample );
pp->bChromaFormat = v->chromaformat; |
d8039ef8 |
DXVA_CONTEXT_REPORT_ID(avctx, ctx)++;
if (DXVA_CONTEXT_REPORT_ID(avctx, ctx) >= (1 << 16))
DXVA_CONTEXT_REPORT_ID(avctx, ctx) = 1;
pp->bPicScanFixed = DXVA_CONTEXT_REPORT_ID(avctx, ctx) >> 8;
pp->bPicScanMethod = DXVA_CONTEXT_REPORT_ID(avctx, ctx) & 0xff; |
f0f86627 |
pp->bPicReadbackRequests = 0;
pp->bRcontrol = v->rnd;
pp->bPicSpatialResid8 = (v->panscanflag << 7) |
(v->refdist_flag << 6) |
(s->loop_filter << 5) |
(v->fastuvmc << 4) |
(v->extended_mv << 3) |
(v->dquant << 1) |
(v->vstransform );
pp->bPicOverflowBlocks = (v->quantizer_mode << 6) |
(v->multires << 5) | |
c2f7417e |
(v->resync_marker << 4) | |
f0f86627 |
(v->rangered << 3) |
(s->max_b_frames ); |
1f948745 |
pp->bPicExtrapolation = (!v->interlace || v->fcm == PROGRESSIVE) ? 1 : 2; |
0aedd8c0 |
pp->bPicDeblocked = ((!pp->bPicBackwardPrediction && v->overlap) << 6) |
((v->profile != PROFILE_ADVANCED && v->rangeredfrm) << 5) | |
f0f86627 |
(s->loop_filter << 1);
pp->bPicDeblockConfined = (v->postprocflag << 7) |
(v->broadcast << 6) |
(v->interlace << 5) |
(v->tfcntrflag << 4) |
(v->finterpflag << 3) | |
ce5e49b0 |
((s->pict_type != AV_PICTURE_TYPE_B) << 2) | |
f0f86627 |
(v->psf << 1) |
(v->extended_dmv ); |
ce5e49b0 |
if (s->pict_type != AV_PICTURE_TYPE_I) |
f0f86627 |
pp->bPic4MVallowed = v->mv_mode == MV_PMODE_MIXED_MV ||
(v->mv_mode == MV_PMODE_INTENSITY_COMP &&
v->mv_mode2 == MV_PMODE_MIXED_MV);
if (v->profile == PROFILE_ADVANCED)
pp->bPicOBMC = (v->range_mapy_flag << 7) |
(v->range_mapy << 4) |
(v->range_mapuv_flag << 3) |
(v->range_mapuv );
pp->bPicBinPB = 0; |
8abdf46b |
pp->bMV_RPS = (v->fcm == ILACE_FIELD && pp->bPicBackwardPrediction) ? v->refdist + 9 : 0; |
e1facd3f |
pp->bReservedBits = v->pq; |
f0f86627 |
if (s->picture_structure == PICT_FRAME) { |
c5562890 |
if (intcomp) {
pp->wBitstreamFcodes = v->lumscale;
pp->wBitstreamPCEelements = v->lumshift;
} else {
pp->wBitstreamFcodes = 32;
pp->wBitstreamPCEelements = 0;
} |
f0f86627 |
} else {
/* Syntax: (top_field_param << 8) | bottom_field_param */ |
c5562890 |
if (intcomp) {
pp->wBitstreamFcodes = (v->lumscale << 8) | v->lumscale2;
pp->wBitstreamPCEelements = (v->lumshift << 8) | v->lumshift2;
} else {
pp->wBitstreamFcodes = (32 << 8) | 32;
pp->wBitstreamPCEelements = 0;
} |
f0f86627 |
}
pp->bBitstreamConcealmentNeed = 0;
pp->bBitstreamConcealmentMethod = 0;
}
static void fill_slice(AVCodecContext *avctx, DXVA_SliceInfo *slice,
unsigned position, unsigned size)
{
const VC1Context *v = avctx->priv_data;
const MpegEncContext *s = &v->s;
memset(slice, 0, sizeof(*slice));
slice->wHorizontalPosition = 0;
slice->wVerticalPosition = s->mb_y;
slice->dwSliceBitsInBuffer = 8 * size;
slice->dwSliceDataLocation = position;
slice->bStartCodeBitOffset = 0; |
3021d1be |
slice->bReservedBits = (s->pict_type == AV_PICTURE_TYPE_B && !v->bi_type) ? v->bfraction_lut_index + 9 : 0; |
61ff0431 |
slice->wMBbitOffset = v->p_frame_skipped ? 0xffff : get_bits_count(&s->gb) + (avctx->codec_id == AV_CODEC_ID_VC1 ? 32 : 0); |
99ee8ee0 |
/* XXX We store the index of the first MB and it will be fixed later */
slice->wNumberMBsInSlice = (s->mb_y >> v->field_mode) * s->mb_width + s->mb_x; |
f0f86627 |
slice->wQuantizerScaleCode = v->pq;
slice->wBadSliceChopping = 0;
}
static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, |
d8039ef8 |
DECODER_BUFFER_DESC *bs,
DECODER_BUFFER_DESC *sc) |
f0f86627 |
{
const VC1Context *v = avctx->priv_data; |
ab28108a |
AVDXVAContext *ctx = DXVA_CONTEXT(avctx); |
f0f86627 |
const MpegEncContext *s = &v->s; |
ad0c9f2d |
struct dxva2_picture_context *ctx_pic = s->current_picture_ptr->hwaccel_picture_private; |
f0f86627 |
static const uint8_t start_code[] = { 0, 0, 1, 0x0d }; |
36ef5369 |
const unsigned start_code_size = avctx->codec_id == AV_CODEC_ID_VC1 ? sizeof(start_code) : 0; |
99ee8ee0 |
const unsigned mb_count = s->mb_width * (s->mb_height >> v->field_mode);
DXVA_SliceInfo *slice = NULL; |
4600a85e |
void *dxva_data_ptr; |
99ee8ee0 |
uint8_t *dxva_data, *current, *end; |
f0f86627 |
unsigned dxva_size; |
99ee8ee0 |
unsigned padding;
unsigned i; |
d8039ef8 |
unsigned type; |
f0f86627 |
|
d8039ef8 |
#if CONFIG_D3D11VA |
ab28108a |
if (ff_dxva2_is_d3d11(avctx)) { |
d8039ef8 |
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 |
f0f86627 |
|
4600a85e |
dxva_data = dxva_data_ptr; |
99ee8ee0 |
current = dxva_data;
end = dxva_data + dxva_size;
for (i = 0; i < ctx_pic->slice_count; i++) {
unsigned position, size;
slice = &ctx_pic->slice[i];
position = slice->dwSliceDataLocation;
size = slice->dwSliceBitsInBuffer / 8;
if (start_code_size + size > end - current) {
av_log(avctx, AV_LOG_ERROR, "Failed to build bitstream");
break;
}
slice->dwSliceDataLocation = current - dxva_data;
if (i < ctx_pic->slice_count - 1)
slice->wNumberMBsInSlice =
slice[1].wNumberMBsInSlice - slice[0].wNumberMBsInSlice;
else
slice->wNumberMBsInSlice =
mb_count - slice[0].wNumberMBsInSlice;
/* write the appropriate frame, field or slice start code */
if (start_code_size) {
memcpy(current, start_code, start_code_size);
if (i == 0 && v->second_field)
current[3] = 0x0c;
else if (i > 0)
current[3] = 0x0b;
current += start_code_size;
slice->dwSliceBitsInBuffer += start_code_size * 8; |
b87ff344 |
} |
99ee8ee0 |
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->dwSliceBitsInBuffer += padding * 8; |
f0f86627 |
} |
99ee8ee0 |
|
d8039ef8 |
#if CONFIG_D3D11VA |
ab28108a |
if (ff_dxva2_is_d3d11(avctx)) |
d8039ef8 |
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 |
99ee8ee0 |
if (i < ctx_pic->slice_count)
return -1; |
f0f86627 |
|
d8039ef8 |
#if CONFIG_D3D11VA |
ab28108a |
if (ff_dxva2_is_d3d11(avctx)) { |
d8039ef8 |
D3D11_VIDEO_DECODER_BUFFER_DESC *dsc11 = bs;
memset(dsc11, 0, sizeof(*dsc11));
dsc11->BufferType = type; |
99ee8ee0 |
dsc11->DataSize = current - dxva_data;
dsc11->NumMBsInBuffer = mb_count; |
d8039ef8 |
type = D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL;
}
#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; |
99ee8ee0 |
dsc2->DataSize = current - dxva_data;
dsc2->NumMBsInBuffer = mb_count; |
d8039ef8 |
type = DXVA2_SliceControlBufferType;
}
#endif |
f0f86627 |
return ff_dxva2_commit_buffer(avctx, ctx, sc, |
d8039ef8 |
type, |
99ee8ee0 |
ctx_pic->slice,
ctx_pic->slice_count * sizeof(*ctx_pic->slice),
mb_count); |
f0f86627 |
}
|
c57a5936 |
static int dxva2_vc1_start_frame(AVCodecContext *avctx,
av_unused const uint8_t *buffer,
av_unused uint32_t size) |
f0f86627 |
{
const VC1Context *v = avctx->priv_data; |
ab28108a |
AVDXVAContext *ctx = DXVA_CONTEXT(avctx); |
ad0c9f2d |
struct dxva2_picture_context *ctx_pic = v->s.current_picture_ptr->hwaccel_picture_private; |
f0f86627 |
|
77742c75 |
if (!DXVA_CONTEXT_VALID(avctx, ctx)) |
f0f86627 |
return -1;
assert(ctx_pic);
fill_picture_parameters(avctx, ctx, v, &ctx_pic->pp);
|
99ee8ee0 |
ctx_pic->slice_count = 0; |
f0f86627 |
ctx_pic->bitstream_size = 0;
ctx_pic->bitstream = NULL;
return 0;
}
|
c57a5936 |
static int dxva2_vc1_decode_slice(AVCodecContext *avctx,
const uint8_t *buffer,
uint32_t size) |
f0f86627 |
{
const VC1Context *v = avctx->priv_data;
const Picture *current_picture = v->s.current_picture_ptr; |
ad0c9f2d |
struct dxva2_picture_context *ctx_pic = current_picture->hwaccel_picture_private; |
99ee8ee0 |
unsigned position; |
f0f86627 |
|
99ee8ee0 |
if (ctx_pic->slice_count >= MAX_SLICES) {
avpriv_request_sample(avctx, "%d slices in dxva2",
ctx_pic->slice_count); |
f0f86627 |
return -1; |
99ee8ee0 |
} |
f0f86627 |
|
36ef5369 |
if (avctx->codec_id == AV_CODEC_ID_VC1 && |
f0f86627 |
size >= 4 && IS_MARKER(AV_RB32(buffer))) {
buffer += 4;
size -= 4;
}
|
99ee8ee0 |
if (!ctx_pic->bitstream)
ctx_pic->bitstream = buffer;
ctx_pic->bitstream_size += size; |
f0f86627 |
|
99ee8ee0 |
position = buffer - ctx_pic->bitstream;
fill_slice(avctx, &ctx_pic->slice[ctx_pic->slice_count++], position, size); |
f0f86627 |
return 0;
}
|
c57a5936 |
static int dxva2_vc1_end_frame(AVCodecContext *avctx) |
f0f86627 |
{
VC1Context *v = avctx->priv_data; |
ad0c9f2d |
struct dxva2_picture_context *ctx_pic = v->s.current_picture_ptr->hwaccel_picture_private; |
2c541554 |
int ret; |
f0f86627 |
|
99ee8ee0 |
if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0) |
f0f86627 |
return -1;
|
f6774f90 |
ret = ff_dxva2_common_end_frame(avctx, v->s.current_picture_ptr->f, |
2c541554 |
&ctx_pic->pp, sizeof(ctx_pic->pp),
NULL, 0,
commit_bitstream_and_slice_buffer);
if (!ret)
ff_mpeg_draw_horiz_band(&v->s, 0, avctx->height);
return ret; |
f0f86627 |
}
#if CONFIG_WMV3_DXVA2_HWACCEL |
3a71bcc2 |
const AVHWAccel ff_wmv3_dxva2_hwaccel = { |
f0f86627 |
.name = "wmv3_dxva2", |
72415b2a |
.type = AVMEDIA_TYPE_VIDEO, |
36ef5369 |
.id = AV_CODEC_ID_WMV3, |
716d413c |
.pix_fmt = AV_PIX_FMT_DXVA2_VLD, |
70143a39 |
.init = ff_dxva2_decode_init,
.uninit = ff_dxva2_decode_uninit, |
c57a5936 |
.start_frame = dxva2_vc1_start_frame,
.decode_slice = dxva2_vc1_decode_slice,
.end_frame = dxva2_vc1_end_frame, |
b46a77f1 |
.frame_params = ff_dxva2_common_frame_params, |
a871ef0c |
.frame_priv_data_size = sizeof(struct dxva2_picture_context), |
70143a39 |
.priv_data_size = sizeof(FFDXVASharedContext), |
f0f86627 |
};
#endif
|
d8039ef8 |
#if CONFIG_VC1_DXVA2_HWACCEL |
3a71bcc2 |
const AVHWAccel ff_vc1_dxva2_hwaccel = { |
f0f86627 |
.name = "vc1_dxva2", |
72415b2a |
.type = AVMEDIA_TYPE_VIDEO, |
36ef5369 |
.id = AV_CODEC_ID_VC1, |
716d413c |
.pix_fmt = AV_PIX_FMT_DXVA2_VLD, |
70143a39 |
.init = ff_dxva2_decode_init,
.uninit = ff_dxva2_decode_uninit, |
c57a5936 |
.start_frame = dxva2_vc1_start_frame,
.decode_slice = dxva2_vc1_decode_slice,
.end_frame = dxva2_vc1_end_frame, |
b46a77f1 |
.frame_params = ff_dxva2_common_frame_params, |
a871ef0c |
.frame_priv_data_size = sizeof(struct dxva2_picture_context), |
70143a39 |
.priv_data_size = sizeof(FFDXVASharedContext), |
f0f86627 |
}; |
d8039ef8 |
#endif
#if CONFIG_WMV3_D3D11VA_HWACCEL |
3a71bcc2 |
const AVHWAccel ff_wmv3_d3d11va_hwaccel = { |
d8039ef8 |
.name = "wmv3_d3d11va",
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_WMV3,
.pix_fmt = AV_PIX_FMT_D3D11VA_VLD, |
70143a39 |
.init = ff_dxva2_decode_init,
.uninit = ff_dxva2_decode_uninit, |
d8039ef8 |
.start_frame = dxva2_vc1_start_frame,
.decode_slice = dxva2_vc1_decode_slice,
.end_frame = dxva2_vc1_end_frame, |
b46a77f1 |
.frame_params = ff_dxva2_common_frame_params, |
d8039ef8 |
.frame_priv_data_size = sizeof(struct dxva2_picture_context), |
70143a39 |
.priv_data_size = sizeof(FFDXVASharedContext),
};
#endif
#if CONFIG_WMV3_D3D11VA2_HWACCEL |
3a71bcc2 |
const AVHWAccel ff_wmv3_d3d11va2_hwaccel = { |
70143a39 |
.name = "wmv3_d3d11va2",
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_WMV3,
.pix_fmt = AV_PIX_FMT_D3D11,
.init = ff_dxva2_decode_init,
.uninit = ff_dxva2_decode_uninit,
.start_frame = dxva2_vc1_start_frame,
.decode_slice = dxva2_vc1_decode_slice,
.end_frame = dxva2_vc1_end_frame, |
b46a77f1 |
.frame_params = ff_dxva2_common_frame_params, |
70143a39 |
.frame_priv_data_size = sizeof(struct dxva2_picture_context),
.priv_data_size = sizeof(FFDXVASharedContext), |
d8039ef8 |
};
#endif
#if CONFIG_VC1_D3D11VA_HWACCEL |
3a71bcc2 |
const AVHWAccel ff_vc1_d3d11va_hwaccel = { |
d8039ef8 |
.name = "vc1_d3d11va",
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_VC1,
.pix_fmt = AV_PIX_FMT_D3D11VA_VLD, |
70143a39 |
.init = ff_dxva2_decode_init,
.uninit = ff_dxva2_decode_uninit,
.start_frame = dxva2_vc1_start_frame,
.decode_slice = dxva2_vc1_decode_slice,
.end_frame = dxva2_vc1_end_frame, |
b46a77f1 |
.frame_params = ff_dxva2_common_frame_params, |
70143a39 |
.frame_priv_data_size = sizeof(struct dxva2_picture_context),
.priv_data_size = sizeof(FFDXVASharedContext),
};
#endif
#if CONFIG_VC1_D3D11VA2_HWACCEL |
3a71bcc2 |
const AVHWAccel ff_vc1_d3d11va2_hwaccel = { |
70143a39 |
.name = "vc1_d3d11va2",
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_VC1,
.pix_fmt = AV_PIX_FMT_D3D11,
.init = ff_dxva2_decode_init,
.uninit = ff_dxva2_decode_uninit, |
d8039ef8 |
.start_frame = dxva2_vc1_start_frame,
.decode_slice = dxva2_vc1_decode_slice,
.end_frame = dxva2_vc1_end_frame, |
59347c24 |
.frame_params = ff_dxva2_common_frame_params, |
d8039ef8 |
.frame_priv_data_size = sizeof(struct dxva2_picture_context), |
70143a39 |
.priv_data_size = sizeof(FFDXVASharedContext), |
d8039ef8 |
};
#endif |