Browse code

lavc: add mediacodec hwaccel support

Matthieu Bouron authored on 2016/03/12 01:21:04
Showing 14 changed files
... ...
@@ -2555,6 +2555,7 @@ h264_d3d11va_hwaccel_select="h264_decoder"
2555 2555
 h264_dxva2_hwaccel_deps="dxva2"
2556 2556
 h264_dxva2_hwaccel_select="h264_decoder"
2557 2557
 h264_mediacodec_decoder_deps="mediacodec"
2558
+h264_mediacodec_hwaccel_deps="mediacodec"
2558 2559
 h264_mediacodec_decoder_select="h264_mp4toannexb_bsf h264_parser"
2559 2560
 h264_mmal_decoder_deps="mmal"
2560 2561
 h264_mmal_decoder_select="mmal"
... ...
@@ -10,6 +10,7 @@ HEADERS = avcodec.h                                                     \
10 10
           dv_profile.h                                                  \
11 11
           dxva2.h                                                       \
12 12
           jni.h                                                         \
13
+          mediacodec.h                                                  \
13 14
           qsv.h                                                         \
14 15
           vaapi.h                                                       \
15 16
           vda.h                                                         \
... ...
@@ -35,6 +36,7 @@ OBJS = allcodecs.o                                                      \
35 35
        imgconvert.o                                                     \
36 36
        jni.o                                                            \
37 37
        mathtables.o                                                     \
38
+       mediacodec.o                                                     \
38 39
        options.o                                                        \
39 40
        parser.o                                                         \
40 41
        profiles.o                                                       \
... ...
@@ -92,7 +94,7 @@ OBJS-$(CONFIG_LSP)                     += lsp.o
92 92
 OBJS-$(CONFIG_LZF)                     += lzf.o
93 93
 OBJS-$(CONFIG_MDCT)                    += mdct_fixed.o mdct_float.o mdct_fixed_32.o
94 94
 OBJS-$(CONFIG_ME_CMP)                  += me_cmp.o
95
-OBJS-$(CONFIG_MEDIACODEC)              += mediacodecdec.o mediacodec_wrapper.o mediacodec_sw_buffer.o
95
+OBJS-$(CONFIG_MEDIACODEC)              += mediacodecdec.o mediacodec_surface.o mediacodec_wrapper.o mediacodec_sw_buffer.o
96 96
 OBJS-$(CONFIG_MPEG_ER)                 += mpeg_er.o
97 97
 OBJS-$(CONFIG_MPEGAUDIO)               += mpegaudio.o mpegaudiodata.o   \
98 98
                                           mpegaudiodecheader.o
... ...
@@ -993,7 +995,7 @@ SKIPHEADERS-$(CONFIG_JNI)              += ffjni.h
993 993
 SKIPHEADERS-$(CONFIG_LIBSCHROEDINGER)  += libschroedinger.h
994 994
 SKIPHEADERS-$(CONFIG_LIBVPX)           += libvpx.h
995 995
 SKIPHEADERS-$(CONFIG_LIBWEBP_ENCODER)  += libwebpenc_common.h
996
-SKIPHEADERS-$(CONFIG_MEDIACODEC)       += mediacodecdec.h mediacodec_wrapper.h mediacodec_sw_buffer.h
996
+SKIPHEADERS-$(CONFIG_MEDIACODEC)       += mediacodecdec.h mediacodec_surface.h mediacodec_wrapper.h mediacodec_sw_buffer.h
997 997
 SKIPHEADERS-$(CONFIG_NVENC)            += nvenc.h
998 998
 SKIPHEADERS-$(CONFIG_QSV)              += qsv.h qsv_internal.h
999 999
 SKIPHEADERS-$(CONFIG_QSVDEC)           += qsvdec.h
... ...
@@ -72,6 +72,7 @@ void avcodec_register_all(void)
72 72
     REGISTER_HWACCEL(H264_CUVID,        h264_cuvid);
73 73
     REGISTER_HWACCEL(H264_D3D11VA,      h264_d3d11va);
74 74
     REGISTER_HWACCEL(H264_DXVA2,        h264_dxva2);
75
+    REGISTER_HWACCEL(H264_MEDIACODEC,   h264_mediacodec);
75 76
     REGISTER_HWACCEL(H264_MMAL,         h264_mmal);
76 77
     REGISTER_HWACCEL(H264_QSV,          h264_qsv);
77 78
     REGISTER_HWACCEL(H264_VAAPI,        h264_vaapi);
78 79
new file mode 100644
... ...
@@ -0,0 +1,133 @@
0
+/*
1
+ * Android MediaCodec public API functions
2
+ *
3
+ * Copyright (c) 2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
4
+ *
5
+ * This file is part of FFmpeg.
6
+ *
7
+ * FFmpeg is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * FFmpeg is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with FFmpeg; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ */
21
+
22
+#include "config.h"
23
+
24
+#if CONFIG_H264_MEDIACODEC_HWACCEL
25
+
26
+#include <jni.h>
27
+
28
+#include "libavcodec/avcodec.h"
29
+#include "libavutil/atomic.h"
30
+#include "libavutil/mem.h"
31
+
32
+#include "ffjni.h"
33
+#include "mediacodec.h"
34
+#include "mediacodecdec.h"
35
+
36
+AVMediaCodecContext *av_mediacodec_alloc_context(void)
37
+{
38
+    return av_mallocz(sizeof(AVMediaCodecContext));
39
+}
40
+
41
+int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx, void *surface)
42
+{
43
+    int ret = 0;
44
+    JNIEnv *env = NULL;
45
+    int attached = 0;
46
+
47
+    env = ff_jni_attach_env(&attached, avctx);
48
+    if (!env) {
49
+        return AVERROR_EXTERNAL;
50
+    }
51
+
52
+    ctx->surface = (*env)->NewGlobalRef(env, surface);
53
+    if (ctx->surface) {
54
+        avctx->hwaccel_context = ctx;
55
+    } else {
56
+        av_log(avctx, AV_LOG_ERROR, "Could not create new global reference\n");
57
+        ret = AVERROR_EXTERNAL;
58
+    }
59
+
60
+    if (attached) {
61
+        ff_jni_detach_env(avctx);
62
+    }
63
+
64
+    return ret;
65
+}
66
+
67
+void av_mediacodec_default_free(AVCodecContext *avctx)
68
+{
69
+    JNIEnv *env = NULL;
70
+    int attached = 0;
71
+
72
+    AVMediaCodecContext *ctx = avctx->hwaccel_context;
73
+
74
+    if (!ctx) {
75
+        return;
76
+    }
77
+
78
+    env = ff_jni_attach_env(&attached, avctx);
79
+    if (!env) {
80
+        return;
81
+    }
82
+
83
+    if (ctx->surface) {
84
+        (*env)->DeleteGlobalRef(env, ctx->surface);
85
+        ctx->surface = NULL;
86
+    }
87
+
88
+    if (attached) {
89
+        ff_jni_detach_env(avctx);
90
+    }
91
+
92
+    av_freep(&avctx->hwaccel_context);
93
+}
94
+
95
+int av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render)
96
+{
97
+    MediaCodecDecContext *ctx = buffer->ctx;
98
+    int released = avpriv_atomic_int_add_and_fetch(&buffer->released, 1);
99
+
100
+    if (released == 1) {
101
+        return ff_AMediaCodec_releaseOutputBuffer(ctx->codec, buffer->index, render);
102
+    }
103
+
104
+    return 0;
105
+}
106
+
107
+#else
108
+
109
+#include <stdlib.h>
110
+
111
+#include "mediacodec.h"
112
+
113
+AVMediaCodecContext *av_mediacodec_alloc_context(void)
114
+{
115
+    return NULL;
116
+}
117
+
118
+int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx, void *surface)
119
+{
120
+    return 0;
121
+}
122
+
123
+void av_mediacodec_default_free(AVCodecContext *avctx)
124
+{
125
+}
126
+
127
+int av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render)
128
+{
129
+    return 0;
130
+}
131
+
132
+#endif
0 133
new file mode 100644
... ...
@@ -0,0 +1,88 @@
0
+/*
1
+ * Android MediaCodec public API
2
+ *
3
+ * Copyright (c) 2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
4
+ *
5
+ * This file is part of FFmpeg.
6
+ *
7
+ * FFmpeg is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * FFmpeg is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with FFmpeg; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ */
21
+
22
+#ifndef AVCODEC_MEDIACODEC_H
23
+#define AVCODEC_MEDIACODEC_H
24
+
25
+#include "libavcodec/avcodec.h"
26
+
27
+/**
28
+ * This structure holds a reference to a android/view/Surface object that will
29
+ * be used as output by the decoder.
30
+ *
31
+ */
32
+typedef struct AVMediaCodecContext {
33
+
34
+    /**
35
+     * android/view/Surface object reference.
36
+     */
37
+    void *surface;
38
+
39
+} AVMediaCodecContext;
40
+
41
+/**
42
+ * Allocate and initialize a MediaCodec context.
43
+ *
44
+ * When decoding with MediaCodec is finished, the caller must free the
45
+ * MediaCodec context with av_mediacodec_default_free.
46
+ *
47
+ * @return a pointer to a newly allocated AVMediaCodecContext on success, NULL otherwise
48
+ */
49
+AVMediaCodecContext *av_mediacodec_alloc_context(void);
50
+
51
+/**
52
+ * Convenience function that sets up the MediaCodec context.
53
+ *
54
+ * @param avctx codec context
55
+ * @param ctx MediaCodec context to initialize
56
+ * @param surface reference to an android/view/Surface
57
+ * @return 0 on success, < 0 otherwise
58
+ */
59
+int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx, void *surface);
60
+
61
+/**
62
+ * This function must be called to free the MediaCodec context initialized with
63
+ * av_mediacodec_default_init().
64
+ *
65
+ * @param avctx codec context
66
+ */
67
+void av_mediacodec_default_free(AVCodecContext *avctx);
68
+
69
+/**
70
+ * Opaque structure representing a MediaCodec buffer to render.
71
+ */
72
+typedef struct MediaCodecBuffer AVMediaCodecBuffer;
73
+
74
+/**
75
+ * Release a MediaCodec buffer and render it to the surface that is associated
76
+ * with the decoder. This function should only be called once on a given
77
+ * buffer, once released the underlying buffer returns to the codec, thus
78
+ * subsequent calls to this function will have no effect.
79
+ *
80
+ * @param buffer the buffer to render
81
+ * @param render 1 to release and render the buffer to the surface or 0 to
82
+ * discard the buffer
83
+ * @return 0 on success, < 0 otherwise
84
+ */
85
+int av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render);
86
+
87
+#endif /* AVCODEC_MEDIACODEC_H */
0 88
new file mode 100644
... ...
@@ -0,0 +1,66 @@
0
+/*
1
+ * Android MediaCodec Surface functions
2
+ *
3
+ * Copyright (c) 2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
4
+ *
5
+ * This file is part of FFmpeg.
6
+ *
7
+ * FFmpeg is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * FFmpeg is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with FFmpeg; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ */
21
+
22
+#include <jni.h>
23
+
24
+#include "ffjni.h"
25
+#include "mediacodec_surface.h"
26
+
27
+void *ff_mediacodec_surface_ref(void *surface, void *log_ctx)
28
+{
29
+    int attached = 0;
30
+    JNIEnv *env = NULL;
31
+
32
+    void *reference = NULL;
33
+
34
+    env = ff_jni_attach_env(&attached, log_ctx);
35
+    if (!env) {
36
+        return NULL;
37
+    }
38
+
39
+    reference = (*env)->NewGlobalRef(env, surface);
40
+
41
+    if (attached) {
42
+        ff_jni_detach_env(log_ctx);
43
+    }
44
+
45
+    return reference;
46
+}
47
+
48
+int ff_mediacodec_surface_unref(void *surface, void *log_ctx)
49
+{
50
+    int attached = 0;
51
+    JNIEnv *env = NULL;
52
+
53
+    env = ff_jni_attach_env(&attached, log_ctx);
54
+    if (!env) {
55
+        return AVERROR_EXTERNAL;
56
+    }
57
+
58
+    (*env)->DeleteGlobalRef(env, surface);
59
+
60
+    if (attached) {
61
+        ff_jni_detach_env(log_ctx);
62
+    }
63
+
64
+    return 0;
65
+}
0 66
new file mode 100644
... ...
@@ -0,0 +1,31 @@
0
+/*
1
+ * Android MediaCodec Surface functions
2
+ *
3
+ * Copyright (c) 2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
4
+ *
5
+ * This file is part of FFmpeg.
6
+ *
7
+ * FFmpeg is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * FFmpeg is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with FFmpeg; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ */
21
+
22
+#ifndef AVCODEC_MEDIACODEC_SURFACE_H
23
+#define AVCODEC_MEDIACODEC_SURFACE_H
24
+
25
+#include "libavcodec/avcodec.h"
26
+
27
+void *ff_mediacodec_surface_ref(void *surface, void *log_ctx);
28
+int ff_mediacodec_surface_unref(void *surface, void *log_ctx);
29
+
30
+#endif /* AVCODEC_MEDIACODEC_SURFACE_H */
... ...
@@ -1416,12 +1416,9 @@ int ff_AMediaCodec_configure(FFAMediaCodec* codec, const FFAMediaFormat* format,
1416 1416
     int attached = 0;
1417 1417
     JNIEnv *env = NULL;
1418 1418
 
1419
-    /* TODO: implement surface handling */
1420
-    av_assert0(surface == NULL);
1421
-
1422 1419
     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1423 1420
 
1424
-    (*env)->CallVoidMethod(env, codec->object, codec->jfields.configure_id, format->object, NULL, NULL, flags);
1421
+    (*env)->CallVoidMethod(env, codec->object, codec->jfields.configure_id, format->object, surface, NULL, flags);
1425 1422
     if (ff_jni_exception_check(env, 1, codec) < 0) {
1426 1423
         ret = AVERROR_EXTERNAL;
1427 1424
         goto fail;
... ...
@@ -23,6 +23,7 @@
23 23
 #include <string.h>
24 24
 #include <sys/types.h>
25 25
 
26
+#include "libavutil/atomic.h"
26 27
 #include "libavutil/common.h"
27 28
 #include "libavutil/mem.h"
28 29
 #include "libavutil/log.h"
... ...
@@ -33,6 +34,8 @@
33 33
 #include "avcodec.h"
34 34
 #include "internal.h"
35 35
 
36
+#include "mediacodec.h"
37
+#include "mediacodec_surface.h"
36 38
 #include "mediacodec_sw_buffer.h"
37 39
 #include "mediacodec_wrapper.h"
38 40
 #include "mediacodecdec.h"
... ...
@@ -118,6 +121,10 @@ static enum AVPixelFormat mcdec_map_color_format(AVCodecContext *avctx,
118 118
     int i;
119 119
     enum AVPixelFormat ret = AV_PIX_FMT_NONE;
120 120
 
121
+    if (s->surface) {
122
+        return AV_PIX_FMT_MEDIACODEC;
123
+    }
124
+
121 125
     if (!strcmp(s->codec_name, "OMX.k3.video.decoder.avc") && color_format == COLOR_FormatYCbYCr) {
122 126
         s->color_format = color_format = COLOR_TI_FormatYUV420PackedSemiPlanar;
123 127
     }
... ...
@@ -134,7 +141,117 @@ static enum AVPixelFormat mcdec_map_color_format(AVCodecContext *avctx,
134 134
     return ret;
135 135
 }
136 136
 
137
-static int mediacodec_wrap_buffer(AVCodecContext *avctx,
137
+static void ff_mediacodec_dec_ref(MediaCodecDecContext *s)
138
+{
139
+    avpriv_atomic_int_add_and_fetch(&s->refcount, 1);
140
+}
141
+
142
+static void ff_mediacodec_dec_unref(MediaCodecDecContext *s)
143
+{
144
+    if (!s)
145
+        return;
146
+
147
+    if (!avpriv_atomic_int_add_and_fetch(&s->refcount, -1)) {
148
+        if (s->codec) {
149
+            ff_AMediaCodec_delete(s->codec);
150
+            s->codec = NULL;
151
+        }
152
+
153
+        if (s->format) {
154
+            ff_AMediaFormat_delete(s->format);
155
+            s->format = NULL;
156
+        }
157
+
158
+        if (s->surface) {
159
+            ff_mediacodec_surface_unref(s->surface, NULL);
160
+            s->surface = NULL;
161
+        }
162
+
163
+        av_freep(&s->codec_name);
164
+        av_freep(&s);
165
+    }
166
+}
167
+
168
+static void mediacodec_buffer_release(void *opaque, uint8_t *data)
169
+{
170
+    AVMediaCodecBuffer *buffer = opaque;
171
+    MediaCodecDecContext *ctx = buffer->ctx;
172
+    int released = avpriv_atomic_int_get(&buffer->released);
173
+
174
+    if (!released) {
175
+        ff_AMediaCodec_releaseOutputBuffer(ctx->codec, buffer->index, 0);
176
+    }
177
+
178
+    ff_mediacodec_dec_unref(ctx);
179
+    av_freep(&buffer);
180
+}
181
+
182
+static int mediacodec_wrap_hw_buffer(AVCodecContext *avctx,
183
+                                  MediaCodecDecContext *s,
184
+                                  ssize_t index,
185
+                                  FFAMediaCodecBufferInfo *info,
186
+                                  AVFrame *frame)
187
+{
188
+    int ret = 0;
189
+    int status = 0;
190
+    AVMediaCodecBuffer *buffer = NULL;
191
+
192
+    frame->buf[0] = NULL;
193
+    frame->width = avctx->width;
194
+    frame->height = avctx->height;
195
+    frame->format = avctx->pix_fmt;
196
+
197
+    if (avctx->pkt_timebase.num && avctx->pkt_timebase.den) {
198
+        frame->pkt_pts = av_rescale_q(info->presentationTimeUs,
199
+                                      av_make_q(1, 1000000),
200
+                                      avctx->pkt_timebase);
201
+    } else {
202
+        frame->pkt_pts = info->presentationTimeUs;
203
+    }
204
+    frame->pkt_dts = AV_NOPTS_VALUE;
205
+
206
+    buffer = av_mallocz(sizeof(AVMediaCodecBuffer));
207
+    if (!buffer) {
208
+        ret = AVERROR(ENOMEM);
209
+        goto fail;
210
+    }
211
+
212
+    buffer->released = 0;
213
+
214
+    frame->buf[0] = av_buffer_create(NULL,
215
+                                     0,
216
+                                     mediacodec_buffer_release,
217
+                                     buffer,
218
+                                     AV_BUFFER_FLAG_READONLY);
219
+
220
+    if (!frame->buf[0]) {
221
+        ret = AVERROR(ENOMEM);
222
+        goto fail;
223
+
224
+    }
225
+
226
+    buffer->ctx = s;
227
+    ff_mediacodec_dec_ref(s);
228
+
229
+    buffer->index = index;
230
+    buffer->pts = info->presentationTimeUs;
231
+
232
+    frame->data[3] = (uint8_t *)buffer;
233
+
234
+    return 0;
235
+fail:
236
+    av_freep(buffer);
237
+    av_buffer_unref(&frame->buf[0]);
238
+    status = ff_AMediaCodec_releaseOutputBuffer(s->codec, index, 0);
239
+    if (status < 0) {
240
+        av_log(avctx, AV_LOG_ERROR, "Failed to release output buffer\n");
241
+        ret = AVERROR_EXTERNAL;
242
+    }
243
+
244
+    return ret;
245
+}
246
+
247
+static int mediacodec_wrap_sw_buffer(AVCodecContext *avctx,
138 248
                                   MediaCodecDecContext *s,
139 249
                                   uint8_t *data,
140 250
                                   size_t size,
... ...
@@ -304,6 +421,30 @@ static int mediacodec_dec_parse_format(AVCodecContext *avctx, MediaCodecDecConte
304 304
     return ff_set_dimensions(avctx, width, height);
305 305
 }
306 306
 
307
+
308
+static int mediacodec_dec_flush_codec(AVCodecContext *avctx, MediaCodecDecContext *s)
309
+{
310
+    FFAMediaCodec *codec = s->codec;
311
+    int status;
312
+
313
+    s->dequeued_buffer_nb = 0;
314
+
315
+    s->draining = 0;
316
+    s->flushing = 0;
317
+    s->eos = 0;
318
+
319
+    status = ff_AMediaCodec_flush(codec);
320
+    if (status < 0) {
321
+        av_log(avctx, AV_LOG_ERROR, "Failed to flush codec\n");
322
+        return AVERROR_EXTERNAL;
323
+    }
324
+
325
+    s->first_buffer = 0;
326
+    s->first_buffer_at = av_gettime();
327
+
328
+    return 0;
329
+}
330
+
307 331
 int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s,
308 332
                            const char *mime, FFAMediaFormat *format)
309 333
 {
... ...
@@ -311,7 +452,24 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s,
311 311
     int status;
312 312
     int profile;
313 313
 
314
+    enum AVPixelFormat pix_fmt;
315
+    static const enum AVPixelFormat pix_fmts[] = {
316
+        AV_PIX_FMT_MEDIACODEC,
317
+        AV_PIX_FMT_NONE,
318
+    };
319
+
314 320
     s->first_buffer_at = av_gettime();
321
+    s->refcount = 1;
322
+
323
+    pix_fmt = ff_get_format(avctx, pix_fmts);
324
+    if (pix_fmt == AV_PIX_FMT_MEDIACODEC) {
325
+        AVMediaCodecContext *user_ctx = avctx->hwaccel_context;
326
+
327
+        if (user_ctx && user_ctx->surface) {
328
+            s->surface = ff_mediacodec_surface_ref(user_ctx->surface, avctx);
329
+            av_log(avctx, AV_LOG_INFO, "Using surface %p\n", s->surface);
330
+        }
331
+    }
315 332
 
316 333
     profile = ff_AMediaCodecProfile_getProfileFromAVCodecContext(avctx);
317 334
     if (profile < 0) {
... ...
@@ -332,7 +490,7 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s,
332 332
         goto fail;
333 333
     }
334 334
 
335
-    status = ff_AMediaCodec_configure(s->codec, format, NULL, NULL, 0);
335
+    status = ff_AMediaCodec_configure(s->codec, format, s->surface, NULL, 0);
336 336
     if (status < 0) {
337 337
         char *desc = ff_AMediaFormat_toString(format);
338 338
         av_log(avctx, AV_LOG_ERROR,
... ...
@@ -380,7 +538,7 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s,
380 380
 {
381 381
     int ret;
382 382
     int offset = 0;
383
-    int need_flushing = 0;
383
+    int need_draining = 0;
384 384
     uint8_t *data;
385 385
     ssize_t index;
386 386
     size_t size;
... ...
@@ -392,15 +550,21 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s,
392 392
     int64_t input_dequeue_timeout_us = INPUT_DEQUEUE_TIMEOUT_US;
393 393
     int64_t output_dequeue_timeout_us = OUTPUT_DEQUEUE_TIMEOUT_US;
394 394
 
395
+    if (s->flushing) {
396
+        av_log(avctx, AV_LOG_ERROR, "Decoder is flushing and cannot accept new buffer "
397
+                                    "until all output buffers have been released\n");
398
+        return AVERROR_EXTERNAL;
399
+    }
400
+
395 401
     if (pkt->size == 0) {
396
-        need_flushing = 1;
402
+        need_draining = 1;
397 403
     }
398 404
 
399
-    if (s->flushing && s->eos) {
405
+    if (s->draining && s->eos) {
400 406
         return 0;
401 407
     }
402 408
 
403
-    while (offset < pkt->size || (need_flushing && !s->flushing)) {
409
+    while (offset < pkt->size || (need_draining && !s->draining)) {
404 410
         int size;
405 411
 
406 412
         index = ff_AMediaCodec_dequeueInputBuffer(codec, input_dequeue_timeout_us);
... ...
@@ -419,26 +583,37 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s,
419 419
             return AVERROR_EXTERNAL;
420 420
         }
421 421
 
422
-        if (need_flushing) {
422
+        if (need_draining) {
423
+            int64_t pts = pkt->pts;
423 424
             uint32_t flags = ff_AMediaCodec_getBufferFlagEndOfStream(codec);
424 425
 
426
+            if (s->surface) {
427
+                pts = av_rescale_q(pts, avctx->pkt_timebase, av_make_q(1, 1000000));
428
+            }
429
+
425 430
             av_log(avctx, AV_LOG_DEBUG, "Sending End Of Stream signal\n");
426 431
 
427
-            status = ff_AMediaCodec_queueInputBuffer(codec, index, 0, 0, pkt->pts, flags);
432
+            status = ff_AMediaCodec_queueInputBuffer(codec, index, 0, 0, pts, flags);
428 433
             if (status < 0) {
429 434
                 av_log(avctx, AV_LOG_ERROR, "Failed to queue input empty buffer (status = %d)\n", status);
430 435
                 return AVERROR_EXTERNAL;
431 436
             }
432 437
 
433
-            s->flushing = 1;
438
+            s->draining = 1;
434 439
             break;
435 440
         } else {
441
+            int64_t pts = pkt->pts;
442
+
436 443
             size = FFMIN(pkt->size - offset, size);
437 444
 
438 445
             memcpy(data, pkt->data + offset, size);
439 446
             offset += size;
440 447
 
441
-            status = ff_AMediaCodec_queueInputBuffer(codec, index, 0, size, pkt->pts, 0);
448
+            if (s->surface && avctx->pkt_timebase.num && avctx->pkt_timebase.den) {
449
+                pts = av_rescale_q(pts, avctx->pkt_timebase, av_make_q(1, 1000000));
450
+            }
451
+
452
+            status = ff_AMediaCodec_queueInputBuffer(codec, index, 0, size, pts, 0);
442 453
             if (status < 0) {
443 454
                 av_log(avctx, AV_LOG_ERROR, "Failed to queue input buffer (status = %d)\n", status);
444 455
                 return AVERROR_EXTERNAL;
... ...
@@ -446,7 +621,7 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s,
446 446
         }
447 447
     }
448 448
 
449
-    if (need_flushing || s->flushing) {
449
+    if (need_draining || s->draining) {
450 450
         /* If the codec is flushing or need to be flushed, block for a fair
451 451
          * amount of time to ensure we got a frame */
452 452
         output_dequeue_timeout_us = OUTPUT_DEQUEUE_BLOCK_TIMEOUT_US;
... ...
@@ -475,15 +650,22 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s,
475 475
         }
476 476
 
477 477
         if (info.size) {
478
-            data = ff_AMediaCodec_getOutputBuffer(codec, index, &size);
479
-            if (!data) {
480
-                av_log(avctx, AV_LOG_ERROR, "Failed to get output buffer\n");
481
-                return AVERROR_EXTERNAL;
482
-            }
483
-
484
-            if ((ret = mediacodec_wrap_buffer(avctx, s, data, size, index, &info, frame)) < 0) {
485
-                av_log(avctx, AV_LOG_ERROR, "Failed to wrap MediaCodec buffer\n");
486
-                return ret;
478
+            if (s->surface) {
479
+                if ((ret = mediacodec_wrap_hw_buffer(avctx, s, index, &info, frame)) < 0) {
480
+                    av_log(avctx, AV_LOG_ERROR, "Failed to wrap MediaCodec buffer\n");
481
+                    return ret;
482
+                }
483
+            } else {
484
+                data = ff_AMediaCodec_getOutputBuffer(codec, index, &size);
485
+                if (!data) {
486
+                    av_log(avctx, AV_LOG_ERROR, "Failed to get output buffer\n");
487
+                    return AVERROR_EXTERNAL;
488
+                }
489
+
490
+                if ((ret = mediacodec_wrap_sw_buffer(avctx, s, data, size, index, &info, frame)) < 0) {
491
+                    av_log(avctx, AV_LOG_ERROR, "Failed to wrap MediaCodec buffer\n");
492
+                    return ret;
493
+                }
487 494
             }
488 495
 
489 496
             *got_frame = 1;
... ...
@@ -525,9 +707,9 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s,
525 525
     } else if (ff_AMediaCodec_infoOutputBuffersChanged(codec, index)) {
526 526
         ff_AMediaCodec_cleanOutputBuffers(codec);
527 527
     } else if (ff_AMediaCodec_infoTryAgainLater(codec, index)) {
528
-        if (s->flushing) {
528
+        if (s->draining) {
529 529
             av_log(avctx, AV_LOG_ERROR, "Failed to dequeue output buffer within %" PRIi64 "ms "
530
-                                        "while flushing remaining frames, output will probably lack frames\n",
530
+                                        "while draining remaining frames, output will probably lack frames\n",
531 531
                                         output_dequeue_timeout_us / 1000);
532 532
         } else {
533 533
             av_log(avctx, AV_LOG_DEBUG, "No output buffer available, try again later\n");
... ...
@@ -542,39 +724,37 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s,
542 542
 
543 543
 int ff_mediacodec_dec_flush(AVCodecContext *avctx, MediaCodecDecContext *s)
544 544
 {
545
-    FFAMediaCodec *codec = s->codec;
546
-    int status;
547
-
548
-    s->dequeued_buffer_nb = 0;
545
+    if (!s->surface || avpriv_atomic_int_get(&s->refcount) == 1) {
546
+        int ret;
549 547
 
550
-    s->flushing = 0;
551
-    s->eos = 0;
548
+        /* No frames (holding a reference to the codec) are retained by the
549
+         * user, thus we can flush the codec and returns accordingly */
550
+        if ((ret = mediacodec_dec_flush_codec(avctx, s)) < 0) {
551
+            return ret;
552
+        }
552 553
 
553
-    status = ff_AMediaCodec_flush(codec);
554
-    if (status < 0) {
555
-        av_log(avctx, AV_LOG_ERROR, "Failed to flush codec\n");
556
-        return AVERROR_EXTERNAL;
554
+        return 1;
557 555
     }
558 556
 
559
-    s->first_buffer = 0;
560
-    s->first_buffer_at = av_gettime();
561
-
557
+    s->flushing = 1;
562 558
     return 0;
563 559
 }
564 560
 
565 561
 int ff_mediacodec_dec_close(AVCodecContext *avctx, MediaCodecDecContext *s)
566 562
 {
567
-    if (s->codec) {
568
-        ff_AMediaCodec_delete(s->codec);
569
-        s->codec = NULL;
570
-    }
571
-
572
-    if (s->format) {
573
-        ff_AMediaFormat_delete(s->format);
574
-        s->format = NULL;
575
-    }
576
-
577
-    av_freep(&s->codec_name);
563
+    ff_mediacodec_dec_unref(s);
578 564
 
579 565
     return 0;
580 566
 }
567
+
568
+int ff_mediacodec_dec_is_flushing(AVCodecContext *avctx, MediaCodecDecContext *s)
569
+{
570
+    return s->flushing;
571
+}
572
+
573
+AVHWAccel ff_h264_mediacodec_hwaccel = {
574
+    .name    = "mediacodec",
575
+    .type    = AVMEDIA_TYPE_VIDEO,
576
+    .id      = AV_CODEC_ID_H264,
577
+    .pix_fmt = AV_PIX_FMT_MEDIACODEC,
578
+};
... ...
@@ -34,12 +34,17 @@
34 34
 
35 35
 typedef struct MediaCodecDecContext {
36 36
 
37
+    volatile int refcount;
38
+
37 39
     char *codec_name;
38 40
 
39 41
     FFAMediaCodec *codec;
40 42
     FFAMediaFormat *format;
41 43
 
44
+    void *surface;
45
+
42 46
     int started;
47
+    int draining;
43 48
     int flushing;
44 49
     int eos;
45 50
 
... ...
@@ -78,4 +83,16 @@ int ff_mediacodec_dec_flush(AVCodecContext *avctx,
78 78
 int ff_mediacodec_dec_close(AVCodecContext *avctx,
79 79
                             MediaCodecDecContext *s);
80 80
 
81
+int ff_mediacodec_dec_is_flushing(AVCodecContext *avctx,
82
+                                  MediaCodecDecContext *s);
83
+
84
+typedef struct MediaCodecBuffer {
85
+
86
+    MediaCodecDecContext *ctx;
87
+    ssize_t index;
88
+    int64_t pts;
89
+    volatile int released;
90
+
91
+} MediaCodecBuffer;
92
+
81 93
 #endif /* AVCODEC_MEDIACODECDEC_H */
... ...
@@ -41,7 +41,7 @@
41 41
 
42 42
 typedef struct MediaCodecH264DecContext {
43 43
 
44
-    MediaCodecDecContext ctx;
44
+    MediaCodecDecContext *ctx;
45 45
 
46 46
     AVBSFContext *bsf;
47 47
 
... ...
@@ -55,7 +55,8 @@ static av_cold int mediacodec_decode_close(AVCodecContext *avctx)
55 55
 {
56 56
     MediaCodecH264DecContext *s = avctx->priv_data;
57 57
 
58
-    ff_mediacodec_dec_close(avctx, &s->ctx);
58
+    ff_mediacodec_dec_close(avctx, s->ctx);
59
+    s->ctx = NULL;
59 60
 
60 61
     av_fifo_free(s->fifo);
61 62
 
... ...
@@ -184,7 +185,15 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx)
184 184
         goto done;
185 185
     }
186 186
 
187
-    if ((ret = ff_mediacodec_dec_init(avctx, &s->ctx, CODEC_MIME, format)) < 0) {
187
+    s->ctx = av_mallocz(sizeof(*s->ctx));
188
+    if (!s->ctx) {
189
+        av_log(avctx, AV_LOG_ERROR, "Failed to allocate MediaCodecDecContext\n");
190
+        ret = AVERROR(ENOMEM);
191
+        goto done;
192
+    }
193
+
194
+    if ((ret = ff_mediacodec_dec_init(avctx, s->ctx, CODEC_MIME, format)) < 0) {
195
+        s->ctx = NULL;
188 196
         goto done;
189 197
     }
190 198
 
... ...
@@ -233,7 +242,7 @@ static int mediacodec_process_data(AVCodecContext *avctx, AVFrame *frame,
233 233
 {
234 234
     MediaCodecH264DecContext *s = avctx->priv_data;
235 235
 
236
-    return ff_mediacodec_dec_decode(avctx, &s->ctx, frame, got_frame, pkt);
236
+    return ff_mediacodec_dec_decode(avctx, s->ctx, frame, got_frame, pkt);
237 237
 }
238 238
 
239 239
 static int mediacodec_decode_frame(AVCodecContext *avctx, void *data,
... ...
@@ -260,6 +269,32 @@ static int mediacodec_decode_frame(AVCodecContext *avctx, void *data,
260 260
         av_fifo_generic_write(s->fifo, &input_pkt, sizeof(input_pkt), NULL);
261 261
     }
262 262
 
263
+    /*
264
+     * MediaCodec.flush() discards both input and output buffers, thus we
265
+     * need to delay the call to this function until the user has released or
266
+     * renderered the frames he retains.
267
+     *
268
+     * After we have buffered an input packet, check if the codec is in the
269
+     * flushing state. If it is, we need to call ff_mediacodec_dec_flush.
270
+     *
271
+     * ff_mediacodec_dec_flush returns 0 if the flush cannot be performed on
272
+     * the codec (because the user retains frames). The codec stays in the
273
+     * flushing state.
274
+     *
275
+     * ff_mediacodec_dec_flush returns 1 if the flush can actually be
276
+     * performed on the codec. The codec leaves the flushing state and can
277
+     * process again packets.
278
+     *
279
+     * ff_mediacodec_dec_flush returns a negative value if an error has
280
+     * occured.
281
+     *
282
+     */
283
+    if (ff_mediacodec_dec_is_flushing(avctx, s->ctx)) {
284
+        if (!ff_mediacodec_dec_flush(avctx, s->ctx)) {
285
+            return avpkt->size;
286
+        }
287
+    }
288
+
263 289
     /* process buffered data */
264 290
     while (!*got_frame) {
265 291
         /* prepare the input data -- convert to Annex B if needed */
... ...
@@ -271,7 +306,7 @@ static int mediacodec_decode_frame(AVCodecContext *avctx, void *data,
271 271
             /* no more data */
272 272
             if (av_fifo_size(s->fifo) < sizeof(AVPacket)) {
273 273
                 return avpkt->size ? avpkt->size :
274
-                    ff_mediacodec_dec_decode(avctx, &s->ctx, frame, got_frame, avpkt);
274
+                    ff_mediacodec_dec_decode(avctx, s->ctx, frame, got_frame, avpkt);
275 275
             }
276 276
 
277 277
             av_fifo_generic_read(s->fifo, &input_pkt, sizeof(input_pkt), NULL);
... ...
@@ -318,7 +353,7 @@ static void mediacodec_decode_flush(AVCodecContext *avctx)
318 318
 
319 319
     av_packet_unref(&s->filtered_pkt);
320 320
 
321
-    ff_mediacodec_dec_flush(avctx, &s->ctx);
321
+    ff_mediacodec_dec_flush(avctx, s->ctx);
322 322
 }
323 323
 
324 324
 AVCodec ff_h264_mediacodec_decoder = {
... ...
@@ -28,7 +28,7 @@
28 28
 #include "libavutil/version.h"
29 29
 
30 30
 #define LIBAVCODEC_VERSION_MAJOR  57
31
-#define LIBAVCODEC_VERSION_MINOR  48
31
+#define LIBAVCODEC_VERSION_MINOR  49
32 32
 #define LIBAVCODEC_VERSION_MICRO 103
33 33
 
34 34
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
... ...
@@ -1974,6 +1974,10 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
1974 1974
         .name = "qsv",
1975 1975
         .flags = AV_PIX_FMT_FLAG_HWACCEL,
1976 1976
     },
1977
+    [AV_PIX_FMT_MEDIACODEC] = {
1978
+        .name = "mediacodec",
1979
+        .flags = AV_PIX_FMT_FLAG_HWACCEL,
1980
+    },
1977 1981
     [AV_PIX_FMT_MMAL] = {
1978 1982
         .name = "mmal",
1979 1983
         .flags = AV_PIX_FMT_FLAG_HWACCEL,
... ...
@@ -303,6 +303,8 @@ enum AVPixelFormat {
303 303
     AV_PIX_FMT_GBRAP10BE,  ///< planar GBR 4:4:4:4 40bpp, big-endian
304 304
     AV_PIX_FMT_GBRAP10LE,  ///< planar GBR 4:4:4:4 40bpp, little-endian
305 305
 
306
+    AV_PIX_FMT_MEDIACODEC, ///< hardware decoding through MediaCodec
307
+
306 308
     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
307 309
 };
308 310