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