2 * Intel MediaSDK QSV codec-independent code
4 * copyright (c) 2013 Luca Barbato
5 * copyright (c) 2015 Anton Khirnov <anton@khirnov.net>
7 * This file is part of FFmpeg.
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include <sys/types.h>
27 #include <mfx/mfxvideo.h>
29 #include "libavutil/common.h"
30 #include "libavutil/mem.h"
31 #include "libavutil/log.h"
32 #include "libavutil/pixfmt.h"
33 #include "libavutil/time.h"
38 #include "qsv_internal.h"
41 int ff_qsv_map_pixfmt(enum AVPixelFormat format)
44 case AV_PIX_FMT_YUV420P:
45 case AV_PIX_FMT_YUVJ420P:
46 return AV_PIX_FMT_NV12;
48 return AVERROR(ENOSYS);
52 int ff_qsv_decode_init(AVCodecContext *avctx, QSVContext *q, AVPacket *avpkt)
54 mfxVideoParam param = { { 0 } };
55 mfxBitstream bs = { { { 0 } } };
58 q->iopattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
60 if (avctx->hwaccel_context) {
61 AVQSVContext *qsv = avctx->hwaccel_context;
63 q->session = qsv->session;
64 q->iopattern = qsv->iopattern;
65 q->ext_buffers = qsv->ext_buffers;
66 q->nb_ext_buffers = qsv->nb_ext_buffers;
69 ret = ff_qsv_init_internal_session(avctx, &q->internal_qs,
74 q->session = q->internal_qs.session;
79 bs.Data = avpkt->data;
80 bs.DataLength = avpkt->size;
81 bs.MaxLength = bs.DataLength;
82 bs.TimeStamp = avpkt->pts;
84 return AVERROR_INVALIDDATA;
86 ret = ff_qsv_codec_id_to_mfx(avctx->codec_id);
88 av_log(avctx, AV_LOG_ERROR, "Unsupported codec_id %08x\n", avctx->codec_id);
92 param.mfx.CodecId = ret;
94 ret = MFXVideoDECODE_DecodeHeader(q->session, &bs, ¶m);
95 if (MFX_ERR_MORE_DATA==ret) {
96 /* this code means that header not found so we return packet size to skip
100 } else if (ret < 0) {
101 av_log(avctx, AV_LOG_ERROR, "Decode header error %d\n", ret);
102 return ff_qsv_error(ret);
104 param.IOPattern = q->iopattern;
105 param.AsyncDepth = q->async_depth;
106 param.ExtParam = q->ext_buffers;
107 param.NumExtParam = q->nb_ext_buffers;
108 param.mfx.FrameInfo.BitDepthLuma = 8;
109 param.mfx.FrameInfo.BitDepthChroma = 8;
111 ret = MFXVideoDECODE_Init(q->session, ¶m);
113 if (MFX_ERR_INVALID_VIDEO_PARAM==ret) {
114 av_log(avctx, AV_LOG_ERROR,
115 "Error initializing the MFX video decoder, unsupported video\n");
117 av_log(avctx, AV_LOG_ERROR,
118 "Error initializing the MFX video decoder %d\n", ret);
120 return ff_qsv_error(ret);
123 avctx->pix_fmt = AV_PIX_FMT_NV12;
124 avctx->profile = param.mfx.CodecProfile;
125 avctx->level = param.mfx.CodecLevel;
126 avctx->coded_width = param.mfx.FrameInfo.Width;
127 avctx->coded_height = param.mfx.FrameInfo.Height;
128 avctx->width = param.mfx.FrameInfo.CropW - param.mfx.FrameInfo.CropX;
129 avctx->height = param.mfx.FrameInfo.CropH - param.mfx.FrameInfo.CropY;
131 /* maximum decoder latency should be not exceed max DPB size for h.264 and
132 HEVC which is 16 for both cases.
133 So weare pre-allocating fifo big enough for 17 elements:
135 if (!q->async_fifo) {
136 q->async_fifo = av_fifo_alloc((1 + 16) *
137 (sizeof(mfxSyncPoint) + sizeof(QSVFrame*)));
139 return AVERROR(ENOMEM);
142 q->input_fifo = av_fifo_alloc(1024*16);
144 return AVERROR(ENOMEM);
151 static int alloc_frame(AVCodecContext *avctx, QSVFrame *frame)
155 ret = ff_get_buffer(avctx, frame->frame, AV_GET_BUFFER_FLAG_REF);
159 if (frame->frame->format == AV_PIX_FMT_QSV) {
160 frame->surface = (mfxFrameSurface1*)frame->frame->data[3];
162 frame->surface_internal.Info.BitDepthLuma = 8;
163 frame->surface_internal.Info.BitDepthChroma = 8;
164 frame->surface_internal.Info.FourCC = MFX_FOURCC_NV12;
165 frame->surface_internal.Info.Width = avctx->coded_width;
166 frame->surface_internal.Info.Height = avctx->coded_height;
167 frame->surface_internal.Info.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
169 frame->surface_internal.Data.PitchLow = frame->frame->linesize[0];
170 frame->surface_internal.Data.Y = frame->frame->data[0];
171 frame->surface_internal.Data.UV = frame->frame->data[1];
173 frame->surface = &frame->surface_internal;
179 static void qsv_clear_unused_frames(QSVContext *q)
181 QSVFrame *cur = q->work_frames;
183 if (cur->surface && !cur->surface->Data.Locked && !cur->queued) {
185 av_frame_unref(cur->frame);
191 static int get_surface(AVCodecContext *avctx, QSVContext *q, mfxFrameSurface1 **surf)
193 QSVFrame *frame, **last;
196 qsv_clear_unused_frames(q);
198 frame = q->work_frames;
199 last = &q->work_frames;
201 if (!frame->surface) {
202 ret = alloc_frame(avctx, frame);
205 *surf = frame->surface;
213 frame = av_mallocz(sizeof(*frame));
215 return AVERROR(ENOMEM);
216 frame->frame = av_frame_alloc();
219 return AVERROR(ENOMEM);
223 ret = alloc_frame(avctx, frame);
227 *surf = frame->surface;
232 static QSVFrame *find_frame(QSVContext *q, mfxFrameSurface1 *surf)
234 QSVFrame *cur = q->work_frames;
236 if (surf == cur->surface)
243 /* This function uses for 'smart' releasing of consumed data
244 from the input bitstream fifo.
245 Since the input fifo mapped to mfxBitstream which does not understand
246 a wrapping of data over fifo end, we should also to relocate a possible
247 data rest to fifo begin. If rest of data is absent then we just reset fifo's
248 pointers to initial positions.
249 NOTE the case when fifo does contain unconsumed data is rare and typical
250 amount of such data is 1..4 bytes.
252 static void qsv_fifo_relocate(AVFifoBuffer *f, int bytes_to_free)
257 av_fifo_drain(f, bytes_to_free);
259 data_size = av_fifo_size(f);
261 if (f->buffer!=f->rptr) {
262 if ( (f->end - f->rptr) < data_size) {
263 data_rest = data_size - (f->end - f->rptr);
264 data_size-=data_rest;
265 memmove(f->buffer+data_size, f->buffer, data_rest);
267 memmove(f->buffer, f->rptr, data_size);
268 data_size+= data_rest;
272 f->wptr = f->buffer + data_size;
277 int ff_qsv_decode(AVCodecContext *avctx, QSVContext *q,
278 AVFrame *frame, int *got_frame,
282 mfxFrameSurface1 *insurf;
283 mfxFrameSurface1 *outsurf;
285 mfxBitstream bs = { { { 0 } } };
290 if (!q->engine_ready) {
291 ret = ff_qsv_decode_init(avctx, q, avpkt);
297 if (av_fifo_size(q->input_fifo)) {
298 /* we have got rest of previous packet into buffer */
299 if (av_fifo_space(q->input_fifo) < avpkt->size) {
300 ret = av_fifo_grow(q->input_fifo, avpkt->size);
304 av_fifo_generic_write(q->input_fifo, avpkt->data, avpkt->size, NULL);
305 bs.Data = q->input_fifo->rptr;
306 bs.DataLength = av_fifo_size(q->input_fifo);
309 bs.Data = avpkt->data;
310 bs.DataLength = avpkt->size;
312 bs.MaxLength = bs.DataLength;
313 bs.TimeStamp = avpkt->pts;
317 ret = get_surface(avctx, q, &insurf);
321 ret = MFXVideoDECODE_DecodeFrameAsync(q->session, avpkt->size ? &bs : NULL,
322 insurf, &outsurf, &sync);
323 if (ret != MFX_WRN_DEVICE_BUSY)
328 if (MFX_WRN_VIDEO_PARAM_CHANGED==ret) {
329 /* TODO: handle here sequence header changing */
333 QSVFrame *out_frame = find_frame(q, outsurf);
336 av_log(avctx, AV_LOG_ERROR,
337 "The returned surface does not correspond to any frame\n");
341 out_frame->queued = 1;
342 av_fifo_generic_write(q->async_fifo, &out_frame, sizeof(out_frame), NULL);
343 av_fifo_generic_write(q->async_fifo, &sync, sizeof(sync), NULL);
347 if (MFX_ERR_MORE_SURFACE != ret && ret < 0)
351 /* make sure we do not enter an infinite loop if the SDK
352 * did not consume any data and did not return anything */
353 if (!sync && !bs.DataOffset) {
354 av_log(avctx, AV_LOG_WARNING, "A decode call did not consume any data\n");
355 bs.DataOffset = avpkt->size;
359 qsv_fifo_relocate(q->input_fifo, bs.DataOffset);
360 } else if (bs.DataOffset!=avpkt->size) {
361 /* some data of packet was not consumed. store it to local buffer */
362 av_fifo_generic_write(q->input_fifo, avpkt->data+bs.DataOffset,
363 avpkt->size - bs.DataOffset, NULL);
366 if (MFX_ERR_MORE_DATA!=ret && ret < 0) {
367 av_log(avctx, AV_LOG_ERROR, "Error %d during QSV decoding.\n", ret);
368 return ff_qsv_error(ret);
370 n_out_frames = av_fifo_size(q->async_fifo) / (sizeof(out_frame)+sizeof(sync));
372 if (n_out_frames > q->async_depth || (!avpkt->size && n_out_frames) ) {
375 av_fifo_generic_read(q->async_fifo, &out_frame, sizeof(out_frame), NULL);
376 av_fifo_generic_read(q->async_fifo, &sync, sizeof(sync), NULL);
377 out_frame->queued = 0;
379 MFXVideoCORE_SyncOperation(q->session, sync, 60000);
381 src_frame = out_frame->frame;
383 ret = av_frame_ref(frame, src_frame);
387 outsurf = out_frame->surface;
389 frame->pkt_pts = frame->pts = outsurf->Data.TimeStamp;
392 outsurf->Info.PicStruct & MFX_PICSTRUCT_FRAME_TRIPLING ? 4 :
393 outsurf->Info.PicStruct & MFX_PICSTRUCT_FRAME_DOUBLING ? 2 :
394 outsurf->Info.PicStruct & MFX_PICSTRUCT_FIELD_REPEATED ? 1 : 0;
395 frame->top_field_first =
396 outsurf->Info.PicStruct & MFX_PICSTRUCT_FIELD_TFF;
397 frame->interlaced_frame =
398 !(outsurf->Info.PicStruct & MFX_PICSTRUCT_PROGRESSIVE);
406 int ff_qsv_decode_close(QSVContext *q)
408 QSVFrame *cur = q->work_frames;
411 q->work_frames = cur->next;
412 av_frame_free(&cur->frame);
414 cur = q->work_frames;
417 av_fifo_free(q->async_fifo);
418 q->async_fifo = NULL;
420 av_fifo_free(q->input_fifo);
421 q->input_fifo = NULL;
423 MFXVideoDECODE_Close(q->session);
426 ff_qsv_close_internal_session(&q->internal_qs);