Browse code

lavc: add MMAL hardware decoder wrapper

Based on a patch by Rodger Combs.

Signed-off-by: Anton Khirnov <anton@khirnov.net>

wm4 authored on 2015/03/28 07:04:08
Showing 10 changed files
... ...
@@ -25,6 +25,7 @@ version <next>:
25 25
 - TDSC decoder
26 26
 - DTS lossless extension (XLL) decoding (not lossless, disabled by default)
27 27
 - Intel QSV-accelerated H.264 encoding
28
+- MMAL-accelerated H.264 decoding
28 29
 
29 30
 
30 31
 version 11:
... ...
@@ -217,6 +217,7 @@ External library support:
217 217
   --enable-libxcb-xfixes   enable X11 grabbing mouse rendering [auto]
218 218
   --enable-libxvid         enable Xvid encoding via xvidcore,
219 219
                            native MPEG-4/Xvid encoder exists [no]
220
+  --enable-mmal            enable decoding via MMAL [no]
220 221
   --enable-openssl         enable openssl [no]
221 222
   --enable-x11grab         enable X11 grabbing (legacy) [no]
222 223
   --enable-zlib            enable zlib [autodetect]
... ...
@@ -1182,6 +1183,7 @@ EXTERNAL_LIBRARY_LIST="
1182 1182
     libxcb_shm
1183 1183
     libxcb_xfixes
1184 1184
     libxvid
1185
+    mmal
1185 1186
     openssl
1186 1187
     x11grab
1187 1188
     zlib
... ...
@@ -1970,6 +1972,10 @@ h263_vdpau_hwaccel_deps="vdpau"
1970 1970
 h263_vdpau_hwaccel_select="h263_decoder"
1971 1971
 h264_dxva2_hwaccel_deps="dxva2"
1972 1972
 h264_dxva2_hwaccel_select="h264_decoder"
1973
+h264_mmal_decoder_deps="mmal"
1974
+h264_mmal_hwaccel_deps="mmal"
1975
+h264_mmal_decoder_select="h264_decoder"
1976
+h264_mmal_encoder_deps="mmal"
1973 1977
 h264_qsv_hwaccel_deps="libmfx"
1974 1978
 h264_vaapi_hwaccel_deps="vaapi"
1975 1979
 h264_vaapi_hwaccel_select="h264_decoder"
... ...
@@ -4255,6 +4261,13 @@ enabled libx265           && require_pkg_config x265 x265.h x265_encoder_encode
4255 4255
                                die "ERROR: libx265 version must be >= 17."; }
4256 4256
 enabled libxavs           && require libxavs xavs.h xavs_encoder_encode -lxavs
4257 4257
 enabled libxvid           && require libxvid xvid.h xvid_global -lxvidcore
4258
+enabled mmal              && { check_lib interface/mmal/mmal.h mmal_port_connect -lmmal_core -lmmal_util -lmmal_vc_client -lbcm_host ||
4259
+                                { ! enabled cross_compile && {
4260
+                                    add_cflags -isystem/opt/vc/include/ -isystem/opt/vc/include/interface/vmcs_host/linux -isystem/opt/vc/include/interface/vcos/pthreads -fgnu89-inline ;
4261
+                                    add_extralibs -L/opt/vc/lib/ -lmmal_core -lmmal_util -lmmal_vc_client -lbcm_host ;
4262
+                                    check_lib interface/mmal/mmal.h mmal_port_connect ; }
4263
+                                check_lib interface/mmal/mmal.h mmal_port_connect ; } ||
4264
+                               die "ERROR: mmal not found"; }
4258 4265
 enabled openssl           && { check_lib openssl/ssl.h SSL_library_init -lssl -lcrypto ||
4259 4266
                                check_lib openssl/ssl.h SSL_library_init -lssl32 -leay32 ||
4260 4267
                                check_lib openssl/ssl.h SSL_library_init -lssl -lcrypto -lws2_32 -lgdi32 ||
... ...
@@ -13,6 +13,9 @@ libavutil:     2014-08-09
13 13
 
14 14
 API changes, most recent first:
15 15
 
16
+2015-xx-xx - xxxxxxx - lavu 54.10.0
17
+  Add AV_PIX_FMT_MMAL for MMAL hardware acceleration.
18
+
16 19
 2015-xx-xx - xxxxxxx - lavc 56.13
17 20
   Add width, height, coded_width, coded_height and format to
18 21
   AVCodecParserContext.
... ...
@@ -224,6 +224,7 @@ OBJS-$(CONFIG_H264_DECODER)            += h264.o h264_cabac.o h264_cavlc.o \
224 224
                                           h264_direct.o h264_loopfilter.o  \
225 225
                                           h264_mb.o h264_picture.o h264_ps.o \
226 226
                                           h264_refs.o h264_sei.o h264_slice.o
227
+OBJS-$(CONFIG_H264_MMAL_DECODER)       += mmaldec.o
227 228
 OBJS-$(CONFIG_H264_QSV_DECODER)        += qsvdec_h264.o
228 229
 OBJS-$(CONFIG_H264_QSV_ENCODER)        += qsvenc_h264.o
229 230
 OBJS-$(CONFIG_HEVC_DECODER)            += hevc.o hevc_mvs.o hevc_ps.o hevc_sei.o \
... ...
@@ -77,6 +77,7 @@ void avcodec_register_all(void)
77 77
     REGISTER_HWACCEL(H263_VAAPI,        h263_vaapi);
78 78
     REGISTER_HWACCEL(H263_VDPAU,        h263_vdpau);
79 79
     REGISTER_HWACCEL(H264_DXVA2,        h264_dxva2);
80
+    REGISTER_HWACCEL(H264_MMAL,         h264_mmal);
80 81
     REGISTER_HWACCEL(H264_QSV,          h264_qsv);
81 82
     REGISTER_HWACCEL(H264_VAAPI,        h264_vaapi);
82 83
     REGISTER_HWACCEL(H264_VDA,          h264_vda);
... ...
@@ -161,6 +162,7 @@ void avcodec_register_all(void)
161 161
     REGISTER_DECODER(H263I,             h263i);
162 162
     REGISTER_ENCODER(H263P,             h263p);
163 163
     REGISTER_DECODER(H264,              h264);
164
+    REGISTER_DECODER(H264_MMAL,         h264_mmal);
164 165
     REGISTER_DECODER(H264_QSV,          h264_qsv);
165 166
     REGISTER_DECODER(HEVC,              hevc);
166 167
     REGISTER_DECODER(HNM4_VIDEO,        hnm4_video);
167 168
new file mode 100644
... ...
@@ -0,0 +1,770 @@
0
+/*
1
+ * MMAL Video Decoder
2
+ * Copyright (c) 2015 Rodger Combs
3
+ *
4
+ * This file is part of Libav.
5
+ *
6
+ * Libav is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * Libav is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with Libav; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+/**
22
+ * @file
23
+ * MMAL Video Decoder
24
+ */
25
+
26
+#include "avcodec.h"
27
+#include "internal.h"
28
+#include "libavutil/atomic.h"
29
+#include "libavutil/avassert.h"
30
+#include "libavutil/buffer.h"
31
+#include "libavutil/common.h"
32
+#include "libavutil/opt.h"
33
+#include "libavutil/log.h"
34
+
35
+#include <bcm_host.h>
36
+#include <interface/mmal/mmal.h>
37
+#include <interface/mmal/util/mmal_util.h>
38
+#include <interface/mmal/util/mmal_util_params.h>
39
+#include <interface/mmal/util/mmal_default_components.h>
40
+
41
+typedef struct FFBufferEntry {
42
+    AVBufferRef *ref;
43
+    void *data;
44
+    size_t length;
45
+    int64_t pts, dts;
46
+    int flags;
47
+    struct FFBufferEntry *next;
48
+} FFBufferEntry;
49
+
50
+// MMAL_POOL_T destroys all of its MMAL_BUFFER_HEADER_Ts. If we want correct
51
+// refcounting for AVFrames, we can free the MMAL_POOL_T only after all AVFrames
52
+// have been unreferenced.
53
+typedef struct FFPoolRef {
54
+    volatile int refcount;
55
+    MMAL_POOL_T *pool;
56
+} FFPoolRef;
57
+
58
+typedef struct FFBufferRef {
59
+    MMAL_BUFFER_HEADER_T *buffer;
60
+    FFPoolRef *pool;
61
+} FFBufferRef;
62
+
63
+typedef struct MMALDecodeContext {
64
+    AVClass *av_class;
65
+    int extra_buffers;
66
+
67
+    AVBitStreamFilterContext *bsfc;
68
+
69
+    MMAL_COMPONENT_T *decoder;
70
+    MMAL_QUEUE_T *queue_decoded_frames;
71
+    MMAL_POOL_T *pool_in;
72
+    FFPoolRef *pool_out;
73
+
74
+    // Waiting input packets. Because the libavcodec API requires decoding and
75
+    // returning packets in lockstep, it can happen that queue_decoded_frames
76
+    // contains almost all surfaces - then the decoder input queue can quickly
77
+    // fill up and won't accept new input either. Without consuming input, the
78
+    // libavcodec API can't return new frames, and we have a logical deadlock.
79
+    // This is avoided by queuing such buffers here.
80
+    FFBufferEntry *waiting_buffers, *waiting_buffers_tail;
81
+
82
+    int64_t packets_sent;
83
+    int64_t frames_output;
84
+    int eos_received;
85
+    int eos_sent;
86
+} MMALDecodeContext;
87
+
88
+// Assume decoder is guaranteed to produce output after at least this many
89
+// packets (where each packet contains 1 frame).
90
+#define MAX_DELAYED_FRAMES 16
91
+
92
+static void ffmmal_poolref_unref(FFPoolRef *ref)
93
+{
94
+    if (ref && avpriv_atomic_int_add_and_fetch(&ref->refcount, -1) == 0) {
95
+        mmal_pool_destroy(ref->pool);
96
+        av_free(ref);
97
+    }
98
+}
99
+
100
+static void ffmmal_release_frame(void *opaque, uint8_t *data)
101
+{
102
+    FFBufferRef *ref = (void *)data;
103
+
104
+    mmal_buffer_header_release(ref->buffer);
105
+    ffmmal_poolref_unref(ref->pool);
106
+
107
+    av_free(ref);
108
+}
109
+
110
+// Setup frame with a new reference to buffer. The buffer must have been
111
+// allocated from the given pool.
112
+static int ffmmal_set_ref(AVFrame *frame, FFPoolRef *pool,
113
+                          MMAL_BUFFER_HEADER_T *buffer)
114
+{
115
+    FFBufferRef *ref = av_mallocz(sizeof(*ref));
116
+    if (!ref)
117
+        return AVERROR(ENOMEM);
118
+
119
+    ref->pool = pool;
120
+    ref->buffer = buffer;
121
+
122
+    frame->buf[0] = av_buffer_create((void *)ref, sizeof(*ref),
123
+                                     ffmmal_release_frame, NULL,
124
+                                     AV_BUFFER_FLAG_READONLY);
125
+    if (!frame->buf[0]) {
126
+        av_free(ref);
127
+        return AVERROR(ENOMEM);
128
+    }
129
+
130
+    avpriv_atomic_int_add_and_fetch(&ref->pool->refcount, 1);
131
+    mmal_buffer_header_acquire(buffer);
132
+
133
+    frame->format = AV_PIX_FMT_MMAL;
134
+    frame->data[3] = (uint8_t *)ref->buffer;
135
+    return 0;
136
+}
137
+
138
+static void ffmmal_stop_decoder(AVCodecContext *avctx)
139
+{
140
+    MMALDecodeContext *ctx = avctx->priv_data;
141
+    MMAL_COMPONENT_T *decoder = ctx->decoder;
142
+    MMAL_BUFFER_HEADER_T *buffer;
143
+
144
+    mmal_port_disable(decoder->input[0]);
145
+    mmal_port_disable(decoder->output[0]);
146
+    mmal_port_disable(decoder->control);
147
+
148
+    mmal_port_flush(decoder->input[0]);
149
+    mmal_port_flush(decoder->output[0]);
150
+    mmal_port_flush(decoder->control);
151
+
152
+    while ((buffer = mmal_queue_get(ctx->queue_decoded_frames)))
153
+        mmal_buffer_header_release(buffer);
154
+
155
+    while (ctx->waiting_buffers) {
156
+        FFBufferEntry *buffer = ctx->waiting_buffers;
157
+
158
+        ctx->waiting_buffers = buffer->next;
159
+
160
+        av_buffer_unref(&buffer->ref);
161
+        av_free(buffer);
162
+    }
163
+    ctx->waiting_buffers_tail = NULL;
164
+
165
+    ctx->frames_output = ctx->eos_received = ctx->eos_sent = ctx->packets_sent = 0;
166
+}
167
+
168
+static av_cold int ffmmal_close_decoder(AVCodecContext *avctx)
169
+{
170
+    MMALDecodeContext *ctx = avctx->priv_data;
171
+
172
+    if (ctx->decoder)
173
+        ffmmal_stop_decoder(avctx);
174
+
175
+    mmal_component_destroy(ctx->decoder);
176
+    ctx->decoder = NULL;
177
+    mmal_queue_destroy(ctx->queue_decoded_frames);
178
+    mmal_pool_destroy(ctx->pool_in);
179
+    ffmmal_poolref_unref(ctx->pool_out);
180
+
181
+    if (ctx->bsfc)
182
+        av_bitstream_filter_close(ctx->bsfc);
183
+
184
+    return 0;
185
+}
186
+
187
+static void input_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
188
+{
189
+    if (!buffer->cmd) {
190
+        AVBufferRef *buf = buffer->user_data;
191
+        av_buffer_unref(&buf);
192
+    }
193
+    mmal_buffer_header_release(buffer);
194
+}
195
+
196
+static void output_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
197
+{
198
+    AVCodecContext *avctx = (AVCodecContext*)port->userdata;
199
+    MMALDecodeContext *ctx = avctx->priv_data;
200
+
201
+    mmal_queue_put(ctx->queue_decoded_frames, buffer);
202
+}
203
+
204
+static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
205
+{
206
+    AVCodecContext *avctx = (AVCodecContext*)port->userdata;
207
+    MMAL_STATUS_T status;
208
+
209
+    if (buffer->cmd == MMAL_EVENT_ERROR) {
210
+        status = *(uint32_t *)buffer->data;
211
+        av_log(avctx, AV_LOG_ERROR, "MMAL error %d on control port\n", (int)status);
212
+    } else {
213
+        char s[20];
214
+        av_get_codec_tag_string(s, sizeof(s), buffer->cmd);
215
+        av_log(avctx, AV_LOG_WARNING, "Unknown MMAL event %s on control port\n", s);
216
+    }
217
+
218
+    mmal_buffer_header_release(buffer);
219
+}
220
+
221
+// Feed free output buffers to the decoder.
222
+static int ffmmal_fill_output_port(AVCodecContext *avctx)
223
+{
224
+    MMALDecodeContext *ctx = avctx->priv_data;
225
+    MMAL_BUFFER_HEADER_T *buffer;
226
+    MMAL_STATUS_T status;
227
+
228
+    if (!ctx->pool_out)
229
+        return AVERROR_UNKNOWN; // format change code failed with OOM previously
230
+
231
+    while ((buffer = mmal_queue_get(ctx->pool_out->pool->queue))) {
232
+        if ((status = mmal_port_send_buffer(ctx->decoder->output[0], buffer))) {
233
+            mmal_buffer_header_release(buffer);
234
+            av_log(avctx, AV_LOG_ERROR, "MMAL error %d when sending output buffer.\n", (int)status);
235
+            return AVERROR_UNKNOWN;
236
+        }
237
+    }
238
+
239
+    return 0;
240
+}
241
+
242
+static enum AVColorSpace ffmmal_csp_to_av_csp(MMAL_FOURCC_T fourcc)
243
+{
244
+    switch (fourcc) {
245
+    case MMAL_COLOR_SPACE_BT470_2_BG:
246
+    case MMAL_COLOR_SPACE_BT470_2_M:
247
+    case MMAL_COLOR_SPACE_ITUR_BT601:   return AVCOL_SPC_BT470BG;
248
+    case MMAL_COLOR_SPACE_ITUR_BT709:   return AVCOL_SPC_BT709;
249
+    case MMAL_COLOR_SPACE_FCC:          return AVCOL_SPC_FCC;
250
+    case MMAL_COLOR_SPACE_SMPTE240M:    return AVCOL_SPC_SMPTE240M;
251
+    default:                            return AVCOL_SPC_UNSPECIFIED;
252
+    }
253
+}
254
+
255
+static int ffmal_update_format(AVCodecContext *avctx)
256
+{
257
+    MMALDecodeContext *ctx = avctx->priv_data;
258
+    MMAL_STATUS_T status;
259
+    int ret = 0;
260
+    MMAL_COMPONENT_T *decoder = ctx->decoder;
261
+    MMAL_ES_FORMAT_T *format_out = decoder->output[0]->format;
262
+
263
+    ffmmal_poolref_unref(ctx->pool_out);
264
+    if (!(ctx->pool_out = av_mallocz(sizeof(*ctx->pool_out)))) {
265
+        ret = AVERROR(ENOMEM);
266
+        goto fail;
267
+    }
268
+    ctx->pool_out->refcount = 1;
269
+
270
+    if (!format_out)
271
+        goto fail;
272
+
273
+    if ((status = mmal_port_parameter_set_uint32(decoder->output[0], MMAL_PARAMETER_EXTRA_BUFFERS, ctx->extra_buffers)))
274
+        goto fail;
275
+
276
+    if (avctx->pix_fmt == AV_PIX_FMT_MMAL) {
277
+        format_out->encoding = MMAL_ENCODING_OPAQUE;
278
+    } else {
279
+        format_out->encoding_variant = format_out->encoding = MMAL_ENCODING_I420;
280
+    }
281
+
282
+    if ((status = mmal_port_format_commit(decoder->output[0])))
283
+        goto fail;
284
+
285
+    if ((ret = ff_set_dimensions(avctx, format_out->es->video.crop.x + format_out->es->video.crop.width,
286
+                                        format_out->es->video.crop.y + format_out->es->video.crop.height)) < 0)
287
+        goto fail;
288
+
289
+    if (format_out->es->video.par.num && format_out->es->video.par.den) {
290
+        avctx->sample_aspect_ratio.num = format_out->es->video.par.num;
291
+        avctx->sample_aspect_ratio.den = format_out->es->video.par.den;
292
+    }
293
+
294
+    avctx->colorspace = ffmmal_csp_to_av_csp(format_out->es->video.color_space);
295
+
296
+    decoder->output[0]->buffer_size =
297
+        FFMAX(decoder->output[0]->buffer_size_min, decoder->output[0]->buffer_size_recommended);
298
+    decoder->output[0]->buffer_num =
299
+        FFMAX(decoder->output[0]->buffer_num_min, decoder->output[0]->buffer_num_recommended) + ctx->extra_buffers;
300
+    ctx->pool_out->pool = mmal_pool_create(decoder->output[0]->buffer_num,
301
+                                           decoder->output[0]->buffer_size);
302
+    if (!ctx->pool_out->pool) {
303
+        ret = AVERROR(ENOMEM);
304
+        goto fail;
305
+    }
306
+
307
+    return 0;
308
+
309
+fail:
310
+    return ret < 0 ? ret : AVERROR_UNKNOWN;
311
+}
312
+
313
+static av_cold int ffmmal_init_decoder(AVCodecContext *avctx)
314
+{
315
+    MMALDecodeContext *ctx = avctx->priv_data;
316
+    MMAL_STATUS_T status;
317
+    MMAL_ES_FORMAT_T *format_in;
318
+    MMAL_COMPONENT_T *decoder;
319
+    int ret = 0;
320
+
321
+    bcm_host_init();
322
+
323
+    if ((ret = ff_get_format(avctx, avctx->codec->pix_fmts)) < 0)
324
+        return ret;
325
+
326
+    avctx->pix_fmt = ret;
327
+
328
+    if ((status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &ctx->decoder)))
329
+        goto fail;
330
+
331
+    decoder = ctx->decoder;
332
+
333
+    format_in = decoder->input[0]->format;
334
+    format_in->type = MMAL_ES_TYPE_VIDEO;
335
+    format_in->encoding = MMAL_ENCODING_H264;
336
+    format_in->es->video.width = FFALIGN(avctx->width, 32);
337
+    format_in->es->video.height = FFALIGN(avctx->height, 16);
338
+    format_in->es->video.crop.width = avctx->width;
339
+    format_in->es->video.crop.height = avctx->height;
340
+    format_in->es->video.frame_rate.num = 24000;
341
+    format_in->es->video.frame_rate.den = 1001;
342
+    format_in->es->video.par.num = avctx->sample_aspect_ratio.num;
343
+    format_in->es->video.par.den = avctx->sample_aspect_ratio.den;
344
+    format_in->flags = MMAL_ES_FORMAT_FLAG_FRAMED;
345
+
346
+    if (avctx->codec->id == AV_CODEC_ID_H264 && avctx->extradata && avctx->extradata[0] == 1) {
347
+        uint8_t *dummy_p;
348
+        int dummy_int;
349
+        ctx->bsfc = av_bitstream_filter_init("h264_mp4toannexb");
350
+        if (!ctx->bsfc) {
351
+            av_log(avctx, AV_LOG_ERROR, "Cannot open the h264_mp4toannexb BSF!\n");
352
+            ret = AVERROR(ENOSYS);
353
+            goto fail;
354
+        }
355
+        av_bitstream_filter_filter(ctx->bsfc, avctx, NULL, &dummy_p, &dummy_int, NULL, 0, 0);
356
+    }
357
+
358
+    if (avctx->extradata_size) {
359
+        if ((status = mmal_format_extradata_alloc(format_in, avctx->extradata_size)))
360
+            goto fail;
361
+        format_in->extradata_size = avctx->extradata_size;
362
+        memcpy(format_in->extradata, avctx->extradata, format_in->extradata_size);
363
+    }
364
+
365
+    if ((status = mmal_port_format_commit(decoder->input[0])))
366
+        goto fail;
367
+
368
+    decoder->input[0]->buffer_num =
369
+        FFMAX(decoder->input[0]->buffer_num_min, 20);
370
+    decoder->input[0]->buffer_size =
371
+        FFMAX(decoder->input[0]->buffer_size_min, 512 * 1024);
372
+    ctx->pool_in = mmal_pool_create(decoder->input[0]->buffer_num, 0);
373
+    if (!ctx->pool_in) {
374
+        ret = AVERROR(ENOMEM);
375
+        goto fail;
376
+    }
377
+
378
+    if ((ret = ffmal_update_format(avctx)) < 0)
379
+        goto fail;
380
+
381
+    ctx->queue_decoded_frames = mmal_queue_create();
382
+    if (!ctx->queue_decoded_frames)
383
+        goto fail;
384
+
385
+    decoder->input[0]->userdata = (void*)avctx;
386
+    decoder->output[0]->userdata = (void*)avctx;
387
+    decoder->control->userdata = (void*)avctx;
388
+
389
+    if ((status = mmal_port_enable(decoder->control, control_port_cb)))
390
+        goto fail;
391
+    if ((status = mmal_port_enable(decoder->input[0], input_callback)))
392
+        goto fail;
393
+    if ((status = mmal_port_enable(decoder->output[0], output_callback)))
394
+        goto fail;
395
+
396
+    if ((status = mmal_component_enable(decoder)))
397
+        goto fail;
398
+
399
+    return 0;
400
+
401
+fail:
402
+    ffmmal_close_decoder(avctx);
403
+    return ret < 0 ? ret : AVERROR_UNKNOWN;
404
+}
405
+
406
+static void ffmmal_flush(AVCodecContext *avctx)
407
+{
408
+    MMALDecodeContext *ctx = avctx->priv_data;
409
+    MMAL_COMPONENT_T *decoder = ctx->decoder;
410
+    MMAL_STATUS_T status;
411
+
412
+    ffmmal_stop_decoder(avctx);
413
+
414
+    if ((status = mmal_port_enable(decoder->control, control_port_cb)))
415
+        goto fail;
416
+    if ((status = mmal_port_enable(decoder->input[0], input_callback)))
417
+        goto fail;
418
+    if ((status = mmal_port_enable(decoder->output[0], output_callback)))
419
+        goto fail;
420
+
421
+    return;
422
+
423
+fail:
424
+    av_log(avctx, AV_LOG_ERROR, "MMAL flush error: %i\n", (int)status);
425
+}
426
+
427
+// Split packets and add them to the waiting_buffers list. We don't queue them
428
+// immediately, because it can happen that the decoder is temporarily blocked
429
+// (due to us not reading/returning enough output buffers) and won't accept
430
+// new input. (This wouldn't be an issue if MMAL input buffers always were
431
+// complete frames - then the input buffer just would have to be big enough.)
432
+static int ffmmal_add_packet(AVCodecContext *avctx, AVPacket *avpkt)
433
+{
434
+    MMALDecodeContext *ctx = avctx->priv_data;
435
+    AVBufferRef *buf = NULL;
436
+    int size = 0;
437
+    uint8_t *data = (uint8_t *)"";
438
+    uint8_t *start;
439
+    int ret = 0;
440
+
441
+    ctx->packets_sent++;
442
+
443
+    if (avpkt->size) {
444
+        if (ctx->bsfc) {
445
+            uint8_t *tmp_data;
446
+            int tmp_size;
447
+            if ((ret = av_bitstream_filter_filter(ctx->bsfc, avctx, NULL,
448
+                                                  &tmp_data, &tmp_size,
449
+                                                  avpkt->data, avpkt->size,
450
+                                                  avpkt->flags & AV_PKT_FLAG_KEY)) < 0)
451
+                goto done;
452
+            buf = av_buffer_create(tmp_data, tmp_size, NULL, NULL, 0);
453
+        } else {
454
+            if (avpkt->buf) {
455
+                buf = av_buffer_ref(avpkt->buf);
456
+            } else {
457
+                buf = av_buffer_alloc(avpkt->size);
458
+                if (buf)
459
+                    memcpy(buf->data, avpkt->data, avpkt->size);
460
+            }
461
+        }
462
+        if (!buf) {
463
+            ret = AVERROR(ENOMEM);
464
+            goto done;
465
+        }
466
+        size = buf->size;
467
+        data = buf->data;
468
+    }
469
+
470
+    start = data;
471
+
472
+    do {
473
+        FFBufferEntry *buffer = av_mallocz(sizeof(*buffer));
474
+        if (!buffer) {
475
+            ret = AVERROR(ENOMEM);
476
+            goto done;
477
+        }
478
+
479
+        buffer->data = data;
480
+        buffer->length = FFMIN(size, ctx->decoder->input[0]->buffer_size);
481
+
482
+        if (data == start)
483
+            buffer->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_START;
484
+
485
+        data += buffer->length;
486
+        size -= buffer->length;
487
+
488
+        buffer->pts = avpkt->pts == AV_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : avpkt->pts;
489
+        buffer->dts = avpkt->dts == AV_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : avpkt->dts;
490
+
491
+        if (!size)
492
+            buffer->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END;
493
+
494
+        if (!buffer->length) {
495
+            buffer->flags |= MMAL_BUFFER_HEADER_FLAG_EOS;
496
+            ctx->eos_sent = 1;
497
+        }
498
+
499
+        if (buf) {
500
+            buffer->ref = av_buffer_ref(buf);
501
+            if (!buffer->ref) {
502
+                av_free(buffer);
503
+                ret = AVERROR(ENOMEM);
504
+                goto done;
505
+            }
506
+        }
507
+
508
+        // Insert at end of the list
509
+        if (!ctx->waiting_buffers)
510
+            ctx->waiting_buffers = buffer;
511
+        if (ctx->waiting_buffers_tail)
512
+            ctx->waiting_buffers_tail->next = buffer;
513
+        ctx->waiting_buffers_tail = buffer;
514
+    } while (size);
515
+
516
+done:
517
+    av_buffer_unref(&buf);
518
+    return ret;
519
+}
520
+
521
+// Move prepared/split packets from waiting_buffers to the MMAL decoder.
522
+static int ffmmal_fill_input_port(AVCodecContext *avctx)
523
+{
524
+    MMALDecodeContext *ctx = avctx->priv_data;
525
+
526
+    while (ctx->waiting_buffers) {
527
+        MMAL_BUFFER_HEADER_T *mbuffer;
528
+        FFBufferEntry *buffer;
529
+        MMAL_STATUS_T status;
530
+
531
+        mbuffer = mmal_queue_get(ctx->pool_in->queue);
532
+        if (!mbuffer)
533
+            return 0;
534
+
535
+        buffer = ctx->waiting_buffers;
536
+
537
+        mmal_buffer_header_reset(mbuffer);
538
+        mbuffer->cmd = 0;
539
+        mbuffer->pts = buffer->pts;
540
+        mbuffer->dts = buffer->dts;
541
+        mbuffer->flags = buffer->flags;
542
+        mbuffer->data = buffer->data;
543
+        mbuffer->length = buffer->length;
544
+        mbuffer->user_data = buffer->ref;
545
+        mbuffer->alloc_size = ctx->decoder->input[0]->buffer_size;
546
+
547
+        if ((status = mmal_port_send_buffer(ctx->decoder->input[0], mbuffer))) {
548
+            mmal_buffer_header_release(mbuffer);
549
+            av_buffer_unref(&buffer->ref);
550
+        }
551
+
552
+        // Remove from start of the list
553
+        ctx->waiting_buffers = buffer->next;
554
+        if (ctx->waiting_buffers_tail == buffer)
555
+            ctx->waiting_buffers_tail = NULL;
556
+        av_free(buffer);
557
+
558
+        if (status) {
559
+            av_log(avctx, AV_LOG_ERROR, "MMAL error %d when sending input\n", (int)status);
560
+            return AVERROR_UNKNOWN;
561
+        }
562
+    }
563
+
564
+    return 0;
565
+}
566
+
567
+static int ffmal_copy_frame(AVCodecContext *avctx,  AVFrame *frame,
568
+                            MMAL_BUFFER_HEADER_T *buffer)
569
+{
570
+    MMALDecodeContext *ctx = avctx->priv_data;
571
+    int ret = 0;
572
+
573
+    if (avctx->pix_fmt == AV_PIX_FMT_MMAL) {
574
+        if (!ctx->pool_out)
575
+            return AVERROR_UNKNOWN; // format change code failed with OOM previously
576
+
577
+        if ((ret = ff_decode_frame_props(avctx, frame)) < 0)
578
+            goto done;
579
+
580
+        if ((ret = ffmmal_set_ref(frame, ctx->pool_out, buffer)) < 0)
581
+            goto done;
582
+    } else {
583
+        int w = FFALIGN(avctx->width, 32);
584
+        int h = FFALIGN(avctx->height, 16);
585
+        char *ptr;
586
+        int plane;
587
+        int i;
588
+
589
+        if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
590
+            goto done;
591
+
592
+        ptr = buffer->data + buffer->type->video.offset[0];
593
+        for (i = 0; i < avctx->height; i++)
594
+            memcpy(frame->data[0] + frame->linesize[0] * i, ptr + w * i, avctx->width);
595
+
596
+        ptr += w * h;
597
+
598
+        for (plane = 1; plane < 3; plane++) {
599
+            for (i = 0; i < avctx->height / 2; i++)
600
+                memcpy(frame->data[plane] + frame->linesize[plane] * i, ptr + w / 2 * i, (avctx->width + 1) / 2);
601
+            ptr += w / 2 * h / 2;
602
+        }
603
+    }
604
+
605
+    if (buffer->pts != MMAL_TIME_UNKNOWN) {
606
+        frame->pkt_pts = buffer->pts;
607
+        frame->pts = buffer->pts;
608
+    }
609
+
610
+done:
611
+    return ret;
612
+}
613
+
614
+// Fetch a decoded buffer and place it into the frame parameter.
615
+static int ffmmal_read_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame)
616
+{
617
+    MMALDecodeContext *ctx = avctx->priv_data;
618
+    MMAL_BUFFER_HEADER_T *buffer = NULL;
619
+    MMAL_STATUS_T status = 0;
620
+    int ret = 0;
621
+
622
+    if (ctx->eos_received)
623
+        goto done;
624
+
625
+    while (1) {
626
+        // To ensure decoding in lockstep with a constant delay between fed packets
627
+        // and output frames, we always wait until an output buffer is available.
628
+        // Except during start we don't know after how many input packets the decoder
629
+        // is going to return the first buffer, and we can't distinguish decoder
630
+        // being busy from decoder waiting for input. So just poll at the start and
631
+        // keep feeding new data to the buffer.
632
+        // We are pretty sure the decoder will produce output if we sent more input
633
+        // frames than what a h264 decoder could logically delay. This avoids too
634
+        // excessive buffering.
635
+        // We also wait if we sent eos, but didn't receive it yet (think of decoding
636
+        // stream with a very low number of frames).
637
+        if (ctx->frames_output || ctx->packets_sent > MAX_DELAYED_FRAMES || ctx->eos_sent) {
638
+            buffer = mmal_queue_wait(ctx->queue_decoded_frames);
639
+        } else {
640
+            buffer = mmal_queue_get(ctx->queue_decoded_frames);
641
+        }
642
+        if (!buffer)
643
+            goto done;
644
+
645
+        ctx->eos_received |= !!(buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS);
646
+        if (ctx->eos_received)
647
+            goto done;
648
+
649
+        if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED) {
650
+            MMAL_COMPONENT_T *decoder = ctx->decoder;
651
+            MMAL_EVENT_FORMAT_CHANGED_T *ev = mmal_event_format_changed_get(buffer);
652
+            MMAL_BUFFER_HEADER_T *stale_buffer;
653
+
654
+            av_log(avctx, AV_LOG_INFO, "Changing output format.\n");
655
+
656
+            if ((status = mmal_port_disable(decoder->output[0])))
657
+                goto done;
658
+
659
+            while ((stale_buffer = mmal_queue_get(ctx->queue_decoded_frames)))
660
+                mmal_buffer_header_release(stale_buffer);
661
+
662
+            mmal_format_copy(decoder->output[0]->format, ev->format);
663
+
664
+            if ((ret = ffmal_update_format(avctx)) < 0)
665
+                goto done;
666
+
667
+            if ((status = mmal_port_enable(decoder->output[0], output_callback)))
668
+                goto done;
669
+
670
+            if ((ret = ffmmal_fill_output_port(avctx)) < 0)
671
+                goto done;
672
+
673
+            if ((ret = ffmmal_fill_input_port(avctx)) < 0)
674
+                goto done;
675
+
676
+            mmal_buffer_header_release(buffer);
677
+            continue;
678
+        } else if (buffer->cmd) {
679
+            char s[20];
680
+            av_get_codec_tag_string(s, sizeof(s), buffer->cmd);
681
+            av_log(avctx, AV_LOG_WARNING, "Unknown MMAL event %s on output port\n", s);
682
+            goto done;
683
+        } else if (buffer->length == 0) {
684
+            // Unused output buffer that got drained after format change.
685
+            mmal_buffer_header_release(buffer);
686
+            continue;
687
+        }
688
+
689
+        ctx->frames_output++;
690
+
691
+        if ((ret = ffmal_copy_frame(avctx, frame, buffer)) < 0)
692
+            goto done;
693
+
694
+        *got_frame = 1;
695
+        break;
696
+    }
697
+
698
+done:
699
+    if (buffer)
700
+        mmal_buffer_header_release(buffer);
701
+    if (status && ret >= 0)
702
+        ret = AVERROR_UNKNOWN;
703
+    return ret;
704
+}
705
+
706
+static int ffmmal_decode(AVCodecContext *avctx, void *data, int *got_frame,
707
+                         AVPacket *avpkt)
708
+{
709
+    AVFrame *frame = data;
710
+    int ret = 0;
711
+
712
+    if ((ret = ffmmal_add_packet(avctx, avpkt)) < 0)
713
+        return ret;
714
+
715
+    if ((ret = ffmmal_fill_input_port(avctx)) < 0)
716
+        return ret;
717
+
718
+    if ((ret = ffmmal_fill_output_port(avctx)) < 0)
719
+        return ret;
720
+
721
+    if ((ret = ffmmal_read_frame(avctx, frame, got_frame)) < 0)
722
+        return ret;
723
+
724
+    // ffmmal_read_frame() can block for a while. Since the decoder is
725
+    // asynchronous, it's a good idea to fill the ports again.
726
+
727
+    if ((ret = ffmmal_fill_output_port(avctx)) < 0)
728
+        return ret;
729
+
730
+    if ((ret = ffmmal_fill_input_port(avctx)) < 0)
731
+        return ret;
732
+
733
+    return ret;
734
+}
735
+
736
+AVHWAccel ff_h264_mmal_hwaccel = {
737
+    .name       = "h264_mmal",
738
+    .type       = AVMEDIA_TYPE_VIDEO,
739
+    .id         = AV_CODEC_ID_H264,
740
+    .pix_fmt    = AV_PIX_FMT_MMAL,
741
+};
742
+
743
+static const AVOption options[]={
744
+    {"extra_buffers", "extra buffers", offsetof(MMALDecodeContext, extra_buffers), AV_OPT_TYPE_INT, {.i64 = 10}, 0, 256, 0},
745
+    {NULL}
746
+};
747
+
748
+static const AVClass ffmmaldec_class = {
749
+    .class_name = "mmaldec",
750
+    .option     = options,
751
+    .version    = LIBAVUTIL_VERSION_INT,
752
+};
753
+
754
+AVCodec ff_h264_mmal_decoder = {
755
+    .name           = "h264_mmal",
756
+    .long_name      = NULL_IF_CONFIG_SMALL("h264 (mmal)"),
757
+    .type           = AVMEDIA_TYPE_VIDEO,
758
+    .id             = AV_CODEC_ID_H264,
759
+    .priv_data_size = sizeof(MMALDecodeContext),
760
+    .init           = ffmmal_init_decoder,
761
+    .close          = ffmmal_close_decoder,
762
+    .decode         = ffmmal_decode,
763
+    .flush          = ffmmal_flush,
764
+    .priv_class     = &ffmmaldec_class,
765
+    .capabilities   = CODEC_CAP_DELAY,
766
+    .pix_fmts       = (const enum AVPixelFormat[]) { AV_PIX_FMT_MMAL,
767
+                                                     AV_PIX_FMT_YUV420P,
768
+                                                     AV_PIX_FMT_NONE},
769
+};
... ...
@@ -29,7 +29,7 @@
29 29
 #include "libavutil/version.h"
30 30
 
31 31
 #define LIBAVCODEC_VERSION_MAJOR 56
32
-#define LIBAVCODEC_VERSION_MINOR 20
32
+#define LIBAVCODEC_VERSION_MINOR 21
33 33
 #define LIBAVCODEC_VERSION_MICRO  0
34 34
 
35 35
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
... ...
@@ -1567,6 +1567,10 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
1567 1567
         .name = "qsv",
1568 1568
         .flags = AV_PIX_FMT_FLAG_HWACCEL,
1569 1569
     },
1570
+    [AV_PIX_FMT_MMAL] = {
1571
+        .name = "mmal",
1572
+        .flags = AV_PIX_FMT_FLAG_HWACCEL,
1573
+    },
1570 1574
 };
1571 1575
 
1572 1576
 static const char *color_range_names[AVCOL_RANGE_NB] = {
... ...
@@ -214,6 +214,11 @@ enum AVPixelFormat {
214 214
      *  mfxFrameSurface1 structure.
215 215
      */
216 216
     AV_PIX_FMT_QSV,
217
+    /**
218
+     * HW acceleration though MMAL, data[3] contains a pointer to the
219
+     * MMAL_BUFFER_HEADER_T structure.
220
+     */
221
+    AV_PIX_FMT_MMAL,
217 222
 
218 223
     AV_PIX_FMT_NB,        ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions
219 224
 
... ...
@@ -54,8 +54,8 @@
54 54
  */
55 55
 
56 56
 #define LIBAVUTIL_VERSION_MAJOR 54
57
-#define LIBAVUTIL_VERSION_MINOR  9
58
-#define LIBAVUTIL_VERSION_MICRO  1
57
+#define LIBAVUTIL_VERSION_MINOR 10
58
+#define LIBAVUTIL_VERSION_MICRO  0
59 59
 
60 60
 #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
61 61
                                                LIBAVUTIL_VERSION_MINOR, \