]> git.sesse.net Git - ffmpeg/blob - libavcodec/qsvdec_h264.c
libavcodec/qsvdec_h264.c: SPS parsing is now performed by MFXVideoDECODE_DecodeHeader...
[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 filter for converting to Annex B
43     AVBitStreamFilterContext *bsf;
44
45     AVFifoBuffer *packet_fifo;
46
47     AVPacket input_ref;
48     AVPacket pkt_filtered;
49     uint8_t *filtered_data;
50 } QSVH264Context;
51
52 static void qsv_clear_buffers(QSVH264Context *s)
53 {
54     AVPacket pkt;
55     while (av_fifo_size(s->packet_fifo) >= sizeof(pkt)) {
56         av_fifo_generic_read(s->packet_fifo, &pkt, sizeof(pkt), NULL);
57         av_packet_unref(&pkt);
58     }
59
60     if (s->filtered_data != s->input_ref.data)
61         av_freep(&s->filtered_data);
62     s->filtered_data = NULL;
63     av_packet_unref(&s->input_ref);
64 }
65
66 static av_cold int qsv_decode_close(AVCodecContext *avctx)
67 {
68     QSVH264Context *s = avctx->priv_data;
69
70     ff_qsv_decode_close(&s->qsv);
71
72     qsv_clear_buffers(s);
73
74     av_fifo_free(s->packet_fifo);
75
76     av_bitstream_filter_close(s->bsf);
77
78     return 0;
79 }
80
81 static av_cold int qsv_decode_init(AVCodecContext *avctx)
82 {
83     QSVH264Context *s = avctx->priv_data;
84     int ret;
85
86     s->packet_fifo = av_fifo_alloc(sizeof(AVPacket));
87     if (!s->packet_fifo) {
88         ret = AVERROR(ENOMEM);
89         goto fail;
90     }
91
92     s->bsf = av_bitstream_filter_init("h264_mp4toannexb");
93     if (!s->bsf) {
94         ret = AVERROR(ENOMEM);
95         goto fail;
96     }
97
98     return 0;
99 fail:
100     qsv_decode_close(avctx);
101     return ret;
102 }
103
104 static int qsv_process_data(AVCodecContext *avctx, AVFrame *frame,
105                             int *got_frame, AVPacket *pkt)
106 {
107     QSVH264Context *s = avctx->priv_data;
108     int ret;
109
110     if (!s->qsv.session || AV_PIX_FMT_NONE==avctx->pix_fmt) {
111         ret = ff_qsv_decode_init(avctx, &s->qsv, pkt);
112         /* consume packet without a header */
113         if (AVERROR(EAGAIN)==ret)
114             return pkt->size;
115         if (ret < 0)
116             return ret;
117     }
118
119     return ff_qsv_decode(avctx, &s->qsv, frame, got_frame, pkt);
120 }
121
122 static int qsv_decode_frame(AVCodecContext *avctx, void *data,
123                             int *got_frame, AVPacket *avpkt)
124 {
125     QSVH264Context *s = avctx->priv_data;
126     AVFrame *frame    = data;
127     int ret;
128
129     /* buffer the input packet */
130     if (avpkt->size) {
131         AVPacket input_ref = { 0 };
132
133         if (av_fifo_space(s->packet_fifo) < sizeof(input_ref)) {
134             ret = av_fifo_realloc2(s->packet_fifo,
135                                    av_fifo_size(s->packet_fifo) + sizeof(input_ref));
136             if (ret < 0)
137                 return ret;
138         }
139
140         ret = av_packet_ref(&input_ref, avpkt);
141         if (ret < 0)
142             return ret;
143         av_fifo_generic_write(s->packet_fifo, &input_ref, sizeof(input_ref), NULL);
144     }
145
146     /* process buffered data */
147     while (!*got_frame) {
148         /* prepare the input data -- convert to Annex B if needed */
149         if (s->pkt_filtered.size <= 0) {
150             int size;
151
152             /* no more data */
153             if (av_fifo_size(s->packet_fifo) < sizeof(AVPacket))
154                 return avpkt->size ? avpkt->size : ff_qsv_decode(avctx, &s->qsv, frame, got_frame, avpkt);
155
156             if (s->filtered_data != s->input_ref.data)
157                 av_freep(&s->filtered_data);
158             s->filtered_data = NULL;
159             av_packet_unref(&s->input_ref);
160
161             av_fifo_generic_read(s->packet_fifo, &s->input_ref, sizeof(s->input_ref), NULL);
162             ret = av_bitstream_filter_filter(s->bsf, avctx, NULL,
163                                              &s->filtered_data, &size,
164                                              s->input_ref.data, s->input_ref.size, 0);
165             if (ret < 0) {
166                 s->filtered_data = s->input_ref.data;
167                 size             = s->input_ref.size;
168             }
169             s->pkt_filtered      = s->input_ref;
170             s->pkt_filtered.data = s->filtered_data;
171             s->pkt_filtered.size = size;
172         }
173
174         ret = qsv_process_data(avctx, frame, got_frame, &s->pkt_filtered);
175         if (ret < 0)
176             return ret;
177
178         s->pkt_filtered.size -= ret;
179         s->pkt_filtered.data += ret;
180     }
181
182     return avpkt->size;
183 }
184
185 static void qsv_decode_flush(AVCodecContext *avctx)
186 {
187     QSVH264Context *s = avctx->priv_data;
188
189     qsv_clear_buffers(s);
190 }
191
192 AVHWAccel ff_h264_qsv_hwaccel = {
193     .name           = "h264_qsv",
194     .type           = AVMEDIA_TYPE_VIDEO,
195     .id             = AV_CODEC_ID_H264,
196     .pix_fmt        = AV_PIX_FMT_QSV,
197 };
198
199 #define OFFSET(x) offsetof(QSVH264Context, x)
200 #define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
201 static const AVOption options[] = {
202     { "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 },
203     { NULL },
204 };
205
206 static const AVClass class = {
207     .class_name = "h264_qsv",
208     .item_name  = av_default_item_name,
209     .option     = options,
210     .version    = LIBAVUTIL_VERSION_INT,
211 };
212
213 AVCodec ff_h264_qsv_decoder = {
214     .name           = "h264_qsv",
215     .long_name      = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (Intel Quick Sync Video acceleration)"),
216     .priv_data_size = sizeof(QSVH264Context),
217     .type           = AVMEDIA_TYPE_VIDEO,
218     .id             = AV_CODEC_ID_H264,
219     .init           = qsv_decode_init,
220     .decode         = qsv_decode_frame,
221     .flush          = qsv_decode_flush,
222     .close          = qsv_decode_close,
223     .capabilities   = CODEC_CAP_DELAY,
224     .priv_class     = &class,
225 };