Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
F
ffmpeg
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
ffmpeg
Commits
4737fe69
Commit
4737fe69
authored
Jan 21, 2016
by
Matthieu Bouron
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
lavc: add h264 mediacodec decoder
parent
3ab17851
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
3232 additions
and
2 deletions
+3232
-2
Changelog
Changelog
+1
-0
MAINTAINERS
MAINTAINERS
+1
-0
configure
configure
+5
-0
Makefile
libavcodec/Makefile
+3
-0
allcodecs.c
libavcodec/allcodecs.c
+1
-0
mediacodec_sw_buffer.c
libavcodec/mediacodec_sw_buffer.c
+339
-0
mediacodec_sw_buffer.h
libavcodec/mediacodec_sw_buffer.h
+62
-0
mediacodec_wrapper.c
libavcodec/mediacodec_wrapper.c
+1705
-0
mediacodec_wrapper.h
libavcodec/mediacodec_wrapper.h
+125
-0
mediacodecdec.c
libavcodec/mediacodecdec.c
+570
-0
mediacodecdec.h
libavcodec/mediacodecdec.h
+82
-0
mediacodecdec_h264.c
libavcodec/mediacodecdec_h264.c
+336
-0
version.h
libavcodec/version.h
+2
-2
No files found.
Changelog
View file @
4737fe69
...
@@ -11,6 +11,7 @@ version <next>:
...
@@ -11,6 +11,7 @@ version <next>:
- bench and abench filters
- bench and abench filters
- ciescope filter
- ciescope filter
- protocol blacklisting API
- protocol blacklisting API
- MediaCodec H264 decoding
version 3.0:
version 3.0:
...
...
MAINTAINERS
View file @
4737fe69
...
@@ -308,6 +308,7 @@ Codecs:
...
@@ -308,6 +308,7 @@ Codecs:
Hardware acceleration:
Hardware acceleration:
crystalhd.c Philip Langdale
crystalhd.c Philip Langdale
dxva2* Hendrik Leppkes, Laurent Aimar
dxva2* Hendrik Leppkes, Laurent Aimar
mediacodec* Matthieu Bouron
vaapi* Gwenole Beauchesne
vaapi* Gwenole Beauchesne
vda* Sebastien Zwickert
vda* Sebastien Zwickert
vdpau* Philip Langdale, Carl Eugen Hoyos
vdpau* Philip Langdale, Carl Eugen Hoyos
...
...
configure
View file @
4737fe69
...
@@ -276,6 +276,7 @@ External library support:
...
@@ -276,6 +276,7 @@ External library support:
--enable-libzvbi enable teletext support via libzvbi [no]
--enable-libzvbi enable teletext support via libzvbi [no]
--disable-lzma disable lzma [autodetect]
--disable-lzma disable lzma [autodetect]
--enable-decklink enable Blackmagic DeckLink I/O support [no]
--enable-decklink enable Blackmagic DeckLink I/O support [no]
--enable-mediacodec enable Android MediaCodec support [no]
--enable-mmal enable decoding via MMAL [no]
--enable-mmal enable decoding via MMAL [no]
--enable-netcdf enable NetCDF, needed for sofalizer filter [no]
--enable-netcdf enable NetCDF, needed for sofalizer filter [no]
--enable-nvenc enable NVIDIA NVENC support [no]
--enable-nvenc enable NVIDIA NVENC support [no]
...
@@ -1501,6 +1502,7 @@ EXTERNAL_LIBRARY_LIST="
...
@@ -1501,6 +1502,7 @@ EXTERNAL_LIBRARY_LIST="
libzmq
libzmq
libzvbi
libzvbi
lzma
lzma
mediacodec
mmal
mmal
netcdf
netcdf
nvenc
nvenc
...
@@ -2505,6 +2507,8 @@ h264_d3d11va_hwaccel_deps="d3d11va"
...
@@ -2505,6 +2507,8 @@ h264_d3d11va_hwaccel_deps="d3d11va"
h264_d3d11va_hwaccel_select
=
"h264_decoder"
h264_d3d11va_hwaccel_select
=
"h264_decoder"
h264_dxva2_hwaccel_deps
=
"dxva2"
h264_dxva2_hwaccel_deps
=
"dxva2"
h264_dxva2_hwaccel_select
=
"h264_decoder"
h264_dxva2_hwaccel_select
=
"h264_decoder"
h264_mediacodec_decoder_deps
=
"mediacodec"
h264_mediacodec_decoder_select
=
"h264_mp4toannexb_bsf h264_parser"
h264_mmal_decoder_deps
=
"mmal"
h264_mmal_decoder_deps
=
"mmal"
h264_mmal_decoder_select
=
"mmal"
h264_mmal_decoder_select
=
"mmal"
h264_mmal_hwaccel_deps
=
"mmal"
h264_mmal_hwaccel_deps
=
"mmal"
...
@@ -5672,6 +5676,7 @@ enabled libzmq && require_pkg_config libzmq zmq.h zmq_ctx_new
...
@@ -5672,6 +5676,7 @@ enabled libzmq && require_pkg_config libzmq zmq.h zmq_ctx_new
enabled libzvbi
&&
require libzvbi libzvbi.h vbi_decoder_new
-lzvbi
&&
enabled libzvbi
&&
require libzvbi libzvbi.h vbi_decoder_new
-lzvbi
&&
{
check_cpp_condition libzvbi.h
"VBI_VERSION_MAJOR > 0 || VBI_VERSION_MINOR > 2 || VBI_VERSION_MINOR == 2 && VBI_VERSION_MICRO >= 28"
||
{
check_cpp_condition libzvbi.h
"VBI_VERSION_MAJOR > 0 || VBI_VERSION_MINOR > 2 || VBI_VERSION_MINOR == 2 && VBI_VERSION_MICRO >= 28"
||
enabled gpl
||
die
"ERROR: libzvbi requires version 0.2.28 or --enable-gpl."
;
}
enabled gpl
||
die
"ERROR: libzvbi requires version 0.2.28 or --enable-gpl."
;
}
enabled mediacodec
&&
{
enabled jni
||
die
"ERROR: mediacodec requires --enable-jni"
;
}
enabled mmal
&&
{
check_lib interface/mmal/mmal.h mmal_port_connect
-lmmal_core
-lmmal_util
-lmmal_vc_client
-lbcm_host
||
enabled mmal
&&
{
check_lib interface/mmal/mmal.h mmal_port_connect
-lmmal_core
-lmmal_util
-lmmal_vc_client
-lbcm_host
||
{
!
enabled cross_compile
&&
{
{
!
enabled cross_compile
&&
{
add_cflags
-isystem
/opt/vc/include/
-isystem
/opt/vc/include/interface/vmcs_host/linux
-isystem
/opt/vc/include/interface/vcos/pthreads
-fgnu89-inline
;
add_cflags
-isystem
/opt/vc/include/
-isystem
/opt/vc/include/interface/vmcs_host/linux
-isystem
/opt/vc/include/interface/vcos/pthreads
-fgnu89-inline
;
...
...
libavcodec/Makefile
View file @
4737fe69
...
@@ -91,6 +91,7 @@ OBJS-$(CONFIG_LSP) += lsp.o
...
@@ -91,6 +91,7 @@ OBJS-$(CONFIG_LSP) += lsp.o
OBJS-$(CONFIG_LZF)
+=
lzf.o
OBJS-$(CONFIG_LZF)
+=
lzf.o
OBJS-$(CONFIG_MDCT)
+=
mdct_fixed.o
mdct_float.o
mdct_fixed_32.o
OBJS-$(CONFIG_MDCT)
+=
mdct_fixed.o
mdct_float.o
mdct_fixed_32.o
OBJS-$(CONFIG_ME_CMP)
+=
me_cmp.o
OBJS-$(CONFIG_ME_CMP)
+=
me_cmp.o
OBJS-$(CONFIG_MEDIACODEC)
+=
mediacodecdec.o
mediacodec_wrapper.o
mediacodec_sw_buffer.o
OBJS-$(CONFIG_MPEG_ER)
+=
mpeg_er.o
OBJS-$(CONFIG_MPEG_ER)
+=
mpeg_er.o
OBJS-$(CONFIG_MPEGAUDIO)
+=
mpegaudio.o
mpegaudiodata.o
\
OBJS-$(CONFIG_MPEGAUDIO)
+=
mpegaudio.o
mpegaudiodata.o
\
mpegaudiodecheader.o
mpegaudiodecheader.o
...
@@ -306,6 +307,7 @@ OBJS-$(CONFIG_H264_DECODER) += h264.o h264_cabac.o h264_cavlc.o \
...
@@ -306,6 +307,7 @@ OBJS-$(CONFIG_H264_DECODER) += h264.o h264_cabac.o h264_cavlc.o \
h264_direct.o
h264_loopfilter.o
\
h264_direct.o
h264_loopfilter.o
\
h264_mb.o
h264_picture.o
h264_ps.o
\
h264_mb.o
h264_picture.o
h264_ps.o
\
h264_refs.o
h264_sei.o
h264_slice.o
h264_refs.o
h264_sei.o
h264_slice.o
OBJS-$(CONFIG_H264_MEDIACODEC_DECODER)
+=
mediacodecdec_h264.o
OBJS-$(CONFIG_H264_MMAL_DECODER)
+=
mmaldec.o
OBJS-$(CONFIG_H264_MMAL_DECODER)
+=
mmaldec.o
OBJS-$(CONFIG_H264_VDA_DECODER)
+=
vda_h264_dec.o
OBJS-$(CONFIG_H264_VDA_DECODER)
+=
vda_h264_dec.o
OBJS-$(CONFIG_H264_QSV_DECODER)
+=
qsvdec_h2645.o
OBJS-$(CONFIG_H264_QSV_DECODER)
+=
qsvdec_h2645.o
...
@@ -944,6 +946,7 @@ SKIPHEADERS-$(CONFIG_LIBSCHROEDINGER) += libschroedinger.h
...
@@ -944,6 +946,7 @@ SKIPHEADERS-$(CONFIG_LIBSCHROEDINGER) += libschroedinger.h
SKIPHEADERS-$(CONFIG_LIBUTVIDEO)
+=
libutvideo.h
SKIPHEADERS-$(CONFIG_LIBUTVIDEO)
+=
libutvideo.h
SKIPHEADERS-$(CONFIG_LIBVPX)
+=
libvpx.h
SKIPHEADERS-$(CONFIG_LIBVPX)
+=
libvpx.h
SKIPHEADERS-$(CONFIG_LIBWEBP_ENCODER)
+=
libwebpenc_common.h
SKIPHEADERS-$(CONFIG_LIBWEBP_ENCODER)
+=
libwebpenc_common.h
SKIPHEADERS-$(CONFIG_MEDIACODEC)
+=
mediacodecdec.h
mediacodec_wrapper.h
mediacodec_sw_buffer.h
SKIPHEADERS-$(CONFIG_QSV)
+=
qsv.h
qsv_internal.h
SKIPHEADERS-$(CONFIG_QSV)
+=
qsv.h
qsv_internal.h
SKIPHEADERS-$(CONFIG_QSVDEC)
+=
qsvdec.h
SKIPHEADERS-$(CONFIG_QSVDEC)
+=
qsvdec.h
SKIPHEADERS-$(CONFIG_QSVENC)
+=
qsvenc.h
SKIPHEADERS-$(CONFIG_QSVENC)
+=
qsvenc.h
...
...
libavcodec/allcodecs.c
View file @
4737fe69
...
@@ -196,6 +196,7 @@ void avcodec_register_all(void)
...
@@ -196,6 +196,7 @@ void avcodec_register_all(void)
REGISTER_ENCDEC
(
H263P
,
h263p
);
REGISTER_ENCDEC
(
H263P
,
h263p
);
REGISTER_DECODER
(
H264
,
h264
);
REGISTER_DECODER
(
H264
,
h264
);
REGISTER_DECODER
(
H264_CRYSTALHD
,
h264_crystalhd
);
REGISTER_DECODER
(
H264_CRYSTALHD
,
h264_crystalhd
);
REGISTER_DECODER
(
H264_MEDIACODEC
,
h264_mediacodec
);
REGISTER_DECODER
(
H264_MMAL
,
h264_mmal
);
REGISTER_DECODER
(
H264_MMAL
,
h264_mmal
);
REGISTER_DECODER
(
H264_QSV
,
h264_qsv
);
REGISTER_DECODER
(
H264_QSV
,
h264_qsv
);
REGISTER_DECODER
(
H264_VDA
,
h264_vda
);
REGISTER_DECODER
(
H264_VDA
,
h264_vda
);
...
...
libavcodec/mediacodec_sw_buffer.c
0 → 100644
View file @
4737fe69
/*
* Android MediaCodec software buffer copy functions
*
* Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include <sys/types.h>
#include "libavutil/frame.h"
#include "libavutil/mem.h"
#include "avcodec.h"
#include "mediacodecdec.h"
#include "mediacodec_wrapper.h"
#include "mediacodec_sw_buffer.h"
#define QCOM_TILE_WIDTH 64
#define QCOM_TILE_HEIGHT 32
#define QCOM_TILE_SIZE (QCOM_TILE_WIDTH * QCOM_TILE_HEIGHT)
#define QCOM_TILE_GROUP_SIZE (4 * QCOM_TILE_SIZE)
/**
* The code handling the the various YUV color formats is taken from the
* GStreamer project.
*
* Gstreamer reference:
* https://cgit.freedesktop.org/gstreamer/gst-plugins-bad/tree/sys/androidmedia/
*
* Copyright (C) 2012, Collabora Ltd.
* Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* Copyright (C) 2012, Rafaël Carré <funman@videolanorg>
*
* Copyright (C) 2015, Sebastian Dröge <sebastian@centricular.com>
*
* Copyright (C) 2014-2015, Collabora Ltd.
* Author: Matthieu Bouron <matthieu.bouron@gcollabora.com>
*
* Copyright (C) 2015, Edward Hervey
* Author: Edward Hervey <bilboed@gmail.com>
*
* Copyright (C) 2015, Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
void
ff_mediacodec_sw_buffer_copy_yuv420_planar
(
AVCodecContext
*
avctx
,
MediaCodecDecContext
*
s
,
uint8_t
*
data
,
size_t
size
,
FFAMediaCodecBufferInfo
*
info
,
AVFrame
*
frame
)
{
int
i
;
uint8_t
*
src
=
NULL
;
for
(
i
=
0
;
i
<
3
;
i
++
)
{
int
stride
=
s
->
stride
;
int
height
;
src
=
data
+
info
->
offset
;
if
(
i
==
0
)
{
height
=
avctx
->
height
;
src
+=
s
->
crop_top
*
s
->
stride
;
src
+=
s
->
crop_left
;
}
else
{
height
=
avctx
->
height
/
2
;
stride
=
(
s
->
stride
+
1
)
/
2
;
src
+=
s
->
slice_height
*
s
->
stride
;
if
(
i
==
2
)
{
src
+=
((
s
->
slice_height
+
1
)
/
2
)
*
stride
;
}
src
+=
s
->
crop_top
*
stride
;
src
+=
(
s
->
crop_left
/
2
);
}
if
(
frame
->
linesize
[
i
]
==
stride
)
{
memcpy
(
frame
->
data
[
i
],
src
,
height
*
stride
);
}
else
{
int
j
,
width
;
uint8_t
*
dst
=
frame
->
data
[
i
];
if
(
i
==
0
)
{
width
=
avctx
->
width
;
}
else
if
(
i
==
1
)
{
width
=
FFMIN
(
frame
->
linesize
[
i
],
FFALIGN
(
avctx
->
width
,
2
));
}
for
(
j
=
0
;
j
<
height
;
j
++
)
{
memcpy
(
dst
,
src
,
width
);
src
+=
stride
;
dst
+=
frame
->
linesize
[
i
];
}
}
}
}
void
ff_mediacodec_sw_buffer_copy_yuv420_semi_planar
(
AVCodecContext
*
avctx
,
MediaCodecDecContext
*
s
,
uint8_t
*
data
,
size_t
size
,
FFAMediaCodecBufferInfo
*
info
,
AVFrame
*
frame
)
{
int
i
;
uint8_t
*
src
=
NULL
;
for
(
i
=
0
;
i
<
2
;
i
++
)
{
int
height
;
src
=
data
+
info
->
offset
;
if
(
i
==
0
)
{
height
=
avctx
->
height
;
src
+=
s
->
crop_top
*
s
->
stride
;
src
+=
s
->
crop_left
;
}
else
if
(
i
==
1
)
{
height
=
avctx
->
height
/
2
;
src
+=
s
->
slice_height
*
s
->
stride
;
src
+=
s
->
crop_top
*
s
->
stride
;
src
+=
s
->
crop_left
;
}
if
(
frame
->
linesize
[
i
]
==
s
->
stride
)
{
memcpy
(
frame
->
data
[
i
],
src
,
height
*
s
->
stride
);
}
else
{
int
j
,
width
;
uint8_t
*
dst
=
frame
->
data
[
i
];
if
(
i
==
0
)
{
width
=
avctx
->
width
;
}
else
if
(
i
==
1
)
{
width
=
FFMIN
(
frame
->
linesize
[
i
],
FFALIGN
(
avctx
->
width
,
2
));
}
for
(
j
=
0
;
j
<
height
;
j
++
)
{
memcpy
(
dst
,
src
,
width
);
src
+=
s
->
stride
;
dst
+=
frame
->
linesize
[
i
];
}
}
}
}
void
ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar
(
AVCodecContext
*
avctx
,
MediaCodecDecContext
*
s
,
uint8_t
*
data
,
size_t
size
,
FFAMediaCodecBufferInfo
*
info
,
AVFrame
*
frame
)
{
int
i
;
uint8_t
*
src
=
NULL
;
for
(
i
=
0
;
i
<
2
;
i
++
)
{
int
height
;
src
=
data
+
info
->
offset
;
if
(
i
==
0
)
{
height
=
avctx
->
height
;
}
else
if
(
i
==
1
)
{
height
=
avctx
->
height
/
2
;
src
+=
(
s
->
slice_height
-
s
->
crop_top
/
2
)
*
s
->
stride
;
src
+=
s
->
crop_top
*
s
->
stride
;
src
+=
s
->
crop_left
;
}
if
(
frame
->
linesize
[
i
]
==
s
->
stride
)
{
memcpy
(
frame
->
data
[
i
],
src
,
height
*
s
->
stride
);
}
else
{
int
j
,
width
;
uint8_t
*
dst
=
frame
->
data
[
i
];
if
(
i
==
0
)
{
width
=
avctx
->
width
;
}
else
if
(
i
==
1
)
{
width
=
FFMIN
(
frame
->
linesize
[
i
],
FFALIGN
(
avctx
->
width
,
2
));
}
for
(
j
=
0
;
j
<
height
;
j
++
)
{
memcpy
(
dst
,
src
,
width
);
src
+=
s
->
stride
;
dst
+=
frame
->
linesize
[
i
];
}
}
}
}
/**
* The code handling the QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka
* color format is taken from the VLC project.
*
* VLC reference:
* http://git.videolan.org/?p=vlc.git;a=blob;f=modules/codec/omxil/qcom.c;hb=HEAD
*
* VLC copyright notice:
*
*****************************************************************************
* qcom.c : pixel format translation for Qualcomm tiled nv12
*****************************************************************************
* Copyright © 2012 Rafaël Carré
*
* Authors: Rafaël Carré <funman@videolanorg>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*
*/
static
size_t
qcom_tile_pos
(
size_t
x
,
size_t
y
,
size_t
w
,
size_t
h
)
{
size_t
flim
=
x
+
(
y
&
~
1
)
*
w
;
if
(
y
&
1
)
{
flim
+=
(
x
&
~
3
)
+
2
;
}
else
if
((
h
&
1
)
==
0
||
y
!=
(
h
-
1
))
{
flim
+=
(
x
+
2
)
&
~
3
;
}
return
flim
;
}
void
ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar_64x32Tile2m8ka
(
AVCodecContext
*
avctx
,
MediaCodecDecContext
*
s
,
uint8_t
*
data
,
size_t
size
,
FFAMediaCodecBufferInfo
*
info
,
AVFrame
*
frame
)
{
size_t
width
=
frame
->
width
;
size_t
linesize
=
frame
->
linesize
[
0
];
size_t
height
=
frame
->
height
;
const
size_t
tile_w
=
(
width
-
1
)
/
QCOM_TILE_WIDTH
+
1
;
const
size_t
tile_w_align
=
(
tile_w
+
1
)
&
~
1
;
const
size_t
tile_h_luma
=
(
height
-
1
)
/
QCOM_TILE_HEIGHT
+
1
;
const
size_t
tile_h_chroma
=
(
height
/
2
-
1
)
/
QCOM_TILE_HEIGHT
+
1
;
size_t
luma_size
=
tile_w_align
*
tile_h_luma
*
QCOM_TILE_SIZE
;
if
((
luma_size
%
QCOM_TILE_GROUP_SIZE
)
!=
0
)
luma_size
=
(((
luma_size
-
1
)
/
QCOM_TILE_GROUP_SIZE
)
+
1
)
*
QCOM_TILE_GROUP_SIZE
;
for
(
size_t
y
=
0
;
y
<
tile_h_luma
;
y
++
)
{
size_t
row_width
=
width
;
for
(
size_t
x
=
0
;
x
<
tile_w
;
x
++
)
{
size_t
tile_width
=
row_width
;
size_t
tile_height
=
height
;
/* dest luma memory index for this tile */
size_t
luma_idx
=
y
*
QCOM_TILE_HEIGHT
*
linesize
+
x
*
QCOM_TILE_WIDTH
;
/* dest chroma memory index for this tile */
/* XXX: remove divisions */
size_t
chroma_idx
=
(
luma_idx
/
linesize
)
*
linesize
/
2
+
(
luma_idx
%
linesize
);
/* luma source pointer for this tile */
const
uint8_t
*
src_luma
=
data
+
qcom_tile_pos
(
x
,
y
,
tile_w_align
,
tile_h_luma
)
*
QCOM_TILE_SIZE
;
/* chroma source pointer for this tile */
const
uint8_t
*
src_chroma
=
data
+
luma_size
+
qcom_tile_pos
(
x
,
y
/
2
,
tile_w_align
,
tile_h_chroma
)
*
QCOM_TILE_SIZE
;
if
(
y
&
1
)
src_chroma
+=
QCOM_TILE_SIZE
/
2
;
/* account for right columns */
if
(
tile_width
>
QCOM_TILE_WIDTH
)
tile_width
=
QCOM_TILE_WIDTH
;
/* account for bottom rows */
if
(
tile_height
>
QCOM_TILE_HEIGHT
)
tile_height
=
QCOM_TILE_HEIGHT
;
tile_height
/=
2
;
while
(
tile_height
--
)
{
memcpy
(
frame
->
data
[
0
]
+
luma_idx
,
src_luma
,
tile_width
);
src_luma
+=
QCOM_TILE_WIDTH
;
luma_idx
+=
linesize
;
memcpy
(
frame
->
data
[
0
]
+
luma_idx
,
src_luma
,
tile_width
);
src_luma
+=
QCOM_TILE_WIDTH
;
luma_idx
+=
linesize
;
memcpy
(
frame
->
data
[
1
]
+
chroma_idx
,
src_chroma
,
tile_width
);
src_chroma
+=
QCOM_TILE_WIDTH
;
chroma_idx
+=
linesize
;
}
row_width
-=
QCOM_TILE_WIDTH
;
}
height
-=
QCOM_TILE_HEIGHT
;
}
}
libavcodec/mediacodec_sw_buffer.h
0 → 100644
View file @
4737fe69
/*
* Android MediaCodec software buffer copy functions
*
* Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_MEDIACODEC_SW_BUFFER_H
#define AVCODEC_MEDIACODEC_SW_BUFFER_H
#include <sys/types.h>
#include "libavutil/frame.h"
#include "avcodec.h"
#include "mediacodecdec.h"
#include "mediacodec_wrapper.h"
void
ff_mediacodec_sw_buffer_copy_yuv420_planar
(
AVCodecContext
*
avctx
,
MediaCodecDecContext
*
s
,
uint8_t
*
data
,
size_t
size
,
FFAMediaCodecBufferInfo
*
info
,
AVFrame
*
frame
);
void
ff_mediacodec_sw_buffer_copy_yuv420_semi_planar
(
AVCodecContext
*
avctx
,
MediaCodecDecContext
*
s
,
uint8_t
*
data
,
size_t
size
,
FFAMediaCodecBufferInfo
*
info
,
AVFrame
*
frame
);
void
ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar
(
AVCodecContext
*
avctx
,
MediaCodecDecContext
*
s
,
uint8_t
*
data
,
size_t
size
,
FFAMediaCodecBufferInfo
*
info
,
AVFrame
*
frame
);
void
ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar_64x32Tile2m8ka
(
AVCodecContext
*
avctx
,
MediaCodecDecContext
*
s
,
uint8_t
*
data
,
size_t
size
,
FFAMediaCodecBufferInfo
*
info
,
AVFrame
*
frame
);
#endif
/* AVCODEC_MEDIACODEC_SW_BUFFER_H */
libavcodec/mediacodec_wrapper.c
0 → 100644
View file @
4737fe69
/*
* Android MediaCodec Wrapper
*
* Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <jni.h>
#include "libavutil/avassert.h"
#include "libavutil/mem.h"
#include "libavutil/avstring.h"
#include "ffjni.h"
#include "version.h"
#include "mediacodec_wrapper.h"
struct
JNIAMediaCodecListFields
{
jclass
mediaformat_class
;
jmethodID
create_video_format_id
;
jclass
mediacodec_list_class
;
jmethodID
init_id
;
jmethodID
find_decoder_for_format_id
;
jmethodID
get_codec_count_id
;
jmethodID
get_codec_info_at_id
;
jclass
mediacodec_info_class
;
jmethodID
get_name_id
;
jmethodID
get_supported_types_id
;
jmethodID
is_encoder_id
;
}
JNIAMediaCodecListFields
;
static
const
struct
FFJniField
jfields_mapping
[]
=
{
{
"android/media/MediaFormat"
,
NULL
,
NULL
,
FF_JNI_CLASS
,
offsetof
(
struct
JNIAMediaCodecListFields
,
mediaformat_class
),
1
},
{
"android/media/MediaFormat"
,
"createVideoFormat"
,
"(Ljava/lang/String;II)Landroid/media/MediaFormat;"
,
FF_JNI_STATIC_METHOD
,
offsetof
(
struct
JNIAMediaCodecListFields
,
create_video_format_id
),
1
},
{
"android/media/MediaCodecList"
,
NULL
,
NULL
,
FF_JNI_CLASS
,
offsetof
(
struct
JNIAMediaCodecListFields
,
mediacodec_list_class
),
1
},
{
"android/media/MediaCodecList"
,
"<init>"
,
"(I)V"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecListFields
,
init_id
),
0
},
{
"android/media/MediaCodecList"
,
"findDecoderForFormat"
,
"(Landroid/media/MediaFormat;)Ljava/lang/String;"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecListFields
,
find_decoder_for_format_id
),
0
},
{
"android/media/MediaCodecList"
,
"getCodecCount"
,
"()I"
,
FF_JNI_STATIC_METHOD
,
offsetof
(
struct
JNIAMediaCodecListFields
,
get_codec_count_id
),
1
},
{
"android/media/MediaCodecList"
,
"getCodecInfoAt"
,
"(I)Landroid/media/MediaCodecInfo;"
,
FF_JNI_STATIC_METHOD
,
offsetof
(
struct
JNIAMediaCodecListFields
,
get_codec_info_at_id
),
1
},
{
"android/media/MediaCodecInfo"
,
NULL
,
NULL
,
FF_JNI_CLASS
,
offsetof
(
struct
JNIAMediaCodecListFields
,
mediacodec_info_class
),
1
},
{
"android/media/MediaCodecInfo"
,
"getName"
,
"()Ljava/lang/String;"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecListFields
,
get_name_id
),
1
},
{
"android/media/MediaCodecInfo"
,
"getSupportedTypes"
,
"()[Ljava/lang/String;"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecListFields
,
get_supported_types_id
),
1
},
{
"android/media/MediaCodecInfo"
,
"isEncoder"
,
"()Z"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecListFields
,
is_encoder_id
),
1
},
{
NULL
}
};
#define JNI_ATTACH_ENV_OR_RETURN(env, attached, log_ctx, ret) do { \
(env) = ff_jni_attach_env(attached, log_ctx); \
if (!(env)) { \
return ret; \
} \
} while (0)
#define JNI_ATTACH_ENV_OR_RETURN_VOID(env, attached, log_ctx) do { \
(env) = ff_jni_attach_env(attached, log_ctx); \
if (!(env)) { \
return; \
} \
} while (0)
#define JNI_DETACH_ENV(attached, log_ctx) do { \
if (attached) \
ff_jni_detach_env(log_ctx); \
} while (0)
char
*
ff_AMediaCodecList_getCodecNameByType
(
const
char
*
mime
,
int
width
,
int
height
,
void
*
log_ctx
)
{
int
ret
;
char
*
name
=
NULL
;
char
*
supported_type
=
NULL
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
struct
JNIAMediaCodecListFields
jfields
=
{
0
};
jobject
format
=
NULL
;
jobject
codec
=
NULL
;
jstring
tmp
=
NULL
;
jobject
info
=
NULL
;
jobject
type
=
NULL
;
jobjectArray
types
=
NULL
;
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
log_ctx
,
NULL
);
if
((
ret
=
ff_jni_init_jfields
(
env
,
&
jfields
,
jfields_mapping
,
0
,
log_ctx
))
<
0
)
{
goto
done
;
}
if
(
jfields
.
init_id
&&
jfields
.
find_decoder_for_format_id
)
{
tmp
=
ff_jni_utf_chars_to_jstring
(
env
,
mime
,
log_ctx
);
if
(
!
tmp
)
{
goto
done
;
}
format
=
(
*
env
)
->
CallStaticObjectMethod
(
env
,
jfields
.
mediaformat_class
,
jfields
.
create_video_format_id
,
tmp
,
width
,
height
);
if
(
ff_jni_exception_check
(
env
,
1
,
log_ctx
)
<
0
)
{
goto
done
;
}
(
*
env
)
->
DeleteLocalRef
(
env
,
tmp
);
codec
=
(
*
env
)
->
NewObject
(
env
,
jfields
.
mediacodec_list_class
,
jfields
.
init_id
,
0
);
if
(
ff_jni_exception_check
(
env
,
1
,
log_ctx
)
<
0
)
{
goto
done
;
}
tmp
=
(
*
env
)
->
CallObjectMethod
(
env
,
codec
,
jfields
.
find_decoder_for_format_id
,
format
);
if
(
ff_jni_exception_check
(
env
,
1
,
log_ctx
)
<
0
)
{
goto
done
;
}
if
(
!
tmp
)
{
av_log
(
NULL
,
AV_LOG_ERROR
,
"Could not find decoder in media codec list "
"for format { mime=%s width=%d height=%d }
\n
"
,
mime
,
width
,
height
);
goto
done
;
}
name
=
ff_jni_jstring_to_utf_chars
(
env
,
tmp
,
log_ctx
);
if
(
!
name
)
{
goto
done
;
}
}
else
{
int
i
;
int
codec_count
;
codec_count
=
(
*
env
)
->
CallStaticIntMethod
(
env
,
jfields
.
mediacodec_list_class
,
jfields
.
get_codec_count_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
log_ctx
)
<
0
)
{
goto
done
;
}
for
(
i
=
0
;
i
<
codec_count
;
i
++
)
{
int
j
;
int
type_count
;
int
is_encoder
;
info
=
(
*
env
)
->
CallStaticObjectMethod
(
env
,
jfields
.
mediacodec_list_class
,
jfields
.
get_codec_info_at_id
,
i
);
if
(
ff_jni_exception_check
(
env
,
1
,
log_ctx
)
<
0
)
{
goto
done
;
}
types
=
(
*
env
)
->
CallObjectMethod
(
env
,
info
,
jfields
.
get_supported_types_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
log_ctx
)
<
0
)
{
goto
done
;
}
is_encoder
=
(
*
env
)
->
CallBooleanMethod
(
env
,
info
,
jfields
.
is_encoder_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
log_ctx
)
<
0
)
{
goto
done
;
}
if
(
is_encoder
)
{
continue
;
}
type_count
=
(
*
env
)
->
GetArrayLength
(
env
,
types
);
for
(
j
=
0
;
j
<
type_count
;
j
++
)
{
type
=
(
*
env
)
->
GetObjectArrayElement
(
env
,
types
,
j
);
if
(
ff_jni_exception_check
(
env
,
1
,
log_ctx
)
<
0
)
{
goto
done
;
}
supported_type
=
ff_jni_jstring_to_utf_chars
(
env
,
type
,
log_ctx
);
if
(
!
supported_type
)
{
goto
done
;
}
if
(
!
av_strcasecmp
(
supported_type
,
mime
))
{
jobject
codec_name
;
codec_name
=
(
*
env
)
->
CallObjectMethod
(
env
,
info
,
jfields
.
get_name_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
log_ctx
)
<
0
)
{
goto
done
;
}
name
=
ff_jni_jstring_to_utf_chars
(
env
,
codec_name
,
log_ctx
);
if
(
!
name
)
{
goto
done
;
}
if
(
strstr
(
name
,
"OMX.google"
))
{
av_freep
(
&
name
);
continue
;
}
}
av_freep
(
&
supported_type
);
}
(
*
env
)
->
DeleteLocalRef
(
env
,
info
);
info
=
NULL
;
(
*
env
)
->
DeleteLocalRef
(
env
,
types
);
types
=
NULL
;
if
(
name
)
break
;
}
}
done:
if
(
format
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
format
);
}
if
(
codec
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
codec
);
}
if
(
tmp
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
tmp
);
}
if
(
info
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
info
);
}
if
(
type
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
type
);
}
if
(
types
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
types
);
}
av_freep
(
&
supported_type
);
ff_jni_reset_jfields
(
env
,
&
jfields
,
jfields_mapping
,
0
,
log_ctx
);
JNI_DETACH_ENV
(
attached
,
log_ctx
);
return
name
;
}
struct
JNIAMediaFormatFields
{
jclass
clazz
;
jmethodID
init_id
;
jmethodID
get_integer_id
;
jmethodID
get_long_id
;
jmethodID
get_float_id
;
jmethodID
get_bytebuffer_id
;
jmethodID
get_string_id
;
jmethodID
set_integer_id
;
jmethodID
set_long_id
;
jmethodID
set_float_id
;
jmethodID
set_bytebuffer_id
;
jmethodID
set_string_id
;
jmethodID
to_string_id
;
}
JNIAMediaFormatFields
;
static
const
struct
FFJniField
jni_amediaformat_mapping
[]
=
{
{
"android/media/MediaFormat"
,
NULL
,
NULL
,
FF_JNI_CLASS
,
offsetof
(
struct
JNIAMediaFormatFields
,
clazz
),
1
},
{
"android/media/MediaFormat"
,
"<init>"
,
"()V"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaFormatFields
,
init_id
),
1
},
{
"android/media/MediaFormat"
,
"getInteger"
,
"(Ljava/lang/String;)I"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaFormatFields
,
get_integer_id
),
1
},
{
"android/media/MediaFormat"
,
"getLong"
,
"(Ljava/lang/String;)J"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaFormatFields
,
get_long_id
),
1
},
{
"android/media/MediaFormat"
,
"getFloat"
,
"(Ljava/lang/String;)F"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaFormatFields
,
get_float_id
),
1
},
{
"android/media/MediaFormat"
,
"getByteBuffer"
,
"(Ljava/lang/String;)Ljava/nio/ByteBuffer;"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaFormatFields
,
get_bytebuffer_id
),
1
},
{
"android/media/MediaFormat"
,
"getString"
,
"(Ljava/lang/String;)Ljava/lang/String;"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaFormatFields
,
get_string_id
),
1
},
{
"android/media/MediaFormat"
,
"setInteger"
,
"(Ljava/lang/String;I)V"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaFormatFields
,
set_integer_id
),
1
},
{
"android/media/MediaFormat"
,
"setLong"
,
"(Ljava/lang/String;J)V"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaFormatFields
,
set_long_id
),
1
},
{
"android/media/MediaFormat"
,
"setFloat"
,
"(Ljava/lang/String;F)V"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaFormatFields
,
set_float_id
),
1
},
{
"android/media/MediaFormat"
,
"setByteBuffer"
,
"(Ljava/lang/String;Ljava/nio/ByteBuffer;)V"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaFormatFields
,
set_bytebuffer_id
),
1
},
{
"android/media/MediaFormat"
,
"setString"
,
"(Ljava/lang/String;Ljava/lang/String;)V"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaFormatFields
,
set_string_id
),
1
},
{
"android/media/MediaFormat"
,
"toString"
,
"()Ljava/lang/String;"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaFormatFields
,
to_string_id
),
1
},
{
NULL
}
};
static
const
AVClass
amediaformat_class
=
{
.
class_name
=
"amediaformat"
,
.
item_name
=
av_default_item_name
,
.
version
=
LIBAVCODEC_VERSION_INT
,
};
struct
FFAMediaFormat
{
const
AVClass
*
class
;
struct
JNIAMediaFormatFields
jfields
;
jobject
object
;
};
FFAMediaFormat
*
ff_AMediaFormat_new
(
void
)
{
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
FFAMediaFormat
*
format
=
NULL
;
format
=
av_mallocz
(
sizeof
(
FFAMediaFormat
));
if
(
!
format
)
{
return
NULL
;
}
format
->
class
=
&
amediaformat_class
;
env
=
ff_jni_attach_env
(
&
attached
,
format
);
if
(
!
env
)
{
av_freep
(
&
format
);
return
NULL
;
}
if
(
ff_jni_init_jfields
(
env
,
&
format
->
jfields
,
jni_amediaformat_mapping
,
1
,
format
)
<
0
)
{
goto
fail
;
}
format
->
object
=
(
*
env
)
->
NewObject
(
env
,
format
->
jfields
.
clazz
,
format
->
jfields
.
init_id
);
if
(
!
format
->
object
)
{
goto
fail
;
}
format
->
object
=
(
*
env
)
->
NewGlobalRef
(
env
,
format
->
object
);
if
(
!
format
->
object
)
{
goto
fail
;
}
JNI_DETACH_ENV
(
attached
,
format
);
return
format
;
fail:
ff_jni_reset_jfields
(
env
,
&
format
->
jfields
,
jni_amediaformat_mapping
,
1
,
format
);
JNI_DETACH_ENV
(
attached
,
format
);
av_freep
(
&
format
);
return
NULL
;
}
static
FFAMediaFormat
*
ff_AMediaFormat_newFromObject
(
void
*
object
)
{
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
FFAMediaFormat
*
format
=
NULL
;
format
=
av_mallocz
(
sizeof
(
FFAMediaFormat
));
if
(
!
format
)
{
return
NULL
;
}
format
->
class
=
&
amediaformat_class
;
env
=
ff_jni_attach_env
(
&
attached
,
format
);
if
(
!
env
)
{
av_freep
(
&
format
);
return
NULL
;
}
if
(
ff_jni_init_jfields
(
env
,
&
format
->
jfields
,
jni_amediaformat_mapping
,
1
,
format
)
<
0
)
{
goto
fail
;
}
format
->
object
=
(
*
env
)
->
NewGlobalRef
(
env
,
object
);
if
(
!
format
->
object
)
{
goto
fail
;
}
JNI_DETACH_ENV
(
attached
,
format
);
return
format
;
fail:
ff_jni_reset_jfields
(
env
,
&
format
->
jfields
,
jni_amediaformat_mapping
,
1
,
format
);
JNI_DETACH_ENV
(
attached
,
format
);
av_freep
(
&
format
);
return
NULL
;
}
int
ff_AMediaFormat_delete
(
FFAMediaFormat
*
format
)
{
int
ret
=
0
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
if
(
!
format
)
{
return
0
;
}
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
format
,
AVERROR_EXTERNAL
);
(
*
env
)
->
DeleteGlobalRef
(
env
,
format
->
object
);
format
->
object
=
NULL
;
ff_jni_reset_jfields
(
env
,
&
format
->
jfields
,
jni_amediaformat_mapping
,
1
,
format
);
JNI_DETACH_ENV
(
attached
,
format
);
av_freep
(
&
format
);
return
ret
;
}
char
*
ff_AMediaFormat_toString
(
FFAMediaFormat
*
format
)
{
char
*
ret
=
NULL
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
jstring
description
=
NULL
;
av_assert0
(
format
!=
NULL
);
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
format
,
NULL
);
description
=
(
*
env
)
->
CallObjectMethod
(
env
,
format
->
object
,
format
->
jfields
.
to_string_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
NULL
)
<
0
)
{
goto
fail
;
}
ret
=
ff_jni_jstring_to_utf_chars
(
env
,
description
,
format
);
fail:
if
(
description
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
description
);
}
JNI_DETACH_ENV
(
attached
,
format
);
return
ret
;
}
int
ff_AMediaFormat_getInt32
(
FFAMediaFormat
*
format
,
const
char
*
name
,
int32_t
*
out
)
{
int
ret
=
1
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
jstring
key
=
NULL
;
av_assert0
(
format
!=
NULL
);
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
format
,
0
);
key
=
ff_jni_utf_chars_to_jstring
(
env
,
name
,
format
);
if
(
!
key
)
{
ret
=
0
;
goto
fail
;
}
*
out
=
(
*
env
)
->
CallIntMethod
(
env
,
format
->
object
,
format
->
jfields
.
get_integer_id
,
key
);
if
((
ret
=
ff_jni_exception_check
(
env
,
1
,
format
))
<
0
)
{
ret
=
0
;
goto
fail
;
}
ret
=
1
;
fail:
if
(
key
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
key
);
}
JNI_DETACH_ENV
(
attached
,
format
);
return
ret
;
}
int
ff_AMediaFormat_getInt64
(
FFAMediaFormat
*
format
,
const
char
*
name
,
int64_t
*
out
)
{
int
ret
=
1
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
jstring
key
=
NULL
;
av_assert0
(
format
!=
NULL
);
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
format
,
0
);
key
=
ff_jni_utf_chars_to_jstring
(
env
,
name
,
format
);
if
(
!
key
)
{
ret
=
0
;
goto
fail
;
}
*
out
=
(
*
env
)
->
CallLongMethod
(
env
,
format
->
object
,
format
->
jfields
.
get_long_id
,
key
);
if
((
ret
=
ff_jni_exception_check
(
env
,
1
,
format
))
<
0
)
{
ret
=
0
;
goto
fail
;
}
ret
=
1
;
fail:
if
(
key
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
key
);
}
JNI_DETACH_ENV
(
attached
,
format
);
return
ret
;
}
int
ff_AMediaFormat_getFloat
(
FFAMediaFormat
*
format
,
const
char
*
name
,
float
*
out
)
{
int
ret
=
1
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
jstring
key
=
NULL
;
av_assert0
(
format
!=
NULL
);
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
format
,
0
);
key
=
ff_jni_utf_chars_to_jstring
(
env
,
name
,
format
);
if
(
!
key
)
{
ret
=
0
;
goto
fail
;
}
*
out
=
(
*
env
)
->
CallFloatMethod
(
env
,
format
->
object
,
format
->
jfields
.
get_float_id
,
key
);
if
((
ret
=
ff_jni_exception_check
(
env
,
1
,
format
))
<
0
)
{
ret
=
0
;
goto
fail
;
}
ret
=
1
;
fail:
if
(
key
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
key
);
}
JNI_DETACH_ENV
(
attached
,
format
);
return
ret
;
}
int
ff_AMediaFormat_getBuffer
(
FFAMediaFormat
*
format
,
const
char
*
name
,
void
**
data
,
size_t
*
size
)
{
int
ret
=
1
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
jstring
key
=
NULL
;
jobject
result
=
NULL
;
av_assert0
(
format
!=
NULL
);
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
format
,
0
);
key
=
ff_jni_utf_chars_to_jstring
(
env
,
name
,
format
);
if
(
!
key
)
{
ret
=
0
;
goto
fail
;
}
result
=
(
*
env
)
->
CallObjectMethod
(
env
,
format
->
object
,
format
->
jfields
.
get_bytebuffer_id
,
key
);
if
((
ret
=
ff_jni_exception_check
(
env
,
1
,
format
))
<
0
)
{
ret
=
0
;
goto
fail
;
}
*
data
=
(
*
env
)
->
GetDirectBufferAddress
(
env
,
result
);
*
size
=
(
*
env
)
->
GetDirectBufferCapacity
(
env
,
result
);
if
(
*
data
&&
*
size
)
{
void
*
src
=
*
data
;
*
data
=
av_malloc
(
*
size
);
if
(
!*
data
)
{
ret
=
0
;
goto
fail
;
}
memcpy
(
*
data
,
src
,
*
size
);
}
ret
=
1
;
fail:
if
(
key
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
key
);
}
if
(
result
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
result
);
}
JNI_DETACH_ENV
(
attached
,
format
);
return
ret
;
}
int
ff_AMediaFormat_getString
(
FFAMediaFormat
*
format
,
const
char
*
name
,
const
char
**
out
)
{
int
ret
=
1
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
jstring
key
=
NULL
;
jstring
result
=
NULL
;
av_assert0
(
format
!=
NULL
);
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
format
,
0
);
key
=
ff_jni_utf_chars_to_jstring
(
env
,
name
,
format
);
if
(
!
key
)
{
ret
=
0
;
goto
fail
;
}
result
=
(
*
env
)
->
CallObjectMethod
(
env
,
format
->
object
,
format
->
jfields
.
get_string_id
,
key
);
if
((
ret
=
ff_jni_exception_check
(
env
,
1
,
format
))
<
0
)
{
ret
=
0
;
goto
fail
;
}
*
out
=
ff_jni_jstring_to_utf_chars
(
env
,
result
,
format
);
if
(
!*
out
)
{
ret
=
0
;
goto
fail
;
}
ret
=
1
;
fail:
if
(
key
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
key
);
}
if
(
result
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
result
);
}
JNI_DETACH_ENV
(
attached
,
format
);
return
ret
;
}
void
ff_AMediaFormat_setInt32
(
FFAMediaFormat
*
format
,
const
char
*
name
,
int32_t
value
)
{
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
jstring
key
=
NULL
;
av_assert0
(
format
!=
NULL
);
JNI_ATTACH_ENV_OR_RETURN_VOID
(
env
,
&
attached
,
format
);
key
=
ff_jni_utf_chars_to_jstring
(
env
,
name
,
format
);
if
(
!
key
)
{
goto
fail
;
}
(
*
env
)
->
CallVoidMethod
(
env
,
format
->
object
,
format
->
jfields
.
set_integer_id
,
key
,
value
);
if
(
ff_jni_exception_check
(
env
,
1
,
format
)
<
0
)
{
goto
fail
;
}
fail:
if
(
key
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
key
);
}
JNI_DETACH_ENV
(
attached
,
format
);
}
void
ff_AMediaFormat_setInt64
(
FFAMediaFormat
*
format
,
const
char
*
name
,
int64_t
value
)
{
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
jstring
key
=
NULL
;
av_assert0
(
format
!=
NULL
);
JNI_ATTACH_ENV_OR_RETURN_VOID
(
env
,
&
attached
,
format
);
key
=
ff_jni_utf_chars_to_jstring
(
env
,
name
,
format
);
if
(
!
key
)
{
goto
fail
;
}
(
*
env
)
->
CallVoidMethod
(
env
,
format
->
object
,
format
->
jfields
.
set_long_id
,
key
,
value
);
if
(
ff_jni_exception_check
(
env
,
1
,
format
)
<
0
)
{
goto
fail
;
}
fail:
if
(
key
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
key
);
}
JNI_DETACH_ENV
(
attached
,
NULL
);
}
void
ff_AMediaFormat_setFloat
(
FFAMediaFormat
*
format
,
const
char
*
name
,
float
value
)
{
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
jstring
key
=
NULL
;
av_assert0
(
format
!=
NULL
);
JNI_ATTACH_ENV_OR_RETURN_VOID
(
env
,
&
attached
,
format
);
key
=
ff_jni_utf_chars_to_jstring
(
env
,
name
,
format
);
if
(
!
key
)
{
goto
fail
;
}
(
*
env
)
->
CallVoidMethod
(
env
,
format
->
object
,
format
->
jfields
.
set_float_id
,
key
,
value
);
if
(
ff_jni_exception_check
(
env
,
1
,
format
)
<
0
)
{
goto
fail
;
}
fail:
if
(
key
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
key
);
}
JNI_DETACH_ENV
(
attached
,
NULL
);
}
void
ff_AMediaFormat_setString
(
FFAMediaFormat
*
format
,
const
char
*
name
,
const
char
*
value
)
{
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
jstring
key
=
NULL
;
jstring
string
=
NULL
;
av_assert0
(
format
!=
NULL
);
JNI_ATTACH_ENV_OR_RETURN_VOID
(
env
,
&
attached
,
format
);
key
=
ff_jni_utf_chars_to_jstring
(
env
,
name
,
format
);
if
(
!
key
)
{
goto
fail
;
}
string
=
ff_jni_utf_chars_to_jstring
(
env
,
value
,
format
);
if
(
!
string
)
{
goto
fail
;
}
(
*
env
)
->
CallVoidMethod
(
env
,
format
->
object
,
format
->
jfields
.
set_string_id
,
key
,
string
);
if
(
ff_jni_exception_check
(
env
,
1
,
format
)
<
0
)
{
goto
fail
;
}
fail:
if
(
key
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
key
);
}
if
(
string
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
string
);
}
JNI_DETACH_ENV
(
attached
,
format
);
}
void
ff_AMediaFormat_setBuffer
(
FFAMediaFormat
*
format
,
const
char
*
name
,
void
*
data
,
size_t
size
)
{
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
jstring
key
=
NULL
;
jobject
buffer
=
NULL
;
void
*
buffer_data
=
NULL
;
av_assert0
(
format
!=
NULL
);
JNI_ATTACH_ENV_OR_RETURN_VOID
(
env
,
&
attached
,
format
);
key
=
ff_jni_utf_chars_to_jstring
(
env
,
name
,
format
);
if
(
!
key
)
{
goto
fail
;
}
if
(
!
data
||
!
size
)
{
goto
fail
;
}
buffer_data
=
av_malloc
(
size
);
if
(
!
buffer_data
)
{
goto
fail
;
}
memcpy
(
buffer_data
,
data
,
size
);
buffer
=
(
*
env
)
->
NewDirectByteBuffer
(
env
,
buffer_data
,
size
);
if
(
!
buffer
)
{
goto
fail
;
}
(
*
env
)
->
CallVoidMethod
(
env
,
format
->
object
,
format
->
jfields
.
set_bytebuffer_id
,
key
,
buffer
);
if
(
ff_jni_exception_check
(
env
,
1
,
format
)
<
0
)
{
goto
fail
;
}
fail:
if
(
key
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
key
);
}
if
(
buffer
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
buffer
);
}
JNI_DETACH_ENV
(
attached
,
format
);
}
struct
JNIAMediaCodecFields
{
jclass
mediacodec_class
;
jfieldID
info_try_again_later_id
;
jfieldID
info_output_buffers_changed_id
;
jfieldID
info_output_format_changed_id
;
jfieldID
buffer_flag_codec_config_id
;
jfieldID
buffer_flag_end_of_stream_id
;
jfieldID
buffer_flag_key_frame_id
;
jfieldID
configure_flag_encode_id
;
jmethodID
create_by_codec_name_id
;
jmethodID
create_decoder_by_type_id
;
jmethodID
create_encoder_by_type_id
;
jmethodID
get_name_id
;
jmethodID
configure_id
;
jmethodID
start_id
;
jmethodID
flush_id
;
jmethodID
stop_id
;
jmethodID
release_id
;
jmethodID
get_output_format_id
;
jmethodID
dequeue_input_buffer_id
;
jmethodID
queue_input_buffer_id
;
jmethodID
get_input_buffer_id
;
jmethodID
get_input_buffers_id
;
jmethodID
dequeue_output_buffer_id
;
jmethodID
get_output_buffer_id
;
jmethodID
get_output_buffers_id
;
jmethodID
release_output_buffer_id
;
jmethodID
release_output_buffer_at_time_id
;
jclass
mediainfo_class
;
jmethodID
init_id
;
jfieldID
flags_id
;
jfieldID
offset_id
;
jfieldID
presentation_time_us_id
;
jfieldID
size_id
;
}
JNIAMediaCodecFields
;
static
const
struct
FFJniField
jni_amediacodec_mapping
[]
=
{
{
"android/media/MediaCodec"
,
NULL
,
NULL
,
FF_JNI_CLASS
,
offsetof
(
struct
JNIAMediaCodecFields
,
mediacodec_class
),
1
},
{
"android/media/MediaCodec"
,
"INFO_TRY_AGAIN_LATER"
,
"I"
,
FF_JNI_STATIC_FIELD
,
offsetof
(
struct
JNIAMediaCodecFields
,
info_try_again_later_id
),
1
},
{
"android/media/MediaCodec"
,
"INFO_OUTPUT_BUFFERS_CHANGED"
,
"I"
,
FF_JNI_STATIC_FIELD
,
offsetof
(
struct
JNIAMediaCodecFields
,
info_output_buffers_changed_id
),
1
},
{
"android/media/MediaCodec"
,
"INFO_OUTPUT_FORMAT_CHANGED"
,
"I"
,
FF_JNI_STATIC_FIELD
,
offsetof
(
struct
JNIAMediaCodecFields
,
info_output_format_changed_id
),
1
},
{
"android/media/MediaCodec"
,
"BUFFER_FLAG_CODEC_CONFIG"
,
"I"
,
FF_JNI_STATIC_FIELD
,
offsetof
(
struct
JNIAMediaCodecFields
,
buffer_flag_codec_config_id
),
1
},
{
"android/media/MediaCodec"
,
"BUFFER_FLAG_END_OF_STREAM"
,
"I"
,
FF_JNI_STATIC_FIELD
,
offsetof
(
struct
JNIAMediaCodecFields
,
buffer_flag_end_of_stream_id
),
1
},
{
"android/media/MediaCodec"
,
"BUFFER_FLAG_KEY_FRAME"
,
"I"
,
FF_JNI_STATIC_FIELD
,
offsetof
(
struct
JNIAMediaCodecFields
,
buffer_flag_key_frame_id
),
0
},
{
"android/media/MediaCodec"
,
"CONFIGURE_FLAG_ENCODE"
,
"I"
,
FF_JNI_STATIC_FIELD
,
offsetof
(
struct
JNIAMediaCodecFields
,
configure_flag_encode_id
),
1
},
{
"android/media/MediaCodec"
,
"createByCodecName"
,
"(Ljava/lang/String;)Landroid/media/MediaCodec;"
,
FF_JNI_STATIC_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
create_by_codec_name_id
),
1
},
{
"android/media/MediaCodec"
,
"createDecoderByType"
,
"(Ljava/lang/String;)Landroid/media/MediaCodec;"
,
FF_JNI_STATIC_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
create_decoder_by_type_id
),
1
},
{
"android/media/MediaCodec"
,
"createEncoderByType"
,
"(Ljava/lang/String;)Landroid/media/MediaCodec;"
,
FF_JNI_STATIC_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
create_encoder_by_type_id
),
1
},
{
"android/media/MediaCodec"
,
"getName"
,
"()Ljava/lang/String;"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
get_name_id
),
1
},
{
"android/media/MediaCodec"
,
"configure"
,
"(Landroid/media/MediaFormat;Landroid/view/Surface;Landroid/media/MediaCrypto;I)V"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
configure_id
),
1
},
{
"android/media/MediaCodec"
,
"start"
,
"()V"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
start_id
),
1
},
{
"android/media/MediaCodec"
,
"flush"
,
"()V"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
flush_id
),
1
},
{
"android/media/MediaCodec"
,
"stop"
,
"()V"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
stop_id
),
1
},
{
"android/media/MediaCodec"
,
"release"
,
"()V"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
release_id
),
1
},
{
"android/media/MediaCodec"
,
"getOutputFormat"
,
"()Landroid/media/MediaFormat;"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
get_output_format_id
),
1
},
{
"android/media/MediaCodec"
,
"dequeueInputBuffer"
,
"(J)I"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
dequeue_input_buffer_id
),
1
},
{
"android/media/MediaCodec"
,
"queueInputBuffer"
,
"(IIIJI)V"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
queue_input_buffer_id
),
1
},
{
"android/media/MediaCodec"
,
"getInputBuffer"
,
"(I)Ljava/nio/ByteBuffer;"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
get_input_buffer_id
),
0
},
{
"android/media/MediaCodec"
,
"getInputBuffers"
,
"()[Ljava/nio/ByteBuffer;"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
get_input_buffers_id
),
1
},
{
"android/media/MediaCodec"
,
"dequeueOutputBuffer"
,
"(Landroid/media/MediaCodec$BufferInfo;J)I"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
dequeue_output_buffer_id
),
1
},
{
"android/media/MediaCodec"
,
"getOutputBuffer"
,
"(I)Ljava/nio/ByteBuffer;"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
get_output_buffer_id
),
0
},
{
"android/media/MediaCodec"
,
"getOutputBuffers"
,
"()[Ljava/nio/ByteBuffer;"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
get_output_buffers_id
),
1
},
{
"android/media/MediaCodec"
,
"releaseOutputBuffer"
,
"(IZ)V"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
release_output_buffer_id
),
1
},
{
"android/media/MediaCodec"
,
"releaseOutputBuffer"
,
"(IJ)V"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
release_output_buffer_at_time_id
),
0
},
{
"android/media/MediaCodec$BufferInfo"
,
NULL
,
NULL
,
FF_JNI_CLASS
,
offsetof
(
struct
JNIAMediaCodecFields
,
mediainfo_class
),
1
},
{
"android/media/MediaCodec.BufferInfo"
,
"<init>"
,
"()V"
,
FF_JNI_METHOD
,
offsetof
(
struct
JNIAMediaCodecFields
,
init_id
),
1
},
{
"android/media/MediaCodec.BufferInfo"
,
"flags"
,
"I"
,
FF_JNI_FIELD
,
offsetof
(
struct
JNIAMediaCodecFields
,
flags_id
),
1
},
{
"android/media/MediaCodec.BufferInfo"
,
"offset"
,
"I"
,
FF_JNI_FIELD
,
offsetof
(
struct
JNIAMediaCodecFields
,
offset_id
),
1
},
{
"android/media/MediaCodec.BufferInfo"
,
"presentationTimeUs"
,
"J"
,
FF_JNI_FIELD
,
offsetof
(
struct
JNIAMediaCodecFields
,
presentation_time_us_id
),
1
},
{
"android/media/MediaCodec.BufferInfo"
,
"size"
,
"I"
,
FF_JNI_FIELD
,
offsetof
(
struct
JNIAMediaCodecFields
,
size_id
),
1
},
{
NULL
}
};
static
const
AVClass
amediacodec_class
=
{
.
class_name
=
"amediacodec"
,
.
item_name
=
av_default_item_name
,
.
version
=
LIBAVCODEC_VERSION_INT
,
};
struct
FFAMediaCodec
{
const
AVClass
*
class
;
struct
JNIAMediaCodecFields
jfields
;
jobject
object
;
jobject
input_buffers
;
jobject
output_buffers
;
int
INFO_TRY_AGAIN_LATER
;
int
INFO_OUTPUT_BUFFERS_CHANGED
;
int
INFO_OUTPUT_FORMAT_CHANGED
;
int
BUFFER_FLAG_CODEC_CONFIG
;
int
BUFFER_FLAG_END_OF_STREAM
;
int
BUFFER_FLAG_KEY_FRAME
;
int
CONFIGURE_FLAG_ENCODE
;
int
has_get_i_o_buffer
;
};
FFAMediaCodec
*
ff_AMediaCodec_createCodecByName
(
const
char
*
name
)
{
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
FFAMediaCodec
*
codec
=
NULL
;
jstring
codec_name
=
NULL
;
codec
=
av_mallocz
(
sizeof
(
FFAMediaCodec
));
if
(
!
codec
)
{
return
NULL
;
}
codec
->
class
=
&
amediacodec_class
;
env
=
ff_jni_attach_env
(
&
attached
,
codec
);
if
(
!
env
)
{
av_freep
(
&
codec
);
return
NULL
;
}
if
(
ff_jni_init_jfields
(
env
,
&
codec
->
jfields
,
jni_amediacodec_mapping
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec_name
=
ff_jni_utf_chars_to_jstring
(
env
,
name
,
codec
);
if
(
!
codec_name
)
{
goto
fail
;
}
codec
->
object
=
(
*
env
)
->
CallStaticObjectMethod
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
create_by_codec_name_id
,
codec_name
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec
->
object
=
(
*
env
)
->
NewGlobalRef
(
env
,
codec
->
object
);
if
(
!
codec
->
object
)
{
goto
fail
;
}
codec
->
INFO_TRY_AGAIN_LATER
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
info_try_again_later_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec
->
BUFFER_FLAG_CODEC_CONFIG
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
buffer_flag_codec_config_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec
->
BUFFER_FLAG_END_OF_STREAM
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
buffer_flag_end_of_stream_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
if
(
codec
->
jfields
.
buffer_flag_key_frame_id
)
{
codec
->
BUFFER_FLAG_KEY_FRAME
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
buffer_flag_key_frame_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
}
codec
->
CONFIGURE_FLAG_ENCODE
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
configure_flag_encode_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec
->
INFO_TRY_AGAIN_LATER
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
info_try_again_later_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec
->
INFO_OUTPUT_BUFFERS_CHANGED
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
info_output_buffers_changed_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec
->
INFO_OUTPUT_FORMAT_CHANGED
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
info_output_format_changed_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
JNI_DETACH_ENV
(
attached
,
codec
);
return
codec
;
fail:
ff_jni_reset_jfields
(
env
,
&
codec
->
jfields
,
jni_amediacodec_mapping
,
1
,
codec
);
if
(
codec_name
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
codec_name
);
}
JNI_DETACH_ENV
(
attached
,
codec
);
av_freep
(
&
codec
);
return
NULL
;
}
FFAMediaCodec
*
ff_AMediaCodec_createDecoderByType
(
const
char
*
mime
)
{
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
FFAMediaCodec
*
codec
=
NULL
;
jstring
mime_type
=
NULL
;
codec
=
av_mallocz
(
sizeof
(
FFAMediaCodec
));
if
(
!
codec
)
{
return
NULL
;
}
codec
->
class
=
&
amediacodec_class
;
env
=
ff_jni_attach_env
(
&
attached
,
codec
);
if
(
!
env
)
{
av_freep
(
&
codec
);
return
NULL
;
}
if
(
ff_jni_init_jfields
(
env
,
&
codec
->
jfields
,
jni_amediacodec_mapping
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
mime_type
=
ff_jni_utf_chars_to_jstring
(
env
,
mime
,
codec
);
if
(
!
mime_type
)
{
goto
fail
;
}
codec
->
object
=
(
*
env
)
->
CallStaticObjectMethod
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
create_decoder_by_type_id
,
mime_type
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec
->
object
=
(
*
env
)
->
NewGlobalRef
(
env
,
codec
->
object
);
if
(
!
codec
->
object
)
{
goto
fail
;
}
codec
->
BUFFER_FLAG_CODEC_CONFIG
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
buffer_flag_codec_config_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec
->
BUFFER_FLAG_END_OF_STREAM
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
buffer_flag_end_of_stream_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
if
(
codec
->
jfields
.
buffer_flag_key_frame_id
)
{
codec
->
BUFFER_FLAG_KEY_FRAME
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
buffer_flag_key_frame_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
}
codec
->
CONFIGURE_FLAG_ENCODE
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
configure_flag_encode_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec
->
INFO_TRY_AGAIN_LATER
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
info_try_again_later_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec
->
INFO_OUTPUT_BUFFERS_CHANGED
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
info_output_buffers_changed_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec
->
INFO_OUTPUT_FORMAT_CHANGED
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
info_output_format_changed_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
if
(
codec
->
jfields
.
get_input_buffer_id
&&
codec
->
jfields
.
get_output_buffer_id
)
{
codec
->
has_get_i_o_buffer
=
1
;
}
JNI_DETACH_ENV
(
attached
,
codec
);
return
codec
;
fail:
ff_jni_reset_jfields
(
env
,
&
codec
->
jfields
,
jni_amediacodec_mapping
,
1
,
codec
);
if
(
mime_type
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
mime_type
);
}
JNI_DETACH_ENV
(
attached
,
codec
);
av_freep
(
&
codec
);
return
NULL
;
}
FFAMediaCodec
*
ff_AMediaCodec_createEncoderByType
(
const
char
*
mime
)
{
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
FFAMediaCodec
*
codec
=
NULL
;
jstring
mime_type
=
NULL
;
codec
=
av_mallocz
(
sizeof
(
FFAMediaCodec
));
if
(
!
codec
)
{
return
NULL
;
}
codec
->
class
=
&
amediacodec_class
;
env
=
ff_jni_attach_env
(
&
attached
,
codec
);
if
(
!
env
)
{
av_freep
(
&
codec
);
return
NULL
;
}
if
(
ff_jni_init_jfields
(
env
,
&
codec
->
jfields
,
jni_amediacodec_mapping
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
mime_type
=
ff_jni_utf_chars_to_jstring
(
env
,
mime
,
codec
);
if
(
!
mime_type
)
{
goto
fail
;
}
codec
->
object
=
(
*
env
)
->
CallStaticObjectMethod
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
create_encoder_by_type_id
,
mime_type
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec
->
object
=
(
*
env
)
->
NewGlobalRef
(
env
,
codec
->
object
);
if
(
!
codec
->
object
)
{
goto
fail
;
}
codec
->
INFO_TRY_AGAIN_LATER
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
info_try_again_later_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec
->
BUFFER_FLAG_CODEC_CONFIG
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
buffer_flag_codec_config_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec
->
BUFFER_FLAG_END_OF_STREAM
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
buffer_flag_end_of_stream_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
if
(
codec
->
jfields
.
buffer_flag_key_frame_id
)
{
codec
->
BUFFER_FLAG_KEY_FRAME
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
buffer_flag_key_frame_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
}
codec
->
CONFIGURE_FLAG_ENCODE
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
configure_flag_encode_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec
->
INFO_TRY_AGAIN_LATER
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
info_try_again_later_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec
->
INFO_OUTPUT_BUFFERS_CHANGED
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
info_output_buffers_changed_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec
->
INFO_OUTPUT_FORMAT_CHANGED
=
(
*
env
)
->
GetStaticIntField
(
env
,
codec
->
jfields
.
mediacodec_class
,
codec
->
jfields
.
info_output_format_changed_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
JNI_DETACH_ENV
(
attached
,
NULL
);
return
codec
;
fail:
ff_jni_reset_jfields
(
env
,
&
codec
->
jfields
,
jni_amediacodec_mapping
,
1
,
codec
);
if
(
mime_type
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
mime_type
);
}
JNI_DETACH_ENV
(
attached
,
codec
);
av_freep
(
&
codec
);
return
NULL
;
}
int
ff_AMediaCodec_delete
(
FFAMediaCodec
*
codec
)
{
int
ret
=
0
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
if
(
!
codec
)
{
return
0
;
}
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
codec
,
AVERROR_EXTERNAL
);
(
*
env
)
->
CallVoidMethod
(
env
,
codec
->
object
,
codec
->
jfields
.
release_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
ret
=
AVERROR_EXTERNAL
;
}
(
*
env
)
->
DeleteGlobalRef
(
env
,
codec
->
object
);
codec
->
object
=
NULL
;
ff_jni_reset_jfields
(
env
,
&
codec
->
jfields
,
jni_amediacodec_mapping
,
1
,
codec
);
JNI_DETACH_ENV
(
attached
,
codec
);
av_freep
(
&
codec
);
return
ret
;
}
char
*
ff_AMediaCodec_getName
(
FFAMediaCodec
*
codec
)
{
char
*
ret
=
NULL
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
jobject
*
name
=
NULL
;
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
codec
,
NULL
);
name
=
(
*
env
)
->
CallObjectMethod
(
env
,
codec
->
object
,
codec
->
jfields
.
get_name_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
ret
=
ff_jni_jstring_to_utf_chars
(
env
,
name
,
codec
);
fail:
JNI_DETACH_ENV
(
attached
,
NULL
);
return
ret
;
}
int
ff_AMediaCodec_configure
(
FFAMediaCodec
*
codec
,
const
FFAMediaFormat
*
format
,
void
*
surface
,
void
*
crypto
,
uint32_t
flags
)
{
int
ret
=
0
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
/* TODO: implement surface handling */
av_assert0
(
surface
==
NULL
);
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
codec
,
AVERROR_EXTERNAL
);
(
*
env
)
->
CallVoidMethod
(
env
,
codec
->
object
,
codec
->
jfields
.
configure_id
,
format
->
object
,
NULL
,
NULL
,
flags
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
ret
=
AVERROR_EXTERNAL
;
goto
fail
;
}
fail:
JNI_DETACH_ENV
(
attached
,
NULL
);
return
ret
;
}
int
ff_AMediaCodec_start
(
FFAMediaCodec
*
codec
)
{
int
ret
=
0
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
codec
,
AVERROR_EXTERNAL
);
(
*
env
)
->
CallVoidMethod
(
env
,
codec
->
object
,
codec
->
jfields
.
start_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
ret
=
AVERROR_EXTERNAL
;
goto
fail
;
}
fail:
JNI_DETACH_ENV
(
attached
,
codec
);
return
ret
;
}
int
ff_AMediaCodec_stop
(
FFAMediaCodec
*
codec
)
{
int
ret
=
0
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
codec
,
AVERROR_EXTERNAL
);
(
*
env
)
->
CallVoidMethod
(
env
,
codec
->
object
,
codec
->
jfields
.
stop_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
ret
=
AVERROR_EXTERNAL
;
goto
fail
;
}
fail:
JNI_DETACH_ENV
(
attached
,
codec
);
return
ret
;
}
int
ff_AMediaCodec_flush
(
FFAMediaCodec
*
codec
)
{
int
ret
=
0
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
codec
,
AVERROR_EXTERNAL
);
(
*
env
)
->
CallVoidMethod
(
env
,
codec
->
object
,
codec
->
jfields
.
flush_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
ret
=
AVERROR_EXTERNAL
;
goto
fail
;
}
fail:
JNI_DETACH_ENV
(
attached
,
codec
);
return
ret
;
}
int
ff_AMediaCodec_releaseOutputBuffer
(
FFAMediaCodec
*
codec
,
size_t
idx
,
int
render
)
{
int
ret
=
0
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
codec
,
AVERROR_EXTERNAL
);
(
*
env
)
->
CallVoidMethod
(
env
,
codec
->
object
,
codec
->
jfields
.
release_output_buffer_id
,
idx
,
render
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
ret
=
AVERROR_EXTERNAL
;
goto
fail
;
}
fail:
JNI_DETACH_ENV
(
attached
,
codec
);
return
ret
;
}
int
ff_AMediaCodec_releaseOutputBufferAtTime
(
FFAMediaCodec
*
codec
,
size_t
idx
,
int64_t
timestampNs
)
{
int
ret
=
0
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
codec
,
AVERROR_EXTERNAL
);
(
*
env
)
->
CallVoidMethod
(
env
,
codec
->
object
,
codec
->
jfields
.
release_output_buffer_at_time_id
,
idx
,
timestampNs
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
ret
=
AVERROR_EXTERNAL
;
goto
fail
;
}
fail:
JNI_DETACH_ENV
(
attached
,
codec
);
return
ret
;
}
ssize_t
ff_AMediaCodec_dequeueInputBuffer
(
FFAMediaCodec
*
codec
,
int64_t
timeoutUs
)
{
int
ret
=
0
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
codec
,
AVERROR_EXTERNAL
);
ret
=
(
*
env
)
->
CallIntMethod
(
env
,
codec
->
object
,
codec
->
jfields
.
dequeue_input_buffer_id
,
timeoutUs
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
ret
=
AVERROR_EXTERNAL
;
goto
fail
;
}
fail:
JNI_DETACH_ENV
(
attached
,
codec
);
return
ret
;
}
int
ff_AMediaCodec_queueInputBuffer
(
FFAMediaCodec
*
codec
,
size_t
idx
,
off_t
offset
,
size_t
size
,
uint64_t
time
,
uint32_t
flags
)
{
int
ret
=
0
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
codec
,
AVERROR_EXTERNAL
);
(
*
env
)
->
CallVoidMethod
(
env
,
codec
->
object
,
codec
->
jfields
.
queue_input_buffer_id
,
idx
,
offset
,
size
,
time
,
flags
);
if
((
ret
=
ff_jni_exception_check
(
env
,
1
,
codec
))
<
0
)
{
ret
=
AVERROR_EXTERNAL
;
goto
fail
;
}
fail:
JNI_DETACH_ENV
(
attached
,
codec
);
return
ret
;
}
ssize_t
ff_AMediaCodec_dequeueOutputBuffer
(
FFAMediaCodec
*
codec
,
FFAMediaCodecBufferInfo
*
info
,
int64_t
timeoutUs
)
{
int
ret
=
0
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
jobject
mediainfo
=
NULL
;
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
codec
,
AVERROR_EXTERNAL
);
mediainfo
=
(
*
env
)
->
NewObject
(
env
,
codec
->
jfields
.
mediainfo_class
,
codec
->
jfields
.
init_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
ret
=
AVERROR_EXTERNAL
;
goto
fail
;
}
ret
=
(
*
env
)
->
CallIntMethod
(
env
,
codec
->
object
,
codec
->
jfields
.
dequeue_output_buffer_id
,
mediainfo
,
timeoutUs
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
ret
=
AVERROR_EXTERNAL
;
goto
fail
;
}
info
->
flags
=
(
*
env
)
->
GetIntField
(
env
,
mediainfo
,
codec
->
jfields
.
flags_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
ret
=
AVERROR_EXTERNAL
;
goto
fail
;
}
info
->
offset
=
(
*
env
)
->
GetIntField
(
env
,
mediainfo
,
codec
->
jfields
.
offset_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
ret
=
AVERROR_EXTERNAL
;
goto
fail
;
}
info
->
presentationTimeUs
=
(
*
env
)
->
GetLongField
(
env
,
mediainfo
,
codec
->
jfields
.
presentation_time_us_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
ret
=
AVERROR_EXTERNAL
;
goto
fail
;
}
info
->
size
=
(
*
env
)
->
GetIntField
(
env
,
mediainfo
,
codec
->
jfields
.
size_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
ret
=
AVERROR_EXTERNAL
;
goto
fail
;
}
fail:
if
(
mediainfo
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
mediainfo
);
}
JNI_DETACH_ENV
(
attached
,
NULL
);
return
ret
;
}
uint8_t
*
ff_AMediaCodec_getInputBuffer
(
FFAMediaCodec
*
codec
,
size_t
idx
,
size_t
*
out_size
)
{
uint8_t
*
ret
=
NULL
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
jobject
buffer
=
NULL
;
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
codec
,
NULL
);
if
(
codec
->
has_get_i_o_buffer
)
{
buffer
=
(
*
env
)
->
CallObjectMethod
(
env
,
codec
->
object
,
codec
->
jfields
.
get_input_buffer_id
,
idx
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
}
else
{
if
(
!
codec
->
input_buffers
)
{
codec
->
input_buffers
=
(
*
env
)
->
CallObjectMethod
(
env
,
codec
->
object
,
codec
->
jfields
.
get_input_buffers_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec
->
input_buffers
=
(
*
env
)
->
NewGlobalRef
(
env
,
codec
->
input_buffers
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
}
buffer
=
(
*
env
)
->
GetObjectArrayElement
(
env
,
codec
->
input_buffers
,
idx
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
}
ret
=
(
*
env
)
->
GetDirectBufferAddress
(
env
,
buffer
);
*
out_size
=
(
*
env
)
->
GetDirectBufferCapacity
(
env
,
buffer
);
fail:
if
(
buffer
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
buffer
);
}
JNI_DETACH_ENV
(
attached
,
codec
);
return
ret
;
}
uint8_t
*
ff_AMediaCodec_getOutputBuffer
(
FFAMediaCodec
*
codec
,
size_t
idx
,
size_t
*
out_size
)
{
uint8_t
*
ret
=
NULL
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
jobject
buffer
=
NULL
;
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
codec
,
NULL
);
if
(
codec
->
has_get_i_o_buffer
)
{
buffer
=
(
*
env
)
->
CallObjectMethod
(
env
,
codec
->
object
,
codec
->
jfields
.
get_output_buffer_id
,
idx
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
}
else
{
if
(
!
codec
->
output_buffers
)
{
codec
->
output_buffers
=
(
*
env
)
->
CallObjectMethod
(
env
,
codec
->
object
,
codec
->
jfields
.
get_output_buffers_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
codec
->
output_buffers
=
(
*
env
)
->
NewGlobalRef
(
env
,
codec
->
output_buffers
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
}
buffer
=
(
*
env
)
->
GetObjectArrayElement
(
env
,
codec
->
output_buffers
,
idx
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
}
ret
=
(
*
env
)
->
GetDirectBufferAddress
(
env
,
buffer
);
*
out_size
=
(
*
env
)
->
GetDirectBufferCapacity
(
env
,
buffer
);
fail:
if
(
buffer
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
buffer
);
}
JNI_DETACH_ENV
(
attached
,
codec
);
return
ret
;
}
FFAMediaFormat
*
ff_AMediaCodec_getOutputFormat
(
FFAMediaCodec
*
codec
)
{
FFAMediaFormat
*
ret
=
NULL
;
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
jobject
mediaformat
=
NULL
;
JNI_ATTACH_ENV_OR_RETURN
(
env
,
&
attached
,
codec
,
NULL
);
mediaformat
=
(
*
env
)
->
CallObjectMethod
(
env
,
codec
->
object
,
codec
->
jfields
.
get_output_format_id
);
if
(
ff_jni_exception_check
(
env
,
1
,
codec
)
<
0
)
{
goto
fail
;
}
ret
=
ff_AMediaFormat_newFromObject
(
mediaformat
);
fail:
if
(
mediaformat
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
mediaformat
);
}
JNI_DETACH_ENV
(
attached
,
codec
);
return
ret
;
}
int
ff_AMediaCodec_infoTryAgainLater
(
FFAMediaCodec
*
codec
,
ssize_t
idx
)
{
return
idx
==
codec
->
INFO_TRY_AGAIN_LATER
;
}
int
ff_AMediaCodec_infoOutputBuffersChanged
(
FFAMediaCodec
*
codec
,
ssize_t
idx
)
{
return
idx
==
codec
->
INFO_OUTPUT_BUFFERS_CHANGED
;
}
int
ff_AMediaCodec_infoOutputFormatChanged
(
FFAMediaCodec
*
codec
,
ssize_t
idx
)
{
return
idx
==
codec
->
INFO_OUTPUT_FORMAT_CHANGED
;
}
int
ff_AMediaCodec_getBufferFlagCodecConfig
(
FFAMediaCodec
*
codec
)
{
return
codec
->
BUFFER_FLAG_CODEC_CONFIG
;
}
int
ff_AMediaCodec_getBufferFlagEndOfStream
(
FFAMediaCodec
*
codec
)
{
return
codec
->
BUFFER_FLAG_END_OF_STREAM
;
}
int
ff_AMediaCodec_getBufferFlagKeyFrame
(
FFAMediaCodec
*
codec
)
{
return
codec
->
BUFFER_FLAG_KEY_FRAME
;
}
int
ff_AMediaCodec_getConfigureFlagEncode
(
FFAMediaCodec
*
codec
)
{
return
codec
->
CONFIGURE_FLAG_ENCODE
;
}
int
ff_AMediaCodec_cleanOutputBuffers
(
FFAMediaCodec
*
codec
)
{
int
ret
=
0
;
if
(
!
codec
->
has_get_i_o_buffer
)
{
if
(
codec
->
output_buffers
)
{
int
attached
=
0
;
JNIEnv
*
env
=
NULL
;
env
=
ff_jni_attach_env
(
&
attached
,
codec
);
if
(
!
env
)
{
ret
=
AVERROR_EXTERNAL
;
goto
fail
;
}
(
*
env
)
->
DeleteGlobalRef
(
env
,
codec
->
output_buffers
);
codec
->
output_buffers
=
NULL
;
JNI_DETACH_ENV
(
attached
,
codec
);
}
}
fail:
return
ret
;
}
libavcodec/mediacodec_wrapper.h
0 → 100644
View file @
4737fe69
/*
* Android MediaCodec Wrapper
*
* Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_MEDIACODEC_WRAPPER_H
#define AVCODEC_MEDIACODEC_WRAPPER_H
#include <stdint.h>
#include <sys/types.h>
/**
* The following API around MediaCodec and MediaFormat is based on the
* NDK one provided by Google since Android 5.0.
*
* Differences from the NDK API:
*
* Buffers returned by ff_AMediaFormat_toString and ff_AMediaFormat_getString
* are newly allocated buffer and must be freed by the user after use.
*
* The MediaCrypto API is not implemented.
*
* ff_AMediaCodec_infoTryAgainLater, ff_AMediaCodec_infoOutputBuffersChanged,
* ff_AMediaCodec_infoOutputFormatChanged, ff_AMediaCodec_cleanOutputBuffers
* ff_AMediaCodec_getName and ff_AMediaCodec_getBufferFlagEndOfStream are not
* part of the original NDK API and are convenience functions to hide JNI
* implementation.
*
* The API around MediaCodecList is not part of the NDK (and is lacking as
* we still need to retreive the codec name to work around faulty decoders
* and encoders).
*
* For documentation, please refers to NdkMediaCodec.h NdkMediaFormat.h and
* http://developer.android.com/reference/android/media/MediaCodec.html.
*
*/
char
*
ff_AMediaCodecList_getCodecNameByType
(
const
char
*
mime
,
int
width
,
int
height
,
void
*
log_ctx
);
struct
FFAMediaFormat
;
typedef
struct
FFAMediaFormat
FFAMediaFormat
;
FFAMediaFormat
*
ff_AMediaFormat_new
(
void
);
int
ff_AMediaFormat_delete
(
FFAMediaFormat
*
format
);
char
*
ff_AMediaFormat_toString
(
FFAMediaFormat
*
format
);
int
ff_AMediaFormat_getInt32
(
FFAMediaFormat
*
format
,
const
char
*
name
,
int32_t
*
out
);
int
ff_AMediaFormat_getInt64
(
FFAMediaFormat
*
format
,
const
char
*
name
,
int64_t
*
out
);
int
ff_AMediaFormat_getFloat
(
FFAMediaFormat
*
format
,
const
char
*
name
,
float
*
out
);
int
ff_AMediaFormat_getBuffer
(
FFAMediaFormat
*
format
,
const
char
*
name
,
void
**
data
,
size_t
*
size
);
int
ff_AMediaFormat_getString
(
FFAMediaFormat
*
format
,
const
char
*
name
,
const
char
**
out
);
void
ff_AMediaFormat_setInt32
(
FFAMediaFormat
*
format
,
const
char
*
name
,
int32_t
value
);
void
ff_AMediaFormat_setInt64
(
FFAMediaFormat
*
format
,
const
char
*
name
,
int64_t
value
);
void
ff_AMediaFormat_setFloat
(
FFAMediaFormat
*
format
,
const
char
*
name
,
float
value
);
void
ff_AMediaFormat_setString
(
FFAMediaFormat
*
format
,
const
char
*
name
,
const
char
*
value
);
void
ff_AMediaFormat_setBuffer
(
FFAMediaFormat
*
format
,
const
char
*
name
,
void
*
data
,
size_t
size
);
struct
FFAMediaCodec
;
typedef
struct
FFAMediaCodec
FFAMediaCodec
;
typedef
struct
FFAMediaCodecCryptoInfo
FFAMediaCodecCryptoInfo
;
struct
FFAMediaCodecBufferInfo
{
int32_t
offset
;
int32_t
size
;
int64_t
presentationTimeUs
;
uint32_t
flags
;
};
typedef
struct
FFAMediaCodecBufferInfo
FFAMediaCodecBufferInfo
;
char
*
ff_AMediaCodec_getName
(
FFAMediaCodec
*
codec
);
FFAMediaCodec
*
ff_AMediaCodec_createCodecByName
(
const
char
*
name
);
FFAMediaCodec
*
ff_AMediaCodec_createDecoderByType
(
const
char
*
mime_type
);
FFAMediaCodec
*
ff_AMediaCodec_createEncoderByType
(
const
char
*
mime_type
);
int
ff_AMediaCodec_configure
(
FFAMediaCodec
*
codec
,
const
FFAMediaFormat
*
format
,
void
*
surface
,
void
*
crypto
,
uint32_t
flags
);
int
ff_AMediaCodec_start
(
FFAMediaCodec
*
codec
);
int
ff_AMediaCodec_stop
(
FFAMediaCodec
*
codec
);
int
ff_AMediaCodec_flush
(
FFAMediaCodec
*
codec
);
int
ff_AMediaCodec_delete
(
FFAMediaCodec
*
codec
);
uint8_t
*
ff_AMediaCodec_getInputBuffer
(
FFAMediaCodec
*
codec
,
size_t
idx
,
size_t
*
out_size
);
uint8_t
*
ff_AMediaCodec_getOutputBuffer
(
FFAMediaCodec
*
codec
,
size_t
idx
,
size_t
*
out_size
);
ssize_t
ff_AMediaCodec_dequeueInputBuffer
(
FFAMediaCodec
*
codec
,
int64_t
timeoutUs
);
int
ff_AMediaCodec_queueInputBuffer
(
FFAMediaCodec
*
codec
,
size_t
idx
,
off_t
offset
,
size_t
size
,
uint64_t
time
,
uint32_t
flags
);
ssize_t
ff_AMediaCodec_dequeueOutputBuffer
(
FFAMediaCodec
*
codec
,
FFAMediaCodecBufferInfo
*
info
,
int64_t
timeoutUs
);
FFAMediaFormat
*
ff_AMediaCodec_getOutputFormat
(
FFAMediaCodec
*
codec
);
int
ff_AMediaCodec_releaseOutputBuffer
(
FFAMediaCodec
*
codec
,
size_t
idx
,
int
render
);
int
ff_AMediaCodec_releaseOutputBufferAtTime
(
FFAMediaCodec
*
codec
,
size_t
idx
,
int64_t
timestampNs
);
int
ff_AMediaCodec_infoTryAgainLater
(
FFAMediaCodec
*
codec
,
ssize_t
idx
);
int
ff_AMediaCodec_infoOutputBuffersChanged
(
FFAMediaCodec
*
codec
,
ssize_t
idx
);
int
ff_AMediaCodec_infoOutputFormatChanged
(
FFAMediaCodec
*
codec
,
ssize_t
indx
);
int
ff_AMediaCodec_getBufferFlagCodecConfig
(
FFAMediaCodec
*
codec
);
int
ff_AMediaCodec_getBufferFlagEndOfStream
(
FFAMediaCodec
*
codec
);
int
ff_AMediaCodec_getBufferFlagKeyFrame
(
FFAMediaCodec
*
codec
);
int
ff_AMediaCodec_getConfigureFlagEncode
(
FFAMediaCodec
*
codec
);
int
ff_AMediaCodec_cleanOutputBuffers
(
FFAMediaCodec
*
codec
);
#endif
/* AVCODEC_MEDIACODEC_WRAPPER_H */
libavcodec/mediacodecdec.c
0 → 100644
View file @
4737fe69
/*
* Android MediaCodec decoder
*
* Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include <sys/types.h>
#include "libavutil/common.h"
#include "libavutil/mem.h"
#include "libavutil/log.h"
#include "libavutil/pixfmt.h"
#include "libavutil/time.h"
#include "libavutil/timestamp.h"
#include "avcodec.h"
#include "internal.h"
#include "mediacodec_sw_buffer.h"
#include "mediacodec_wrapper.h"
#include "mediacodecdec.h"
/**
* OMX.k3.video.decoder.avc, OMX.NVIDIA.* OMX.SEC.avc.dec and OMX.google
* codec workarounds used in various place are taken from the Gstreamer
* project.
*
* Gstreamer references:
* https://cgit.freedesktop.org/gstreamer/gst-plugins-bad/tree/sys/androidmedia/
*
* Gstreamer copyright notice:
*
* Copyright (C) 2012, Collabora Ltd.
* Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* Copyright (C) 2012, Rafaël Carré <funman@videolanorg>
*
* Copyright (C) 2015, Sebastian Dröge <sebastian@centricular.com>
*
* Copyright (C) 2014-2015, Collabora Ltd.
* Author: Matthieu Bouron <matthieu.bouron@gcollabora.com>
*
* Copyright (C) 2015, Edward Hervey
* Author: Edward Hervey <bilboed@gmail.com>
*
* Copyright (C) 2015, Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#define INPUT_DEQUEUE_TIMEOUT_US 8000
#define OUTPUT_DEQUEUE_TIMEOUT_US 8000
#define OUTPUT_DEQUEUE_BLOCK_TIMEOUT_US 1000000
enum
{
COLOR_FormatYUV420Planar
=
0x13
,
COLOR_FormatYUV420SemiPlanar
=
0x15
,
COLOR_FormatYCbYCr
=
0x19
,
COLOR_FormatAndroidOpaque
=
0x7F000789
,
COLOR_QCOM_FormatYUV420SemiPlanar
=
0x7fa30c00
,
COLOR_QCOM_FormatYUV420SemiPlanar32m
=
0x7fa30c04
,
COLOR_QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka
=
0x7fa30c03
,
COLOR_TI_FormatYUV420PackedSemiPlanar
=
0x7f000100
,
COLOR_TI_FormatYUV420PackedSemiPlanarInterlaced
=
0x7f000001
,
};
static
const
struct
{
int
color_format
;
enum
AVPixelFormat
pix_fmt
;
}
color_formats
[]
=
{
{
COLOR_FormatYUV420Planar
,
AV_PIX_FMT_YUV420P
},
{
COLOR_FormatYUV420SemiPlanar
,
AV_PIX_FMT_NV12
},
{
COLOR_QCOM_FormatYUV420SemiPlanar
,
AV_PIX_FMT_NV12
},
{
COLOR_QCOM_FormatYUV420SemiPlanar32m
,
AV_PIX_FMT_NV12
},
{
COLOR_QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka
,
AV_PIX_FMT_NV12
},
{
COLOR_TI_FormatYUV420PackedSemiPlanar
,
AV_PIX_FMT_NV12
},
{
COLOR_TI_FormatYUV420PackedSemiPlanarInterlaced
,
AV_PIX_FMT_NV12
},
{
0
}
};
static
enum
AVPixelFormat
mcdec_map_color_format
(
AVCodecContext
*
avctx
,
MediaCodecDecContext
*
s
,
int
color_format
)
{
int
i
;
enum
AVPixelFormat
ret
=
AV_PIX_FMT_NONE
;
if
(
!
strcmp
(
s
->
codec_name
,
"OMX.k3.video.decoder.avc"
)
&&
color_format
==
COLOR_FormatYCbYCr
)
{
s
->
color_format
=
color_format
=
COLOR_TI_FormatYUV420PackedSemiPlanar
;
}
for
(
i
=
0
;
i
<
FF_ARRAY_ELEMS
(
color_formats
);
i
++
)
{
if
(
color_formats
[
i
].
color_format
==
color_format
)
{
return
color_formats
[
i
].
pix_fmt
;
}
}
av_log
(
avctx
,
AV_LOG_ERROR
,
"Output color format 0x%x (value=%d) is not supported
\n
"
,
color_format
,
color_format
);
return
ret
;
}
static
int
mediacodec_wrap_buffer
(
AVCodecContext
*
avctx
,
MediaCodecDecContext
*
s
,
uint8_t
*
data
,
size_t
size
,
ssize_t
index
,
FFAMediaCodecBufferInfo
*
info
,
AVFrame
*
frame
)
{
int
ret
=
0
;
int
status
=
0
;
frame
->
width
=
avctx
->
width
;
frame
->
height
=
avctx
->
height
;
frame
->
format
=
avctx
->
pix_fmt
;
/* MediaCodec buffers needs to be copied to our own refcounted buffers
* because the flush command invalidates all input and output buffers.
*/
if
((
ret
=
ff_get_buffer
(
avctx
,
frame
,
0
))
<
0
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Could not allocate buffer
\n
"
);
goto
done
;
}
/* Override frame->pkt_pts as ff_get_buffer will override its value based
* on the last avpacket received which is not in sync with the frame:
* * N avpackets can be pushed before 1 frame is actually returned
* * 0-sized avpackets are pushed to flush remaining frames at EOS */
frame
->
pkt_pts
=
info
->
presentationTimeUs
;
av_log
(
avctx
,
AV_LOG_DEBUG
,
"Frame: width=%d stride=%d height=%d slice-height=%d "
"crop-top=%d crop-bottom=%d crop-left=%d crop-right=%d encoder=%s
\n
"
"destination linesizes=%d,%d,%d
\n
"
,
avctx
->
width
,
s
->
stride
,
avctx
->
height
,
s
->
slice_height
,
s
->
crop_top
,
s
->
crop_bottom
,
s
->
crop_left
,
s
->
crop_right
,
s
->
codec_name
,
frame
->
linesize
[
0
],
frame
->
linesize
[
1
],
frame
->
linesize
[
2
]);
switch
(
s
->
color_format
)
{
case
COLOR_FormatYUV420Planar
:
ff_mediacodec_sw_buffer_copy_yuv420_planar
(
avctx
,
s
,
data
,
size
,
info
,
frame
);
break
;
case
COLOR_FormatYUV420SemiPlanar
:
case
COLOR_QCOM_FormatYUV420SemiPlanar
:
case
COLOR_QCOM_FormatYUV420SemiPlanar32m
:
ff_mediacodec_sw_buffer_copy_yuv420_semi_planar
(
avctx
,
s
,
data
,
size
,
info
,
frame
);
break
;
case
COLOR_TI_FormatYUV420PackedSemiPlanar
:
case
COLOR_TI_FormatYUV420PackedSemiPlanarInterlaced
:
ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar
(
avctx
,
s
,
data
,
size
,
info
,
frame
);
break
;
case
COLOR_QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka
:
ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar_64x32Tile2m8ka
(
avctx
,
s
,
data
,
size
,
info
,
frame
);
break
;
default:
av_log
(
avctx
,
AV_LOG_ERROR
,
"Unsupported color format 0x%x (value=%d)
\n
"
,
s
->
color_format
,
s
->
color_format
);
ret
=
AVERROR
(
EINVAL
);
goto
done
;
}
ret
=
0
;
done:
status
=
ff_AMediaCodec_releaseOutputBuffer
(
s
->
codec
,
index
,
0
);
if
(
status
<
0
)
{
av_log
(
NULL
,
AV_LOG_ERROR
,
"Failed to release output buffer
\n
"
);
ret
=
AVERROR_EXTERNAL
;
}
return
ret
;
}
static
int
mediacodec_dec_parse_format
(
AVCodecContext
*
avctx
,
MediaCodecDecContext
*
s
)
{
int
width
=
0
;
int
height
=
0
;
int32_t
value
=
0
;
char
*
format
=
NULL
;
if
(
!
s
->
format
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Output MediaFormat is not set
\n
"
);
return
AVERROR
(
EINVAL
);
}
format
=
ff_AMediaFormat_toString
(
s
->
format
);
if
(
!
format
)
{
return
AVERROR_EXTERNAL
;
}
av_log
(
avctx
,
AV_LOG_DEBUG
,
"Parsing MediaFormat %s
\n
"
,
format
);
av_freep
(
&
format
);
/* Mandatory fields */
if
(
!
ff_AMediaFormat_getInt32
(
s
->
format
,
"width"
,
&
value
))
{
format
=
ff_AMediaFormat_toString
(
s
->
format
);
av_log
(
avctx
,
AV_LOG_ERROR
,
"Could not get %s from format %s
\n
"
,
"width"
,
format
);
av_freep
(
&
format
);
return
AVERROR_EXTERNAL
;
}
s
->
width
=
value
;
if
(
!
ff_AMediaFormat_getInt32
(
s
->
format
,
"height"
,
&
value
))
{
format
=
ff_AMediaFormat_toString
(
s
->
format
);
av_log
(
avctx
,
AV_LOG_ERROR
,
"Could not get %s from format %s
\n
"
,
"height"
,
format
);
av_freep
(
&
format
);
return
AVERROR_EXTERNAL
;
}
s
->
height
=
value
;
if
(
!
ff_AMediaFormat_getInt32
(
s
->
format
,
"stride"
,
&
value
))
{
format
=
ff_AMediaFormat_toString
(
s
->
format
);
av_log
(
avctx
,
AV_LOG_ERROR
,
"Could not get %s from format %s
\n
"
,
"stride"
,
format
);
av_freep
(
&
format
);
return
AVERROR_EXTERNAL
;
}
s
->
stride
=
value
>=
0
?
value
:
s
->
width
;
if
(
!
ff_AMediaFormat_getInt32
(
s
->
format
,
"slice-height"
,
&
value
))
{
format
=
ff_AMediaFormat_toString
(
s
->
format
);
av_log
(
avctx
,
AV_LOG_ERROR
,
"Could not get %s from format %s
\n
"
,
"slice-height"
,
format
);
av_freep
(
&
format
);
return
AVERROR_EXTERNAL
;
}
if
(
value
>
0
)
{
s
->
slice_height
=
value
;
}
else
{
s
->
slice_height
=
s
->
height
;
}
if
(
strstr
(
s
->
codec_name
,
"OMX.Nvidia."
))
{
s
->
slice_height
=
FFALIGN
(
s
->
height
,
16
);
}
else
if
(
strstr
(
s
->
codec_name
,
"OMX.SEC.avc.dec"
))
{
s
->
slice_height
=
avctx
->
height
;
s
->
stride
=
avctx
->
width
;
}
if
(
!
ff_AMediaFormat_getInt32
(
s
->
format
,
"color-format"
,
&
value
))
{
format
=
ff_AMediaFormat_toString
(
s
->
format
);
av_log
(
avctx
,
AV_LOG_ERROR
,
"Could not get %s from format %s
\n
"
,
"color-format"
,
format
);
av_freep
(
&
format
);
return
AVERROR_EXTERNAL
;
}
s
->
color_format
=
value
;
s
->
pix_fmt
=
avctx
->
pix_fmt
=
mcdec_map_color_format
(
avctx
,
s
,
value
);
if
(
avctx
->
pix_fmt
==
AV_PIX_FMT_NONE
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Output color format is not supported
\n
"
);
return
AVERROR
(
EINVAL
);
}
/* Optional fields */
if
(
ff_AMediaFormat_getInt32
(
s
->
format
,
"crop-top"
,
&
value
))
s
->
crop_top
=
value
;
if
(
ff_AMediaFormat_getInt32
(
s
->
format
,
"crop-bottom"
,
&
value
))
s
->
crop_bottom
=
value
;
if
(
ff_AMediaFormat_getInt32
(
s
->
format
,
"crop-left"
,
&
value
))
s
->
crop_left
=
value
;
if
(
ff_AMediaFormat_getInt32
(
s
->
format
,
"crop-right"
,
&
value
))
s
->
crop_right
=
value
;
width
=
s
->
crop_right
+
1
-
s
->
crop_left
;
height
=
s
->
crop_bottom
+
1
-
s
->
crop_top
;
av_log
(
avctx
,
AV_LOG_INFO
,
"Output crop parameters top=%d bottom=%d left=%d right=%d, "
"resulting dimensions width=%d height=%d
\n
"
,
s
->
crop_top
,
s
->
crop_bottom
,
s
->
crop_left
,
s
->
crop_right
,
width
,
height
);
return
ff_set_dimensions
(
avctx
,
width
,
height
);
}
int
ff_mediacodec_dec_init
(
AVCodecContext
*
avctx
,
MediaCodecDecContext
*
s
,
const
char
*
mime
,
FFAMediaFormat
*
format
)
{
int
ret
=
0
;
int
status
;
s
->
first_buffer_at
=
av_gettime
();
s
->
codec_name
=
ff_AMediaCodecList_getCodecNameByType
(
mime
,
avctx
->
width
,
avctx
->
height
,
avctx
);
if
(
!
s
->
codec_name
)
{
ret
=
AVERROR_EXTERNAL
;
goto
fail
;
}
av_log
(
avctx
,
AV_LOG_DEBUG
,
"Found decoder %s
\n
"
,
s
->
codec_name
);
s
->
codec
=
ff_AMediaCodec_createCodecByName
(
s
->
codec_name
);
if
(
!
s
->
codec
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Failed to create media decoder for type %s and name %s
\n
"
,
mime
,
s
->
codec_name
);
ret
=
AVERROR_EXTERNAL
;
goto
fail
;
}
status
=
ff_AMediaCodec_configure
(
s
->
codec
,
format
,
NULL
,
NULL
,
0
);
if
(
status
<
0
)
{
char
*
desc
=
ff_AMediaFormat_toString
(
format
);
av_log
(
avctx
,
AV_LOG_ERROR
,
"Failed to configure codec (status = %d) with format %s
\n
"
,
status
,
desc
);
av_freep
(
&
desc
);
ret
=
AVERROR_EXTERNAL
;
goto
fail
;
}
status
=
ff_AMediaCodec_start
(
s
->
codec
);
if
(
status
<
0
)
{
char
*
desc
=
ff_AMediaFormat_toString
(
format
);
av_log
(
avctx
,
AV_LOG_ERROR
,
"Failed to start codec (status = %d) with format %s
\n
"
,
status
,
desc
);
av_freep
(
&
desc
);
ret
=
AVERROR_EXTERNAL
;
goto
fail
;
}
s
->
format
=
ff_AMediaCodec_getOutputFormat
(
s
->
codec
);
if
(
s
->
format
)
{
if
((
ret
=
mediacodec_dec_parse_format
(
avctx
,
s
))
<
0
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Failed to configure context
\n
"
);
goto
fail
;
}
}
av_log
(
avctx
,
AV_LOG_DEBUG
,
"MediaCodec %p started successfully
\n
"
,
s
->
codec
);
return
0
;
fail:
av_log
(
avctx
,
AV_LOG_ERROR
,
"MediaCodec %p failed to start
\n
"
,
s
->
codec
);
ff_mediacodec_dec_close
(
avctx
,
s
);
return
ret
;
}
int
ff_mediacodec_dec_decode
(
AVCodecContext
*
avctx
,
MediaCodecDecContext
*
s
,
AVFrame
*
frame
,
int
*
got_frame
,
AVPacket
*
pkt
)
{
int
ret
;
int
offset
=
0
;
int
need_flushing
=
0
;
uint8_t
*
data
;
ssize_t
index
;
size_t
size
;
FFAMediaCodec
*
codec
=
s
->
codec
;
FFAMediaCodecBufferInfo
info
=
{
0
};
int
status
;
int64_t
input_dequeue_timeout_us
=
INPUT_DEQUEUE_TIMEOUT_US
;
int64_t
output_dequeue_timeout_us
=
OUTPUT_DEQUEUE_TIMEOUT_US
;
if
(
pkt
->
size
==
0
)
{
need_flushing
=
1
;
}
if
(
s
->
flushing
&&
need_flushing
&&
s
->
queued_buffer_nb
<=
0
)
{
return
0
;
}
while
(
offset
<
pkt
->
size
||
(
need_flushing
&&
!
s
->
flushing
))
{
int
size
;
index
=
ff_AMediaCodec_dequeueInputBuffer
(
codec
,
input_dequeue_timeout_us
);
if
(
ff_AMediaCodec_infoTryAgainLater
(
codec
,
index
))
{
break
;
}
if
(
index
<
0
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Failed to dequeue input buffer (status=%zd)
\n
"
,
index
);
return
AVERROR_EXTERNAL
;
}
data
=
ff_AMediaCodec_getInputBuffer
(
codec
,
index
,
&
size
);
if
(
!
data
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Failed to get input buffer
\n
"
);
return
AVERROR_EXTERNAL
;
}
if
(
need_flushing
)
{
uint32_t
flags
=
ff_AMediaCodec_getBufferFlagEndOfStream
(
codec
);
av_log
(
avctx
,
AV_LOG_DEBUG
,
"Sending End Of Stream signal
\n
"
);
status
=
ff_AMediaCodec_queueInputBuffer
(
codec
,
index
,
0
,
0
,
pkt
->
pts
,
flags
);
if
(
status
<
0
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Failed to queue input empty buffer (status = %d)
\n
"
,
status
);
return
AVERROR_EXTERNAL
;
}
s
->
flushing
=
1
;
break
;
}
else
{
size
=
FFMIN
(
pkt
->
size
-
offset
,
size
);
memcpy
(
data
,
pkt
->
data
+
offset
,
size
);
offset
+=
size
;
status
=
ff_AMediaCodec_queueInputBuffer
(
codec
,
index
,
0
,
size
,
pkt
->
pts
,
0
);
if
(
status
<
0
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Failed to queue input buffer (status = %d)
\n
"
,
status
);
return
AVERROR_EXTERNAL
;
}
s
->
queued_buffer_nb
++
;
if
(
s
->
queued_buffer_nb
>
s
->
queued_buffer_max
)
s
->
queued_buffer_max
=
s
->
queued_buffer_nb
;
}
}
if
(
s
->
flushing
)
{
/* If the codec is flushing, block for a fair amount of time to
* ensure we got a frame */
output_dequeue_timeout_us
=
OUTPUT_DEQUEUE_BLOCK_TIMEOUT_US
;
}
else
if
(
s
->
dequeued_buffer_nb
==
0
)
{
/* If the codec hasn't produced any frames, do not block so we
* can push data to it as fast as possible, and get the first
* frame */
output_dequeue_timeout_us
=
0
;
}
index
=
ff_AMediaCodec_dequeueOutputBuffer
(
codec
,
&
info
,
output_dequeue_timeout_us
);
if
(
index
>=
0
)
{
int
ret
;
if
(
!
s
->
first_buffer
++
)
{
av_log
(
avctx
,
AV_LOG_DEBUG
,
"Got first buffer after %fms
\n
"
,
(
av_gettime
()
-
s
->
first_buffer_at
)
/
1000
);
}
av_log
(
avctx
,
AV_LOG_DEBUG
,
"Got output buffer %zd"
" offset=%"
PRIi32
" size=%"
PRIi32
" ts=%"
PRIi64
" flags=%"
PRIu32
"
\n
"
,
index
,
info
.
offset
,
info
.
size
,
info
.
presentationTimeUs
,
info
.
flags
);
data
=
ff_AMediaCodec_getOutputBuffer
(
codec
,
index
,
&
size
);
if
(
!
data
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Failed to get output buffer
\n
"
);
return
AVERROR_EXTERNAL
;
}
if
((
ret
=
mediacodec_wrap_buffer
(
avctx
,
s
,
data
,
size
,
index
,
&
info
,
frame
))
<
0
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Failed to wrap MediaCodec buffer
\n
"
);
return
ret
;
}
*
got_frame
=
1
;
s
->
queued_buffer_nb
--
;
s
->
dequeued_buffer_nb
++
;
}
else
if
(
ff_AMediaCodec_infoOutputFormatChanged
(
codec
,
index
))
{
char
*
format
=
NULL
;
if
(
s
->
format
)
{
status
=
ff_AMediaFormat_delete
(
s
->
format
);
if
(
status
<
0
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Failed to delete MediaFormat %p
\n
"
,
s
->
format
);
}
}
s
->
format
=
ff_AMediaCodec_getOutputFormat
(
codec
);
if
(
!
s
->
format
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Failed to get output format
\n
"
);
return
AVERROR_EXTERNAL
;
}
format
=
ff_AMediaFormat_toString
(
s
->
format
);
if
(
!
format
)
{
return
AVERROR_EXTERNAL
;
}
av_log
(
avctx
,
AV_LOG_INFO
,
"Output MediaFormat changed to %s
\n
"
,
format
);
av_freep
(
&
format
);
if
((
ret
=
mediacodec_dec_parse_format
(
avctx
,
s
))
<
0
)
{
return
ret
;
}
}
else
if
(
ff_AMediaCodec_infoOutputBuffersChanged
(
codec
,
index
))
{
ff_AMediaCodec_cleanOutputBuffers
(
codec
);
}
else
if
(
ff_AMediaCodec_infoTryAgainLater
(
codec
,
index
))
{
if
(
s
->
flushing
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Failed to dequeue output buffer within %"
PRIi64
"ms "
"while flushing remaining frames, output will probably lack last %d frames
\n
"
,
output_dequeue_timeout_us
/
1000
,
s
->
queued_buffer_nb
);
}
else
{
av_log
(
avctx
,
AV_LOG_DEBUG
,
"No output buffer available, try again later
\n
"
);
}
}
else
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Failed to dequeue output buffer (status=%zd)
\n
"
,
index
);
return
AVERROR_EXTERNAL
;
}
return
offset
;
}
int
ff_mediacodec_dec_flush
(
AVCodecContext
*
avctx
,
MediaCodecDecContext
*
s
)
{
FFAMediaCodec
*
codec
=
s
->
codec
;
int
status
;
s
->
queued_buffer_nb
=
0
;
s
->
dequeued_buffer_nb
=
0
;
s
->
flushing
=
0
;
status
=
ff_AMediaCodec_flush
(
codec
);
if
(
status
<
0
)
{
av_log
(
NULL
,
AV_LOG_ERROR
,
"Failed to flush MediaCodec %p"
,
codec
);
return
AVERROR_EXTERNAL
;
}
s
->
first_buffer
=
0
;
s
->
first_buffer_at
=
av_gettime
();
return
0
;
}
int
ff_mediacodec_dec_close
(
AVCodecContext
*
avctx
,
MediaCodecDecContext
*
s
)
{
if
(
s
->
codec
)
{
ff_AMediaCodec_delete
(
s
->
codec
);
s
->
codec
=
NULL
;
}
if
(
s
->
format
)
{
ff_AMediaFormat_delete
(
s
->
format
);
s
->
format
=
NULL
;
}
return
0
;
}
libavcodec/mediacodecdec.h
0 → 100644
View file @
4737fe69
/*
* Android MediaCodec decoder
*
* Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_MEDIACODECDEC_H
#define AVCODEC_MEDIACODECDEC_H
#include <stdint.h>
#include <sys/types.h>
#include "libavutil/frame.h"
#include "libavutil/pixfmt.h"
#include "avcodec.h"
#include "mediacodec_wrapper.h"
typedef
struct
MediaCodecDecContext
{
const
char
*
codec_name
;
FFAMediaCodec
*
codec
;
FFAMediaFormat
*
format
;
int
started
;
int
flushing
;
int
width
;
int
height
;
int
stride
;
int
slice_height
;
int
color_format
;
enum
AVPixelFormat
pix_fmt
;
int
crop_top
;
int
crop_bottom
;
int
crop_left
;
int
crop_right
;
int
queued_buffer_nb
;
int
queued_buffer_max
;
uint64_t
dequeued_buffer_nb
;
int
first_buffer
;
double
first_buffer_at
;
}
MediaCodecDecContext
;
int
ff_mediacodec_dec_init
(
AVCodecContext
*
avctx
,
MediaCodecDecContext
*
s
,
const
char
*
mime
,
FFAMediaFormat
*
format
);
int
ff_mediacodec_dec_decode
(
AVCodecContext
*
avctx
,
MediaCodecDecContext
*
s
,
AVFrame
*
frame
,
int
*
got_frame
,
AVPacket
*
pkt
);
int
ff_mediacodec_dec_flush
(
AVCodecContext
*
avctx
,
MediaCodecDecContext
*
s
);
int
ff_mediacodec_dec_close
(
AVCodecContext
*
avctx
,
MediaCodecDecContext
*
s
);
#endif
/* AVCODEC_MEDIACODECDEC_H */
libavcodec/mediacodecdec_h264.c
0 → 100644
View file @
4737fe69
/*
* Android MediaCodec H.264 decoder
*
* Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
#include <string.h>
#include "libavutil/common.h"
#include "libavutil/fifo.h"
#include "libavutil/opt.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/pixfmt.h"
#include "libavutil/atomic.h"
#include "avcodec.h"
#include "internal.h"
#include "mediacodecdec.h"
#include "mediacodec_wrapper.h"
#define CODEC_MIME "video/avc"
typedef
struct
MediaCodecH264DecContext
{
MediaCodecDecContext
ctx
;
AVBitStreamFilterContext
*
bsf
;
AVFifoBuffer
*
fifo
;
AVPacket
input_ref
;
AVPacket
filtered_pkt
;
uint8_t
*
filtered_data
;
}
MediaCodecH264DecContext
;
static
int
h264_extradata_to_annexb_sps_pps
(
AVCodecContext
*
avctx
,
uint8_t
**
extradata_annexb
,
int
*
extradata_annexb_size
,
int
*
sps_offset
,
int
*
sps_size
,
int
*
pps_offset
,
int
*
pps_size
)
{
uint16_t
unit_size
;
uint64_t
total_size
=
0
;
uint8_t
i
,
j
,
unit_nb
;
uint8_t
sps_seen
=
0
;
uint8_t
pps_seen
=
0
;
const
uint8_t
*
extradata
;
static
const
uint8_t
nalu_header
[
4
]
=
{
0x00
,
0x00
,
0x00
,
0x01
};
if
(
avctx
->
extradata_size
<
8
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Too small extradata size, corrupted stream or invalid MP4/AVCC bitstream
\n
"
);
return
AVERROR
(
EINVAL
);
}
*
extradata_annexb
=
NULL
;
*
extradata_annexb_size
=
0
;
*
sps_offset
=
*
sps_size
=
0
;
*
pps_offset
=
*
pps_size
=
0
;
extradata
=
avctx
->
extradata
+
4
;
/* skip length size */
extradata
++
;
for
(
j
=
0
;
j
<
2
;
j
++
)
{
if
(
j
==
0
)
{
/* number of sps unit(s) */
unit_nb
=
*
extradata
++
&
0x1f
;
}
else
{
/* number of pps unit(s) */
unit_nb
=
*
extradata
++
;
}
for
(
i
=
0
;
i
<
unit_nb
;
i
++
)
{
int
err
;
unit_size
=
AV_RB16
(
extradata
);
total_size
+=
unit_size
+
4
;
if
(
total_size
>
INT_MAX
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Too big extradata size, corrupted stream or invalid MP4/AVCC bitstream
\n
"
);
av_freep
(
extradata_annexb
);
return
AVERROR
(
EINVAL
);
}
if
(
extradata
+
2
+
unit_size
>
avctx
->
extradata
+
avctx
->
extradata_size
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Packet header is not contained in global extradata, "
"corrupted stream or invalid MP4/AVCC bitstream
\n
"
);
av_freep
(
extradata_annexb
);
return
AVERROR
(
EINVAL
);
}
if
((
err
=
av_reallocp
(
extradata_annexb
,
total_size
))
<
0
)
{
return
err
;
}
memcpy
(
*
extradata_annexb
+
total_size
-
unit_size
-
4
,
nalu_header
,
4
);
memcpy
(
*
extradata_annexb
+
total_size
-
unit_size
,
extradata
+
2
,
unit_size
);
extradata
+=
2
+
unit_size
;
}
if
(
unit_nb
)
{
if
(
j
==
0
)
{
sps_seen
=
1
;
*
sps_size
=
total_size
;
}
else
{
pps_seen
=
1
;
*
pps_size
=
total_size
-
*
sps_size
;
*
pps_offset
=
*
sps_size
;
}
}
}
*
extradata_annexb_size
=
total_size
;
if
(
!
sps_seen
)
av_log
(
avctx
,
AV_LOG_WARNING
,
"Warning: SPS NALU missing or invalid. "
"The resulting stream may not play.
\n
"
);
if
(
!
pps_seen
)
av_log
(
avctx
,
AV_LOG_WARNING
,
"Warning: PPS NALU missing or invalid. "
"The resulting stream may not play.
\n
"
);
return
0
;
}
static
av_cold
int
mediacodec_decode_close
(
AVCodecContext
*
avctx
)
{
MediaCodecH264DecContext
*
s
=
avctx
->
priv_data
;
ff_mediacodec_dec_close
(
avctx
,
&
s
->
ctx
);
av_fifo_free
(
s
->
fifo
);
av_bitstream_filter_close
(
s
->
bsf
);
return
0
;
}
static
av_cold
int
mediacodec_decode_init
(
AVCodecContext
*
avctx
)
{
int
ret
;
FFAMediaFormat
*
format
=
NULL
;
MediaCodecH264DecContext
*
s
=
avctx
->
priv_data
;
format
=
ff_AMediaFormat_new
();
if
(
!
format
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Failed to create media format
\n
"
);
ret
=
AVERROR_EXTERNAL
;
goto
done
;
}
ff_AMediaFormat_setString
(
format
,
"mime"
,
CODEC_MIME
);
ff_AMediaFormat_setInt32
(
format
,
"width"
,
avctx
->
width
);
ff_AMediaFormat_setInt32
(
format
,
"height"
,
avctx
->
height
);
if
(
avctx
->
extradata
[
0
]
==
1
)
{
uint8_t
*
extradata
=
NULL
;
int
extradata_size
=
0
;
int
sps_offset
,
sps_size
;
int
pps_offset
,
pps_size
;
if
((
ret
=
h264_extradata_to_annexb_sps_pps
(
avctx
,
&
extradata
,
&
extradata_size
,
&
sps_offset
,
&
sps_size
,
&
pps_offset
,
&
pps_size
))
<
0
)
{
goto
done
;
}
ff_AMediaFormat_setBuffer
(
format
,
"csd-0"
,
extradata
+
sps_offset
,
sps_size
);
ff_AMediaFormat_setBuffer
(
format
,
"csd-1"
,
extradata
+
pps_offset
,
pps_size
);
av_freep
(
&
extradata
);
}
else
{
ff_AMediaFormat_setBuffer
(
format
,
"csd-0"
,
avctx
->
extradata
,
avctx
->
extradata_size
);
}
if
((
ret
=
ff_mediacodec_dec_init
(
avctx
,
&
s
->
ctx
,
CODEC_MIME
,
format
))
<
0
)
{
goto
done
;
}
av_log
(
avctx
,
AV_LOG_INFO
,
"MediaCodec started successfully, ret = %d
\n
"
,
ret
);
s
->
fifo
=
av_fifo_alloc
(
sizeof
(
AVPacket
));
if
(
!
s
->
fifo
)
{
ret
=
AVERROR
(
ENOMEM
);
goto
done
;
}
s
->
bsf
=
av_bitstream_filter_init
(
"h264_mp4toannexb"
);
if
(
!
s
->
bsf
)
{
ret
=
AVERROR
(
ENOMEM
);
goto
done
;
}
done:
if
(
format
)
{
ff_AMediaFormat_delete
(
format
);
}
if
(
ret
<
0
)
{
mediacodec_decode_close
(
avctx
);
}
return
ret
;
}
static
int
mediacodec_process_data
(
AVCodecContext
*
avctx
,
AVFrame
*
frame
,
int
*
got_frame
,
AVPacket
*
pkt
)
{
MediaCodecH264DecContext
*
s
=
avctx
->
priv_data
;
return
ff_mediacodec_dec_decode
(
avctx
,
&
s
->
ctx
,
frame
,
got_frame
,
pkt
);
}
static
int
mediacodec_decode_frame
(
AVCodecContext
*
avctx
,
void
*
data
,
int
*
got_frame
,
AVPacket
*
avpkt
)
{
MediaCodecH264DecContext
*
s
=
avctx
->
priv_data
;
AVFrame
*
frame
=
data
;
int
ret
;
/* buffer the input packet */
if
(
avpkt
->
size
)
{
AVPacket
input_ref
=
{
0
};
if
(
av_fifo_space
(
s
->
fifo
)
<
sizeof
(
input_ref
))
{
ret
=
av_fifo_realloc2
(
s
->
fifo
,
av_fifo_size
(
s
->
fifo
)
+
sizeof
(
input_ref
));
if
(
ret
<
0
)
return
ret
;
}
ret
=
av_packet_ref
(
&
input_ref
,
avpkt
);
if
(
ret
<
0
)
return
ret
;
av_fifo_generic_write
(
s
->
fifo
,
&
input_ref
,
sizeof
(
input_ref
),
NULL
);
}
/* process buffered data */
while
(
!*
got_frame
)
{
/* prepare the input data -- convert to Annex B if needed */
if
(
s
->
filtered_pkt
.
size
<=
0
)
{
int
size
;
/* no more data */
if
(
av_fifo_size
(
s
->
fifo
)
<
sizeof
(
AVPacket
))
{
return
avpkt
->
size
?
avpkt
->
size
:
ff_mediacodec_dec_decode
(
avctx
,
&
s
->
ctx
,
frame
,
got_frame
,
avpkt
);
}
if
(
s
->
filtered_data
!=
s
->
input_ref
.
data
)
av_freep
(
&
s
->
filtered_data
);
s
->
filtered_data
=
NULL
;
av_packet_unref
(
&
s
->
input_ref
);
av_fifo_generic_read
(
s
->
fifo
,
&
s
->
input_ref
,
sizeof
(
s
->
input_ref
),
NULL
);
ret
=
av_bitstream_filter_filter
(
s
->
bsf
,
avctx
,
NULL
,
&
s
->
filtered_data
,
&
size
,
s
->
input_ref
.
data
,
s
->
input_ref
.
size
,
0
);
if
(
ret
<
0
)
{
s
->
filtered_data
=
s
->
input_ref
.
data
;
size
=
s
->
input_ref
.
size
;
}
s
->
filtered_pkt
=
s
->
input_ref
;
s
->
filtered_pkt
.
data
=
s
->
filtered_data
;
s
->
filtered_pkt
.
size
=
size
;
}
ret
=
mediacodec_process_data
(
avctx
,
frame
,
got_frame
,
&
s
->
filtered_pkt
);
if
(
ret
<
0
)
return
ret
;
s
->
filtered_pkt
.
size
-=
ret
;
s
->
filtered_pkt
.
data
+=
ret
;
}
return
avpkt
->
size
;
}
static
void
mediacodec_decode_flush
(
AVCodecContext
*
avctx
)
{
MediaCodecH264DecContext
*
s
=
avctx
->
priv_data
;
while
(
av_fifo_size
(
s
->
fifo
))
{
AVPacket
pkt
;
av_fifo_generic_read
(
s
->
fifo
,
&
pkt
,
sizeof
(
pkt
),
NULL
);
av_packet_unref
(
&
pkt
);
}
av_fifo_reset
(
s
->
fifo
);
av_packet_unref
(
&
s
->
input_ref
);
av_init_packet
(
&
s
->
filtered_pkt
);
s
->
filtered_pkt
.
data
=
NULL
;
s
->
filtered_pkt
.
size
=
0
;
ff_mediacodec_dec_flush
(
avctx
,
&
s
->
ctx
);
}
AVCodec
ff_h264_mediacodec_decoder
=
{
.
name
=
"h264_mediacodec"
,
.
long_name
=
NULL_IF_CONFIG_SMALL
(
"H.264 Android MediaCodec decoder"
),
.
type
=
AVMEDIA_TYPE_VIDEO
,
.
id
=
AV_CODEC_ID_H264
,
.
priv_data_size
=
sizeof
(
MediaCodecH264DecContext
),
.
init
=
mediacodec_decode_init
,
.
decode
=
mediacodec_decode_frame
,
.
flush
=
mediacodec_decode_flush
,
.
close
=
mediacodec_decode_close
,
.
capabilities
=
CODEC_CAP_DELAY
,
};
libavcodec/version.h
View file @
4737fe69
...
@@ -28,8 +28,8 @@
...
@@ -28,8 +28,8 @@
#include "libavutil/version.h"
#include "libavutil/version.h"
#define LIBAVCODEC_VERSION_MAJOR 57
#define LIBAVCODEC_VERSION_MAJOR 57
#define LIBAVCODEC_VERSION_MINOR 2
7
#define LIBAVCODEC_VERSION_MINOR 2
8
#define LIBAVCODEC_VERSION_MICRO 10
1
#define LIBAVCODEC_VERSION_MICRO 10
0
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \
LIBAVCODEC_VERSION_MINOR, \
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment