]> git.sesse.net Git - ffmpeg/blob - libavcodec/qsvdec.c
Merge commit 'ea4d46e72945cba37feb7aa154eb970732f513e4'
[ffmpeg] / libavcodec / qsvdec.c
1 /*
2  * Intel MediaSDK QSV codec-independent code
3  *
4  * copyright (c) 2013 Luca Barbato
5  * copyright (c) 2015 Anton Khirnov <anton@khirnov.net>
6  *
7  * This file is part of FFmpeg.
8  *
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.
13  *
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.
18  *
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
22  */
23
24 #include <string.h>
25 #include <sys/types.h>
26
27 #include <mfx/mfxvideo.h>
28
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"
34
35 #include "avcodec.h"
36 #include "internal.h"
37 #include "qsv.h"
38 #include "qsv_internal.h"
39 #include "qsvdec.h"
40
41 int ff_qsv_map_pixfmt(enum AVPixelFormat format)
42 {
43     switch (format) {
44     case AV_PIX_FMT_YUV420P:
45     case AV_PIX_FMT_YUVJ420P:
46         return AV_PIX_FMT_NV12;
47     default:
48         return AVERROR(ENOSYS);
49     }
50 }
51
52 int ff_qsv_decode_init(AVCodecContext *avctx, QSVContext *q)
53 {
54     mfxVideoParam param = { { 0 } };
55     int ret;
56
57     q->async_fifo = av_fifo_alloc((1 + q->async_depth) *
58                                   (sizeof(mfxSyncPoint) + sizeof(QSVFrame*)));
59     if (!q->async_fifo)
60         return AVERROR(ENOMEM);
61
62     q->iopattern  = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
63
64     if (avctx->hwaccel_context) {
65         AVQSVContext *qsv = avctx->hwaccel_context;
66
67         q->session        = qsv->session;
68         q->iopattern      = qsv->iopattern;
69         q->ext_buffers    = qsv->ext_buffers;
70         q->nb_ext_buffers = qsv->nb_ext_buffers;
71     }
72     if (!q->session) {
73         ret = ff_qsv_init_internal_session(avctx, &q->internal_qs, NULL);
74         if (ret < 0)
75             return ret;
76
77         q->session = q->internal_qs.session;
78     }
79
80     ret = ff_qsv_codec_id_to_mfx(avctx->codec_id);
81     if (ret < 0)
82         return ret;
83
84     param.mfx.CodecId      = ret;
85     param.mfx.CodecProfile = avctx->profile;
86     param.mfx.CodecLevel   = avctx->level;
87
88     param.mfx.FrameInfo.BitDepthLuma   = 8;
89     param.mfx.FrameInfo.BitDepthChroma = 8;
90     param.mfx.FrameInfo.Shift          = 0;
91     param.mfx.FrameInfo.FourCC         = MFX_FOURCC_NV12;
92     param.mfx.FrameInfo.Width          = avctx->coded_width;
93     param.mfx.FrameInfo.Height         = avctx->coded_height;
94     param.mfx.FrameInfo.ChromaFormat   = MFX_CHROMAFORMAT_YUV420;
95
96     param.IOPattern   = q->iopattern;
97     param.AsyncDepth  = q->async_depth;
98     param.ExtParam    = q->ext_buffers;
99     param.NumExtParam = q->nb_ext_buffers;
100
101     ret = MFXVideoDECODE_Init(q->session, &param);
102     if (ret < 0) {
103         av_log(avctx, AV_LOG_ERROR, "Error initializing the MFX video decoder\n");
104         return ff_qsv_error(ret);
105     }
106
107     return 0;
108 }
109
110 static int alloc_frame(AVCodecContext *avctx, QSVFrame *frame)
111 {
112     int ret;
113
114     ret = ff_get_buffer(avctx, frame->frame, AV_GET_BUFFER_FLAG_REF);
115     if (ret < 0)
116         return ret;
117
118     if (frame->frame->format == AV_PIX_FMT_QSV) {
119         frame->surface = (mfxFrameSurface1*)frame->frame->data[3];
120     } else {
121         frame->surface_internal.Info.BitDepthLuma   = 8;
122         frame->surface_internal.Info.BitDepthChroma = 8;
123         frame->surface_internal.Info.FourCC         = MFX_FOURCC_NV12;
124         frame->surface_internal.Info.Width          = avctx->coded_width;
125         frame->surface_internal.Info.Height         = avctx->coded_height;
126         frame->surface_internal.Info.ChromaFormat   = MFX_CHROMAFORMAT_YUV420;
127
128         frame->surface_internal.Data.PitchLow = frame->frame->linesize[0];
129         frame->surface_internal.Data.Y        = frame->frame->data[0];
130         frame->surface_internal.Data.UV       = frame->frame->data[1];
131
132         frame->surface = &frame->surface_internal;
133     }
134
135     return 0;
136 }
137
138 static void qsv_clear_unused_frames(QSVContext *q)
139 {
140     QSVFrame *cur = q->work_frames;
141     while (cur) {
142         if (cur->surface && !cur->surface->Data.Locked && !cur->queued) {
143             cur->surface = NULL;
144             av_frame_unref(cur->frame);
145         }
146         cur = cur->next;
147     }
148 }
149
150 static int get_surface(AVCodecContext *avctx, QSVContext *q, mfxFrameSurface1 **surf)
151 {
152     QSVFrame *frame, **last;
153     int ret;
154
155     qsv_clear_unused_frames(q);
156
157     frame = q->work_frames;
158     last  = &q->work_frames;
159     while (frame) {
160         if (!frame->surface) {
161             ret = alloc_frame(avctx, frame);
162             if (ret < 0)
163                 return ret;
164             *surf = frame->surface;
165             return 0;
166         }
167
168         last  = &frame->next;
169         frame = frame->next;
170     }
171
172     frame = av_mallocz(sizeof(*frame));
173     if (!frame)
174         return AVERROR(ENOMEM);
175     frame->frame = av_frame_alloc();
176     if (!frame->frame) {
177         av_freep(&frame);
178         return AVERROR(ENOMEM);
179     }
180     *last = frame;
181
182     ret = alloc_frame(avctx, frame);
183     if (ret < 0)
184         return ret;
185
186     *surf = frame->surface;
187
188     return 0;
189 }
190
191 static QSVFrame *find_frame(QSVContext *q, mfxFrameSurface1 *surf)
192 {
193     QSVFrame *cur = q->work_frames;
194     while (cur) {
195         if (surf == cur->surface)
196             return cur;
197         cur = cur->next;
198     }
199     return NULL;
200 }
201
202 int ff_qsv_decode(AVCodecContext *avctx, QSVContext *q,
203                   AVFrame *frame, int *got_frame,
204                   AVPacket *avpkt)
205 {
206     QSVFrame *out_frame;
207     mfxFrameSurface1 *insurf;
208     mfxFrameSurface1 *outsurf;
209     mfxSyncPoint sync;
210     mfxBitstream bs = { { { 0 } } };
211     int ret;
212
213     if (avpkt->size) {
214         bs.Data       = avpkt->data;
215         bs.DataLength = avpkt->size;
216         bs.MaxLength  = bs.DataLength;
217         bs.TimeStamp  = avpkt->pts;
218     }
219
220     do {
221         ret = get_surface(avctx, q, &insurf);
222         if (ret < 0)
223             return ret;
224
225         ret = MFXVideoDECODE_DecodeFrameAsync(q->session, avpkt->size ? &bs : NULL,
226                                               insurf, &outsurf, &sync);
227         if (ret == MFX_WRN_DEVICE_BUSY)
228             av_usleep(1);
229
230     } while (ret == MFX_WRN_DEVICE_BUSY || ret == MFX_ERR_MORE_SURFACE);
231
232     if (ret != MFX_ERR_NONE &&
233         ret != MFX_ERR_MORE_DATA &&
234         ret != MFX_WRN_VIDEO_PARAM_CHANGED &&
235         ret != MFX_ERR_MORE_SURFACE) {
236         av_log(avctx, AV_LOG_ERROR, "Error during QSV decoding.\n");
237         return ff_qsv_error(ret);
238     }
239
240     if (sync) {
241         QSVFrame *out_frame = find_frame(q, outsurf);
242
243         if (!out_frame) {
244             av_log(avctx, AV_LOG_ERROR,
245                    "The returned surface does not correspond to any frame\n");
246             return AVERROR_BUG;
247         }
248
249         out_frame->queued = 1;
250         av_fifo_generic_write(q->async_fifo, &out_frame, sizeof(out_frame), NULL);
251         av_fifo_generic_write(q->async_fifo, &sync,      sizeof(sync),      NULL);
252     }
253
254     if (!av_fifo_space(q->async_fifo) ||
255         (!avpkt->size && av_fifo_size(q->async_fifo))) {
256         AVFrame *src_frame;
257
258         av_fifo_generic_read(q->async_fifo, &out_frame, sizeof(out_frame), NULL);
259         av_fifo_generic_read(q->async_fifo, &sync,      sizeof(sync),      NULL);
260         out_frame->queued = 0;
261
262         MFXVideoCORE_SyncOperation(q->session, sync, 60000);
263
264         src_frame = out_frame->frame;
265
266         ret = av_frame_ref(frame, src_frame);
267         if (ret < 0)
268             return ret;
269
270         outsurf = out_frame->surface;
271
272         frame->pkt_pts = frame->pts = outsurf->Data.TimeStamp;
273
274         frame->repeat_pict =
275             outsurf->Info.PicStruct & MFX_PICSTRUCT_FRAME_TRIPLING ? 4 :
276             outsurf->Info.PicStruct & MFX_PICSTRUCT_FRAME_DOUBLING ? 2 :
277             outsurf->Info.PicStruct & MFX_PICSTRUCT_FIELD_REPEATED ? 1 : 0;
278         frame->top_field_first =
279             outsurf->Info.PicStruct & MFX_PICSTRUCT_FIELD_TFF;
280         frame->interlaced_frame =
281             !(outsurf->Info.PicStruct & MFX_PICSTRUCT_PROGRESSIVE);
282
283         *got_frame = 1;
284     }
285
286     return bs.DataOffset;
287 }
288
289 int ff_qsv_decode_close(QSVContext *q)
290 {
291     QSVFrame *cur = q->work_frames;
292
293     while (cur) {
294         q->work_frames = cur->next;
295         av_frame_free(&cur->frame);
296         av_freep(&cur);
297         cur = q->work_frames;
298     }
299
300     av_fifo_free(q->async_fifo);
301     q->async_fifo = NULL;
302
303     MFXVideoDECODE_Close(q->session);
304     q->session = NULL;
305
306     ff_qsv_close_internal_session(&q->internal_qs);
307
308     return 0;
309 }