]> git.sesse.net Git - ffmpeg/blob - libavcodec/qsvdec.c
996d8e8fefd4ec125a9739cc6328959406ff9f76
[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->iopattern  = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
58
59     if (avctx->hwaccel_context) {
60         AVQSVContext *qsv = avctx->hwaccel_context;
61
62         q->session        = qsv->session;
63         q->iopattern      = qsv->iopattern;
64         q->ext_buffers    = qsv->ext_buffers;
65         q->nb_ext_buffers = qsv->nb_ext_buffers;
66     }
67     if (!q->session) {
68         ret = ff_qsv_init_internal_session(avctx, &q->internal_qs, NULL);
69         if (ret < 0)
70             return ret;
71
72         q->session = q->internal_qs.session;
73     }
74
75     ret = ff_qsv_codec_id_to_mfx(avctx->codec_id);
76     if (ret < 0)
77         return ret;
78
79     param.mfx.CodecId      = ret;
80     param.mfx.CodecProfile = avctx->profile;
81     param.mfx.CodecLevel   = avctx->level;
82
83     param.mfx.FrameInfo.BitDepthLuma   = 8;
84     param.mfx.FrameInfo.BitDepthChroma = 8;
85     param.mfx.FrameInfo.Shift          = 0;
86     param.mfx.FrameInfo.FourCC         = MFX_FOURCC_NV12;
87     param.mfx.FrameInfo.Width          = avctx->coded_width;
88     param.mfx.FrameInfo.Height         = avctx->coded_height;
89     param.mfx.FrameInfo.ChromaFormat   = MFX_CHROMAFORMAT_YUV420;
90
91     param.IOPattern   = q->iopattern;
92     param.AsyncDepth  = q->async_depth;
93     param.ExtParam    = q->ext_buffers;
94     param.NumExtParam = q->nb_ext_buffers;
95
96     ret = MFXVideoDECODE_Init(q->session, &param);
97     if (ret < 0) {
98         av_log(avctx, AV_LOG_ERROR, "Error initializing the MFX video decoder\n");
99         return ff_qsv_error(ret);
100     }
101
102     return 0;
103 }
104
105 static int alloc_frame(AVCodecContext *avctx, QSVFrame *frame)
106 {
107     int ret;
108
109     ret = ff_get_buffer(avctx, frame->frame, AV_GET_BUFFER_FLAG_REF);
110     if (ret < 0)
111         return ret;
112
113     if (frame->frame->format == AV_PIX_FMT_QSV) {
114         frame->surface = (mfxFrameSurface1*)frame->frame->data[3];
115     } else {
116         frame->surface_internal.Info.BitDepthLuma   = 8;
117         frame->surface_internal.Info.BitDepthChroma = 8;
118         frame->surface_internal.Info.FourCC         = MFX_FOURCC_NV12;
119         frame->surface_internal.Info.Width          = avctx->coded_width;
120         frame->surface_internal.Info.Height         = avctx->coded_height;
121         frame->surface_internal.Info.ChromaFormat   = MFX_CHROMAFORMAT_YUV420;
122
123         frame->surface_internal.Data.PitchLow = frame->frame->linesize[0];
124         frame->surface_internal.Data.Y        = frame->frame->data[0];
125         frame->surface_internal.Data.UV       = frame->frame->data[1];
126
127         frame->surface = &frame->surface_internal;
128     }
129
130     return 0;
131 }
132
133 static void qsv_clear_unused_frames(QSVContext *q)
134 {
135     QSVFrame *cur = q->work_frames;
136     while (cur) {
137         if (cur->surface && !cur->surface->Data.Locked) {
138             cur->surface = NULL;
139             av_frame_unref(cur->frame);
140         }
141         cur = cur->next;
142     }
143 }
144
145 static int get_surface(AVCodecContext *avctx, QSVContext *q, mfxFrameSurface1 **surf)
146 {
147     QSVFrame *frame, **last;
148     int ret;
149
150     qsv_clear_unused_frames(q);
151
152     frame = q->work_frames;
153     last  = &q->work_frames;
154     while (frame) {
155         if (!frame->surface) {
156             ret = alloc_frame(avctx, frame);
157             if (ret < 0)
158                 return ret;
159             *surf = frame->surface;
160             return 0;
161         }
162
163         last  = &frame->next;
164         frame = frame->next;
165     }
166
167     frame = av_mallocz(sizeof(*frame));
168     if (!frame)
169         return AVERROR(ENOMEM);
170     frame->frame = av_frame_alloc();
171     if (!frame->frame) {
172         av_freep(&frame);
173         return AVERROR(ENOMEM);
174     }
175     *last = frame;
176
177     ret = alloc_frame(avctx, frame);
178     if (ret < 0)
179         return ret;
180
181     *surf = frame->surface;
182
183     return 0;
184 }
185
186 static AVFrame *find_frame(QSVContext *q, mfxFrameSurface1 *surf)
187 {
188     QSVFrame *cur = q->work_frames;
189     while (cur) {
190         if (surf == cur->surface)
191             return cur->frame;
192         cur = cur->next;
193     }
194     return NULL;
195 }
196
197 int ff_qsv_decode(AVCodecContext *avctx, QSVContext *q,
198                   AVFrame *frame, int *got_frame,
199                   AVPacket *avpkt)
200 {
201     mfxFrameSurface1 *insurf;
202     mfxFrameSurface1 *outsurf;
203     mfxSyncPoint sync;
204     mfxBitstream bs = { { { 0 } } };
205     int ret;
206
207     if (avpkt->size) {
208         bs.Data       = avpkt->data;
209         bs.DataLength = avpkt->size;
210         bs.MaxLength  = bs.DataLength;
211         bs.TimeStamp  = avpkt->pts;
212     }
213
214     do {
215         ret = get_surface(avctx, q, &insurf);
216         if (ret < 0)
217             return ret;
218
219         ret = MFXVideoDECODE_DecodeFrameAsync(q->session, avpkt->size ? &bs : NULL,
220                                               insurf, &outsurf, &sync);
221         if (ret == MFX_WRN_DEVICE_BUSY)
222             av_usleep(1);
223
224     } while (ret == MFX_WRN_DEVICE_BUSY || ret == MFX_ERR_MORE_SURFACE);
225
226     if (ret != MFX_ERR_NONE &&
227         ret != MFX_ERR_MORE_DATA &&
228         ret != MFX_WRN_VIDEO_PARAM_CHANGED &&
229         ret != MFX_ERR_MORE_SURFACE) {
230         av_log(avctx, AV_LOG_ERROR, "Error during QSV decoding.\n");
231         return ff_qsv_error(ret);
232     }
233
234     if (sync) {
235         AVFrame *src_frame;
236
237         MFXVideoCORE_SyncOperation(q->session, sync, 60000);
238
239         src_frame = find_frame(q, outsurf);
240         if (!src_frame) {
241             av_log(avctx, AV_LOG_ERROR,
242                    "The returned surface does not correspond to any frame\n");
243             return AVERROR_BUG;
244         }
245
246         ret = av_frame_ref(frame, src_frame);
247         if (ret < 0)
248             return ret;
249
250         frame->pkt_pts = frame->pts = outsurf->Data.TimeStamp;
251
252         frame->repeat_pict =
253             outsurf->Info.PicStruct & MFX_PICSTRUCT_FRAME_TRIPLING ? 4 :
254             outsurf->Info.PicStruct & MFX_PICSTRUCT_FRAME_DOUBLING ? 2 :
255             outsurf->Info.PicStruct & MFX_PICSTRUCT_FIELD_REPEATED ? 1 : 0;
256         frame->top_field_first =
257             outsurf->Info.PicStruct & MFX_PICSTRUCT_FIELD_TFF;
258         frame->interlaced_frame =
259             !(outsurf->Info.PicStruct & MFX_PICSTRUCT_PROGRESSIVE);
260
261         *got_frame = 1;
262     }
263
264     return bs.DataOffset;
265 }
266
267 int ff_qsv_decode_close(QSVContext *q)
268 {
269     QSVFrame *cur = q->work_frames;
270
271     while (cur) {
272         q->work_frames = cur->next;
273         av_frame_free(&cur->frame);
274         av_freep(&cur);
275         cur = q->work_frames;
276     }
277     ff_qsv_close_internal_session(&q->internal_qs);
278
279     return 0;
280 }