]> git.sesse.net Git - ffmpeg/blob - libavcodec/qsvdec_h264.c
Merge commit 'be101bc1e357c50fcb740bc4870b3bacc93a5727'
[ffmpeg] / libavcodec / qsvdec_h264.c
1 /*
2  * Intel MediaSDK QSV based H.264 decoder
3  *
4  * copyright (c) 2013 Luca Barbato
5  * copyright (c) 2015 Anton Khirnov
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
25 #include <stdint.h>
26 #include <string.h>
27
28 #include <mfx/mfxvideo.h>
29
30 #include "libavutil/common.h"
31 #include "libavutil/fifo.h"
32 #include "libavutil/opt.h"
33
34 #include "avcodec.h"
35 #include "internal.h"
36 #include "qsvdec.h"
37
38 typedef struct QSVH264Context {
39     AVClass *class;
40     QSVContext qsv;
41
42     // the internal parser and codec context for parsing the data
43     AVCodecParserContext *parser;
44     AVCodecContext *avctx_internal;
45     enum AVPixelFormat orig_pix_fmt;
46
47     // the filter for converting to Annex B
48     AVBitStreamFilterContext *bsf;
49
50     AVFifoBuffer *packet_fifo;
51
52     AVPacket input_ref;
53     AVPacket pkt_filtered;
54     uint8_t *filtered_data;
55 } QSVH264Context;
56
57 static void qsv_clear_buffers(QSVH264Context *s)
58 {
59     AVPacket pkt;
60     while (av_fifo_size(s->packet_fifo) >= sizeof(pkt)) {
61         av_fifo_generic_read(s->packet_fifo, &pkt, sizeof(pkt), NULL);
62         av_packet_unref(&pkt);
63     }
64
65     if (s->filtered_data != s->input_ref.data)
66         av_freep(&s->filtered_data);
67     s->filtered_data = NULL;
68     av_packet_unref(&s->input_ref);
69 }
70
71 static av_cold int qsv_decode_close(AVCodecContext *avctx)
72 {
73     QSVH264Context *s = avctx->priv_data;
74
75     ff_qsv_decode_close(&s->qsv);
76
77     qsv_clear_buffers(s);
78
79     av_fifo_free(s->packet_fifo);
80
81     av_bitstream_filter_close(s->bsf);
82     av_parser_close(s->parser);
83     avcodec_free_context(&s->avctx_internal);
84
85     return 0;
86 }
87
88 static av_cold int qsv_decode_init(AVCodecContext *avctx)
89 {
90     QSVH264Context *s = avctx->priv_data;
91     int ret;
92
93     s->orig_pix_fmt = AV_PIX_FMT_NONE;
94
95     s->packet_fifo = av_fifo_alloc(sizeof(AVPacket));
96     if (!s->packet_fifo) {
97         ret = AVERROR(ENOMEM);
98         goto fail;
99     }
100
101     s->bsf = av_bitstream_filter_init("h264_mp4toannexb");
102     if (!s->bsf) {
103         ret = AVERROR(ENOMEM);
104         goto fail;
105     }
106
107     s->avctx_internal = avcodec_alloc_context3(NULL);
108     if (!s->avctx_internal) {
109         ret = AVERROR(ENOMEM);
110         goto fail;
111     }
112
113     if (avctx->extradata) {
114         s->avctx_internal->extradata = av_mallocz(avctx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
115         if (!s->avctx_internal->extradata) {
116             ret = AVERROR(ENOMEM);
117             goto fail;
118         }
119         memcpy(s->avctx_internal->extradata, avctx->extradata,
120                avctx->extradata_size);
121         s->avctx_internal->extradata_size = avctx->extradata_size;
122     }
123
124     s->parser = av_parser_init(AV_CODEC_ID_H264);
125     if (!s->parser) {
126         ret = AVERROR(ENOMEM);
127         goto fail;
128     }
129     s->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
130
131     return 0;
132 fail:
133     qsv_decode_close(avctx);
134     return ret;
135 }
136
137 static int qsv_process_data(AVCodecContext *avctx, AVFrame *frame,
138                             int *got_frame, AVPacket *pkt)
139 {
140     QSVH264Context *s = avctx->priv_data;
141     uint8_t *dummy_data;
142     int dummy_size;
143     int ret;
144
145     /* we assume the packets are already split properly and want
146      * just the codec parameters here */
147     av_parser_parse2(s->parser, s->avctx_internal,
148                      &dummy_data, &dummy_size,
149                      pkt->data, pkt->size, pkt->pts, pkt->dts,
150                      pkt->pos);
151
152     /* TODO: flush delayed frames on reinit */
153     if (s->parser->format       != s->orig_pix_fmt    ||
154         s->parser->coded_width  != avctx->coded_width ||
155         s->parser->coded_height != avctx->coded_height) {
156
157         enum AVPixelFormat pix_fmts[3] = { AV_PIX_FMT_QSV,
158                                            AV_PIX_FMT_NONE,
159                                            AV_PIX_FMT_NONE };
160         enum AVPixelFormat qsv_format;
161
162         qsv_format = ff_qsv_map_pixfmt(s->parser->format);
163         if (qsv_format < 0) {
164             av_log(avctx, AV_LOG_ERROR,
165                    "Only 8-bit YUV420 streams are supported.\n");
166             ret = AVERROR(ENOSYS);
167             goto reinit_fail;
168         }
169
170         s->orig_pix_fmt     = s->parser->format;
171         avctx->pix_fmt      = pix_fmts[1] = qsv_format;
172         avctx->width        = s->parser->width;
173         avctx->height       = s->parser->height;
174         avctx->coded_width  = s->parser->coded_width;
175         avctx->coded_height = s->parser->coded_height;
176         avctx->level        = s->avctx_internal->level;
177         avctx->profile      = s->avctx_internal->profile;
178
179         ret = ff_get_format(avctx, pix_fmts);
180         if (ret < 0)
181             goto reinit_fail;
182
183         avctx->pix_fmt = ret;
184
185         ret = ff_qsv_decode_init(avctx, &s->qsv);
186         if (ret < 0)
187             goto reinit_fail;
188     }
189
190     return ff_qsv_decode(avctx, &s->qsv, frame, got_frame, &s->pkt_filtered);
191
192 reinit_fail:
193     s->orig_pix_fmt = s->parser->format = avctx->pix_fmt = AV_PIX_FMT_NONE;
194     return ret;
195 }
196
197 static int qsv_decode_frame(AVCodecContext *avctx, void *data,
198                             int *got_frame, AVPacket *avpkt)
199 {
200     QSVH264Context *s = avctx->priv_data;
201     AVFrame *frame    = data;
202     int ret;
203
204     /* buffer the input packet */
205     if (avpkt->size) {
206         AVPacket input_ref = { 0 };
207
208         if (av_fifo_space(s->packet_fifo) < sizeof(input_ref)) {
209             ret = av_fifo_realloc2(s->packet_fifo,
210                                    av_fifo_size(s->packet_fifo) + sizeof(input_ref));
211             if (ret < 0)
212                 return ret;
213         }
214
215         ret = av_packet_ref(&input_ref, avpkt);
216         if (ret < 0)
217             return ret;
218         av_fifo_generic_write(s->packet_fifo, &input_ref, sizeof(input_ref), NULL);
219     }
220
221     /* process buffered data */
222     while (!*got_frame) {
223         /* prepare the input data -- convert to Annex B if needed */
224         if (s->pkt_filtered.size <= 0) {
225             int size;
226
227             /* no more data */
228             if (av_fifo_size(s->packet_fifo) < sizeof(AVPacket))
229                 return avpkt->size ? avpkt->size : ff_qsv_decode(avctx, &s->qsv, frame, got_frame, avpkt);
230
231             if (s->filtered_data != s->input_ref.data)
232                 av_freep(&s->filtered_data);
233             s->filtered_data = NULL;
234             av_packet_unref(&s->input_ref);
235
236             av_fifo_generic_read(s->packet_fifo, &s->input_ref, sizeof(s->input_ref), NULL);
237             ret = av_bitstream_filter_filter(s->bsf, avctx, NULL,
238                                              &s->filtered_data, &size,
239                                              s->input_ref.data, s->input_ref.size, 0);
240             if (ret < 0) {
241                 s->filtered_data = s->input_ref.data;
242                 size             = s->input_ref.size;
243             }
244             s->pkt_filtered      = s->input_ref;
245             s->pkt_filtered.data = s->filtered_data;
246             s->pkt_filtered.size = size;
247         }
248
249         ret = qsv_process_data(avctx, frame, got_frame, &s->pkt_filtered);
250         if (ret < 0)
251             return ret;
252
253         s->pkt_filtered.size -= ret;
254         s->pkt_filtered.data += ret;
255     }
256
257     return avpkt->size;
258 }
259
260 static void qsv_decode_flush(AVCodecContext *avctx)
261 {
262     QSVH264Context *s = avctx->priv_data;
263
264     qsv_clear_buffers(s);
265     s->orig_pix_fmt = AV_PIX_FMT_NONE;
266 }
267
268 AVHWAccel ff_h264_qsv_hwaccel = {
269     .name           = "h264_qsv",
270     .type           = AVMEDIA_TYPE_VIDEO,
271     .id             = AV_CODEC_ID_H264,
272     .pix_fmt        = AV_PIX_FMT_QSV,
273 };
274
275 #define OFFSET(x) offsetof(QSVH264Context, x)
276 #define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
277 static const AVOption options[] = {
278     { "async_depth", "Internal parallelization depth, the higher the value the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 0, INT_MAX, VD },
279     { NULL },
280 };
281
282 static const AVClass class = {
283     .class_name = "h264_qsv",
284     .item_name  = av_default_item_name,
285     .option     = options,
286     .version    = LIBAVUTIL_VERSION_INT,
287 };
288
289 AVCodec ff_h264_qsv_decoder = {
290     .name           = "h264_qsv",
291     .long_name      = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (Intel Quick Sync Video acceleration)"),
292     .priv_data_size = sizeof(QSVH264Context),
293     .type           = AVMEDIA_TYPE_VIDEO,
294     .id             = AV_CODEC_ID_H264,
295     .init           = qsv_decode_init,
296     .decode         = qsv_decode_frame,
297     .flush          = qsv_decode_flush,
298     .close          = qsv_decode_close,
299     .capabilities   = CODEC_CAP_DELAY,
300     .priv_class     = &class,
301 };