Browse code

lavc: add h264 mediacodec decoder

Matthieu Bouron authored on 2016/01/21 17:29:39
Showing 13 changed files
... ...
@@ -11,6 +11,7 @@ version <next>:
11 11
 - bench and abench filters
12 12
 - ciescope filter
13 13
 - protocol blacklisting API
14
+- MediaCodec H264 decoding
14 15
 
15 16
 
16 17
 version 3.0:
... ...
@@ -308,6 +308,7 @@ Codecs:
308 308
 Hardware acceleration:
309 309
   crystalhd.c                           Philip Langdale
310 310
   dxva2*                                Hendrik Leppkes, Laurent Aimar
311
+  mediacodec*                           Matthieu Bouron
311 312
   vaapi*                                Gwenole Beauchesne
312 313
   vda*                                  Sebastien Zwickert
313 314
   vdpau*                                Philip Langdale, Carl Eugen Hoyos
... ...
@@ -276,6 +276,7 @@ External library support:
276 276
   --enable-libzvbi         enable teletext support via libzvbi [no]
277 277
   --disable-lzma           disable lzma [autodetect]
278 278
   --enable-decklink        enable Blackmagic DeckLink I/O support [no]
279
+  --enable-mediacodec      enable Android MediaCodec support [no]
279 280
   --enable-mmal            enable decoding via MMAL [no]
280 281
   --enable-netcdf          enable NetCDF, needed for sofalizer filter [no]
281 282
   --enable-nvenc           enable NVIDIA NVENC support [no]
... ...
@@ -1501,6 +1502,7 @@ EXTERNAL_LIBRARY_LIST="
1501 1501
     libzmq
1502 1502
     libzvbi
1503 1503
     lzma
1504
+    mediacodec
1504 1505
     mmal
1505 1506
     netcdf
1506 1507
     nvenc
... ...
@@ -2505,6 +2507,8 @@ h264_d3d11va_hwaccel_deps="d3d11va"
2505 2505
 h264_d3d11va_hwaccel_select="h264_decoder"
2506 2506
 h264_dxva2_hwaccel_deps="dxva2"
2507 2507
 h264_dxva2_hwaccel_select="h264_decoder"
2508
+h264_mediacodec_decoder_deps="mediacodec"
2509
+h264_mediacodec_decoder_select="h264_mp4toannexb_bsf h264_parser"
2508 2510
 h264_mmal_decoder_deps="mmal"
2509 2511
 h264_mmal_decoder_select="mmal"
2510 2512
 h264_mmal_hwaccel_deps="mmal"
... ...
@@ -5672,6 +5676,7 @@ enabled libzmq            && require_pkg_config libzmq zmq.h zmq_ctx_new
5672 5672
 enabled libzvbi           && require libzvbi libzvbi.h vbi_decoder_new -lzvbi &&
5673 5673
                              { check_cpp_condition libzvbi.h "VBI_VERSION_MAJOR > 0 || VBI_VERSION_MINOR > 2 || VBI_VERSION_MINOR == 2 && VBI_VERSION_MICRO >= 28" ||
5674 5674
                                enabled gpl || die "ERROR: libzvbi requires version 0.2.28 or --enable-gpl."; }
5675
+enabled mediacodec        && { enabled jni || die "ERROR: mediacodec requires --enable-jni"; }
5675 5676
 enabled mmal              && { check_lib interface/mmal/mmal.h mmal_port_connect -lmmal_core -lmmal_util -lmmal_vc_client -lbcm_host ||
5676 5677
                                 { ! enabled cross_compile && {
5677 5678
                                     add_cflags -isystem/opt/vc/include/ -isystem/opt/vc/include/interface/vmcs_host/linux -isystem/opt/vc/include/interface/vcos/pthreads -fgnu89-inline ;
... ...
@@ -91,6 +91,7 @@ OBJS-$(CONFIG_LSP)                     += lsp.o
91 91
 OBJS-$(CONFIG_LZF)                     += lzf.o
92 92
 OBJS-$(CONFIG_MDCT)                    += mdct_fixed.o mdct_float.o mdct_fixed_32.o
93 93
 OBJS-$(CONFIG_ME_CMP)                  += me_cmp.o
94
+OBJS-$(CONFIG_MEDIACODEC)              += mediacodecdec.o mediacodec_wrapper.o mediacodec_sw_buffer.o
94 95
 OBJS-$(CONFIG_MPEG_ER)                 += mpeg_er.o
95 96
 OBJS-$(CONFIG_MPEGAUDIO)               += mpegaudio.o mpegaudiodata.o   \
96 97
                                           mpegaudiodecheader.o
... ...
@@ -306,6 +307,7 @@ OBJS-$(CONFIG_H264_DECODER)            += h264.o h264_cabac.o h264_cavlc.o \
306 306
                                           h264_direct.o h264_loopfilter.o  \
307 307
                                           h264_mb.o h264_picture.o h264_ps.o \
308 308
                                           h264_refs.o h264_sei.o h264_slice.o
309
+OBJS-$(CONFIG_H264_MEDIACODEC_DECODER) += mediacodecdec_h264.o
309 310
 OBJS-$(CONFIG_H264_MMAL_DECODER)       += mmaldec.o
310 311
 OBJS-$(CONFIG_H264_VDA_DECODER)        += vda_h264_dec.o
311 312
 OBJS-$(CONFIG_H264_QSV_DECODER)        += qsvdec_h2645.o
... ...
@@ -944,6 +946,7 @@ SKIPHEADERS-$(CONFIG_LIBSCHROEDINGER)  += libschroedinger.h
944 944
 SKIPHEADERS-$(CONFIG_LIBUTVIDEO)       += libutvideo.h
945 945
 SKIPHEADERS-$(CONFIG_LIBVPX)           += libvpx.h
946 946
 SKIPHEADERS-$(CONFIG_LIBWEBP_ENCODER)  += libwebpenc_common.h
947
+SKIPHEADERS-$(CONFIG_MEDIACODEC)       += mediacodecdec.h mediacodec_wrapper.h mediacodec_sw_buffer.h
947 948
 SKIPHEADERS-$(CONFIG_QSV)              += qsv.h qsv_internal.h
948 949
 SKIPHEADERS-$(CONFIG_QSVDEC)           += qsvdec.h
949 950
 SKIPHEADERS-$(CONFIG_QSVENC)           += qsvenc.h
... ...
@@ -196,6 +196,7 @@ void avcodec_register_all(void)
196 196
     REGISTER_ENCDEC (H263P,             h263p);
197 197
     REGISTER_DECODER(H264,              h264);
198 198
     REGISTER_DECODER(H264_CRYSTALHD,    h264_crystalhd);
199
+    REGISTER_DECODER(H264_MEDIACODEC,   h264_mediacodec);
199 200
     REGISTER_DECODER(H264_MMAL,         h264_mmal);
200 201
     REGISTER_DECODER(H264_QSV,          h264_qsv);
201 202
     REGISTER_DECODER(H264_VDA,          h264_vda);
202 203
new file mode 100644
... ...
@@ -0,0 +1,339 @@
0
+/*
1
+ * Android MediaCodec software buffer copy functions
2
+ *
3
+ * Copyright (c) 2015-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 <string.h>
23
+#include <sys/types.h>
24
+
25
+#include "libavutil/frame.h"
26
+#include "libavutil/mem.h"
27
+
28
+#include "avcodec.h"
29
+#include "mediacodecdec.h"
30
+#include "mediacodec_wrapper.h"
31
+#include "mediacodec_sw_buffer.h"
32
+
33
+#define QCOM_TILE_WIDTH 64
34
+#define QCOM_TILE_HEIGHT 32
35
+#define QCOM_TILE_SIZE (QCOM_TILE_WIDTH * QCOM_TILE_HEIGHT)
36
+#define QCOM_TILE_GROUP_SIZE (4 * QCOM_TILE_SIZE)
37
+
38
+/**
39
+ * The code handling the the various YUV color formats is taken from the
40
+ * GStreamer project.
41
+ *
42
+ * Gstreamer reference:
43
+ * https://cgit.freedesktop.org/gstreamer/gst-plugins-bad/tree/sys/androidmedia/
44
+ *
45
+ * Copyright (C) 2012, Collabora Ltd.
46
+ *   Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
47
+ *
48
+ * Copyright (C) 2012, Rafaël Carré <funman@videolanorg>
49
+ *
50
+ * Copyright (C) 2015, Sebastian Dröge <sebastian@centricular.com>
51
+ *
52
+ * Copyright (C) 2014-2015, Collabora Ltd.
53
+ *   Author: Matthieu Bouron <matthieu.bouron@gcollabora.com>
54
+ *
55
+ * Copyright (C) 2015, Edward Hervey
56
+ *   Author: Edward Hervey <bilboed@gmail.com>
57
+ *
58
+ * Copyright (C) 2015, Matthew Waters <matthew@centricular.com>
59
+ *
60
+ * This library is free software; you can redistribute it and/or
61
+ * modify it under the terms of the GNU Lesser General Public
62
+ * License as published by the Free Software Foundation
63
+ * version 2.1 of the License.
64
+ *
65
+ * This library is distributed in the hope that it will be useful,
66
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
67
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
68
+ * Lesser General Public License for more details.
69
+ *
70
+ * You should have received a copy of the GNU Lesser General Public
71
+ * License along with this library; if not, write to the Free Software
72
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
73
+ *
74
+ */
75
+void ff_mediacodec_sw_buffer_copy_yuv420_planar(AVCodecContext *avctx,
76
+                                                MediaCodecDecContext *s,
77
+                                                uint8_t *data,
78
+                                                size_t size,
79
+                                                FFAMediaCodecBufferInfo *info,
80
+                                                AVFrame *frame)
81
+{
82
+    int i;
83
+    uint8_t *src = NULL;
84
+
85
+    for (i = 0; i < 3; i++) {
86
+        int stride = s->stride;
87
+        int height;
88
+
89
+        src = data + info->offset;
90
+        if (i == 0) {
91
+            height = avctx->height;
92
+
93
+            src += s->crop_top * s->stride;
94
+            src += s->crop_left;
95
+        } else {
96
+            height = avctx->height / 2;
97
+            stride = (s->stride + 1) / 2;
98
+
99
+            src += s->slice_height * s->stride;
100
+
101
+            if (i == 2) {
102
+                src += ((s->slice_height + 1) / 2) * stride;
103
+            }
104
+
105
+            src += s->crop_top * stride;
106
+            src += (s->crop_left / 2);
107
+        }
108
+
109
+        if (frame->linesize[i] == stride) {
110
+            memcpy(frame->data[i], src, height * stride);
111
+        } else {
112
+            int j, width;
113
+            uint8_t *dst = frame->data[i];
114
+
115
+            if (i == 0) {
116
+                width = avctx->width;
117
+            } else if (i == 1) {
118
+                width = FFMIN(frame->linesize[i], FFALIGN(avctx->width, 2));
119
+            }
120
+
121
+            for (j = 0; j < height; j++) {
122
+                memcpy(dst, src, width);
123
+                src += stride;
124
+                dst += frame->linesize[i];
125
+            }
126
+        }
127
+    }
128
+}
129
+
130
+void ff_mediacodec_sw_buffer_copy_yuv420_semi_planar(AVCodecContext *avctx,
131
+                                                     MediaCodecDecContext *s,
132
+                                                     uint8_t *data,
133
+                                                     size_t size,
134
+                                                     FFAMediaCodecBufferInfo *info,
135
+                                                     AVFrame *frame)
136
+{
137
+    int i;
138
+    uint8_t *src = NULL;
139
+
140
+    for (i = 0; i < 2; i++) {
141
+        int height;
142
+
143
+        src = data + info->offset;
144
+        if (i == 0) {
145
+            height = avctx->height;
146
+
147
+            src += s->crop_top * s->stride;
148
+            src += s->crop_left;
149
+        } else if (i == 1) {
150
+            height = avctx->height / 2;
151
+
152
+            src += s->slice_height * s->stride;
153
+            src += s->crop_top * s->stride;
154
+            src += s->crop_left;
155
+        }
156
+
157
+        if (frame->linesize[i] == s->stride) {
158
+            memcpy(frame->data[i], src, height * s->stride);
159
+        } else {
160
+            int j, width;
161
+            uint8_t *dst = frame->data[i];
162
+
163
+            if (i == 0) {
164
+                width = avctx->width;
165
+            } else if (i == 1) {
166
+                width = FFMIN(frame->linesize[i], FFALIGN(avctx->width, 2));
167
+            }
168
+
169
+            for (j = 0; j < height; j++) {
170
+                memcpy(dst, src, width);
171
+                src += s->stride;
172
+                dst += frame->linesize[i];
173
+            }
174
+        }
175
+    }
176
+}
177
+
178
+
179
+
180
+void ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar(AVCodecContext *avctx,
181
+                                                            MediaCodecDecContext *s,
182
+                                                            uint8_t *data,
183
+                                                            size_t size,
184
+                                                            FFAMediaCodecBufferInfo *info,
185
+                                                            AVFrame *frame)
186
+{
187
+    int i;
188
+    uint8_t *src = NULL;
189
+
190
+    for (i = 0; i < 2; i++) {
191
+        int height;
192
+
193
+        src = data + info->offset;
194
+        if (i == 0) {
195
+            height = avctx->height;
196
+        } else if (i == 1) {
197
+            height = avctx->height / 2;
198
+
199
+            src += (s->slice_height - s->crop_top / 2) * s->stride;
200
+
201
+            src += s->crop_top * s->stride;
202
+            src += s->crop_left;
203
+        }
204
+
205
+        if (frame->linesize[i] == s->stride) {
206
+            memcpy(frame->data[i], src, height * s->stride);
207
+        } else {
208
+            int j, width;
209
+            uint8_t *dst = frame->data[i];
210
+
211
+            if (i == 0) {
212
+                width = avctx->width;
213
+            } else if (i == 1) {
214
+                width = FFMIN(frame->linesize[i], FFALIGN(avctx->width, 2));
215
+            }
216
+
217
+            for (j = 0; j < height; j++) {
218
+                memcpy(dst, src, width);
219
+                src += s->stride;
220
+                dst += frame->linesize[i];
221
+            }
222
+        }
223
+    }
224
+}
225
+
226
+/**
227
+ * The code handling the QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka
228
+ * color format is taken from the VLC project.
229
+ *
230
+ * VLC reference:
231
+ * http://git.videolan.org/?p=vlc.git;a=blob;f=modules/codec/omxil/qcom.c;hb=HEAD
232
+ *
233
+ * VLC copyright notice:
234
+ *
235
+ *****************************************************************************
236
+ * qcom.c : pixel format translation for Qualcomm tiled nv12
237
+ *****************************************************************************
238
+ * Copyright © 2012 Rafaël Carré
239
+ *
240
+ * Authors: Rafaël Carré <funman@videolanorg>
241
+ *
242
+ * This program is free software; you can redistribute it and/or modify it
243
+ * under the terms of the GNU Lesser General Public License as published by
244
+ * the Free Software Foundation; either version 2.1 of the License, or
245
+ * (at your option) any later version.
246
+ *
247
+ * This program is distributed in the hope that it will be useful,
248
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
249
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
250
+ * GNU Lesser General Public License for more details.
251
+ *
252
+ * You should have received a copy of the GNU Lesser General Public License
253
+ * along with this program; if not, write to the Free Software Foundation,
254
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
255
+ *
256
+ */
257
+
258
+static size_t qcom_tile_pos(size_t x, size_t y, size_t w, size_t h)
259
+{
260
+  size_t flim = x + (y & ~1) * w;
261
+
262
+  if (y & 1) {
263
+    flim += (x & ~3) + 2;
264
+  } else if ((h & 1) == 0 || y != (h - 1)) {
265
+    flim += (x + 2) & ~3;
266
+  }
267
+
268
+  return flim;
269
+}
270
+
271
+void ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar_64x32Tile2m8ka(AVCodecContext *avctx,
272
+                                                                           MediaCodecDecContext *s,
273
+                                                                           uint8_t *data,
274
+                                                                           size_t size,
275
+                                                                           FFAMediaCodecBufferInfo *info,
276
+                                                                           AVFrame *frame)
277
+{
278
+    size_t width = frame->width;
279
+    size_t linesize = frame->linesize[0];
280
+    size_t height = frame->height;
281
+
282
+    const size_t tile_w = (width - 1) / QCOM_TILE_WIDTH + 1;
283
+    const size_t tile_w_align = (tile_w + 1) & ~1;
284
+    const size_t tile_h_luma = (height - 1) / QCOM_TILE_HEIGHT + 1;
285
+    const size_t tile_h_chroma = (height / 2 - 1) / QCOM_TILE_HEIGHT + 1;
286
+
287
+    size_t luma_size = tile_w_align * tile_h_luma * QCOM_TILE_SIZE;
288
+    if((luma_size % QCOM_TILE_GROUP_SIZE) != 0)
289
+        luma_size = (((luma_size - 1) / QCOM_TILE_GROUP_SIZE) + 1) * QCOM_TILE_GROUP_SIZE;
290
+
291
+    for(size_t y = 0; y < tile_h_luma; y++) {
292
+        size_t row_width = width;
293
+        for(size_t x = 0; x < tile_w; x++) {
294
+            size_t tile_width = row_width;
295
+            size_t tile_height = height;
296
+            /* dest luma memory index for this tile */
297
+            size_t luma_idx = y * QCOM_TILE_HEIGHT * linesize + x * QCOM_TILE_WIDTH;
298
+            /* dest chroma memory index for this tile */
299
+            /* XXX: remove divisions */
300
+            size_t chroma_idx = (luma_idx / linesize) * linesize / 2 + (luma_idx % linesize);
301
+
302
+            /* luma source pointer for this tile */
303
+            const uint8_t *src_luma  = data
304
+                + qcom_tile_pos(x, y,tile_w_align, tile_h_luma) * QCOM_TILE_SIZE;
305
+
306
+            /* chroma source pointer for this tile */
307
+            const uint8_t *src_chroma = data + luma_size
308
+                + qcom_tile_pos(x, y/2, tile_w_align, tile_h_chroma) * QCOM_TILE_SIZE;
309
+            if (y & 1)
310
+                src_chroma += QCOM_TILE_SIZE/2;
311
+
312
+            /* account for right columns */
313
+            if (tile_width > QCOM_TILE_WIDTH)
314
+                tile_width = QCOM_TILE_WIDTH;
315
+
316
+            /* account for bottom rows */
317
+            if (tile_height > QCOM_TILE_HEIGHT)
318
+                tile_height = QCOM_TILE_HEIGHT;
319
+
320
+            tile_height /= 2;
321
+            while (tile_height--) {
322
+                memcpy(frame->data[0] + luma_idx, src_luma, tile_width);
323
+                src_luma += QCOM_TILE_WIDTH;
324
+                luma_idx += linesize;
325
+
326
+                memcpy(frame->data[0] + luma_idx, src_luma, tile_width);
327
+                src_luma += QCOM_TILE_WIDTH;
328
+                luma_idx += linesize;
329
+
330
+                memcpy(frame->data[1] + chroma_idx, src_chroma, tile_width);
331
+                src_chroma += QCOM_TILE_WIDTH;
332
+                chroma_idx += linesize;
333
+            }
334
+            row_width -= QCOM_TILE_WIDTH;
335
+        }
336
+        height -= QCOM_TILE_HEIGHT;
337
+    }
338
+}
0 339
new file mode 100644
... ...
@@ -0,0 +1,62 @@
0
+/*
1
+ * Android MediaCodec software buffer copy functions
2
+ *
3
+ * Copyright (c) 2015-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_SW_BUFFER_H
23
+#define AVCODEC_MEDIACODEC_SW_BUFFER_H
24
+
25
+#include <sys/types.h>
26
+
27
+#include "libavutil/frame.h"
28
+
29
+#include "avcodec.h"
30
+#include "mediacodecdec.h"
31
+#include "mediacodec_wrapper.h"
32
+
33
+void ff_mediacodec_sw_buffer_copy_yuv420_planar(AVCodecContext *avctx,
34
+                                                MediaCodecDecContext *s,
35
+                                                uint8_t *data,
36
+                                                size_t size,
37
+                                                FFAMediaCodecBufferInfo *info,
38
+                                                AVFrame *frame);
39
+
40
+void ff_mediacodec_sw_buffer_copy_yuv420_semi_planar(AVCodecContext *avctx,
41
+                                                     MediaCodecDecContext *s,
42
+                                                     uint8_t *data,
43
+                                                     size_t size,
44
+                                                     FFAMediaCodecBufferInfo *info,
45
+                                                     AVFrame *frame);
46
+
47
+void ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar(AVCodecContext *avctx,
48
+                                                     MediaCodecDecContext *s,
49
+                                                     uint8_t *data,
50
+                                                     size_t size,
51
+                                                     FFAMediaCodecBufferInfo *info,
52
+                                                     AVFrame *frame);
53
+
54
+void ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar_64x32Tile2m8ka(AVCodecContext *avctx,
55
+                                                     MediaCodecDecContext *s,
56
+                                                     uint8_t *data,
57
+                                                     size_t size,
58
+                                                     FFAMediaCodecBufferInfo *info,
59
+                                                     AVFrame *frame);
60
+
61
+#endif /* AVCODEC_MEDIACODEC_SW_BUFFER_H */
0 62
new file mode 100644
... ...
@@ -0,0 +1,1705 @@
0
+/*
1
+ * Android MediaCodec Wrapper
2
+ *
3
+ * Copyright (c) 2015-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 "libavutil/avassert.h"
25
+#include "libavutil/mem.h"
26
+#include "libavutil/avstring.h"
27
+
28
+#include "ffjni.h"
29
+#include "version.h"
30
+#include "mediacodec_wrapper.h"
31
+
32
+struct JNIAMediaCodecListFields {
33
+
34
+    jclass mediaformat_class;
35
+    jmethodID create_video_format_id;
36
+
37
+    jclass mediacodec_list_class;
38
+    jmethodID init_id;
39
+    jmethodID find_decoder_for_format_id;
40
+
41
+    jmethodID get_codec_count_id;
42
+    jmethodID get_codec_info_at_id;
43
+
44
+    jclass mediacodec_info_class;
45
+    jmethodID get_name_id;
46
+    jmethodID get_supported_types_id;
47
+    jmethodID is_encoder_id;
48
+
49
+} JNIAMediaCodecListFields;
50
+
51
+static const struct FFJniField jfields_mapping[] = {
52
+    { "android/media/MediaFormat", NULL, NULL, FF_JNI_CLASS, offsetof(struct JNIAMediaCodecListFields, mediaformat_class), 1 },
53
+        { "android/media/MediaFormat", "createVideoFormat", "(Ljava/lang/String;II)Landroid/media/MediaFormat;", FF_JNI_STATIC_METHOD, offsetof(struct JNIAMediaCodecListFields, create_video_format_id), 1 },
54
+
55
+    { "android/media/MediaCodecList", NULL, NULL, FF_JNI_CLASS, offsetof(struct JNIAMediaCodecListFields, mediacodec_list_class), 1 },
56
+        { "android/media/MediaCodecList", "<init>", "(I)V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, init_id), 0 },
57
+        { "android/media/MediaCodecList", "findDecoderForFormat", "(Landroid/media/MediaFormat;)Ljava/lang/String;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, find_decoder_for_format_id), 0 },
58
+
59
+        { "android/media/MediaCodecList", "getCodecCount", "()I", FF_JNI_STATIC_METHOD, offsetof(struct JNIAMediaCodecListFields, get_codec_count_id), 1 },
60
+        { "android/media/MediaCodecList", "getCodecInfoAt", "(I)Landroid/media/MediaCodecInfo;", FF_JNI_STATIC_METHOD, offsetof(struct JNIAMediaCodecListFields, get_codec_info_at_id), 1 },
61
+
62
+    { "android/media/MediaCodecInfo", NULL, NULL, FF_JNI_CLASS, offsetof(struct JNIAMediaCodecListFields, mediacodec_info_class), 1 },
63
+        { "android/media/MediaCodecInfo", "getName", "()Ljava/lang/String;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, get_name_id), 1 },
64
+        { "android/media/MediaCodecInfo", "getSupportedTypes", "()[Ljava/lang/String;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, get_supported_types_id), 1 },
65
+        { "android/media/MediaCodecInfo", "isEncoder", "()Z", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, is_encoder_id), 1 },
66
+
67
+    { NULL }
68
+};
69
+
70
+#define JNI_ATTACH_ENV_OR_RETURN(env, attached, log_ctx, ret) do { \
71
+    (env) = ff_jni_attach_env(attached, log_ctx);                  \
72
+    if (!(env)) {                                                  \
73
+        return ret;                                                \
74
+    }                                                              \
75
+} while (0)
76
+
77
+#define JNI_ATTACH_ENV_OR_RETURN_VOID(env, attached, log_ctx) do { \
78
+    (env) = ff_jni_attach_env(attached, log_ctx);              \
79
+    if (!(env)) {                                                  \
80
+        return;                                                    \
81
+    }                                                              \
82
+} while (0)
83
+
84
+#define JNI_DETACH_ENV(attached, log_ctx) do { \
85
+    if (attached)                              \
86
+        ff_jni_detach_env(log_ctx);            \
87
+} while (0)
88
+
89
+char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int width, int height, void *log_ctx)
90
+{
91
+    int ret;
92
+    char *name = NULL;
93
+    char *supported_type = NULL;
94
+
95
+    int attached = 0;
96
+    JNIEnv *env = NULL;
97
+    struct JNIAMediaCodecListFields jfields = { 0 };
98
+
99
+    jobject format = NULL;
100
+    jobject codec = NULL;
101
+    jstring tmp = NULL;
102
+
103
+    jobject info = NULL;
104
+    jobject type = NULL;
105
+    jobjectArray types = NULL;
106
+
107
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, log_ctx, NULL);
108
+
109
+    if ((ret = ff_jni_init_jfields(env, &jfields, jfields_mapping, 0, log_ctx)) < 0) {
110
+        goto done;
111
+    }
112
+
113
+    if (jfields.init_id && jfields.find_decoder_for_format_id) {
114
+        tmp = ff_jni_utf_chars_to_jstring(env, mime, log_ctx);
115
+        if (!tmp) {
116
+            goto done;
117
+        }
118
+
119
+        format = (*env)->CallStaticObjectMethod(env, jfields.mediaformat_class, jfields.create_video_format_id, tmp, width, height);
120
+        if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
121
+            goto done;
122
+        }
123
+        (*env)->DeleteLocalRef(env, tmp);
124
+
125
+        codec = (*env)->NewObject(env, jfields.mediacodec_list_class, jfields.init_id, 0);
126
+        if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
127
+            goto done;
128
+        }
129
+
130
+        tmp = (*env)->CallObjectMethod(env, codec, jfields.find_decoder_for_format_id, format);
131
+        if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
132
+            goto done;
133
+        }
134
+        if (!tmp) {
135
+            av_log(NULL, AV_LOG_ERROR, "Could not find decoder in media codec list "
136
+                                       "for format { mime=%s width=%d height=%d }\n", mime, width, height);
137
+            goto done;
138
+        }
139
+
140
+        name = ff_jni_jstring_to_utf_chars(env, tmp, log_ctx);
141
+        if (!name) {
142
+            goto done;
143
+        }
144
+
145
+    } else {
146
+        int i;
147
+        int codec_count;
148
+
149
+        codec_count = (*env)->CallStaticIntMethod(env, jfields.mediacodec_list_class, jfields.get_codec_count_id);
150
+        if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
151
+            goto done;
152
+        }
153
+
154
+        for(i = 0; i < codec_count; i++) {
155
+            int j;
156
+            int type_count;
157
+            int is_encoder;
158
+
159
+            info = (*env)->CallStaticObjectMethod(env, jfields.mediacodec_list_class, jfields.get_codec_info_at_id, i);
160
+            if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
161
+                goto done;
162
+            }
163
+
164
+            types = (*env)->CallObjectMethod(env, info, jfields.get_supported_types_id);
165
+            if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
166
+                goto done;
167
+            }
168
+
169
+            is_encoder = (*env)->CallBooleanMethod(env, info, jfields.is_encoder_id);
170
+            if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
171
+                goto done;
172
+            }
173
+
174
+            if (is_encoder) {
175
+                continue;
176
+            }
177
+
178
+            type_count = (*env)->GetArrayLength(env, types);
179
+            for (j = 0; j < type_count; j++) {
180
+
181
+                type = (*env)->GetObjectArrayElement(env, types, j);
182
+                if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
183
+                    goto done;
184
+                }
185
+
186
+                supported_type = ff_jni_jstring_to_utf_chars(env, type, log_ctx);
187
+                if (!supported_type) {
188
+                    goto done;
189
+                }
190
+
191
+                if (!av_strcasecmp(supported_type, mime)) {
192
+                    jobject codec_name;
193
+
194
+                    codec_name = (*env)->CallObjectMethod(env, info, jfields.get_name_id);
195
+                    if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
196
+                        goto done;
197
+                    }
198
+
199
+                    name = ff_jni_jstring_to_utf_chars(env, codec_name, log_ctx);
200
+                    if (!name) {
201
+                        goto done;
202
+                    }
203
+
204
+                    if (strstr(name, "OMX.google")) {
205
+                        av_freep(&name);
206
+                        continue;
207
+                    }
208
+                }
209
+
210
+                av_freep(&supported_type);
211
+            }
212
+
213
+            (*env)->DeleteLocalRef(env, info);
214
+            info = NULL;
215
+
216
+            (*env)->DeleteLocalRef(env, types);
217
+            types = NULL;
218
+
219
+            if (name)
220
+                break;
221
+        }
222
+    }
223
+
224
+done:
225
+    if (format) {
226
+        (*env)->DeleteLocalRef(env, format);
227
+    }
228
+
229
+    if (codec) {
230
+        (*env)->DeleteLocalRef(env, codec);
231
+    }
232
+
233
+    if (tmp) {
234
+        (*env)->DeleteLocalRef(env, tmp);
235
+    }
236
+
237
+    if (info) {
238
+        (*env)->DeleteLocalRef(env, info);
239
+    }
240
+
241
+    if (type) {
242
+        (*env)->DeleteLocalRef(env, type);
243
+    }
244
+
245
+    if (types) {
246
+        (*env)->DeleteLocalRef(env, types);
247
+    }
248
+
249
+    av_freep(&supported_type);
250
+
251
+    ff_jni_reset_jfields(env, &jfields, jfields_mapping, 0, log_ctx);
252
+
253
+    JNI_DETACH_ENV(attached, log_ctx);
254
+
255
+    return name;
256
+}
257
+
258
+struct JNIAMediaFormatFields {
259
+
260
+    jclass clazz;
261
+
262
+    jmethodID init_id;
263
+
264
+    jmethodID get_integer_id;
265
+    jmethodID get_long_id;
266
+    jmethodID get_float_id;
267
+    jmethodID get_bytebuffer_id;
268
+    jmethodID get_string_id;
269
+
270
+    jmethodID set_integer_id;
271
+    jmethodID set_long_id;
272
+    jmethodID set_float_id;
273
+    jmethodID set_bytebuffer_id;
274
+    jmethodID set_string_id;
275
+
276
+    jmethodID to_string_id;
277
+
278
+} JNIAMediaFormatFields;
279
+
280
+static const struct FFJniField jni_amediaformat_mapping[] = {
281
+    { "android/media/MediaFormat", NULL, NULL, FF_JNI_CLASS, offsetof(struct JNIAMediaFormatFields, clazz), 1 },
282
+
283
+        { "android/media/MediaFormat", "<init>", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, init_id), 1 },
284
+
285
+        { "android/media/MediaFormat", "getInteger", "(Ljava/lang/String;)I", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, get_integer_id), 1 },
286
+        { "android/media/MediaFormat", "getLong", "(Ljava/lang/String;)J", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, get_long_id), 1 },
287
+        { "android/media/MediaFormat", "getFloat", "(Ljava/lang/String;)F", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, get_float_id), 1 },
288
+        { "android/media/MediaFormat", "getByteBuffer", "(Ljava/lang/String;)Ljava/nio/ByteBuffer;", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, get_bytebuffer_id), 1 },
289
+        { "android/media/MediaFormat", "getString", "(Ljava/lang/String;)Ljava/lang/String;", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, get_string_id), 1 },
290
+
291
+        { "android/media/MediaFormat", "setInteger", "(Ljava/lang/String;I)V", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, set_integer_id), 1 },
292
+        { "android/media/MediaFormat", "setLong", "(Ljava/lang/String;J)V", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, set_long_id), 1 },
293
+        { "android/media/MediaFormat", "setFloat", "(Ljava/lang/String;F)V", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, set_float_id), 1 },
294
+        { "android/media/MediaFormat", "setByteBuffer", "(Ljava/lang/String;Ljava/nio/ByteBuffer;)V", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, set_bytebuffer_id), 1 },
295
+        { "android/media/MediaFormat", "setString", "(Ljava/lang/String;Ljava/lang/String;)V", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, set_string_id), 1 },
296
+
297
+        { "android/media/MediaFormat", "toString", "()Ljava/lang/String;", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, to_string_id), 1 },
298
+
299
+    { NULL }
300
+};
301
+
302
+static const AVClass amediaformat_class = {
303
+    .class_name = "amediaformat",
304
+    .item_name  = av_default_item_name,
305
+    .version    = LIBAVCODEC_VERSION_INT,
306
+};
307
+
308
+struct FFAMediaFormat {
309
+
310
+    const AVClass *class;
311
+    struct JNIAMediaFormatFields jfields;
312
+    jobject object;
313
+};
314
+
315
+FFAMediaFormat *ff_AMediaFormat_new(void)
316
+{
317
+    int attached = 0;
318
+    JNIEnv *env = NULL;
319
+    FFAMediaFormat *format = NULL;
320
+
321
+    format = av_mallocz(sizeof(FFAMediaFormat));
322
+    if (!format) {
323
+        return NULL;
324
+    }
325
+    format->class = &amediaformat_class;
326
+
327
+    env = ff_jni_attach_env(&attached, format);
328
+    if (!env) {
329
+        av_freep(&format);
330
+        return NULL;
331
+    }
332
+
333
+    if (ff_jni_init_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format) < 0) {
334
+        goto fail;
335
+    }
336
+
337
+    format->object = (*env)->NewObject(env, format->jfields.clazz, format->jfields.init_id);
338
+    if (!format->object) {
339
+        goto fail;
340
+    }
341
+
342
+    format->object = (*env)->NewGlobalRef(env, format->object);
343
+    if (!format->object) {
344
+        goto fail;
345
+    }
346
+
347
+    JNI_DETACH_ENV(attached, format);
348
+
349
+    return format;
350
+fail:
351
+    ff_jni_reset_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format);
352
+
353
+    JNI_DETACH_ENV(attached, format);
354
+
355
+    av_freep(&format);
356
+
357
+    return NULL;
358
+}
359
+
360
+static FFAMediaFormat *ff_AMediaFormat_newFromObject(void *object)
361
+{
362
+    int attached = 0;
363
+    JNIEnv *env = NULL;
364
+    FFAMediaFormat *format = NULL;
365
+
366
+    format = av_mallocz(sizeof(FFAMediaFormat));
367
+    if (!format) {
368
+        return NULL;
369
+    }
370
+    format->class = &amediaformat_class;
371
+
372
+    env = ff_jni_attach_env(&attached, format);
373
+    if (!env) {
374
+        av_freep(&format);
375
+        return NULL;
376
+    }
377
+
378
+    if (ff_jni_init_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format) < 0) {
379
+        goto fail;
380
+    }
381
+
382
+    format->object = (*env)->NewGlobalRef(env, object);
383
+    if (!format->object) {
384
+        goto fail;
385
+    }
386
+
387
+    JNI_DETACH_ENV(attached, format);
388
+
389
+    return format;
390
+fail:
391
+    ff_jni_reset_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format);
392
+
393
+    JNI_DETACH_ENV(attached, format);
394
+
395
+    av_freep(&format);
396
+
397
+    return NULL;
398
+}
399
+
400
+
401
+int ff_AMediaFormat_delete(FFAMediaFormat* format)
402
+{
403
+    int ret = 0;
404
+
405
+    int attached = 0;
406
+    JNIEnv *env = NULL;
407
+
408
+    if (!format) {
409
+        return 0;
410
+    }
411
+
412
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, AVERROR_EXTERNAL);
413
+
414
+    (*env)->DeleteGlobalRef(env, format->object);
415
+    format->object = NULL;
416
+
417
+    ff_jni_reset_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format);
418
+
419
+    JNI_DETACH_ENV(attached, format);
420
+
421
+    av_freep(&format);
422
+
423
+    return ret;
424
+}
425
+
426
+char* ff_AMediaFormat_toString(FFAMediaFormat* format)
427
+{
428
+    char *ret = NULL;
429
+
430
+    int attached = 0;
431
+    JNIEnv *env = NULL;
432
+    jstring description = NULL;
433
+
434
+    av_assert0(format != NULL);
435
+
436
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, NULL);
437
+
438
+    description = (*env)->CallObjectMethod(env, format->object, format->jfields.to_string_id);
439
+    if (ff_jni_exception_check(env, 1, NULL) < 0) {
440
+        goto fail;
441
+    }
442
+
443
+    ret = ff_jni_jstring_to_utf_chars(env, description, format);
444
+fail:
445
+
446
+    if (description) {
447
+        (*env)->DeleteLocalRef(env, description);
448
+    }
449
+
450
+    JNI_DETACH_ENV(attached, format);
451
+
452
+    return ret;
453
+}
454
+
455
+int ff_AMediaFormat_getInt32(FFAMediaFormat* format, const char *name, int32_t *out)
456
+{
457
+    int ret = 1;
458
+
459
+    int attached = 0;
460
+    JNIEnv *env = NULL;
461
+    jstring key = NULL;
462
+
463
+    av_assert0(format != NULL);
464
+
465
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0);
466
+
467
+    key = ff_jni_utf_chars_to_jstring(env, name, format);
468
+    if (!key) {
469
+        ret = 0;
470
+        goto fail;
471
+    }
472
+
473
+    *out = (*env)->CallIntMethod(env, format->object, format->jfields.get_integer_id, key);
474
+    if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
475
+        ret = 0;
476
+        goto fail;
477
+    }
478
+
479
+    ret = 1;
480
+fail:
481
+    if (key) {
482
+        (*env)->DeleteLocalRef(env, key);
483
+    }
484
+
485
+    JNI_DETACH_ENV(attached, format);
486
+
487
+    return ret;
488
+}
489
+
490
+int ff_AMediaFormat_getInt64(FFAMediaFormat* format, const char *name, int64_t *out)
491
+{
492
+    int ret = 1;
493
+
494
+    int attached = 0;
495
+    JNIEnv *env = NULL;
496
+    jstring key = NULL;
497
+
498
+    av_assert0(format != NULL);
499
+
500
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0);
501
+
502
+    key = ff_jni_utf_chars_to_jstring(env, name, format);
503
+    if (!key) {
504
+        ret = 0;
505
+        goto fail;
506
+    }
507
+
508
+    *out = (*env)->CallLongMethod(env, format->object, format->jfields.get_long_id, key);
509
+    if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
510
+        ret = 0;
511
+        goto fail;
512
+    }
513
+
514
+    ret = 1;
515
+fail:
516
+    if (key) {
517
+        (*env)->DeleteLocalRef(env, key);
518
+    }
519
+
520
+    JNI_DETACH_ENV(attached, format);
521
+
522
+    return ret;
523
+}
524
+
525
+int ff_AMediaFormat_getFloat(FFAMediaFormat* format, const char *name, float *out)
526
+{
527
+    int ret = 1;
528
+
529
+    int attached = 0;
530
+    JNIEnv *env = NULL;
531
+    jstring key = NULL;
532
+
533
+    av_assert0(format != NULL);
534
+
535
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0);
536
+
537
+    key = ff_jni_utf_chars_to_jstring(env, name, format);
538
+    if (!key) {
539
+        ret = 0;
540
+        goto fail;
541
+    }
542
+
543
+    *out = (*env)->CallFloatMethod(env, format->object, format->jfields.get_float_id, key);
544
+    if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
545
+        ret = 0;
546
+        goto fail;
547
+    }
548
+
549
+    ret = 1;
550
+fail:
551
+    if (key) {
552
+        (*env)->DeleteLocalRef(env, key);
553
+    }
554
+
555
+    JNI_DETACH_ENV(attached, format);
556
+
557
+    return ret;
558
+}
559
+
560
+int ff_AMediaFormat_getBuffer(FFAMediaFormat* format, const char *name, void** data, size_t *size)
561
+{
562
+    int ret = 1;
563
+
564
+    int attached = 0;
565
+    JNIEnv *env = NULL;
566
+    jstring key = NULL;
567
+    jobject result = NULL;
568
+
569
+    av_assert0(format != NULL);
570
+
571
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0);
572
+
573
+    key = ff_jni_utf_chars_to_jstring(env, name, format);
574
+    if (!key) {
575
+        ret = 0;
576
+        goto fail;
577
+    }
578
+
579
+    result = (*env)->CallObjectMethod(env, format->object, format->jfields.get_bytebuffer_id, key);
580
+    if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
581
+        ret = 0;
582
+        goto fail;
583
+    }
584
+
585
+    *data = (*env)->GetDirectBufferAddress(env, result);
586
+    *size = (*env)->GetDirectBufferCapacity(env, result);
587
+
588
+    if (*data && *size) {
589
+        void *src = *data;
590
+        *data = av_malloc(*size);
591
+        if (!*data) {
592
+            ret = 0;
593
+            goto fail;
594
+        }
595
+
596
+        memcpy(*data, src, *size);
597
+    }
598
+
599
+    ret = 1;
600
+fail:
601
+    if (key) {
602
+        (*env)->DeleteLocalRef(env, key);
603
+    }
604
+
605
+    if (result) {
606
+        (*env)->DeleteLocalRef(env, result);
607
+    }
608
+
609
+    JNI_DETACH_ENV(attached, format);
610
+
611
+    return ret;
612
+}
613
+
614
+int ff_AMediaFormat_getString(FFAMediaFormat* format, const char *name, const char **out)
615
+{
616
+    int ret = 1;
617
+
618
+    int attached = 0;
619
+    JNIEnv *env = NULL;
620
+    jstring key = NULL;
621
+    jstring result = NULL;
622
+
623
+    av_assert0(format != NULL);
624
+
625
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0);
626
+
627
+    key = ff_jni_utf_chars_to_jstring(env, name, format);
628
+    if (!key) {
629
+        ret = 0;
630
+        goto fail;
631
+    }
632
+
633
+    result = (*env)->CallObjectMethod(env, format->object, format->jfields.get_string_id, key);
634
+    if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
635
+        ret = 0;
636
+        goto fail;
637
+    }
638
+
639
+    *out = ff_jni_jstring_to_utf_chars(env, result, format);
640
+    if (!*out) {
641
+        ret = 0;
642
+        goto fail;
643
+    }
644
+
645
+    ret = 1;
646
+fail:
647
+    if (key) {
648
+        (*env)->DeleteLocalRef(env, key);
649
+    }
650
+
651
+    if (result) {
652
+        (*env)->DeleteLocalRef(env, result);
653
+    }
654
+
655
+    JNI_DETACH_ENV(attached, format);
656
+
657
+    return ret;
658
+}
659
+
660
+
661
+void ff_AMediaFormat_setInt32(FFAMediaFormat* format, const char* name, int32_t value)
662
+{
663
+    int attached = 0;
664
+    JNIEnv *env = NULL;
665
+    jstring key = NULL;
666
+
667
+    av_assert0(format != NULL);
668
+
669
+    JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format);
670
+
671
+    key = ff_jni_utf_chars_to_jstring(env, name, format);
672
+    if (!key) {
673
+        goto fail;
674
+    }
675
+
676
+    (*env)->CallVoidMethod(env, format->object, format->jfields.set_integer_id, key, value);
677
+    if (ff_jni_exception_check(env, 1, format) < 0) {
678
+        goto fail;
679
+    }
680
+
681
+fail:
682
+    if (key) {
683
+        (*env)->DeleteLocalRef(env, key);
684
+    }
685
+
686
+    JNI_DETACH_ENV(attached, format);
687
+}
688
+
689
+void ff_AMediaFormat_setInt64(FFAMediaFormat* format, const char* name, int64_t value)
690
+{
691
+    int attached = 0;
692
+    JNIEnv *env = NULL;
693
+    jstring key = NULL;
694
+
695
+    av_assert0(format != NULL);
696
+
697
+    JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format);
698
+
699
+    key = ff_jni_utf_chars_to_jstring(env, name, format);
700
+    if (!key) {
701
+        goto fail;
702
+    }
703
+
704
+    (*env)->CallVoidMethod(env, format->object, format->jfields.set_long_id, key, value);
705
+    if (ff_jni_exception_check(env, 1, format) < 0) {
706
+        goto fail;
707
+    }
708
+
709
+fail:
710
+    if (key) {
711
+        (*env)->DeleteLocalRef(env, key);
712
+    }
713
+
714
+    JNI_DETACH_ENV(attached, NULL);
715
+}
716
+
717
+void ff_AMediaFormat_setFloat(FFAMediaFormat* format, const char* name, float value)
718
+{
719
+    int attached = 0;
720
+    JNIEnv *env = NULL;
721
+    jstring key = NULL;
722
+
723
+    av_assert0(format != NULL);
724
+
725
+    JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format);
726
+
727
+    key = ff_jni_utf_chars_to_jstring(env, name, format);
728
+    if (!key) {
729
+        goto fail;
730
+    }
731
+
732
+    (*env)->CallVoidMethod(env, format->object, format->jfields.set_float_id, key, value);
733
+    if (ff_jni_exception_check(env, 1, format) < 0) {
734
+        goto fail;
735
+    }
736
+
737
+fail:
738
+    if (key) {
739
+        (*env)->DeleteLocalRef(env, key);
740
+    }
741
+
742
+    JNI_DETACH_ENV(attached, NULL);
743
+}
744
+
745
+void ff_AMediaFormat_setString(FFAMediaFormat* format, const char* name, const char* value)
746
+{
747
+    int attached = 0;
748
+    JNIEnv *env = NULL;
749
+    jstring key = NULL;
750
+    jstring string = NULL;
751
+
752
+    av_assert0(format != NULL);
753
+
754
+    JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format);
755
+
756
+    key = ff_jni_utf_chars_to_jstring(env, name, format);
757
+    if (!key) {
758
+        goto fail;
759
+    }
760
+
761
+    string = ff_jni_utf_chars_to_jstring(env, value, format);
762
+    if (!string) {
763
+        goto fail;
764
+    }
765
+
766
+    (*env)->CallVoidMethod(env, format->object, format->jfields.set_string_id, key, string);
767
+    if (ff_jni_exception_check(env, 1, format) < 0) {
768
+        goto fail;
769
+    }
770
+
771
+fail:
772
+    if (key) {
773
+        (*env)->DeleteLocalRef(env, key);
774
+    }
775
+
776
+    if (string) {
777
+        (*env)->DeleteLocalRef(env, string);
778
+    }
779
+
780
+    JNI_DETACH_ENV(attached, format);
781
+}
782
+
783
+void ff_AMediaFormat_setBuffer(FFAMediaFormat* format, const char* name, void* data, size_t size)
784
+{
785
+    int attached = 0;
786
+    JNIEnv *env = NULL;
787
+    jstring key = NULL;
788
+    jobject buffer = NULL;
789
+    void *buffer_data = NULL;
790
+
791
+    av_assert0(format != NULL);
792
+
793
+    JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format);
794
+
795
+    key = ff_jni_utf_chars_to_jstring(env, name, format);
796
+    if (!key) {
797
+        goto fail;
798
+    }
799
+
800
+    if (!data || !size) {
801
+        goto fail;
802
+    }
803
+
804
+    buffer_data = av_malloc(size);
805
+    if (!buffer_data) {
806
+        goto fail;
807
+    }
808
+
809
+    memcpy(buffer_data, data, size);
810
+
811
+    buffer = (*env)->NewDirectByteBuffer(env, buffer_data, size);
812
+    if (!buffer) {
813
+        goto fail;
814
+    }
815
+
816
+    (*env)->CallVoidMethod(env, format->object, format->jfields.set_bytebuffer_id, key, buffer);
817
+    if (ff_jni_exception_check(env, 1, format) < 0) {
818
+        goto fail;
819
+    }
820
+
821
+fail:
822
+    if (key) {
823
+        (*env)->DeleteLocalRef(env, key);
824
+    }
825
+
826
+    if (buffer) {
827
+        (*env)->DeleteLocalRef(env, buffer);
828
+    }
829
+
830
+    JNI_DETACH_ENV(attached, format);
831
+}
832
+
833
+struct JNIAMediaCodecFields {
834
+
835
+    jclass mediacodec_class;
836
+
837
+    jfieldID info_try_again_later_id;
838
+    jfieldID info_output_buffers_changed_id;
839
+    jfieldID info_output_format_changed_id;
840
+
841
+    jfieldID buffer_flag_codec_config_id;
842
+    jfieldID buffer_flag_end_of_stream_id;
843
+    jfieldID buffer_flag_key_frame_id;
844
+
845
+    jfieldID configure_flag_encode_id;
846
+
847
+    jmethodID create_by_codec_name_id;
848
+    jmethodID create_decoder_by_type_id;
849
+    jmethodID create_encoder_by_type_id;
850
+
851
+    jmethodID get_name_id;
852
+
853
+    jmethodID configure_id;
854
+    jmethodID start_id;
855
+    jmethodID flush_id;
856
+    jmethodID stop_id;
857
+    jmethodID release_id;
858
+
859
+    jmethodID get_output_format_id;
860
+
861
+    jmethodID dequeue_input_buffer_id;
862
+    jmethodID queue_input_buffer_id;
863
+    jmethodID get_input_buffer_id;
864
+    jmethodID get_input_buffers_id;
865
+
866
+    jmethodID dequeue_output_buffer_id;
867
+    jmethodID get_output_buffer_id;
868
+    jmethodID get_output_buffers_id;
869
+    jmethodID release_output_buffer_id;
870
+    jmethodID release_output_buffer_at_time_id;
871
+
872
+    jclass mediainfo_class;
873
+
874
+    jmethodID init_id;
875
+
876
+    jfieldID flags_id;
877
+    jfieldID offset_id;
878
+    jfieldID presentation_time_us_id;
879
+    jfieldID size_id;
880
+
881
+} JNIAMediaCodecFields;
882
+
883
+static const struct FFJniField jni_amediacodec_mapping[] = {
884
+    { "android/media/MediaCodec", NULL, NULL, FF_JNI_CLASS, offsetof(struct JNIAMediaCodecFields, mediacodec_class), 1 },
885
+
886
+        { "android/media/MediaCodec", "INFO_TRY_AGAIN_LATER", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, info_try_again_later_id), 1 },
887
+        { "android/media/MediaCodec", "INFO_OUTPUT_BUFFERS_CHANGED", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, info_output_buffers_changed_id), 1 },
888
+        { "android/media/MediaCodec", "INFO_OUTPUT_FORMAT_CHANGED", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, info_output_format_changed_id), 1 },
889
+
890
+        { "android/media/MediaCodec", "BUFFER_FLAG_CODEC_CONFIG", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, buffer_flag_codec_config_id), 1 },
891
+        { "android/media/MediaCodec", "BUFFER_FLAG_END_OF_STREAM", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, buffer_flag_end_of_stream_id), 1 },
892
+        { "android/media/MediaCodec", "BUFFER_FLAG_KEY_FRAME", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, buffer_flag_key_frame_id), 0 },
893
+
894
+        { "android/media/MediaCodec", "CONFIGURE_FLAG_ENCODE", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, configure_flag_encode_id), 1 },
895
+
896
+        { "android/media/MediaCodec", "createByCodecName", "(Ljava/lang/String;)Landroid/media/MediaCodec;", FF_JNI_STATIC_METHOD, offsetof(struct JNIAMediaCodecFields, create_by_codec_name_id), 1 },
897
+        { "android/media/MediaCodec", "createDecoderByType", "(Ljava/lang/String;)Landroid/media/MediaCodec;", FF_JNI_STATIC_METHOD, offsetof(struct JNIAMediaCodecFields, create_decoder_by_type_id), 1 },
898
+        { "android/media/MediaCodec", "createEncoderByType", "(Ljava/lang/String;)Landroid/media/MediaCodec;", FF_JNI_STATIC_METHOD, offsetof(struct JNIAMediaCodecFields, create_encoder_by_type_id), 1 },
899
+
900
+        { "android/media/MediaCodec", "getName", "()Ljava/lang/String;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, get_name_id), 1 },
901
+
902
+        { "android/media/MediaCodec", "configure", "(Landroid/media/MediaFormat;Landroid/view/Surface;Landroid/media/MediaCrypto;I)V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, configure_id), 1 },
903
+        { "android/media/MediaCodec", "start", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, start_id), 1 },
904
+        { "android/media/MediaCodec", "flush", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, flush_id), 1 },
905
+        { "android/media/MediaCodec", "stop", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, stop_id), 1 },
906
+        { "android/media/MediaCodec", "release", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, release_id), 1 },
907
+
908
+        { "android/media/MediaCodec", "getOutputFormat", "()Landroid/media/MediaFormat;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, get_output_format_id), 1 },
909
+
910
+        { "android/media/MediaCodec", "dequeueInputBuffer", "(J)I", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, dequeue_input_buffer_id), 1 },
911
+        { "android/media/MediaCodec", "queueInputBuffer", "(IIIJI)V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, queue_input_buffer_id), 1 },
912
+        { "android/media/MediaCodec", "getInputBuffer", "(I)Ljava/nio/ByteBuffer;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, get_input_buffer_id), 0 },
913
+        { "android/media/MediaCodec", "getInputBuffers", "()[Ljava/nio/ByteBuffer;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, get_input_buffers_id), 1 },
914
+
915
+
916
+        { "android/media/MediaCodec", "dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, dequeue_output_buffer_id), 1 },
917
+        { "android/media/MediaCodec", "getOutputBuffer", "(I)Ljava/nio/ByteBuffer;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, get_output_buffer_id), 0 },
918
+        { "android/media/MediaCodec", "getOutputBuffers", "()[Ljava/nio/ByteBuffer;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, get_output_buffers_id), 1 },
919
+        { "android/media/MediaCodec", "releaseOutputBuffer", "(IZ)V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, release_output_buffer_id), 1 },
920
+        { "android/media/MediaCodec", "releaseOutputBuffer", "(IJ)V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, release_output_buffer_at_time_id), 0 },
921
+
922
+    { "android/media/MediaCodec$BufferInfo", NULL, NULL, FF_JNI_CLASS, offsetof(struct JNIAMediaCodecFields, mediainfo_class), 1 },
923
+
924
+        { "android/media/MediaCodec.BufferInfo", "<init>", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, init_id), 1 },
925
+        { "android/media/MediaCodec.BufferInfo", "flags", "I", FF_JNI_FIELD, offsetof(struct JNIAMediaCodecFields, flags_id), 1 },
926
+        { "android/media/MediaCodec.BufferInfo", "offset", "I", FF_JNI_FIELD, offsetof(struct JNIAMediaCodecFields, offset_id), 1 },
927
+        { "android/media/MediaCodec.BufferInfo", "presentationTimeUs", "J", FF_JNI_FIELD, offsetof(struct JNIAMediaCodecFields, presentation_time_us_id), 1 },
928
+        { "android/media/MediaCodec.BufferInfo", "size", "I", FF_JNI_FIELD, offsetof(struct JNIAMediaCodecFields, size_id), 1 },
929
+
930
+    { NULL }
931
+};
932
+
933
+
934
+static const AVClass amediacodec_class = {
935
+    .class_name = "amediacodec",
936
+    .item_name  = av_default_item_name,
937
+    .version    = LIBAVCODEC_VERSION_INT,
938
+};
939
+
940
+struct FFAMediaCodec {
941
+
942
+    const AVClass *class;
943
+
944
+    struct JNIAMediaCodecFields jfields;
945
+
946
+    jobject object;
947
+
948
+    jobject input_buffers;
949
+    jobject output_buffers;
950
+
951
+    int INFO_TRY_AGAIN_LATER;
952
+    int INFO_OUTPUT_BUFFERS_CHANGED;
953
+    int INFO_OUTPUT_FORMAT_CHANGED;
954
+
955
+    int BUFFER_FLAG_CODEC_CONFIG;
956
+    int BUFFER_FLAG_END_OF_STREAM;
957
+    int BUFFER_FLAG_KEY_FRAME;
958
+
959
+    int CONFIGURE_FLAG_ENCODE;
960
+
961
+    int has_get_i_o_buffer;
962
+};
963
+
964
+FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name)
965
+{
966
+    int attached = 0;
967
+    JNIEnv *env = NULL;
968
+    FFAMediaCodec *codec = NULL;
969
+    jstring codec_name = NULL;
970
+
971
+    codec = av_mallocz(sizeof(FFAMediaCodec));
972
+    if (!codec) {
973
+        return NULL;
974
+    }
975
+    codec->class = &amediacodec_class;
976
+
977
+    env = ff_jni_attach_env(&attached, codec);
978
+    if (!env) {
979
+        av_freep(&codec);
980
+        return NULL;
981
+    }
982
+
983
+    if (ff_jni_init_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec) < 0) {
984
+        goto fail;
985
+    }
986
+
987
+    codec_name = ff_jni_utf_chars_to_jstring(env, name, codec);
988
+    if (!codec_name) {
989
+        goto fail;
990
+    }
991
+
992
+    codec->object = (*env)->CallStaticObjectMethod(env, codec->jfields.mediacodec_class, codec->jfields.create_by_codec_name_id, codec_name);
993
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
994
+        goto fail;
995
+    }
996
+
997
+    codec->object = (*env)->NewGlobalRef(env, codec->object);
998
+    if (!codec->object) {
999
+        goto fail;
1000
+    }
1001
+
1002
+    codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
1003
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1004
+        goto fail;
1005
+    }
1006
+
1007
+    codec->BUFFER_FLAG_CODEC_CONFIG = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_codec_config_id);
1008
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1009
+        goto fail;
1010
+    }
1011
+
1012
+    codec->BUFFER_FLAG_END_OF_STREAM = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_end_of_stream_id);
1013
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1014
+        goto fail;
1015
+    }
1016
+
1017
+    if (codec->jfields.buffer_flag_key_frame_id) {
1018
+        codec->BUFFER_FLAG_KEY_FRAME = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_key_frame_id);
1019
+        if (ff_jni_exception_check(env, 1, codec) < 0) {
1020
+            goto fail;
1021
+        }
1022
+    }
1023
+
1024
+    codec->CONFIGURE_FLAG_ENCODE = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.configure_flag_encode_id);
1025
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1026
+        goto fail;
1027
+    }
1028
+
1029
+    codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
1030
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1031
+        goto fail;
1032
+    }
1033
+
1034
+    codec->INFO_OUTPUT_BUFFERS_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_buffers_changed_id);
1035
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1036
+        goto fail;
1037
+    }
1038
+
1039
+    codec->INFO_OUTPUT_FORMAT_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_format_changed_id);
1040
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1041
+        goto fail;
1042
+    }
1043
+
1044
+    JNI_DETACH_ENV(attached, codec);
1045
+
1046
+    return codec;
1047
+fail:
1048
+    ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
1049
+
1050
+    if (codec_name) {
1051
+        (*env)->DeleteLocalRef(env, codec_name);
1052
+    }
1053
+
1054
+    JNI_DETACH_ENV(attached, codec);
1055
+
1056
+    av_freep(&codec);
1057
+
1058
+    return NULL;
1059
+}
1060
+
1061
+FFAMediaCodec* ff_AMediaCodec_createDecoderByType(const char *mime)
1062
+{
1063
+    int attached = 0;
1064
+    JNIEnv *env = NULL;
1065
+    FFAMediaCodec *codec = NULL;
1066
+    jstring mime_type = NULL;
1067
+
1068
+    codec = av_mallocz(sizeof(FFAMediaCodec));
1069
+    if (!codec) {
1070
+        return NULL;
1071
+    }
1072
+    codec->class = &amediacodec_class;
1073
+
1074
+    env = ff_jni_attach_env(&attached, codec);
1075
+    if (!env) {
1076
+        av_freep(&codec);
1077
+        return NULL;
1078
+    }
1079
+
1080
+    if (ff_jni_init_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec) < 0) {
1081
+        goto fail;
1082
+    }
1083
+
1084
+    mime_type = ff_jni_utf_chars_to_jstring(env, mime, codec);
1085
+    if (!mime_type) {
1086
+        goto fail;
1087
+    }
1088
+
1089
+    codec->object = (*env)->CallStaticObjectMethod(env, codec->jfields.mediacodec_class, codec->jfields.create_decoder_by_type_id, mime_type);
1090
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1091
+        goto fail;
1092
+    }
1093
+
1094
+    codec->object = (*env)->NewGlobalRef(env, codec->object);
1095
+    if (!codec->object) {
1096
+        goto fail;
1097
+    }
1098
+
1099
+    codec->BUFFER_FLAG_CODEC_CONFIG = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_codec_config_id);
1100
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1101
+        goto fail;
1102
+    }
1103
+
1104
+    codec->BUFFER_FLAG_END_OF_STREAM = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_end_of_stream_id);
1105
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1106
+        goto fail;
1107
+    }
1108
+
1109
+    if (codec->jfields.buffer_flag_key_frame_id) {
1110
+        codec->BUFFER_FLAG_KEY_FRAME = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_key_frame_id);
1111
+        if (ff_jni_exception_check(env, 1, codec) < 0) {
1112
+            goto fail;
1113
+        }
1114
+    }
1115
+
1116
+    codec->CONFIGURE_FLAG_ENCODE = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.configure_flag_encode_id);
1117
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1118
+        goto fail;
1119
+    }
1120
+
1121
+    codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
1122
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1123
+        goto fail;
1124
+    }
1125
+
1126
+    codec->INFO_OUTPUT_BUFFERS_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_buffers_changed_id);
1127
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1128
+        goto fail;
1129
+    }
1130
+
1131
+    codec->INFO_OUTPUT_FORMAT_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_format_changed_id);
1132
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1133
+        goto fail;
1134
+    }
1135
+
1136
+    if (codec->jfields.get_input_buffer_id && codec->jfields.get_output_buffer_id) {
1137
+        codec->has_get_i_o_buffer = 1;
1138
+    }
1139
+
1140
+    JNI_DETACH_ENV(attached, codec);
1141
+
1142
+    return codec;
1143
+fail:
1144
+    ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
1145
+
1146
+    if (mime_type) {
1147
+        (*env)->DeleteLocalRef(env, mime_type);
1148
+    }
1149
+
1150
+    JNI_DETACH_ENV(attached, codec);
1151
+
1152
+    av_freep(&codec);
1153
+
1154
+    return NULL;
1155
+}
1156
+
1157
+FFAMediaCodec* ff_AMediaCodec_createEncoderByType(const char *mime)
1158
+{
1159
+    int attached = 0;
1160
+    JNIEnv *env = NULL;
1161
+    FFAMediaCodec *codec = NULL;
1162
+    jstring mime_type = NULL;
1163
+
1164
+    codec = av_mallocz(sizeof(FFAMediaCodec));
1165
+    if (!codec) {
1166
+        return NULL;
1167
+    }
1168
+    codec->class = &amediacodec_class;
1169
+
1170
+    env = ff_jni_attach_env(&attached, codec);
1171
+    if (!env) {
1172
+        av_freep(&codec);
1173
+        return NULL;
1174
+    }
1175
+
1176
+    if (ff_jni_init_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec) < 0) {
1177
+        goto fail;
1178
+    }
1179
+
1180
+    mime_type = ff_jni_utf_chars_to_jstring(env, mime, codec);
1181
+    if (!mime_type) {
1182
+        goto fail;
1183
+    }
1184
+
1185
+    codec->object = (*env)->CallStaticObjectMethod(env, codec->jfields.mediacodec_class, codec->jfields.create_encoder_by_type_id, mime_type);
1186
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1187
+        goto fail;
1188
+    }
1189
+
1190
+    codec->object = (*env)->NewGlobalRef(env, codec->object);
1191
+    if (!codec->object) {
1192
+        goto fail;
1193
+    }
1194
+
1195
+    codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
1196
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1197
+        goto fail;
1198
+    }
1199
+
1200
+    codec->BUFFER_FLAG_CODEC_CONFIG = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_codec_config_id);
1201
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1202
+        goto fail;
1203
+    }
1204
+
1205
+    codec->BUFFER_FLAG_END_OF_STREAM = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_end_of_stream_id);
1206
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1207
+        goto fail;
1208
+    }
1209
+
1210
+    if (codec->jfields.buffer_flag_key_frame_id) {
1211
+        codec->BUFFER_FLAG_KEY_FRAME = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_key_frame_id);
1212
+        if (ff_jni_exception_check(env, 1, codec) < 0) {
1213
+            goto fail;
1214
+        }
1215
+    }
1216
+
1217
+    codec->CONFIGURE_FLAG_ENCODE = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.configure_flag_encode_id);
1218
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1219
+        goto fail;
1220
+    }
1221
+
1222
+    codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
1223
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1224
+        goto fail;
1225
+    }
1226
+
1227
+    codec->INFO_OUTPUT_BUFFERS_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_buffers_changed_id);
1228
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1229
+        goto fail;
1230
+    }
1231
+
1232
+    codec->INFO_OUTPUT_FORMAT_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_format_changed_id);
1233
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1234
+        goto fail;
1235
+    }
1236
+
1237
+    JNI_DETACH_ENV(attached, NULL);
1238
+
1239
+    return codec;
1240
+fail:
1241
+    ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
1242
+
1243
+    if (mime_type) {
1244
+        (*env)->DeleteLocalRef(env, mime_type);
1245
+    }
1246
+
1247
+    JNI_DETACH_ENV(attached, codec);
1248
+
1249
+    av_freep(&codec);
1250
+
1251
+    return NULL;
1252
+}
1253
+
1254
+
1255
+int ff_AMediaCodec_delete(FFAMediaCodec* codec)
1256
+{
1257
+    int ret = 0;
1258
+
1259
+    int attached = 0;
1260
+    JNIEnv *env = NULL;
1261
+
1262
+    if (!codec) {
1263
+        return 0;
1264
+    }
1265
+
1266
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1267
+
1268
+    (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_id);
1269
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1270
+        ret = AVERROR_EXTERNAL;
1271
+    }
1272
+
1273
+    (*env)->DeleteGlobalRef(env, codec->object);
1274
+    codec->object = NULL;
1275
+
1276
+    ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
1277
+
1278
+    JNI_DETACH_ENV(attached, codec);
1279
+
1280
+    av_freep(&codec);
1281
+
1282
+    return ret;
1283
+}
1284
+
1285
+char *ff_AMediaCodec_getName(FFAMediaCodec *codec)
1286
+{
1287
+    char *ret = NULL;
1288
+    int attached = 0;
1289
+    JNIEnv *env = NULL;
1290
+    jobject *name = NULL;
1291
+
1292
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL);
1293
+
1294
+    name = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_name_id);
1295
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1296
+        goto fail;
1297
+    }
1298
+
1299
+    ret = ff_jni_jstring_to_utf_chars(env, name, codec);
1300
+
1301
+fail:
1302
+    JNI_DETACH_ENV(attached, NULL);
1303
+
1304
+    return ret;
1305
+}
1306
+
1307
+int ff_AMediaCodec_configure(FFAMediaCodec* codec, const FFAMediaFormat* format, void* surface, void *crypto, uint32_t flags)
1308
+{
1309
+    int ret = 0;
1310
+    int attached = 0;
1311
+    JNIEnv *env = NULL;
1312
+
1313
+    /* TODO: implement surface handling */
1314
+    av_assert0(surface == NULL);
1315
+
1316
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1317
+
1318
+    (*env)->CallVoidMethod(env, codec->object, codec->jfields.configure_id, format->object, NULL, NULL, flags);
1319
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1320
+        ret = AVERROR_EXTERNAL;
1321
+        goto fail;
1322
+    }
1323
+
1324
+fail:
1325
+    JNI_DETACH_ENV(attached, NULL);
1326
+
1327
+    return ret;
1328
+}
1329
+
1330
+int ff_AMediaCodec_start(FFAMediaCodec* codec)
1331
+{
1332
+    int ret = 0;
1333
+    int attached = 0;
1334
+    JNIEnv *env = NULL;
1335
+
1336
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1337
+
1338
+    (*env)->CallVoidMethod(env, codec->object, codec->jfields.start_id);
1339
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1340
+        ret = AVERROR_EXTERNAL;
1341
+        goto fail;
1342
+    }
1343
+
1344
+fail:
1345
+    JNI_DETACH_ENV(attached, codec);
1346
+
1347
+    return ret;
1348
+}
1349
+
1350
+int ff_AMediaCodec_stop(FFAMediaCodec* codec)
1351
+{
1352
+    int ret = 0;
1353
+    int attached = 0;
1354
+    JNIEnv *env = NULL;
1355
+
1356
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1357
+
1358
+    (*env)->CallVoidMethod(env, codec->object, codec->jfields.stop_id);
1359
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1360
+        ret = AVERROR_EXTERNAL;
1361
+        goto fail;
1362
+    }
1363
+
1364
+fail:
1365
+    JNI_DETACH_ENV(attached, codec);
1366
+
1367
+    return ret;
1368
+}
1369
+
1370
+int ff_AMediaCodec_flush(FFAMediaCodec* codec)
1371
+{
1372
+    int ret = 0;
1373
+    int attached = 0;
1374
+    JNIEnv *env = NULL;
1375
+
1376
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1377
+
1378
+    (*env)->CallVoidMethod(env, codec->object, codec->jfields.flush_id);
1379
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1380
+        ret = AVERROR_EXTERNAL;
1381
+        goto fail;
1382
+    }
1383
+
1384
+fail:
1385
+    JNI_DETACH_ENV(attached, codec);
1386
+
1387
+    return ret;
1388
+}
1389
+
1390
+
1391
+int ff_AMediaCodec_releaseOutputBuffer(FFAMediaCodec* codec, size_t idx, int render)
1392
+{
1393
+    int ret = 0;
1394
+    int attached = 0;
1395
+    JNIEnv *env = NULL;
1396
+
1397
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1398
+
1399
+    (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_id, idx, render);
1400
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1401
+        ret = AVERROR_EXTERNAL;
1402
+        goto fail;
1403
+    }
1404
+
1405
+fail:
1406
+    JNI_DETACH_ENV(attached, codec);
1407
+
1408
+    return ret;
1409
+}
1410
+
1411
+int ff_AMediaCodec_releaseOutputBufferAtTime(FFAMediaCodec *codec, size_t idx, int64_t timestampNs)
1412
+{
1413
+    int ret = 0;
1414
+    int attached = 0;
1415
+    JNIEnv *env = NULL;
1416
+
1417
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1418
+
1419
+    (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_at_time_id, idx, timestampNs);
1420
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1421
+        ret = AVERROR_EXTERNAL;
1422
+        goto fail;
1423
+    }
1424
+
1425
+fail:
1426
+    JNI_DETACH_ENV(attached, codec);
1427
+
1428
+    return ret;
1429
+}
1430
+
1431
+
1432
+ssize_t ff_AMediaCodec_dequeueInputBuffer(FFAMediaCodec* codec, int64_t timeoutUs)
1433
+{
1434
+    int ret = 0;
1435
+    int attached = 0;
1436
+    JNIEnv *env = NULL;
1437
+
1438
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1439
+
1440
+    ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_input_buffer_id, timeoutUs);
1441
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1442
+        ret = AVERROR_EXTERNAL;
1443
+        goto fail;
1444
+    }
1445
+
1446
+fail:
1447
+    JNI_DETACH_ENV(attached, codec);
1448
+
1449
+    return ret;
1450
+}
1451
+
1452
+int ff_AMediaCodec_queueInputBuffer(FFAMediaCodec* codec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags)
1453
+{
1454
+    int ret = 0;
1455
+    int attached = 0;
1456
+    JNIEnv *env = NULL;
1457
+
1458
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1459
+
1460
+    (*env)->CallVoidMethod(env, codec->object, codec->jfields.queue_input_buffer_id, idx, offset, size, time, flags);
1461
+    if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
1462
+        ret = AVERROR_EXTERNAL;
1463
+        goto fail;
1464
+    }
1465
+
1466
+fail:
1467
+    JNI_DETACH_ENV(attached, codec);
1468
+
1469
+    return ret;
1470
+}
1471
+
1472
+ssize_t ff_AMediaCodec_dequeueOutputBuffer(FFAMediaCodec* codec, FFAMediaCodecBufferInfo *info, int64_t timeoutUs)
1473
+{
1474
+    int ret = 0;
1475
+    int attached = 0;
1476
+    JNIEnv *env = NULL;
1477
+
1478
+    jobject mediainfo = NULL;
1479
+
1480
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1481
+
1482
+    mediainfo = (*env)->NewObject(env, codec->jfields.mediainfo_class, codec->jfields.init_id);
1483
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1484
+        ret = AVERROR_EXTERNAL;
1485
+        goto fail;
1486
+    }
1487
+
1488
+    ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_output_buffer_id, mediainfo, timeoutUs);
1489
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1490
+        ret = AVERROR_EXTERNAL;
1491
+        goto fail;
1492
+    }
1493
+
1494
+    info->flags = (*env)->GetIntField(env, mediainfo, codec->jfields.flags_id);
1495
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1496
+        ret = AVERROR_EXTERNAL;
1497
+        goto fail;
1498
+    }
1499
+
1500
+    info->offset = (*env)->GetIntField(env, mediainfo, codec->jfields.offset_id);
1501
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1502
+        ret = AVERROR_EXTERNAL;
1503
+        goto fail;
1504
+    }
1505
+
1506
+    info->presentationTimeUs = (*env)->GetLongField(env, mediainfo, codec->jfields.presentation_time_us_id);
1507
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1508
+        ret = AVERROR_EXTERNAL;
1509
+        goto fail;
1510
+    }
1511
+
1512
+    info->size = (*env)->GetIntField(env, mediainfo, codec->jfields.size_id);
1513
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1514
+        ret = AVERROR_EXTERNAL;
1515
+        goto fail;
1516
+    }
1517
+fail:
1518
+    if (mediainfo) {
1519
+        (*env)->DeleteLocalRef(env, mediainfo);
1520
+    }
1521
+
1522
+    JNI_DETACH_ENV(attached, NULL);
1523
+
1524
+    return ret;
1525
+}
1526
+
1527
+uint8_t* ff_AMediaCodec_getInputBuffer(FFAMediaCodec* codec, size_t idx, size_t *out_size)
1528
+{
1529
+    uint8_t *ret = NULL;
1530
+    int attached = 0;
1531
+    JNIEnv *env = NULL;
1532
+
1533
+    jobject buffer = NULL;
1534
+
1535
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL);
1536
+
1537
+    if (codec->has_get_i_o_buffer) {
1538
+        buffer = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_input_buffer_id, idx);
1539
+        if (ff_jni_exception_check(env, 1, codec) < 0) {
1540
+            goto fail;
1541
+        }
1542
+    } else {
1543
+        if (!codec->input_buffers) {
1544
+            codec->input_buffers = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_input_buffers_id);
1545
+            if (ff_jni_exception_check(env, 1, codec) < 0) {
1546
+                goto fail;
1547
+            }
1548
+
1549
+            codec->input_buffers = (*env)->NewGlobalRef(env, codec->input_buffers);
1550
+            if (ff_jni_exception_check(env, 1, codec) < 0) {
1551
+                goto fail;
1552
+            }
1553
+        }
1554
+
1555
+        buffer = (*env)->GetObjectArrayElement(env, codec->input_buffers, idx);
1556
+        if (ff_jni_exception_check(env, 1, codec) < 0) {
1557
+            goto fail;
1558
+        }
1559
+    }
1560
+
1561
+    ret = (*env)->GetDirectBufferAddress(env, buffer);
1562
+    *out_size = (*env)->GetDirectBufferCapacity(env, buffer);
1563
+fail:
1564
+    if (buffer) {
1565
+        (*env)->DeleteLocalRef(env, buffer);
1566
+    }
1567
+
1568
+    JNI_DETACH_ENV(attached, codec);
1569
+
1570
+    return ret;
1571
+}
1572
+
1573
+uint8_t* ff_AMediaCodec_getOutputBuffer(FFAMediaCodec* codec, size_t idx, size_t *out_size)
1574
+{
1575
+    uint8_t *ret = NULL;
1576
+    int attached = 0;
1577
+    JNIEnv *env = NULL;
1578
+
1579
+    jobject buffer = NULL;
1580
+
1581
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL);
1582
+
1583
+    if (codec->has_get_i_o_buffer) {
1584
+        buffer = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_buffer_id, idx);
1585
+        if (ff_jni_exception_check(env, 1, codec) < 0) {
1586
+            goto fail;
1587
+        }
1588
+    } else {
1589
+        if (!codec->output_buffers) {
1590
+            codec->output_buffers = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_buffers_id);
1591
+            if (ff_jni_exception_check(env, 1, codec) < 0) {
1592
+                goto fail;
1593
+            }
1594
+
1595
+            codec->output_buffers = (*env)->NewGlobalRef(env, codec->output_buffers);
1596
+            if (ff_jni_exception_check(env, 1, codec) < 0) {
1597
+                goto fail;
1598
+            }
1599
+        }
1600
+
1601
+        buffer = (*env)->GetObjectArrayElement(env, codec->output_buffers, idx);
1602
+        if (ff_jni_exception_check(env, 1, codec) < 0) {
1603
+            goto fail;
1604
+        }
1605
+    }
1606
+
1607
+    ret = (*env)->GetDirectBufferAddress(env, buffer);
1608
+    *out_size = (*env)->GetDirectBufferCapacity(env, buffer);
1609
+fail:
1610
+    if (buffer) {
1611
+        (*env)->DeleteLocalRef(env, buffer);
1612
+    }
1613
+
1614
+    JNI_DETACH_ENV(attached, codec);
1615
+
1616
+    return ret;
1617
+}
1618
+
1619
+FFAMediaFormat* ff_AMediaCodec_getOutputFormat(FFAMediaCodec* codec)
1620
+{
1621
+    FFAMediaFormat *ret = NULL;
1622
+    int attached = 0;
1623
+    JNIEnv *env = NULL;
1624
+
1625
+    jobject mediaformat = NULL;
1626
+
1627
+    JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL);
1628
+
1629
+    mediaformat = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_format_id);
1630
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
1631
+        goto fail;
1632
+    }
1633
+
1634
+    ret = ff_AMediaFormat_newFromObject(mediaformat);
1635
+fail:
1636
+    if (mediaformat) {
1637
+        (*env)->DeleteLocalRef(env, mediaformat);
1638
+    }
1639
+
1640
+    JNI_DETACH_ENV(attached, codec);
1641
+
1642
+    return ret;
1643
+}
1644
+
1645
+int ff_AMediaCodec_infoTryAgainLater(FFAMediaCodec *codec, ssize_t idx)
1646
+{
1647
+    return idx == codec->INFO_TRY_AGAIN_LATER;
1648
+}
1649
+
1650
+int ff_AMediaCodec_infoOutputBuffersChanged(FFAMediaCodec *codec, ssize_t idx)
1651
+{
1652
+    return idx == codec->INFO_OUTPUT_BUFFERS_CHANGED;
1653
+}
1654
+
1655
+int ff_AMediaCodec_infoOutputFormatChanged(FFAMediaCodec *codec, ssize_t idx)
1656
+{
1657
+    return idx == codec->INFO_OUTPUT_FORMAT_CHANGED;
1658
+}
1659
+
1660
+int ff_AMediaCodec_getBufferFlagCodecConfig(FFAMediaCodec *codec)
1661
+{
1662
+    return codec->BUFFER_FLAG_CODEC_CONFIG;
1663
+}
1664
+
1665
+int ff_AMediaCodec_getBufferFlagEndOfStream(FFAMediaCodec *codec)
1666
+{
1667
+    return codec->BUFFER_FLAG_END_OF_STREAM;
1668
+}
1669
+
1670
+int ff_AMediaCodec_getBufferFlagKeyFrame(FFAMediaCodec *codec)
1671
+{
1672
+    return codec->BUFFER_FLAG_KEY_FRAME;
1673
+}
1674
+
1675
+int ff_AMediaCodec_getConfigureFlagEncode(FFAMediaCodec *codec)
1676
+{
1677
+    return codec->CONFIGURE_FLAG_ENCODE;
1678
+}
1679
+
1680
+int ff_AMediaCodec_cleanOutputBuffers(FFAMediaCodec *codec)
1681
+{
1682
+    int ret = 0;
1683
+
1684
+    if (!codec->has_get_i_o_buffer) {
1685
+        if (codec->output_buffers) {
1686
+            int attached = 0;
1687
+            JNIEnv *env = NULL;
1688
+
1689
+            env = ff_jni_attach_env(&attached, codec);
1690
+            if (!env) {
1691
+                ret = AVERROR_EXTERNAL;
1692
+                goto fail;
1693
+            }
1694
+
1695
+            (*env)->DeleteGlobalRef(env, codec->output_buffers);
1696
+            codec->output_buffers = NULL;
1697
+
1698
+            JNI_DETACH_ENV(attached, codec);
1699
+        }
1700
+    }
1701
+
1702
+fail:
1703
+    return ret;
1704
+}
0 1705
new file mode 100644
... ...
@@ -0,0 +1,125 @@
0
+/*
1
+ * Android MediaCodec Wrapper
2
+ *
3
+ * Copyright (c) 2015-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_WRAPPER_H
23
+#define AVCODEC_MEDIACODEC_WRAPPER_H
24
+
25
+#include <stdint.h>
26
+#include <sys/types.h>
27
+
28
+/**
29
+ * The following API around MediaCodec and MediaFormat is based on the
30
+ * NDK one provided by Google since Android 5.0.
31
+ *
32
+ * Differences from the NDK API:
33
+ *
34
+ * Buffers returned by ff_AMediaFormat_toString and ff_AMediaFormat_getString
35
+ * are newly allocated buffer and must be freed by the user after use.
36
+ *
37
+ * The MediaCrypto API is not implemented.
38
+ *
39
+ * ff_AMediaCodec_infoTryAgainLater, ff_AMediaCodec_infoOutputBuffersChanged,
40
+ * ff_AMediaCodec_infoOutputFormatChanged, ff_AMediaCodec_cleanOutputBuffers
41
+ * ff_AMediaCodec_getName and ff_AMediaCodec_getBufferFlagEndOfStream are not
42
+ * part of the original NDK API and are convenience functions to hide JNI
43
+ * implementation.
44
+ *
45
+ * The API around MediaCodecList is not part of the NDK (and is lacking as
46
+ * we still need to retreive the codec name to work around faulty decoders
47
+ * and encoders).
48
+ *
49
+ * For documentation, please refers to NdkMediaCodec.h NdkMediaFormat.h and
50
+ * http://developer.android.com/reference/android/media/MediaCodec.html.
51
+ *
52
+ */
53
+
54
+char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int width, int height, void *log_ctx);
55
+
56
+struct FFAMediaFormat;
57
+typedef struct FFAMediaFormat FFAMediaFormat;
58
+
59
+FFAMediaFormat *ff_AMediaFormat_new(void);
60
+int ff_AMediaFormat_delete(FFAMediaFormat* format);
61
+
62
+char* ff_AMediaFormat_toString(FFAMediaFormat* format);
63
+
64
+int ff_AMediaFormat_getInt32(FFAMediaFormat* format, const char *name, int32_t *out);
65
+int ff_AMediaFormat_getInt64(FFAMediaFormat* format, const char *name, int64_t *out);
66
+int ff_AMediaFormat_getFloat(FFAMediaFormat* format, const char *name, float *out);
67
+int ff_AMediaFormat_getBuffer(FFAMediaFormat* format, const char *name, void** data, size_t *size);
68
+int ff_AMediaFormat_getString(FFAMediaFormat* format, const char *name, const char **out);
69
+
70
+void ff_AMediaFormat_setInt32(FFAMediaFormat* format, const char* name, int32_t value);
71
+void ff_AMediaFormat_setInt64(FFAMediaFormat* format, const char* name, int64_t value);
72
+void ff_AMediaFormat_setFloat(FFAMediaFormat* format, const char* name, float value);
73
+void ff_AMediaFormat_setString(FFAMediaFormat* format, const char* name, const char* value);
74
+void ff_AMediaFormat_setBuffer(FFAMediaFormat* format, const char* name, void* data, size_t size);
75
+
76
+struct FFAMediaCodec;
77
+typedef struct FFAMediaCodec FFAMediaCodec;
78
+typedef struct FFAMediaCodecCryptoInfo FFAMediaCodecCryptoInfo;
79
+
80
+struct FFAMediaCodecBufferInfo {
81
+    int32_t offset;
82
+    int32_t size;
83
+    int64_t presentationTimeUs;
84
+    uint32_t flags;
85
+};
86
+typedef struct FFAMediaCodecBufferInfo FFAMediaCodecBufferInfo;
87
+
88
+char *ff_AMediaCodec_getName(FFAMediaCodec *codec);
89
+
90
+FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name);
91
+FFAMediaCodec* ff_AMediaCodec_createDecoderByType(const char *mime_type);
92
+FFAMediaCodec* ff_AMediaCodec_createEncoderByType(const char *mime_type);
93
+
94
+int ff_AMediaCodec_configure(FFAMediaCodec* codec, const FFAMediaFormat* format, void* surface, void *crypto, uint32_t flags);
95
+int ff_AMediaCodec_start(FFAMediaCodec* codec);
96
+int ff_AMediaCodec_stop(FFAMediaCodec* codec);
97
+int ff_AMediaCodec_flush(FFAMediaCodec* codec);
98
+int ff_AMediaCodec_delete(FFAMediaCodec* codec);
99
+
100
+uint8_t* ff_AMediaCodec_getInputBuffer(FFAMediaCodec* codec, size_t idx, size_t *out_size);
101
+uint8_t* ff_AMediaCodec_getOutputBuffer(FFAMediaCodec* codec, size_t idx, size_t *out_size);
102
+
103
+ssize_t ff_AMediaCodec_dequeueInputBuffer(FFAMediaCodec* codec, int64_t timeoutUs);
104
+int ff_AMediaCodec_queueInputBuffer(FFAMediaCodec* codec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags);
105
+
106
+ssize_t ff_AMediaCodec_dequeueOutputBuffer(FFAMediaCodec* codec, FFAMediaCodecBufferInfo *info, int64_t timeoutUs);
107
+FFAMediaFormat* ff_AMediaCodec_getOutputFormat(FFAMediaCodec* codec);
108
+
109
+int ff_AMediaCodec_releaseOutputBuffer(FFAMediaCodec* codec, size_t idx, int render);
110
+int ff_AMediaCodec_releaseOutputBufferAtTime(FFAMediaCodec *codec, size_t idx, int64_t timestampNs);
111
+
112
+int ff_AMediaCodec_infoTryAgainLater(FFAMediaCodec *codec, ssize_t idx);
113
+int ff_AMediaCodec_infoOutputBuffersChanged(FFAMediaCodec *codec, ssize_t idx);
114
+int ff_AMediaCodec_infoOutputFormatChanged(FFAMediaCodec *codec, ssize_t indx);
115
+
116
+int ff_AMediaCodec_getBufferFlagCodecConfig (FFAMediaCodec *codec);
117
+int ff_AMediaCodec_getBufferFlagEndOfStream(FFAMediaCodec *codec);
118
+int ff_AMediaCodec_getBufferFlagKeyFrame(FFAMediaCodec *codec);
119
+
120
+int ff_AMediaCodec_getConfigureFlagEncode(FFAMediaCodec *codec);
121
+
122
+int ff_AMediaCodec_cleanOutputBuffers(FFAMediaCodec *codec);
123
+
124
+#endif /* AVCODEC_MEDIACODEC_WRAPPER_H */
0 125
new file mode 100644
... ...
@@ -0,0 +1,570 @@
0
+/*
1
+ * Android MediaCodec decoder
2
+ *
3
+ * Copyright (c) 2015-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 <string.h>
23
+#include <sys/types.h>
24
+
25
+#include "libavutil/common.h"
26
+#include "libavutil/mem.h"
27
+#include "libavutil/log.h"
28
+#include "libavutil/pixfmt.h"
29
+#include "libavutil/time.h"
30
+#include "libavutil/timestamp.h"
31
+
32
+#include "avcodec.h"
33
+#include "internal.h"
34
+
35
+#include "mediacodec_sw_buffer.h"
36
+#include "mediacodec_wrapper.h"
37
+#include "mediacodecdec.h"
38
+
39
+/**
40
+ * OMX.k3.video.decoder.avc, OMX.NVIDIA.* OMX.SEC.avc.dec and OMX.google
41
+ * codec workarounds used in various place are taken from the Gstreamer
42
+ * project.
43
+ *
44
+ * Gstreamer references:
45
+ * https://cgit.freedesktop.org/gstreamer/gst-plugins-bad/tree/sys/androidmedia/
46
+ *
47
+ * Gstreamer copyright notice:
48
+ *
49
+ * Copyright (C) 2012, Collabora Ltd.
50
+ *   Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
51
+ *
52
+ * Copyright (C) 2012, Rafaël Carré <funman@videolanorg>
53
+ *
54
+ * Copyright (C) 2015, Sebastian Dröge <sebastian@centricular.com>
55
+ *
56
+ * Copyright (C) 2014-2015, Collabora Ltd.
57
+ *   Author: Matthieu Bouron <matthieu.bouron@gcollabora.com>
58
+ *
59
+ * Copyright (C) 2015, Edward Hervey
60
+ *   Author: Edward Hervey <bilboed@gmail.com>
61
+ *
62
+ * Copyright (C) 2015, Matthew Waters <matthew@centricular.com>
63
+ *
64
+ * This library is free software; you can redistribute it and/or
65
+ * modify it under the terms of the GNU Lesser General Public
66
+ * License as published by the Free Software Foundation
67
+ * version 2.1 of the License.
68
+ *
69
+ * This library is distributed in the hope that it will be useful,
70
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
71
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
72
+ * Lesser General Public License for more details.
73
+ *
74
+ * You should have received a copy of the GNU Lesser General Public
75
+ * License along with this library; if not, write to the Free Software
76
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
77
+ *
78
+ */
79
+
80
+#define INPUT_DEQUEUE_TIMEOUT_US 8000
81
+#define OUTPUT_DEQUEUE_TIMEOUT_US 8000
82
+#define OUTPUT_DEQUEUE_BLOCK_TIMEOUT_US 1000000
83
+
84
+enum {
85
+    COLOR_FormatYUV420Planar                              = 0x13,
86
+    COLOR_FormatYUV420SemiPlanar                          = 0x15,
87
+    COLOR_FormatYCbYCr                                    = 0x19,
88
+    COLOR_FormatAndroidOpaque                             = 0x7F000789,
89
+    COLOR_QCOM_FormatYUV420SemiPlanar                     = 0x7fa30c00,
90
+    COLOR_QCOM_FormatYUV420SemiPlanar32m                  = 0x7fa30c04,
91
+    COLOR_QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka = 0x7fa30c03,
92
+    COLOR_TI_FormatYUV420PackedSemiPlanar                 = 0x7f000100,
93
+    COLOR_TI_FormatYUV420PackedSemiPlanarInterlaced       = 0x7f000001,
94
+};
95
+
96
+static const struct {
97
+
98
+    int color_format;
99
+    enum AVPixelFormat pix_fmt;
100
+
101
+} color_formats[] = {
102
+
103
+    { COLOR_FormatYUV420Planar,                              AV_PIX_FMT_YUV420P },
104
+    { COLOR_FormatYUV420SemiPlanar,                          AV_PIX_FMT_NV12    },
105
+    { COLOR_QCOM_FormatYUV420SemiPlanar,                     AV_PIX_FMT_NV12    },
106
+    { COLOR_QCOM_FormatYUV420SemiPlanar32m,                  AV_PIX_FMT_NV12    },
107
+    { COLOR_QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka, AV_PIX_FMT_NV12    },
108
+    { COLOR_TI_FormatYUV420PackedSemiPlanar,                 AV_PIX_FMT_NV12    },
109
+    { COLOR_TI_FormatYUV420PackedSemiPlanarInterlaced,       AV_PIX_FMT_NV12    },
110
+    { 0 }
111
+};
112
+
113
+static enum AVPixelFormat mcdec_map_color_format(AVCodecContext *avctx,
114
+                                                 MediaCodecDecContext *s,
115
+                                                 int color_format)
116
+{
117
+    int i;
118
+    enum AVPixelFormat ret = AV_PIX_FMT_NONE;
119
+
120
+    if (!strcmp(s->codec_name, "OMX.k3.video.decoder.avc") && color_format == COLOR_FormatYCbYCr) {
121
+        s->color_format = color_format = COLOR_TI_FormatYUV420PackedSemiPlanar;
122
+    }
123
+
124
+    for (i = 0; i < FF_ARRAY_ELEMS(color_formats); i++) {
125
+        if (color_formats[i].color_format == color_format) {
126
+            return color_formats[i].pix_fmt;
127
+        }
128
+    }
129
+
130
+    av_log(avctx, AV_LOG_ERROR, "Output color format 0x%x (value=%d) is not supported\n",
131
+        color_format, color_format);
132
+
133
+    return ret;
134
+}
135
+
136
+static int mediacodec_wrap_buffer(AVCodecContext *avctx,
137
+                                  MediaCodecDecContext *s,
138
+                                  uint8_t *data,
139
+                                  size_t size,
140
+                                  ssize_t index,
141
+                                  FFAMediaCodecBufferInfo *info,
142
+                                  AVFrame *frame)
143
+{
144
+    int ret = 0;
145
+    int status = 0;
146
+
147
+    frame->width = avctx->width;
148
+    frame->height = avctx->height;
149
+    frame->format = avctx->pix_fmt;
150
+
151
+    /* MediaCodec buffers needs to be copied to our own refcounted buffers
152
+     * because the flush command invalidates all input and output buffers.
153
+     */
154
+    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
155
+        av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer\n");
156
+        goto done;
157
+    }
158
+
159
+    /* Override frame->pkt_pts as ff_get_buffer will override its value based
160
+     * on the last avpacket received which is not in sync with the frame:
161
+     *   * N avpackets can be pushed before 1 frame is actually returned
162
+     *   * 0-sized avpackets are pushed to flush remaining frames at EOS */
163
+    frame->pkt_pts = info->presentationTimeUs;
164
+
165
+    av_log(avctx, AV_LOG_DEBUG,
166
+            "Frame: width=%d stride=%d height=%d slice-height=%d "
167
+            "crop-top=%d crop-bottom=%d crop-left=%d crop-right=%d encoder=%s\n"
168
+            "destination linesizes=%d,%d,%d\n" ,
169
+            avctx->width, s->stride, avctx->height, s->slice_height,
170
+            s->crop_top, s->crop_bottom, s->crop_left, s->crop_right, s->codec_name,
171
+            frame->linesize[0], frame->linesize[1], frame->linesize[2]);
172
+
173
+    switch (s->color_format) {
174
+    case COLOR_FormatYUV420Planar:
175
+        ff_mediacodec_sw_buffer_copy_yuv420_planar(avctx, s, data, size, info, frame);
176
+        break;
177
+    case COLOR_FormatYUV420SemiPlanar:
178
+    case COLOR_QCOM_FormatYUV420SemiPlanar:
179
+    case COLOR_QCOM_FormatYUV420SemiPlanar32m:
180
+        ff_mediacodec_sw_buffer_copy_yuv420_semi_planar(avctx, s, data, size, info, frame);
181
+        break;
182
+    case COLOR_TI_FormatYUV420PackedSemiPlanar:
183
+    case COLOR_TI_FormatYUV420PackedSemiPlanarInterlaced:
184
+        ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar(avctx, s, data, size, info, frame);
185
+        break;
186
+    case COLOR_QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka:
187
+        ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar_64x32Tile2m8ka(avctx, s, data, size, info, frame);
188
+        break;
189
+    default:
190
+        av_log(avctx, AV_LOG_ERROR, "Unsupported color format 0x%x (value=%d)\n",
191
+            s->color_format, s->color_format);
192
+        ret = AVERROR(EINVAL);
193
+        goto done;
194
+    }
195
+
196
+    ret = 0;
197
+done:
198
+    status = ff_AMediaCodec_releaseOutputBuffer(s->codec, index, 0);
199
+    if (status < 0) {
200
+        av_log(NULL, AV_LOG_ERROR, "Failed to release output buffer\n");
201
+        ret = AVERROR_EXTERNAL;
202
+    }
203
+
204
+    return ret;
205
+}
206
+
207
+static int mediacodec_dec_parse_format(AVCodecContext *avctx, MediaCodecDecContext *s)
208
+{
209
+    int width = 0;
210
+    int height = 0;
211
+    int32_t value = 0;
212
+    char *format = NULL;
213
+
214
+    if (!s->format) {
215
+        av_log(avctx, AV_LOG_ERROR, "Output MediaFormat is not set\n");
216
+        return AVERROR(EINVAL);
217
+    }
218
+
219
+    format = ff_AMediaFormat_toString(s->format);
220
+    if (!format) {
221
+        return AVERROR_EXTERNAL;
222
+    }
223
+    av_log(avctx, AV_LOG_DEBUG, "Parsing MediaFormat %s\n", format);
224
+    av_freep(&format);
225
+
226
+    /* Mandatory fields */
227
+    if (!ff_AMediaFormat_getInt32(s->format, "width", &value)) {
228
+        format = ff_AMediaFormat_toString(s->format);
229
+        av_log(avctx, AV_LOG_ERROR, "Could not get %s from format %s\n", "width", format);
230
+        av_freep(&format);
231
+        return AVERROR_EXTERNAL;
232
+    }
233
+    s->width = value;
234
+
235
+    if (!ff_AMediaFormat_getInt32(s->format, "height", &value)) {
236
+        format = ff_AMediaFormat_toString(s->format);
237
+        av_log(avctx, AV_LOG_ERROR, "Could not get %s from format %s\n", "height", format);
238
+        av_freep(&format);
239
+        return AVERROR_EXTERNAL;
240
+    }
241
+    s->height = value;
242
+
243
+    if (!ff_AMediaFormat_getInt32(s->format, "stride", &value)) {
244
+        format = ff_AMediaFormat_toString(s->format);
245
+        av_log(avctx, AV_LOG_ERROR, "Could not get %s from format %s\n", "stride", format);
246
+        av_freep(&format);
247
+        return AVERROR_EXTERNAL;
248
+    }
249
+    s->stride = value >= 0 ? value : s->width;
250
+
251
+    if (!ff_AMediaFormat_getInt32(s->format, "slice-height", &value)) {
252
+        format = ff_AMediaFormat_toString(s->format);
253
+        av_log(avctx, AV_LOG_ERROR, "Could not get %s from format %s\n", "slice-height", format);
254
+        av_freep(&format);
255
+        return AVERROR_EXTERNAL;
256
+    }
257
+    if (value > 0) {
258
+        s->slice_height = value;
259
+    } else {
260
+        s->slice_height = s->height;
261
+    }
262
+
263
+    if (strstr(s->codec_name, "OMX.Nvidia.")) {
264
+        s->slice_height = FFALIGN(s->height, 16);
265
+    } else if (strstr(s->codec_name, "OMX.SEC.avc.dec")) {
266
+        s->slice_height = avctx->height;
267
+        s->stride = avctx->width;
268
+    }
269
+
270
+    if (!ff_AMediaFormat_getInt32(s->format, "color-format", &value)) {
271
+        format = ff_AMediaFormat_toString(s->format);
272
+        av_log(avctx, AV_LOG_ERROR, "Could not get %s from format %s\n", "color-format", format);
273
+        av_freep(&format);
274
+        return AVERROR_EXTERNAL;
275
+    }
276
+    s->color_format = value;
277
+
278
+    s->pix_fmt = avctx->pix_fmt = mcdec_map_color_format(avctx, s, value);
279
+    if (avctx->pix_fmt == AV_PIX_FMT_NONE) {
280
+        av_log(avctx, AV_LOG_ERROR, "Output color format is not supported\n");
281
+        return AVERROR(EINVAL);
282
+    }
283
+
284
+    /* Optional fields */
285
+    if (ff_AMediaFormat_getInt32(s->format, "crop-top", &value))
286
+        s->crop_top = value;
287
+
288
+    if (ff_AMediaFormat_getInt32(s->format, "crop-bottom", &value))
289
+        s->crop_bottom = value;
290
+
291
+    if (ff_AMediaFormat_getInt32(s->format, "crop-left", &value))
292
+        s->crop_left = value;
293
+
294
+    if (ff_AMediaFormat_getInt32(s->format, "crop-right", &value))
295
+        s->crop_right = value;
296
+
297
+    width = s->crop_right + 1 - s->crop_left;
298
+    height = s->crop_bottom + 1 - s->crop_top;
299
+
300
+    av_log(avctx, AV_LOG_INFO,
301
+        "Output crop parameters top=%d bottom=%d left=%d right=%d, "
302
+        "resulting dimensions width=%d height=%d\n",
303
+        s->crop_top, s->crop_bottom, s->crop_left, s->crop_right,
304
+        width, height);
305
+
306
+    return ff_set_dimensions(avctx, width, height);
307
+}
308
+
309
+int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s,
310
+                           const char *mime, FFAMediaFormat *format)
311
+{
312
+    int ret = 0;
313
+    int status;
314
+
315
+    s->first_buffer_at = av_gettime();
316
+
317
+    s->codec_name = ff_AMediaCodecList_getCodecNameByType(mime, avctx->width, avctx->height, avctx);
318
+    if (!s->codec_name) {
319
+        ret = AVERROR_EXTERNAL;
320
+        goto fail;
321
+    }
322
+
323
+    av_log(avctx, AV_LOG_DEBUG, "Found decoder %s\n", s->codec_name);
324
+    s->codec = ff_AMediaCodec_createCodecByName(s->codec_name);
325
+    if (!s->codec) {
326
+        av_log(avctx, AV_LOG_ERROR, "Failed to create media decoder for type %s and name %s\n", mime, s->codec_name);
327
+        ret = AVERROR_EXTERNAL;
328
+        goto fail;
329
+    }
330
+
331
+    status = ff_AMediaCodec_configure(s->codec, format, NULL, NULL, 0);
332
+    if (status < 0) {
333
+        char *desc = ff_AMediaFormat_toString(format);
334
+        av_log(avctx, AV_LOG_ERROR,
335
+            "Failed to configure codec (status = %d) with format %s\n",
336
+            status, desc);
337
+        av_freep(&desc);
338
+
339
+        ret = AVERROR_EXTERNAL;
340
+        goto fail;
341
+    }
342
+
343
+    status = ff_AMediaCodec_start(s->codec);
344
+    if (status < 0) {
345
+        char *desc = ff_AMediaFormat_toString(format);
346
+        av_log(avctx, AV_LOG_ERROR,
347
+            "Failed to start codec (status = %d) with format %s\n",
348
+            status, desc);
349
+        av_freep(&desc);
350
+        ret = AVERROR_EXTERNAL;
351
+        goto fail;
352
+    }
353
+
354
+    s->format = ff_AMediaCodec_getOutputFormat(s->codec);
355
+    if (s->format) {
356
+        if ((ret = mediacodec_dec_parse_format(avctx, s)) < 0) {
357
+            av_log(avctx, AV_LOG_ERROR,
358
+                "Failed to configure context\n");
359
+            goto fail;
360
+        }
361
+    }
362
+
363
+    av_log(avctx, AV_LOG_DEBUG, "MediaCodec %p started successfully\n", s->codec);
364
+
365
+    return 0;
366
+
367
+fail:
368
+    av_log(avctx, AV_LOG_ERROR, "MediaCodec %p failed to start\n", s->codec);
369
+    ff_mediacodec_dec_close(avctx, s);
370
+    return ret;
371
+}
372
+
373
+int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s,
374
+                             AVFrame *frame, int *got_frame,
375
+                             AVPacket *pkt)
376
+{
377
+    int ret;
378
+    int offset = 0;
379
+    int need_flushing = 0;
380
+    uint8_t *data;
381
+    ssize_t index;
382
+    size_t size;
383
+    FFAMediaCodec *codec = s->codec;
384
+    FFAMediaCodecBufferInfo info = { 0 };
385
+
386
+    int status;
387
+
388
+    int64_t input_dequeue_timeout_us = INPUT_DEQUEUE_TIMEOUT_US;
389
+    int64_t output_dequeue_timeout_us = OUTPUT_DEQUEUE_TIMEOUT_US;
390
+
391
+
392
+    if (pkt->size == 0) {
393
+        need_flushing = 1;
394
+    }
395
+
396
+    if (s->flushing && need_flushing && s->queued_buffer_nb <= 0) {
397
+        return 0;
398
+    }
399
+
400
+    while (offset < pkt->size || (need_flushing && !s->flushing)) {
401
+        int size;
402
+
403
+        index = ff_AMediaCodec_dequeueInputBuffer(codec, input_dequeue_timeout_us);
404
+        if (ff_AMediaCodec_infoTryAgainLater(codec, index)) {
405
+            break;
406
+        }
407
+
408
+        if (index < 0) {
409
+            av_log(avctx, AV_LOG_ERROR, "Failed to dequeue input buffer (status=%zd)\n", index);
410
+            return AVERROR_EXTERNAL;
411
+        }
412
+
413
+        data = ff_AMediaCodec_getInputBuffer(codec, index, &size);
414
+        if (!data) {
415
+            av_log(avctx, AV_LOG_ERROR, "Failed to get input buffer\n");
416
+            return AVERROR_EXTERNAL;
417
+        }
418
+
419
+        if (need_flushing) {
420
+            uint32_t flags = ff_AMediaCodec_getBufferFlagEndOfStream(codec);
421
+
422
+            av_log(avctx, AV_LOG_DEBUG, "Sending End Of Stream signal\n");
423
+
424
+            status = ff_AMediaCodec_queueInputBuffer(codec, index, 0, 0, pkt->pts, flags);
425
+            if (status < 0) {
426
+                av_log(avctx, AV_LOG_ERROR, "Failed to queue input empty buffer (status = %d)\n", status);
427
+                return AVERROR_EXTERNAL;
428
+            }
429
+
430
+            s->flushing = 1;
431
+            break;
432
+        } else {
433
+            size = FFMIN(pkt->size - offset, size);
434
+
435
+            memcpy(data, pkt->data + offset, size);
436
+            offset += size;
437
+
438
+            status = ff_AMediaCodec_queueInputBuffer(codec, index, 0, size, pkt->pts, 0);
439
+            if (status < 0) {
440
+                av_log(avctx, AV_LOG_ERROR, "Failed to queue input buffer (status = %d)\n", status);
441
+                return AVERROR_EXTERNAL;
442
+            }
443
+
444
+            s->queued_buffer_nb++;
445
+            if (s->queued_buffer_nb > s->queued_buffer_max)
446
+                s->queued_buffer_max = s->queued_buffer_nb;
447
+        }
448
+    }
449
+
450
+    if (s->flushing) {
451
+        /* If the codec is flushing, block for a fair amount of time to
452
+        * ensure we got a frame */
453
+        output_dequeue_timeout_us = OUTPUT_DEQUEUE_BLOCK_TIMEOUT_US;
454
+    } else if (s->dequeued_buffer_nb == 0) {
455
+        /* If the codec hasn't produced any frames, do not block so we
456
+         * can push data to it as fast as possible, and get the first
457
+         * frame */
458
+        output_dequeue_timeout_us = 0;
459
+    }
460
+
461
+    index = ff_AMediaCodec_dequeueOutputBuffer(codec, &info, output_dequeue_timeout_us);
462
+    if (index >= 0) {
463
+        int ret;
464
+
465
+        if (!s->first_buffer++) {
466
+            av_log(avctx, AV_LOG_DEBUG, "Got first buffer after %fms\n", (av_gettime() - s->first_buffer_at) / 1000);
467
+        }
468
+
469
+        av_log(avctx, AV_LOG_DEBUG, "Got output buffer %zd"
470
+                " offset=%" PRIi32 " size=%" PRIi32 " ts=%" PRIi64
471
+                " flags=%" PRIu32 "\n", index, info.offset, info.size,
472
+                info.presentationTimeUs, info.flags);
473
+
474
+        data = ff_AMediaCodec_getOutputBuffer(codec, index, &size);
475
+        if (!data) {
476
+            av_log(avctx, AV_LOG_ERROR, "Failed to get output buffer\n");
477
+            return AVERROR_EXTERNAL;
478
+        }
479
+
480
+        if ((ret = mediacodec_wrap_buffer(avctx, s, data, size, index, &info, frame)) < 0) {
481
+            av_log(avctx, AV_LOG_ERROR, "Failed to wrap MediaCodec buffer\n");
482
+            return ret;
483
+        }
484
+
485
+        *got_frame = 1;
486
+        s->queued_buffer_nb--;
487
+        s->dequeued_buffer_nb++;
488
+
489
+    } else if (ff_AMediaCodec_infoOutputFormatChanged(codec, index)) {
490
+        char *format = NULL;
491
+
492
+        if (s->format) {
493
+            status = ff_AMediaFormat_delete(s->format);
494
+            if (status < 0) {
495
+                av_log(avctx, AV_LOG_ERROR, "Failed to delete MediaFormat %p\n", s->format);
496
+            }
497
+        }
498
+
499
+        s->format = ff_AMediaCodec_getOutputFormat(codec);
500
+        if (!s->format) {
501
+            av_log(avctx, AV_LOG_ERROR, "Failed to get output format\n");
502
+            return AVERROR_EXTERNAL;
503
+        }
504
+
505
+        format = ff_AMediaFormat_toString(s->format);
506
+        if (!format) {
507
+            return AVERROR_EXTERNAL;
508
+        }
509
+        av_log(avctx, AV_LOG_INFO, "Output MediaFormat changed to %s\n", format);
510
+        av_freep(&format);
511
+
512
+        if ((ret = mediacodec_dec_parse_format(avctx, s)) < 0) {
513
+            return ret;
514
+        }
515
+
516
+    } else if (ff_AMediaCodec_infoOutputBuffersChanged(codec, index)) {
517
+        ff_AMediaCodec_cleanOutputBuffers(codec);
518
+    } else if (ff_AMediaCodec_infoTryAgainLater(codec, index)) {
519
+        if (s->flushing) {
520
+            av_log(avctx, AV_LOG_ERROR, "Failed to dequeue output buffer within %" PRIi64 "ms "
521
+                                        "while flushing remaining frames, output will probably lack last %d frames\n",
522
+                                        output_dequeue_timeout_us / 1000, s->queued_buffer_nb);
523
+        } else {
524
+            av_log(avctx, AV_LOG_DEBUG, "No output buffer available, try again later\n");
525
+        }
526
+    } else {
527
+        av_log(avctx, AV_LOG_ERROR, "Failed to dequeue output buffer (status=%zd)\n", index);
528
+        return AVERROR_EXTERNAL;
529
+    }
530
+
531
+    return offset;
532
+}
533
+
534
+int ff_mediacodec_dec_flush(AVCodecContext *avctx, MediaCodecDecContext *s)
535
+{
536
+    FFAMediaCodec *codec = s->codec;
537
+    int status;
538
+
539
+    s->queued_buffer_nb = 0;
540
+    s->dequeued_buffer_nb = 0;
541
+
542
+    s->flushing = 0;
543
+
544
+    status = ff_AMediaCodec_flush(codec);
545
+    if (status < 0) {
546
+        av_log(NULL, AV_LOG_ERROR, "Failed to flush MediaCodec %p", codec);
547
+        return AVERROR_EXTERNAL;
548
+    }
549
+
550
+    s->first_buffer = 0;
551
+    s->first_buffer_at = av_gettime();
552
+
553
+    return 0;
554
+}
555
+
556
+int ff_mediacodec_dec_close(AVCodecContext *avctx, MediaCodecDecContext *s)
557
+{
558
+    if (s->codec) {
559
+        ff_AMediaCodec_delete(s->codec);
560
+        s->codec = NULL;
561
+    }
562
+
563
+    if (s->format) {
564
+        ff_AMediaFormat_delete(s->format);
565
+        s->format = NULL;
566
+    }
567
+
568
+    return 0;
569
+}
0 570
new file mode 100644
... ...
@@ -0,0 +1,82 @@
0
+/*
1
+ * Android MediaCodec decoder
2
+ *
3
+ * Copyright (c) 2015-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_MEDIACODECDEC_H
23
+#define AVCODEC_MEDIACODECDEC_H
24
+
25
+#include <stdint.h>
26
+#include <sys/types.h>
27
+
28
+#include "libavutil/frame.h"
29
+#include "libavutil/pixfmt.h"
30
+
31
+#include "avcodec.h"
32
+#include "mediacodec_wrapper.h"
33
+
34
+typedef struct MediaCodecDecContext {
35
+
36
+    const char *codec_name;
37
+
38
+    FFAMediaCodec *codec;
39
+    FFAMediaFormat *format;
40
+
41
+    int started;
42
+    int flushing;
43
+
44
+    int width;
45
+    int height;
46
+    int stride;
47
+    int slice_height;
48
+    int color_format;
49
+    enum AVPixelFormat pix_fmt;
50
+    int crop_top;
51
+    int crop_bottom;
52
+    int crop_left;
53
+    int crop_right;
54
+
55
+    int queued_buffer_nb;
56
+    int queued_buffer_max;
57
+    uint64_t dequeued_buffer_nb;
58
+
59
+    int first_buffer;
60
+    double first_buffer_at;
61
+
62
+} MediaCodecDecContext;
63
+
64
+int ff_mediacodec_dec_init(AVCodecContext *avctx,
65
+                           MediaCodecDecContext *s,
66
+                           const char *mime,
67
+                           FFAMediaFormat *format);
68
+
69
+int ff_mediacodec_dec_decode(AVCodecContext *avctx,
70
+                             MediaCodecDecContext *s,
71
+                             AVFrame *frame,
72
+                             int *got_frame,
73
+                             AVPacket *pkt);
74
+
75
+int ff_mediacodec_dec_flush(AVCodecContext *avctx,
76
+                            MediaCodecDecContext *s);
77
+
78
+int ff_mediacodec_dec_close(AVCodecContext *avctx,
79
+                            MediaCodecDecContext *s);
80
+
81
+#endif /* AVCODEC_MEDIACODECDEC_H */
0 82
new file mode 100644
... ...
@@ -0,0 +1,336 @@
0
+/*
1
+ * Android MediaCodec H.264 decoder
2
+ *
3
+ * Copyright (c) 2015-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 <stdint.h>
23
+#include <string.h>
24
+
25
+#include "libavutil/common.h"
26
+#include "libavutil/fifo.h"
27
+#include "libavutil/opt.h"
28
+#include "libavutil/intreadwrite.h"
29
+#include "libavutil/pixfmt.h"
30
+#include "libavutil/atomic.h"
31
+
32
+#include "avcodec.h"
33
+#include "internal.h"
34
+#include "mediacodecdec.h"
35
+#include "mediacodec_wrapper.h"
36
+
37
+#define CODEC_MIME "video/avc"
38
+
39
+typedef struct MediaCodecH264DecContext {
40
+
41
+    MediaCodecDecContext ctx;
42
+
43
+    AVBitStreamFilterContext *bsf;
44
+
45
+    AVFifoBuffer *fifo;
46
+
47
+    AVPacket input_ref;
48
+    AVPacket filtered_pkt;
49
+    uint8_t *filtered_data;
50
+
51
+} MediaCodecH264DecContext;
52
+
53
+static int h264_extradata_to_annexb_sps_pps(AVCodecContext *avctx,
54
+        uint8_t **extradata_annexb, int *extradata_annexb_size,
55
+        int *sps_offset, int *sps_size,
56
+        int *pps_offset, int *pps_size)
57
+{
58
+    uint16_t unit_size;
59
+    uint64_t total_size = 0;
60
+
61
+    uint8_t i, j, unit_nb;
62
+    uint8_t sps_seen = 0;
63
+    uint8_t pps_seen = 0;
64
+
65
+    const uint8_t *extradata;
66
+    static const uint8_t nalu_header[4] = { 0x00, 0x00, 0x00, 0x01 };
67
+
68
+    if (avctx->extradata_size < 8) {
69
+        av_log(avctx, AV_LOG_ERROR,
70
+            "Too small extradata size, corrupted stream or invalid MP4/AVCC bitstream\n");
71
+        return AVERROR(EINVAL);
72
+    }
73
+
74
+    *extradata_annexb = NULL;
75
+    *extradata_annexb_size = 0;
76
+
77
+    *sps_offset = *sps_size = 0;
78
+    *pps_offset = *pps_size = 0;
79
+
80
+    extradata = avctx->extradata + 4;
81
+
82
+    /* skip length size */
83
+    extradata++;
84
+
85
+    for (j = 0; j < 2; j ++) {
86
+
87
+        if (j == 0) {
88
+            /* number of sps unit(s) */
89
+            unit_nb = *extradata++ & 0x1f;
90
+        } else {
91
+            /* number of pps unit(s) */
92
+            unit_nb = *extradata++;
93
+        }
94
+
95
+        for (i = 0; i < unit_nb; i++) {
96
+            int err;
97
+
98
+            unit_size   = AV_RB16(extradata);
99
+            total_size += unit_size + 4;
100
+
101
+            if (total_size > INT_MAX) {
102
+                av_log(avctx, AV_LOG_ERROR,
103
+                    "Too big extradata size, corrupted stream or invalid MP4/AVCC bitstream\n");
104
+                av_freep(extradata_annexb);
105
+                return AVERROR(EINVAL);
106
+            }
107
+
108
+            if (extradata + 2 + unit_size > avctx->extradata + avctx->extradata_size) {
109
+                av_log(avctx, AV_LOG_ERROR, "Packet header is not contained in global extradata, "
110
+                    "corrupted stream or invalid MP4/AVCC bitstream\n");
111
+                av_freep(extradata_annexb);
112
+                return AVERROR(EINVAL);
113
+            }
114
+
115
+            if ((err = av_reallocp(extradata_annexb, total_size)) < 0) {
116
+                return err;
117
+            }
118
+
119
+            memcpy(*extradata_annexb + total_size - unit_size - 4, nalu_header, 4);
120
+            memcpy(*extradata_annexb + total_size - unit_size, extradata + 2, unit_size);
121
+            extradata += 2 + unit_size;
122
+        }
123
+
124
+        if (unit_nb) {
125
+            if (j == 0) {
126
+                sps_seen = 1;
127
+                *sps_size = total_size;
128
+            } else {
129
+                pps_seen = 1;
130
+                *pps_size = total_size - *sps_size;
131
+                *pps_offset = *sps_size;
132
+            }
133
+        }
134
+    }
135
+
136
+    *extradata_annexb_size = total_size;
137
+
138
+    if (!sps_seen)
139
+        av_log(avctx, AV_LOG_WARNING,
140
+               "Warning: SPS NALU missing or invalid. "
141
+               "The resulting stream may not play.\n");
142
+
143
+    if (!pps_seen)
144
+        av_log(avctx, AV_LOG_WARNING,
145
+               "Warning: PPS NALU missing or invalid. "
146
+               "The resulting stream may not play.\n");
147
+
148
+    return 0;
149
+}
150
+
151
+static av_cold int mediacodec_decode_close(AVCodecContext *avctx)
152
+{
153
+    MediaCodecH264DecContext *s = avctx->priv_data;
154
+
155
+    ff_mediacodec_dec_close(avctx, &s->ctx);
156
+
157
+    av_fifo_free(s->fifo);
158
+
159
+    av_bitstream_filter_close(s->bsf);
160
+
161
+    return 0;
162
+}
163
+
164
+static av_cold int mediacodec_decode_init(AVCodecContext *avctx)
165
+{
166
+    int ret;
167
+    FFAMediaFormat *format = NULL;
168
+    MediaCodecH264DecContext *s = avctx->priv_data;
169
+
170
+    format = ff_AMediaFormat_new();
171
+    if (!format) {
172
+        av_log(avctx, AV_LOG_ERROR, "Failed to create media format\n");
173
+        ret = AVERROR_EXTERNAL;
174
+        goto done;
175
+    }
176
+
177
+    ff_AMediaFormat_setString(format, "mime", CODEC_MIME);
178
+    ff_AMediaFormat_setInt32(format, "width", avctx->width);
179
+    ff_AMediaFormat_setInt32(format, "height", avctx->height);
180
+
181
+    if (avctx->extradata[0] == 1) {
182
+        uint8_t *extradata = NULL;
183
+        int extradata_size = 0;
184
+
185
+        int sps_offset, sps_size;
186
+        int pps_offset, pps_size;
187
+
188
+        if ((ret = h264_extradata_to_annexb_sps_pps(avctx, &extradata, &extradata_size,
189
+                &sps_offset, &sps_size, &pps_offset, &pps_size)) < 0) {
190
+            goto done;
191
+        }
192
+
193
+        ff_AMediaFormat_setBuffer(format, "csd-0", extradata + sps_offset, sps_size);
194
+        ff_AMediaFormat_setBuffer(format, "csd-1", extradata + pps_offset, pps_size);
195
+
196
+        av_freep(&extradata);
197
+    } else {
198
+        ff_AMediaFormat_setBuffer(format, "csd-0", avctx->extradata, avctx->extradata_size);
199
+    }
200
+
201
+    if ((ret = ff_mediacodec_dec_init(avctx, &s->ctx, CODEC_MIME, format)) < 0) {
202
+        goto done;
203
+    }
204
+
205
+    av_log(avctx, AV_LOG_INFO, "MediaCodec started successfully, ret = %d\n", ret);
206
+
207
+    s->fifo = av_fifo_alloc(sizeof(AVPacket));
208
+    if (!s->fifo) {
209
+        ret = AVERROR(ENOMEM);
210
+        goto done;
211
+    }
212
+
213
+    s->bsf = av_bitstream_filter_init("h264_mp4toannexb");
214
+    if (!s->bsf) {
215
+        ret = AVERROR(ENOMEM);
216
+        goto done;
217
+    }
218
+
219
+done:
220
+    if (format) {
221
+        ff_AMediaFormat_delete(format);
222
+    }
223
+
224
+    if (ret < 0) {
225
+        mediacodec_decode_close(avctx);
226
+    }
227
+    return ret;
228
+}
229
+
230
+
231
+static int mediacodec_process_data(AVCodecContext *avctx, AVFrame *frame,
232
+                                   int *got_frame, AVPacket *pkt)
233
+{
234
+    MediaCodecH264DecContext *s = avctx->priv_data;
235
+
236
+    return ff_mediacodec_dec_decode(avctx, &s->ctx, frame, got_frame, pkt);
237
+}
238
+
239
+static int mediacodec_decode_frame(AVCodecContext *avctx, void *data,
240
+                                   int *got_frame, AVPacket *avpkt)
241
+{
242
+    MediaCodecH264DecContext *s = avctx->priv_data;
243
+    AVFrame *frame    = data;
244
+    int ret;
245
+
246
+    /* buffer the input packet */
247
+    if (avpkt->size) {
248
+        AVPacket input_ref = { 0 };
249
+
250
+        if (av_fifo_space(s->fifo) < sizeof(input_ref)) {
251
+            ret = av_fifo_realloc2(s->fifo,
252
+                                   av_fifo_size(s->fifo) + sizeof(input_ref));
253
+            if (ret < 0)
254
+                return ret;
255
+        }
256
+
257
+        ret = av_packet_ref(&input_ref, avpkt);
258
+        if (ret < 0)
259
+            return ret;
260
+        av_fifo_generic_write(s->fifo, &input_ref, sizeof(input_ref), NULL);
261
+    }
262
+
263
+    /* process buffered data */
264
+    while (!*got_frame) {
265
+        /* prepare the input data -- convert to Annex B if needed */
266
+        if (s->filtered_pkt.size <= 0) {
267
+            int size;
268
+
269
+            /* no more data */
270
+            if (av_fifo_size(s->fifo) < sizeof(AVPacket)) {
271
+                return avpkt->size ? avpkt->size :
272
+                    ff_mediacodec_dec_decode(avctx, &s->ctx, frame, got_frame, avpkt);
273
+            }
274
+
275
+            if (s->filtered_data != s->input_ref.data)
276
+                av_freep(&s->filtered_data);
277
+            s->filtered_data = NULL;
278
+            av_packet_unref(&s->input_ref);
279
+
280
+            av_fifo_generic_read(s->fifo, &s->input_ref, sizeof(s->input_ref), NULL);
281
+            ret = av_bitstream_filter_filter(s->bsf, avctx, NULL,
282
+                                             &s->filtered_data, &size,
283
+                                             s->input_ref.data, s->input_ref.size, 0);
284
+            if (ret < 0) {
285
+                s->filtered_data = s->input_ref.data;
286
+                size             = s->input_ref.size;
287
+            }
288
+            s->filtered_pkt      = s->input_ref;
289
+            s->filtered_pkt.data = s->filtered_data;
290
+            s->filtered_pkt.size = size;
291
+        }
292
+
293
+        ret = mediacodec_process_data(avctx, frame, got_frame, &s->filtered_pkt);
294
+        if (ret < 0)
295
+            return ret;
296
+
297
+        s->filtered_pkt.size -= ret;
298
+        s->filtered_pkt.data += ret;
299
+    }
300
+
301
+    return avpkt->size;
302
+}
303
+
304
+static void mediacodec_decode_flush(AVCodecContext *avctx)
305
+{
306
+    MediaCodecH264DecContext *s = avctx->priv_data;
307
+
308
+    while (av_fifo_size(s->fifo)) {
309
+        AVPacket pkt;
310
+        av_fifo_generic_read(s->fifo, &pkt, sizeof(pkt), NULL);
311
+        av_packet_unref(&pkt);
312
+    }
313
+    av_fifo_reset(s->fifo);
314
+
315
+    av_packet_unref(&s->input_ref);
316
+
317
+    av_init_packet(&s->filtered_pkt);
318
+    s->filtered_pkt.data = NULL;
319
+    s->filtered_pkt.size = 0;
320
+
321
+    ff_mediacodec_dec_flush(avctx, &s->ctx);
322
+}
323
+
324
+AVCodec ff_h264_mediacodec_decoder = {
325
+    .name           = "h264_mediacodec",
326
+    .long_name      = NULL_IF_CONFIG_SMALL("H.264 Android MediaCodec decoder"),
327
+    .type           = AVMEDIA_TYPE_VIDEO,
328
+    .id             = AV_CODEC_ID_H264,
329
+    .priv_data_size = sizeof(MediaCodecH264DecContext),
330
+    .init           = mediacodec_decode_init,
331
+    .decode         = mediacodec_decode_frame,
332
+    .flush          = mediacodec_decode_flush,
333
+    .close          = mediacodec_decode_close,
334
+    .capabilities   = CODEC_CAP_DELAY,
335
+};
... ...
@@ -28,8 +28,8 @@
28 28
 #include "libavutil/version.h"
29 29
 
30 30
 #define LIBAVCODEC_VERSION_MAJOR  57
31
-#define LIBAVCODEC_VERSION_MINOR  27
32
-#define LIBAVCODEC_VERSION_MICRO 101
31
+#define LIBAVCODEC_VERSION_MINOR  28
32
+#define LIBAVCODEC_VERSION_MICRO 100
33 33
 
34 34
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
35 35
                                                LIBAVCODEC_VERSION_MINOR, \