... | ... |
@@ -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 |
|