From 98469ebea59c921f46a114bd954f7a27a7c95a41 Mon Sep 17 00:00:00 2001 From: ayache Date: Mon, 4 May 2020 18:58:55 +0200 Subject: [PATCH] Add hw Android decoder/encoder based on MediaCodec to FFmpeg #17 --- captive/ffmpeg/csrc/configure | 8 + captive/ffmpeg/csrc/libavcodec/Makefile | 14 +- captive/ffmpeg/csrc/libavcodec/allcodecs.c | 13 +- captive/ffmpeg/csrc/libavcodec/mediacodec.h | 72 +- .../ffmpeg/csrc/libavcodec/mediacodecdec.c | 926 ++++++++---------- .../ffmpeg/csrc/libavcodec/mediacodecenc.c | 295 ++++++ captive/ffmpeg/csrc/libavutil/pixdesc.c | 146 +-- captive/ffmpeg/csrc/libavutil/pixfmt.h | 4 +- captive/ffmpeg/incarcerate.in | 9 + 9 files changed, 739 insertions(+), 748 deletions(-) create mode 100644 captive/ffmpeg/csrc/libavcodec/mediacodecenc.c diff --git a/captive/ffmpeg/csrc/configure b/captive/ffmpeg/csrc/configure index 51c5db53e6f..84afb755107 100755 --- a/captive/ffmpeg/csrc/configure +++ b/captive/ffmpeg/csrc/configure @@ -202,6 +202,7 @@ External library support: Also note that the following help text describes the purpose of the libraries themselves, not all their features will necessarily be usable by FFmpeg. + --enable-mediandk enable Android MediaCodec support using NDKMediaCodec [autodetect] --disable-alsa disable ALSA support [autodetect] --disable-appkit disable Apple AppKit framework [autodetect] --disable-avfoundation disable Apple AVFoundation framework [autodetect] @@ -1544,6 +1545,7 @@ EXTERNAL_AUTODETECT_LIBRARY_LIST=" sndio xlib zlib + mediandk " EXTERNAL_LIBRARY_GPL_LIST=" @@ -1638,6 +1640,7 @@ EXTERNAL_LIBRARY_LIST=" openal opencl opengl + " HWACCEL_AUTODETECT_LIBRARY_LIST=" @@ -2993,6 +2996,8 @@ libx264_encoder_deps="libx264" libx264rgb_encoder_deps="libx264 x264_csp_bgr" libx264rgb_encoder_select="libx264_encoder" libx265_encoder_deps="libx265" +mediacodec_decoder_deps="mediandk" +mediacodec_encoder_deps="mediandk" libxavs_encoder_deps="libxavs" libxvid_encoder_deps="libxvid" libzvbi_teletext_decoder_deps="libzvbi" @@ -6085,6 +6090,9 @@ enabled rkmpp && { { require_pkg_config rockchip_mpp rockchip_mpp ro { enabled libdrm || die "ERROR: rkmpp requires --enable-libdrm"; } } +enabled mediandk && { check_lib mediandk media/NdkMediaCodec.h AMediaCodec_createCodecByName -lmediandk && + check_lib android android/native_window_jni.h ANativeWindow_fromSurface -landroid; + } if enabled gcrypt; then GCRYPT_CONFIG="${cross_prefix}libgcrypt-config" diff --git a/captive/ffmpeg/csrc/libavcodec/Makefile b/captive/ffmpeg/csrc/libavcodec/Makefile index c4ec09b1c45..bedb71824b8 100644 --- a/captive/ffmpeg/csrc/libavcodec/Makefile +++ b/captive/ffmpeg/csrc/libavcodec/Makefile @@ -9,7 +9,6 @@ HEADERS = avcodec.h \ dv_profile.h \ dxva2.h \ jni.h \ - mediacodec.h \ qsv.h \ vaapi.h \ vda.h \ @@ -18,6 +17,7 @@ HEADERS = avcodec.h \ videotoolbox.h \ vorbis_parser.h \ xvmc.h \ + mediacodec.h \ OBJS = allcodecs.o \ audioconvert.o \ @@ -37,7 +37,6 @@ OBJS = allcodecs.o \ imgconvert.o \ jni.o \ mathtables.o \ - mediacodec.o \ mpeg12framerate.o \ options.o \ mjpegenc_huffman.o \ @@ -100,7 +99,6 @@ OBJS-$(CONFIG_LSP) += lsp.o OBJS-$(CONFIG_LZF) += lzf.o OBJS-$(CONFIG_MDCT) += mdct_fixed.o mdct_float.o mdct_fixed_32.o OBJS-$(CONFIG_ME_CMP) += me_cmp.o -OBJS-$(CONFIG_MEDIACODEC) += mediacodecdec_common.o mediacodec_surface.o mediacodec_wrapper.o mediacodec_sw_buffer.o OBJS-$(CONFIG_MPEG_ER) += mpeg_er.o OBJS-$(CONFIG_MPEGAUDIO) += mpegaudio.o OBJS-$(CONFIG_MPEGAUDIODSP) += mpegaudiodsp.o \ @@ -332,7 +330,6 @@ OBJS-$(CONFIG_H264_DECODER) += h264dec.o h264_cabac.o h264_cavlc.o \ h264_refs.o h264_sei.o \ h264_slice.o h264data.o OBJS-$(CONFIG_H264_CUVID_DECODER) += cuvid.o -OBJS-$(CONFIG_H264_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_H264_MMAL_DECODER) += mmaldec.o OBJS-$(CONFIG_H264_NVENC_ENCODER) += nvenc_h264.o OBJS-$(CONFIG_NVENC_ENCODER) += nvenc_h264.o @@ -351,8 +348,9 @@ OBJS-$(CONFIG_HAP_ENCODER) += hapenc.o hap.o OBJS-$(CONFIG_HEVC_DECODER) += hevcdec.o hevc_mvs.o \ hevc_cabac.o hevc_refs.o hevcpred.o \ hevcdsp.o hevc_filter.o hevc_data.o +OBJS-$(CONFIG_MEDIACODEC_DECODER) += mediacodecdec.o +OBJS-$(CONFIG_MEDIACODEC_ENCODER) += mediacodecenc.o OBJS-$(CONFIG_HEVC_CUVID_DECODER) += cuvid.o -OBJS-$(CONFIG_HEVC_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_HEVC_NVENC_ENCODER) += nvenc_hevc.o OBJS-$(CONFIG_NVENC_HEVC_ENCODER) += nvenc_hevc.o OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec_h2645.o @@ -437,11 +435,9 @@ OBJS-$(CONFIG_MPEG2_QSV_DECODER) += qsvdec_other.o OBJS-$(CONFIG_MPEG2_QSV_ENCODER) += qsvenc_mpeg2.o OBJS-$(CONFIG_MPEG2VIDEO_DECODER) += mpeg12dec.o mpeg12.o mpeg12data.o OBJS-$(CONFIG_MPEG2VIDEO_ENCODER) += mpeg12enc.o mpeg12.o -OBJS-$(CONFIG_MPEG2_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_MPEG2_VAAPI_ENCODER) += vaapi_encode_mpeg2.o OBJS-$(CONFIG_MPEG2_V4L2M2M_DECODER) += v4l2_m2m_dec.o OBJS-$(CONFIG_MPEG4_DECODER) += xvididct.o -OBJS-$(CONFIG_MPEG4_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_MPEG4_OMX_ENCODER) += omx.o OBJS-$(CONFIG_MPEG4_V4L2M2M_DECODER) += v4l2_m2m_dec.o OBJS-$(CONFIG_MPEG4_V4L2M2M_ENCODER) += v4l2_m2m_enc.o @@ -636,7 +632,6 @@ OBJS-$(CONFIG_VP6_DECODER) += vp6.o vp56.o vp56data.o \ OBJS-$(CONFIG_VP7_DECODER) += vp8.o vp56rac.o OBJS-$(CONFIG_VP8_DECODER) += vp8.o vp56rac.o OBJS-$(CONFIG_VP8_CUVID_DECODER) += cuvid.o -OBJS-$(CONFIG_VP8_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_VP8_QSV_DECODER) += qsvdec_other.o OBJS-$(CONFIG_VP8_RKMPP_DECODER) += rkmppdec.o OBJS-$(CONFIG_VP8_VAAPI_ENCODER) += vaapi_encode_vp8.o @@ -646,7 +641,6 @@ OBJS-$(CONFIG_VP9_DECODER) += vp9.o vp9data.o vp9dsp.o vp9lpf.o vp9r vp9block.o vp9prob.o vp9mvs.o vp56rac.o \ vp9dsp_8bpp.o vp9dsp_10bpp.o vp9dsp_12bpp.o OBJS-$(CONFIG_VP9_CUVID_DECODER) += cuvid.o -OBJS-$(CONFIG_VP9_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_VP9_RKMPP_DECODER) += rkmppdec.o OBJS-$(CONFIG_VP9_VAAPI_ENCODER) += vaapi_encode_vp9.o OBJS-$(CONFIG_VPLAYER_DECODER) += textdec.o ass.o @@ -1053,7 +1047,7 @@ SKIPHEADERS-$(CONFIG_DXVA2) += dxva2.h dxva2_internal.h SKIPHEADERS-$(CONFIG_JNI) += ffjni.h SKIPHEADERS-$(CONFIG_LIBVPX) += libvpx.h SKIPHEADERS-$(CONFIG_LIBWEBP_ENCODER) += libwebpenc_common.h -SKIPHEADERS-$(CONFIG_MEDIACODEC) += mediacodecdec_common.h mediacodec_surface.h mediacodec_wrapper.h mediacodec_sw_buffer.h +SKIPHEADERS-$(CONFIG_MEDIANDK) += mediacodec.h SKIPHEADERS-$(CONFIG_NVENC) += nvenc.h SKIPHEADERS-$(CONFIG_QSV) += qsv.h qsv_internal.h SKIPHEADERS-$(CONFIG_QSVDEC) += qsvdec.h diff --git a/captive/ffmpeg/csrc/libavcodec/allcodecs.c b/captive/ffmpeg/csrc/libavcodec/allcodecs.c index 4f34312e673..89bcde576d7 100644 --- a/captive/ffmpeg/csrc/libavcodec/allcodecs.c +++ b/captive/ffmpeg/csrc/libavcodec/allcodecs.c @@ -68,7 +68,6 @@ static void register_all(void) REGISTER_HWACCEL(H264_D3D11VA, h264_d3d11va); REGISTER_HWACCEL(H264_D3D11VA2, h264_d3d11va2); REGISTER_HWACCEL(H264_DXVA2, h264_dxva2); - REGISTER_HWACCEL(H264_MEDIACODEC, h264_mediacodec); REGISTER_HWACCEL(H264_MMAL, h264_mmal); REGISTER_HWACCEL(H264_QSV, h264_qsv); REGISTER_HWACCEL(H264_VAAPI, h264_vaapi); @@ -80,7 +79,6 @@ static void register_all(void) REGISTER_HWACCEL(HEVC_D3D11VA, hevc_d3d11va); REGISTER_HWACCEL(HEVC_D3D11VA2, hevc_d3d11va2); REGISTER_HWACCEL(HEVC_DXVA2, hevc_dxva2); - REGISTER_HWACCEL(HEVC_MEDIACODEC, hevc_mediacodec); REGISTER_HWACCEL(HEVC_QSV, hevc_qsv); REGISTER_HWACCEL(HEVC_VAAPI, hevc_vaapi); REGISTER_HWACCEL(HEVC_VDPAU, hevc_vdpau); @@ -100,9 +98,7 @@ static void register_all(void) REGISTER_HWACCEL(MPEG2_VAAPI, mpeg2_vaapi); REGISTER_HWACCEL(MPEG2_VDPAU, mpeg2_vdpau); REGISTER_HWACCEL(MPEG2_VIDEOTOOLBOX, mpeg2_videotoolbox); - REGISTER_HWACCEL(MPEG2_MEDIACODEC, mpeg2_mediacodec); REGISTER_HWACCEL(MPEG4_CUVID, mpeg4_cuvid); - REGISTER_HWACCEL(MPEG4_MEDIACODEC, mpeg4_mediacodec); REGISTER_HWACCEL(MPEG4_MMAL, mpeg4_mmal); REGISTER_HWACCEL(MPEG4_VAAPI, mpeg4_vaapi); REGISTER_HWACCEL(MPEG4_VDPAU, mpeg4_vdpau); @@ -116,13 +112,11 @@ static void register_all(void) REGISTER_HWACCEL(VC1_MMAL, vc1_mmal); REGISTER_HWACCEL(VC1_QSV, vc1_qsv); REGISTER_HWACCEL(VP8_CUVID, vp8_cuvid); - REGISTER_HWACCEL(VP8_MEDIACODEC, vp8_mediacodec); REGISTER_HWACCEL(VP8_QSV, vp8_qsv); REGISTER_HWACCEL(VP9_CUVID, vp9_cuvid); REGISTER_HWACCEL(VP9_D3D11VA, vp9_d3d11va); REGISTER_HWACCEL(VP9_D3D11VA2, vp9_d3d11va2); REGISTER_HWACCEL(VP9_DXVA2, vp9_dxva2); - REGISTER_HWACCEL(VP9_MEDIACODEC, vp9_mediacodec); REGISTER_HWACCEL(VP9_VAAPI, vp9_vaapi); REGISTER_HWACCEL(WMV3_D3D11VA, wmv3_d3d11va); REGISTER_HWACCEL(WMV3_D3D11VA2, wmv3_d3d11va2); @@ -213,7 +207,6 @@ static void register_all(void) REGISTER_DECODER(H264, h264); REGISTER_DECODER(H264_CRYSTALHD, h264_crystalhd); REGISTER_DECODER(H264_V4L2M2M, h264_v4l2m2m); - REGISTER_DECODER(H264_MEDIACODEC, h264_mediacodec); REGISTER_DECODER(H264_MMAL, h264_mmal); REGISTER_DECODER(H264_QSV, h264_qsv); REGISTER_DECODER(H264_RKMPP, h264_rkmpp); @@ -275,7 +268,6 @@ static void register_all(void) REGISTER_DECODER(MPEG2_CRYSTALHD, mpeg2_crystalhd); REGISTER_DECODER(MPEG2_V4L2M2M, mpeg2_v4l2m2m); REGISTER_DECODER(MPEG2_QSV, mpeg2_qsv); - REGISTER_DECODER(MPEG2_MEDIACODEC, mpeg2_mediacodec); REGISTER_DECODER(MSA1, msa1); REGISTER_DECODER(MSCC, mscc); REGISTER_DECODER(MSMPEG4V1, msmpeg4v1); @@ -684,7 +676,6 @@ static void register_all(void) REGISTER_ENCODER(NVENC_HEVC, nvenc_hevc); #endif REGISTER_DECODER(HEVC_CUVID, hevc_cuvid); - REGISTER_DECODER(HEVC_MEDIACODEC, hevc_mediacodec); REGISTER_ENCODER(HEVC_NVENC, hevc_nvenc); REGISTER_ENCODER(HEVC_QSV, hevc_qsv); REGISTER_ENCODER(HEVC_V4L2M2M, hevc_v4l2m2m); @@ -697,17 +688,15 @@ static void register_all(void) REGISTER_ENCODER(MPEG2_QSV, mpeg2_qsv); REGISTER_ENCODER(MPEG2_VAAPI, mpeg2_vaapi); REGISTER_DECODER(MPEG4_CUVID, mpeg4_cuvid); - REGISTER_DECODER(MPEG4_MEDIACODEC, mpeg4_mediacodec); REGISTER_ENCODER(MPEG4_V4L2M2M, mpeg4_v4l2m2m); REGISTER_DECODER(VC1_CUVID, vc1_cuvid); REGISTER_DECODER(VP8_CUVID, vp8_cuvid); - REGISTER_DECODER(VP8_MEDIACODEC, vp8_mediacodec); REGISTER_DECODER(VP8_QSV, vp8_qsv); REGISTER_ENCODER(VP8_V4L2M2M, vp8_v4l2m2m); REGISTER_ENCODER(VP8_VAAPI, vp8_vaapi); REGISTER_DECODER(VP9_CUVID, vp9_cuvid); - REGISTER_DECODER(VP9_MEDIACODEC, vp9_mediacodec); REGISTER_ENCODER(VP9_VAAPI, vp9_vaapi); + REGISTER_ENCDEC(MEDIACODEC, mediacodec); /* parsers */ REGISTER_PARSER(AAC, aac); diff --git a/captive/ffmpeg/csrc/libavcodec/mediacodec.h b/captive/ffmpeg/csrc/libavcodec/mediacodec.h index 5606d24a1ee..480d4814d25 100644 --- a/captive/ffmpeg/csrc/libavcodec/mediacodec.h +++ b/captive/ffmpeg/csrc/libavcodec/mediacodec.h @@ -1,7 +1,5 @@ /* - * Android MediaCodec public API - * - * Copyright (c) 2016 Matthieu Bouron + * Copyright (c) 2018 Olivier Ayache * * This file is part of FFmpeg. * @@ -20,69 +18,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_MEDIACODEC_H -#define AVCODEC_MEDIACODEC_H - -#include "libavcodec/avcodec.h" - -/** - * This structure holds a reference to a android/view/Surface object that will - * be used as output by the decoder. - * - */ -typedef struct AVMediaCodecContext { - - /** - * android/view/Surface object reference. - */ - void *surface; - -} AVMediaCodecContext; - -/** - * Allocate and initialize a MediaCodec context. - * - * When decoding with MediaCodec is finished, the caller must free the - * MediaCodec context with av_mediacodec_default_free. - * - * @return a pointer to a newly allocated AVMediaCodecContext on success, NULL otherwise - */ -AVMediaCodecContext *av_mediacodec_alloc_context(void); - -/** - * Convenience function that sets up the MediaCodec context. - * - * @param avctx codec context - * @param ctx MediaCodec context to initialize - * @param surface reference to an android/view/Surface - * @return 0 on success, < 0 otherwise - */ -int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx, void *surface); - -/** - * This function must be called to free the MediaCodec context initialized with - * av_mediacodec_default_init(). - * - * @param avctx codec context - */ -void av_mediacodec_default_free(AVCodecContext *avctx); +#include +#include "avcodec.h" -/** - * Opaque structure representing a MediaCodec buffer to render. - */ -typedef struct MediaCodecBuffer AVMediaCodecBuffer; +void mediacodec_alloc_context(AVCodecContext* context, JNIEnv* env, jobject surface_object); -/** - * Release a MediaCodec buffer and render it to the surface that is associated - * with the decoder. This function should only be called once on a given - * buffer, once released the underlying buffer returns to the codec, thus - * subsequent calls to this function will have no effect. - * - * @param buffer the buffer to render - * @param render 1 to release and render the buffer to the surface or 0 to - * discard the buffer - * @return 0 on success, < 0 otherwise - */ -int av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render); +void mediacodec_free_context(AVCodecContext* context); -#endif /* AVCODEC_MEDIACODEC_H */ +void mediacodec_render_frame(AVFrame* frame); diff --git a/captive/ffmpeg/csrc/libavcodec/mediacodecdec.c b/captive/ffmpeg/csrc/libavcodec/mediacodecdec.c index 6962ce2474f..a1fdba9e5fa 100644 --- a/captive/ffmpeg/csrc/libavcodec/mediacodecdec.c +++ b/captive/ffmpeg/csrc/libavcodec/mediacodecdec.c @@ -1,7 +1,5 @@ /* - * Android MediaCodec MPEG-2 / H.264 / H.265 / MPEG-4 / VP8 / VP9 decoders - * - * Copyright (c) 2015-2016 Matthieu Bouron + * Copyright (c) 2018-2020 Olivier Ayache * * This file is part of FFmpeg. * @@ -20,595 +18,495 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include - -#include "libavutil/avassert.h" -#include "libavutil/common.h" -#include "libavutil/fifo.h" -#include "libavutil/opt.h" -#include "libavutil/intreadwrite.h" -#include "libavutil/pixfmt.h" - +#include "mediacodec.h" #include "avcodec.h" +#include "bytestream.h" +#include "internal.h" +#include "h2645_parse.h" #include "h264_parse.h" #include "hevc_parse.h" -#include "internal.h" -#include "mediacodec_wrapper.h" -#include "mediacodecdec_common.h" - -typedef struct MediaCodecH264DecContext { - - MediaCodecDecContext *ctx; - - AVFifoBuffer *fifo; - - AVPacket buffered_pkt; - -} MediaCodecH264DecContext; - -static av_cold int mediacodec_decode_close(AVCodecContext *avctx) -{ - MediaCodecH264DecContext *s = avctx->priv_data; - - ff_mediacodec_dec_close(avctx, s->ctx); - s->ctx = NULL; - - av_fifo_free(s->fifo); - - av_packet_unref(&s->buffered_pkt); - - return 0; -} +#include +#include +#include +#include +#include +#include + +const uint8_t startCode [] = {0x00, 0x00, 0x00, 0x01}; + +typedef struct MediaCodecDecContext { + AMediaCodec* codec; + AMediaFormat* format; + uint8_t* csd; + AVCodecContext *avctx; + H264ParamSets h264_ps; + HEVCParamSets hevc_ps; + HEVCSEIContext hevc_sei; + H2645Packet pkt; + int is_nalff; ///< this flag is != 0 if bitstream is encapsulated + int nal_length_size; ///< Number of bytes used for nal length (1, 2 or 4) + int nuh_layer_id; + const AVClass *class; // needed by private avoptions + enum AVPixelFormat preferred_fmt; + +} MediaCodecDecContext; + +typedef struct MediaCodecSurfaceContext { + JNIEnv* env; + jobject surface_object; + ANativeWindow* surface; +} MediaCodecSurfaceContext; + +typedef struct MediaCodecSurfaceRenderContext { + AMediaCodec* codec; + int index; +} MediaCodecSurfaceRenderContext; + + +static const AVOption options[] = { + { "preferred_fmt", "Sets the preferred pixel format ", offsetof(MediaCodecDecContext, preferred_fmt), AV_OPT_TYPE_PIXEL_FMT, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM}, + { NULL} +}; -#if CONFIG_H264_MEDIACODEC_DECODER || CONFIG_HEVC_MEDIACODEC_DECODER -static int h2645_ps_to_nalu(const uint8_t *src, int src_size, uint8_t **out, int *out_size) -{ - int i; - int ret = 0; - uint8_t *p = NULL; - static const uint8_t nalu_header[] = { 0x00, 0x00, 0x00, 0x01 }; +static const AVClass mediacodec_class = { + .class_name = "MediaCodec decoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; - if (!out || !out_size) { - return AVERROR(EINVAL); +void mediacodec_alloc_context(AVCodecContext* avcontext, JNIEnv* env, jobject surface_object) { + MediaCodecSurfaceContext* context = av_mallocz(sizeof (MediaCodecSurfaceContext)); + if (avcontext && env && surface_object && context) { + context->env = env; + context->surface_object = (*env)->NewGlobalRef(env, surface_object); + avcontext->hwaccel_context = context; + } else { + av_free(context); } +} - p = av_malloc(sizeof(nalu_header) + src_size); - if (!p) { - return AVERROR(ENOMEM); +static MediaCodecSurfaceRenderContext* mediacodec_alloc_surface_context(AMediaCodec* codec, int index) { + MediaCodecSurfaceRenderContext* context = av_mallocz(sizeof (MediaCodecSurfaceRenderContext)); + if (codec && context) { + context->codec = codec; + context->index = index; + } else { + av_freep(&context); } + return context; +} - *out = p; - *out_size = sizeof(nalu_header) + src_size; - - memcpy(p, nalu_header, sizeof(nalu_header)); - memcpy(p + sizeof(nalu_header), src, src_size); - - /* Escape 0x00, 0x00, 0x0{0-3} pattern */ - for (i = 4; i < *out_size; i++) { - if (i < *out_size - 3 && - p[i + 0] == 0 && - p[i + 1] == 0 && - p[i + 2] <= 3) { - uint8_t *new; - - *out_size += 1; - new = av_realloc(*out, *out_size); - if (!new) { - ret = AVERROR(ENOMEM); - goto done; - } - *out = p = new; - - i = i + 2; - memmove(p + i + 1, p + i, *out_size - (i + 1)); - p[i] = 0x03; - } - } -done: - if (ret < 0) { - av_freep(out); - *out_size = 0; +void mediacodec_free_context(AVCodecContext* avcontext) { + if (avcontext->hwaccel_context) { + MediaCodecSurfaceContext* context = avcontext->hwaccel_context; + JNIEnv* env = context->env; + (*env)->DeleteGlobalRef(env, context->surface_object); } - - return ret; + av_freep(&avcontext->hwaccel_context); } -#endif - -#if CONFIG_H264_MEDIACODEC_DECODER -static int h264_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) -{ - int i; - int ret; - - H264ParamSets ps; - const PPS *pps = NULL; - const SPS *sps = NULL; - int is_avc = 0; - int nal_length_size = 0; - memset(&ps, 0, sizeof(ps)); +void mediacodec_render_frame(AVFrame* frame) { + MediaCodecSurfaceRenderContext* context = (MediaCodecSurfaceRenderContext*) frame->data[3]; + AMediaCodec_releaseOutputBuffer(context->codec, context->index, true); + av_freep(&frame->data[3]); +} - ret = ff_h264_decode_extradata(avctx->extradata, avctx->extradata_size, - &ps, &is_avc, &nal_length_size, 0, avctx); - if (ret < 0) { - goto done; +static int getColorFormatFromPixelFormat(enum AVPixelFormat fmt) { + switch (fmt) { + case AV_PIX_FMT_YUV420P: + return 19; + case AV_PIX_FMT_NV12: + return 21; } + return -1; +} - for (i = 0; i < MAX_PPS_COUNT; i++) { - if (ps.pps_list[i]) { - pps = (const PPS*)ps.pps_list[i]->data; - break; - } +static enum AVPixelFormat getPixelFormatFromColorFormat(int fmt) { + switch (fmt) { + case 19: + return AV_PIX_FMT_YUV420P; + case 21: + return AV_PIX_FMT_NV12; } + return AV_PIX_FMT_NONE; +} - if (pps) { - if (ps.sps_list[pps->sps_id]) { - sps = (const SPS*)ps.sps_list[pps->sps_id]->data; - } +static media_status_t configure_and_start(MediaCodecDecContext* context, int error_on_bad_dimensions) { + media_status_t status; + int fmt; + enum AVPixelFormat pix_fmt = AV_PIX_FMT_NONE; + AVCodecContext* avccontext = context->avctx; + + if (avccontext->width <= 0 || avccontext->height <= 0) { + av_log(avccontext, AV_LOG_WARNING, "width (%d) or height (%d) is invalid\n", avccontext->width, avccontext->height); + return error_on_bad_dimensions ? AMEDIA_ERROR_INVALID_PARAMETER : AMEDIA_OK; } - - if (pps && sps) { - uint8_t *data = NULL; - int data_size = 0; - - if ((ret = h2645_ps_to_nalu(sps->data, sps->data_size, &data, &data_size)) < 0) { - goto done; - } - ff_AMediaFormat_setBuffer(format, "csd-0", (void*)data, data_size); - av_freep(&data); - - if ((ret = h2645_ps_to_nalu(pps->data, pps->data_size, &data, &data_size)) < 0) { - goto done; - } - ff_AMediaFormat_setBuffer(format, "csd-1", (void*)data, data_size); - av_freep(&data); + AMediaFormat_setInt32(context->format, AMEDIAFORMAT_KEY_HEIGHT, avccontext->height); + AMediaFormat_setInt32(context->format, AMEDIAFORMAT_KEY_WIDTH, avccontext->width); + + if (avccontext->hwaccel_context) { + MediaCodecSurfaceContext* hwaccel_context = ((MediaCodecSurfaceContext*) avccontext->hwaccel_context); + status = AMediaCodec_configure(context->codec, context->format, hwaccel_context->surface, NULL, 0); + pix_fmt = AV_PIX_FMT_MEDIACODEC; } else { - av_log(avctx, AV_LOG_ERROR, "Could not extract PPS/SPS from extradata"); - ret = AVERROR_INVALIDDATA; + status = AMediaCodec_configure(context->codec, context->format, NULL, NULL, 0); + } + + status |= AMediaFormat_delete(context->format); + + if (status == AMEDIA_OK) { + AMediaFormat_getInt32(AMediaCodec_getOutputFormat(context->codec), AMEDIAFORMAT_KEY_COLOR_FORMAT, &fmt); + avccontext->pix_fmt = pix_fmt != AV_PIX_FMT_NONE ? pix_fmt : getPixelFormatFromColorFormat(fmt); + av_log(avccontext, AV_LOG_DEBUG, "Decoder configured %s\n", AMediaFormat_toString(AMediaCodec_getOutputFormat(context->codec))); + status = AMediaCodec_start(context->codec); } -done: - ff_h264_ps_uninit(&ps); - - return ret; + return status; } -#endif -#if CONFIG_HEVC_MEDIACODEC_DECODER -static int hevc_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) -{ - int i; - int ret; - - HEVCParamSets ps; - HEVCSEIContext sei; - - const HEVCVPS *vps = NULL; - const HEVCPPS *pps = NULL; - const HEVCSPS *sps = NULL; - int is_nalff = 0; - int nal_length_size = 0; - - uint8_t *vps_data = NULL; - uint8_t *sps_data = NULL; - uint8_t *pps_data = NULL; - int vps_data_size = 0; - int sps_data_size = 0; - int pps_data_size = 0; - - memset(&ps, 0, sizeof(ps)); - memset(&sei, 0, sizeof(sei)); - - ret = ff_hevc_decode_extradata(avctx->extradata, avctx->extradata_size, - &ps, &sei, &is_nalff, &nal_length_size, 0, 1, avctx); - if (ret < 0) { - goto done; - } - - for (i = 0; i < HEVC_MAX_VPS_COUNT; i++) { - if (ps.vps_list[i]) { - vps = (const HEVCVPS*)ps.vps_list[i]->data; - break; +static int mediacodec_decode_init(AVCodecContext *avccontext) { + MediaCodecDecContext *context = avccontext->priv_data; + int csd_size, index; + const char* mime_type; + + context->avctx = avccontext; + csd_size = 0; + + if (avccontext->codec_id == AV_CODEC_ID_HEVC) { + mime_type = "video/hevc"; + ff_hevc_decode_extradata(avccontext->extradata, avccontext->extradata_size, &context->hevc_ps, &context->hevc_sei, &context->is_nalff, &context->nal_length_size, avccontext->err_recognition, 0, avccontext); + if (!context->hevc_ps.vps_list[0] || !context->hevc_ps.sps_list[0] || !context->hevc_ps.pps_list[0]) { + return AVERROR(EINVAL); } - } - - for (i = 0; i < HEVC_MAX_PPS_COUNT; i++) { - if (ps.pps_list[i]) { - pps = (const HEVCPPS*)ps.pps_list[i]->data; - break; + csd_size = sizeof (uint8_t) * (((HEVCVPS*)context->hevc_ps.vps_list[0]->data)->data_size + ((HEVCPPS*)context->hevc_ps.pps_list[0]->data)->data_size + ((HEVCSPS*)context->hevc_ps.sps_list[0]->data)->data_size) + sizeof (startCode)*2; + av_log(avccontext, AV_LOG_DEBUG, "extradata decoded, stream %s (nal length: %d)\n", context->is_nalff ? "not encapsulated" : "encapsulated", context->nal_length_size); + } else if (avccontext->codec_id == AV_CODEC_ID_H264) { + mime_type = "video/avc"; + ff_h264_decode_extradata(avccontext->extradata, avccontext->extradata_size, &context->h264_ps, &context->is_nalff, &context->nal_length_size, avccontext->err_recognition, avccontext); + if (!context->h264_ps.pps_list[0] || !context->h264_ps.sps_list[0]) { + return AVERROR(EINVAL); } - } + csd_size = sizeof (uint8_t) * (((PPS*)context->h264_ps.pps_list[0]->data)->data_size + ((SPS*)context->h264_ps.sps_list[0]->data)->data_size) + sizeof (startCode)*2; + av_log(avccontext, AV_LOG_DEBUG, "extradata decoded, stream %s (nal length: %d)\n", context->is_nalff ? "not encapsulated" : "encapsulated", context->nal_length_size); - if (pps) { - if (ps.sps_list[pps->sps_id]) { - sps = (const HEVCSPS*)ps.sps_list[pps->sps_id]->data; + } else if (avccontext->codec_id == AV_CODEC_ID_MPEG4) { + mime_type = "video/mp4v-es"; + if (!avccontext->extradata) { + return AVERROR(EINVAL); } + csd_size = sizeof (uint8_t) * (avccontext->extradata_size); + } else if (avccontext->codec_id == AV_CODEC_ID_VP8) { + mime_type = "video/x-vnd.on2.vp8"; + } else if (avccontext->codec_id == AV_CODEC_ID_VP9) { + mime_type = "video/x-vnd.on2.vp9"; } - if (vps && pps && sps) { - uint8_t *data; - int data_size; + index = 0; - if ((ret = h2645_ps_to_nalu(vps->data, vps->data_size, &vps_data, &vps_data_size)) < 0 || - (ret = h2645_ps_to_nalu(sps->data, sps->data_size, &sps_data, &sps_data_size)) < 0 || - (ret = h2645_ps_to_nalu(pps->data, pps->data_size, &pps_data, &pps_data_size)) < 0) { - goto done; + if (csd_size > 0) { + context->csd = av_malloc(csd_size); + if (!context->csd) { + return AVERROR(ENOMEM); } - - data_size = vps_data_size + sps_data_size + pps_data_size; - data = av_mallocz(data_size); - if (!data) { - ret = AVERROR(ENOMEM); - goto done; - } - - memcpy(data , vps_data, vps_data_size); - memcpy(data + vps_data_size , sps_data, sps_data_size); - memcpy(data + vps_data_size + sps_data_size, pps_data, pps_data_size); - - ff_AMediaFormat_setBuffer(format, "csd-0", data, data_size); - - av_freep(&data); - } else { - av_log(avctx, AV_LOG_ERROR, "Could not extract VPS/PPS/SPS from extradata"); - ret = AVERROR_INVALIDDATA; } - -done: - av_freep(&vps_data); - av_freep(&sps_data); - av_freep(&pps_data); - - return ret; -} -#endif - -#if CONFIG_MPEG2_MEDIACODEC_DECODER -static int mpeg2_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) -{ - int ret = 0; - - if (avctx->extradata) { - ff_AMediaFormat_setBuffer(format, "csd-0", avctx->extradata, avctx->extradata_size); + + if (context->hevc_ps.vps_list[0]) { + struct HEVCVPS* vps = ((HEVCVPS*)context->hevc_ps.vps_list[0]->data); + struct HEVCSPS* sps = ((HEVCSPS*)context->hevc_ps.sps_list[0]->data); + struct HEVCPPS* pps = ((HEVCPPS*)context->hevc_ps.pps_list[0]->data); + memcpy(context->csd, startCode, sizeof (startCode)); + index += sizeof (startCode); + memcpy(context->csd + index, vps->data, vps->data_size); + index += vps->data_size; + memcpy(context->csd + index, startCode, sizeof (startCode)); + index += sizeof (startCode); + memcpy(context->csd + index, sps->data, sps->data_size); + index += sps->data_size; + memcpy(context->csd + index, startCode, sizeof (startCode)); + index += sizeof (startCode); + memcpy(context->csd + index, pps->data, pps->data_size); } - - return ret; -} -#endif - -#if CONFIG_MPEG4_MEDIACODEC_DECODER -static int mpeg4_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) -{ - int ret = 0; - - if (avctx->extradata) { - ff_AMediaFormat_setBuffer(format, "csd-0", avctx->extradata, avctx->extradata_size); + + if (context->h264_ps.pps_list[0]) { + struct SPS* sps = ((SPS*)context->h264_ps.sps_list[0]->data); + struct PPS* pps = ((PPS*)context->h264_ps.pps_list[0]->data); + memcpy(context->csd + index, startCode, sizeof (startCode)); + index += sizeof (startCode); + memcpy(context->csd + index, sps->data, sps->data_size); + index += sps->data_size; + memcpy(context->csd + index, startCode, sizeof (startCode)); + index += sizeof (startCode); + memcpy(context->csd + index, pps->data, pps->data_size); + } + + if (avccontext->codec_id == AV_CODEC_ID_MPEG4) { + memcpy(context->csd + index, avccontext->extradata, avccontext->extradata_size); + } + + av_log(avccontext, AV_LOG_DEBUG, "decoder private data initialized (%d bytes)\n", csd_size); + + context->codec = AMediaCodec_createDecoderByType(mime_type); + + context->format = AMediaFormat_new(); + + AMediaFormat* format = context->format; + AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, mime_type); + AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, getColorFormatFromPixelFormat(avccontext->pix_fmt != AV_PIX_FMT_NONE ? avccontext->pix_fmt : avccontext->codec->pix_fmts[0])); + if (context->csd) { + AMediaFormat_setBuffer(format, "csd-0", context->csd, csd_size); } - return ret; + ff_get_format(avccontext, avccontext->codec->pix_fmts); + + if (avccontext->hwaccel_context && ((MediaCodecSurfaceContext*) avccontext->hwaccel_context)->surface_object) { + MediaCodecSurfaceContext* hwaccel_context = ((MediaCodecSurfaceContext*) avccontext->hwaccel_context); + hwaccel_context->surface = ANativeWindow_fromSurface(hwaccel_context->env, hwaccel_context->surface_object); + } + + return configure_and_start(context, 0); + } -#endif -#if CONFIG_VP8_MEDIACODEC_DECODER || CONFIG_VP9_MEDIACODEC_DECODER -static int vpx_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) -{ +static int decode_nal_units(MediaCodecDecContext *s, const uint8_t *buf, int length) { int ret = 0; - if (avctx->extradata) { - ff_AMediaFormat_setBuffer(format, "csd-0", avctx->extradata, avctx->extradata_size); + /* split the input packet into NAL units, so we know the upper bound on the + * number of slices in the frame */ + ret = ff_h2645_packet_split(&s->pkt, buf, length, s->avctx, s->is_nalff, + s->nal_length_size, s->avctx->codec_id, 1); + if (ret < 0) { + av_log(s->avctx, AV_LOG_ERROR, "Error splitting the input into NAL units.\n"); } return ret; } -#endif - -static av_cold int mediacodec_decode_init(AVCodecContext *avctx) -{ - int ret; - - const char *codec_mime = NULL; - 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; +static int mediacodec_decode_frame(AVCodecContext *avccontext, void *data, + int *got_frame_ptr, AVPacket *avpkt) { + + MediaCodecDecContext *context = avccontext->priv_data; + AMediaCodec* codec = context->codec; + AVFrame* frame = data; + + ssize_t index, indexOutput; + uint8_t *inputBuffer; + + size_t bufferSize; + media_status_t status; + AMediaCodecBufferInfo info; + + if (avccontext->width <= 0 || avccontext->height <= 0) { + AVCodecParserContext* parser_context; + uint8_t* out; + int out_size; + + if (!avpkt->data || !avpkt->size) { + return 0; + } + + parser_context = av_parser_init(avccontext->codec_id); + parser_context->flags |= PARSER_FLAG_COMPLETE_FRAMES; + + av_parser_parse2(parser_context, avccontext, &out, &out_size, avpkt->data, avpkt->size, avpkt->pts, avpkt->dts, avpkt->pos); + av_parser_close(parser_context); + + status = configure_and_start(context, 1); + + if (status != AMEDIA_OK) { + return status; + } } - - switch (avctx->codec_id) { -#if CONFIG_H264_MEDIACODEC_DECODER - case AV_CODEC_ID_H264: - codec_mime = "video/avc"; - - ret = h264_set_extradata(avctx, format); - if (ret < 0) - goto done; - break; -#endif -#if CONFIG_HEVC_MEDIACODEC_DECODER - case AV_CODEC_ID_HEVC: - codec_mime = "video/hevc"; - - ret = hevc_set_extradata(avctx, format); - if (ret < 0) - goto done; - break; -#endif -#if CONFIG_MPEG2_MEDIACODEC_DECODER - case AV_CODEC_ID_MPEG2VIDEO: - codec_mime = "video/mpeg2"; - - ret = mpeg2_set_extradata(avctx, format); - if (ret < 0) - goto done; - break; -#endif -#if CONFIG_MPEG4_MEDIACODEC_DECODER - case AV_CODEC_ID_MPEG4: - codec_mime = "video/mp4v-es", - - ret = mpeg4_set_extradata(avctx, format); - if (ret < 0) - goto done; - break; -#endif -#if CONFIG_VP8_MEDIACODEC_DECODER - case AV_CODEC_ID_VP8: - codec_mime = "video/x-vnd.on2.vp8"; - - ret = vpx_set_extradata(avctx, format); - if (ret < 0) - goto done; - break; -#endif -#if CONFIG_VP9_MEDIACODEC_DECODER - case AV_CODEC_ID_VP9: - codec_mime = "video/x-vnd.on2.vp9"; - - ret = vpx_set_extradata(avctx, format); - if (ret < 0) - goto done; - break; -#endif - default: - av_assert0(0); + + index = AMediaCodec_dequeueInputBuffer(codec, -1); + if (index < 0) { + return 0; } + inputBuffer = AMediaCodec_getInputBuffer(codec, index, &bufferSize); + av_log(avccontext, AV_LOG_DEBUG, "input buffer acquired (index: %ld capacity: %ld nalLength: %d)\n", index, bufferSize, context->nal_length_size); - ff_AMediaFormat_setString(format, "mime", codec_mime); - ff_AMediaFormat_setInt32(format, "width", avctx->width); - ff_AMediaFormat_setInt32(format, "height", avctx->height); + if (avpkt->data) { - s->ctx = av_mallocz(sizeof(*s->ctx)); - if (!s->ctx) { - av_log(avctx, AV_LOG_ERROR, "Failed to allocate MediaCodecDecContext\n"); - ret = AVERROR(ENOMEM); - goto done; - } + if (avccontext->codec_id == AV_CODEC_ID_H264 || avccontext->codec_id == AV_CODEC_ID_HEVC) { + int nalIndex, inputOffset = 0; - if ((ret = ff_mediacodec_dec_init(avctx, s->ctx, codec_mime, format)) < 0) { - s->ctx = NULL; - goto done; - } + decode_nal_units(context, avpkt->data, avpkt->size); - av_log(avctx, AV_LOG_INFO, "MediaCodec started successfully, ret = %d\n", ret); + if (context->nal_length_size == 4) { + memcpy(inputBuffer, avpkt->data, avpkt->size); - s->fifo = av_fifo_alloc(sizeof(AVPacket)); - if (!s->fifo) { - ret = AVERROR(ENOMEM); - goto done; - } + for (nalIndex = 0; nalIndex < context->pkt.nb_nals; nalIndex++) { + memcpy(inputBuffer + inputOffset, startCode, sizeof (startCode)); + inputOffset += context->pkt.nals[nalIndex].raw_size + sizeof (startCode); + + } + } else { + for (nalIndex = 0; nalIndex < context->pkt.nb_nals; nalIndex++) { + memcpy(inputBuffer + inputOffset, startCode, sizeof (startCode)); + memcpy(inputBuffer + inputOffset + sizeof (startCode), context->pkt.nals[nalIndex].data, context->pkt.nals[nalIndex].size); + inputOffset += context->pkt.nals[nalIndex].size + sizeof (startCode); + } + } + }else{ + memcpy(inputBuffer, avpkt->data, avpkt->size); + } -done: - if (format) { - ff_AMediaFormat_delete(format); + status = AMediaCodec_queueInputBuffer(codec, index, 0, avpkt->size, 1000000LL * avpkt->pts * avccontext->pkt_timebase.num / avccontext->pkt_timebase.den, 0); + av_log(avccontext, AV_LOG_DEBUG, "input buffer queued (pts: %lld)\n", 1000000LL * avpkt->pts * avccontext->pkt_timebase.num / avccontext->pkt_timebase.den); + } else { + status = AMediaCodec_queueInputBuffer(codec, index, 0, 0, 0, AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM); + av_log(avccontext, AV_LOG_DEBUG, "end of stream reached"); } - if (ret < 0) { - mediacodec_decode_close(avctx); + if (status != AMEDIA_OK) { + return status; } - return ret; -} + indexOutput = AMediaCodec_dequeueOutputBuffer(codec, &info, 200); + if (indexOutput >= 0) { + int outputColorFormat, width, height, ret, fill; + AMediaFormat* outputFormat; + uint8_t *outputBuffer; -static int mediacodec_process_data(AVCodecContext *avctx, AVFrame *frame, - int *got_frame, AVPacket *pkt) -{ - MediaCodecH264DecContext *s = avctx->priv_data; + outputBuffer = AMediaCodec_getOutputBuffer(codec, indexOutput, &bufferSize); + outputFormat = AMediaCodec_getOutputFormat(codec); + av_log(avccontext, AV_LOG_DEBUG, "output buffer acquired (format: %s)\n", AMediaFormat_toString(outputFormat)); - return ff_mediacodec_dec_decode(avctx, s->ctx, frame, got_frame, pkt); -} + AMediaFormat_getInt32(outputFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, &outputColorFormat); + AMediaFormat_getInt32(outputFormat, AMEDIAFORMAT_KEY_WIDTH, &width); + AMediaFormat_getInt32(outputFormat, AMEDIAFORMAT_KEY_HEIGHT, &height); -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_pkt = { 0 }; - - if (av_fifo_space(s->fifo) < sizeof(input_pkt)) { - ret = av_fifo_realloc2(s->fifo, - av_fifo_size(s->fifo) + sizeof(input_pkt)); - if (ret < 0) + frame->format = getPixelFormatFromColorFormat(outputColorFormat); + frame->width = width; + frame->height = height; + if (!avccontext->hwaccel_context) { + if ((ret = ff_get_buffer(avccontext, frame, 0)) < 0) return ret; } + frame->pts = info.presentationTimeUs * avccontext->pkt_timebase.den / (avccontext->pkt_timebase.num * 1000000LL); - ret = av_packet_ref(&input_pkt, avpkt); - if (ret < 0) - return ret; - av_fifo_generic_write(s->fifo, &input_pkt, sizeof(input_pkt), NULL); - } + av_log(avccontext, AV_LOG_DEBUG, "output frame will be filled (width: %d, height: %d, pixel format: %d, pts: %ld)\n", frame->width, frame->height, frame->format, frame->pts); - /* - * MediaCodec.flush() discards both input and output buffers, thus we - * need to delay the call to this function until the user has released or - * renderered the frames he retains. - * - * After we have buffered an input packet, check if the codec is in the - * flushing state. If it is, we need to call ff_mediacodec_dec_flush. - * - * ff_mediacodec_dec_flush returns 0 if the flush cannot be performed on - * the codec (because the user retains frames). The codec stays in the - * flushing state. - * - * ff_mediacodec_dec_flush returns 1 if the flush can actually be - * performed on the codec. The codec leaves the flushing state and can - * process again packets. - * - * ff_mediacodec_dec_flush returns a negative value if an error has - * occurred. - * - */ - if (ff_mediacodec_dec_is_flushing(avctx, s->ctx)) { - if (!ff_mediacodec_dec_flush(avctx, s->ctx)) { - return avpkt->size; + if (!avccontext->hwaccel_context) { + fill = av_image_fill_arrays(frame->data, frame->linesize, outputBuffer + info.offset, getPixelFormatFromColorFormat(outputColorFormat), width, height, 1); + if (fill >= 0) { + *got_frame_ptr = 1; + } else { + av_log(avccontext, AV_LOG_ERROR, av_err2str(fill)); + return fill; + } + status = AMediaCodec_releaseOutputBuffer(codec, indexOutput, false); + } else { + MediaCodecSurfaceRenderContext* render_context = mediacodec_alloc_surface_context(codec, indexOutput); + if (render_context) { + frame->buf[0] = av_buffer_alloc(1); + frame->format = AV_PIX_FMT_MEDIACODEC; + frame->data[3] = (void*) render_context; + *got_frame_ptr = 1; + } + } + if (status != AMEDIA_OK) { + return status; } } - /* process buffered data */ - while (!*got_frame) { - /* prepare the input data */ - if (s->buffered_pkt.size <= 0) { - av_packet_unref(&s->buffered_pkt); - - /* 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); - } + return avpkt->size; +} - av_fifo_generic_read(s->fifo, &s->buffered_pkt, sizeof(s->buffered_pkt), NULL); - } +static void ff_hevc_ps_uninit(HEVCParamSets *ps) +{ + int i; - ret = mediacodec_process_data(avctx, frame, got_frame, &s->buffered_pkt); - if (ret < 0) - return ret; + for (i = 0; i < HEVC_MAX_VPS_COUNT; i++) + av_buffer_unref(&ps->vps_list[i]); + + for (i = 0; i < HEVC_MAX_SPS_COUNT; i++) + av_buffer_unref(&ps->sps_list[i]); - s->buffered_pkt.size -= ret; - s->buffered_pkt.data += ret; - } + for (i = 0; i < HEVC_MAX_PPS_COUNT; i++) + av_buffer_unref(&ps->pps_list[i]); - return avpkt->size; + ps->vps = NULL; + ps->pps = NULL; + ps->sps = NULL; } -static void mediacodec_decode_flush(AVCodecContext *avctx) +static void ff_hevc_sei_uninit(HEVCSEIContext *ps) { - MediaCodecH264DecContext *s = avctx->priv_data; + av_freep(&ps->a53_caption.a53_caption); + av_freep(&ps->picture_hash.md5_ctx); +} - while (av_fifo_size(s->fifo)) { - AVPacket pkt; - av_fifo_generic_read(s->fifo, &pkt, sizeof(pkt), NULL); - av_packet_unref(&pkt); +static int mediacodec_decode_close(AVCodecContext *avccontext) { + media_status_t status; + MediaCodecDecContext *context = avccontext->priv_data; + status = AMediaCodec_flush(context->codec); + if (status != AMEDIA_OK) { + return status; + } + status = AMediaCodec_stop(context->codec); + av_freep(&context->csd); + ff_h264_ps_uninit(&context->h264_ps); + ff_hevc_ps_uninit(&context->hevc_ps); + ff_hevc_sei_uninit(&context->hevc_sei); + ff_h2645_packet_uninit(&context->pkt); + if (avccontext->hwaccel_context && ((MediaCodecSurfaceContext*) avccontext->hwaccel_context)->surface) { + ANativeWindow_release(((MediaCodecSurfaceContext*) avccontext->hwaccel_context)->surface); + } + if (status != AMEDIA_OK) { + return status; } - av_fifo_reset(s->fifo); - av_packet_unref(&s->buffered_pkt); + av_log(avccontext, AV_LOG_DEBUG, "decoder closed"); + return AMediaCodec_delete(context->codec); +} - ff_mediacodec_dec_flush(avctx, s->ctx); +#define ATTR(x) .x +#define CODECNAME(name) mediacodec_ ## name +#define DECLARE_DECODER(cname, cid) \ +AVCodec ff_mediacodec_##cname##_decoder = { \ + ATTR(name) = AV_STRINGIFY(CODECNAME(cname)), \ + ATTR(long_name) = NULL_IF_CONFIG_SMALL("Android MediaCodec decoder"), \ + ATTR(type) = AVMEDIA_TYPE_VIDEO, \ + ATTR(id) = cid, \ + ATTR(priv_data_size) = sizeof (MediaCodecDecContext), \ + ATTR(init) = mediacodec_decode_init, \ + ATTR(decode) = mediacodec_decode_frame, \ + ATTR(close) = mediacodec_decode_close, \ + ATTR(capabilities) = AV_CODEC_CAP_DELAY, \ + ATTR(pix_fmts) = supported_formats \ +}; \ +supported_codecs[current] = ff_mediacodec_##cname##_decoder; \ +avcodec_register(&supported_codecs[current]); \ +\ +AVHWAccel ff_mediacodec_##cname##_hwaccel = { \ + ATTR(name) = AV_STRINGIFY(CODECNAME(cname)), \ + ATTR(type) = AVMEDIA_TYPE_VIDEO, \ + ATTR(id) = cid, \ + ATTR(pix_fmt) = AV_PIX_FMT_MEDIACODEC \ +}; \ +supported_hwaccel[current] = ff_mediacodec_##cname##_hwaccel; \ +av_register_hwaccel(&supported_hwaccel[current]); \ +current++; \ +\ + +const enum AVPixelFormat supported_formats[] = {AV_PIX_FMT_YUV420P, AV_PIX_FMT_NV12, AV_PIX_FMT_MEDIACODEC}; +struct AVCodec supported_codecs[6]; +struct AVHWAccel supported_hwaccel[6]; +int current = 0; + +static void init_and_register_all_mediacodec() { + DECLARE_DECODER(hevc, AV_CODEC_ID_HEVC) + DECLARE_DECODER(h264, AV_CODEC_ID_H264) + DECLARE_DECODER(mpeg2, AV_CODEC_ID_MPEG2VIDEO) + DECLARE_DECODER(mpeg4, AV_CODEC_ID_MPEG4) + DECLARE_DECODER(vp8, AV_CODEC_ID_VP8) + DECLARE_DECODER(vp9, AV_CODEC_ID_VP9) } -#if CONFIG_H264_MEDIACODEC_DECODER -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 = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, - .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, - .bsfs = "h264_mp4toannexb", -}; -#endif - -#if CONFIG_HEVC_MEDIACODEC_DECODER -AVCodec ff_hevc_mediacodec_decoder = { - .name = "hevc_mediacodec", - .long_name = NULL_IF_CONFIG_SMALL("H.265 Android MediaCodec decoder"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_HEVC, - .priv_data_size = sizeof(MediaCodecH264DecContext), - .init = mediacodec_decode_init, - .decode = mediacodec_decode_frame, - .flush = mediacodec_decode_flush, - .close = mediacodec_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, - .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, - .bsfs = "hevc_mp4toannexb", -}; -#endif - -#if CONFIG_MPEG2_MEDIACODEC_DECODER -AVCodec ff_mpeg2_mediacodec_decoder = { - .name = "mpeg2_mediacodec", - .long_name = NULL_IF_CONFIG_SMALL("MPEG-2 Android MediaCodec decoder"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG2VIDEO, - .priv_data_size = sizeof(MediaCodecH264DecContext), - .init = mediacodec_decode_init, - .decode = mediacodec_decode_frame, - .flush = mediacodec_decode_flush, - .close = mediacodec_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, - .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, +AVCodec ff_mediacodec_decoder = { + .name = "mediacodec", + .init_static_data = init_and_register_all_mediacodec }; -#endif - -#if CONFIG_MPEG4_MEDIACODEC_DECODER -AVCodec ff_mpeg4_mediacodec_decoder = { - .name = "mpeg4_mediacodec", - .long_name = NULL_IF_CONFIG_SMALL("MPEG-4 Android MediaCodec decoder"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG4, - .priv_data_size = sizeof(MediaCodecH264DecContext), - .init = mediacodec_decode_init, - .decode = mediacodec_decode_frame, - .flush = mediacodec_decode_flush, - .close = mediacodec_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, - .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, -}; -#endif - -#if CONFIG_VP8_MEDIACODEC_DECODER -AVCodec ff_vp8_mediacodec_decoder = { - .name = "vp8_mediacodec", - .long_name = NULL_IF_CONFIG_SMALL("VP8 Android MediaCodec decoder"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_VP8, - .priv_data_size = sizeof(MediaCodecH264DecContext), - .init = mediacodec_decode_init, - .decode = mediacodec_decode_frame, - .flush = mediacodec_decode_flush, - .close = mediacodec_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, - .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, -}; -#endif - -#if CONFIG_VP9_MEDIACODEC_DECODER -AVCodec ff_vp9_mediacodec_decoder = { - .name = "vp9_mediacodec", - .long_name = NULL_IF_CONFIG_SMALL("VP9 Android MediaCodec decoder"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_VP9, - .priv_data_size = sizeof(MediaCodecH264DecContext), - .init = mediacodec_decode_init, - .decode = mediacodec_decode_frame, - .flush = mediacodec_decode_flush, - .close = mediacodec_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, - .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, -}; -#endif + diff --git a/captive/ffmpeg/csrc/libavcodec/mediacodecenc.c b/captive/ffmpeg/csrc/libavcodec/mediacodecenc.c new file mode 100644 index 00000000000..dd92832ff67 --- /dev/null +++ b/captive/ffmpeg/csrc/libavcodec/mediacodecenc.c @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2018-2020 Olivier Ayache + * + * 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 "avcodec.h" +#include "internal.h" +#include +#include +#include +#include +#include +#include + +typedef struct MediaCodecEncContext { + AMediaCodec* codec; + AVCodecContext *avctx; + const AVClass *class; // needed by private avoptions + enum AVPixelFormat preferred_fmt; + +} MediaCodecEncContext; + +static const AVOption options[]={ + { "preferred_fmt", "Sets the preferred pixel format ", offsetof(MediaCodecEncContext, preferred_fmt), AV_OPT_TYPE_PIXEL_FMT, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM }, + { NULL } +}; + +static const AVClass mediacodec_class = { + .class_name = "MediaCodec encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static int getColorFormatFromPixelFormat(enum AVPixelFormat fmt) { + switch (fmt) { + case AV_PIX_FMT_YUV420P: + return 19; + case AV_PIX_FMT_NV12: + return 21; + } + return -1; +} + +static enum AVPixelFormat getPixelFormatFromColorFormat(int fmt) { + switch (fmt) { + case 19: + return AV_PIX_FMT_YUV420P; + case 21: + return AV_PIX_FMT_NV12; + } + return AV_PIX_FMT_NONE; +} + +static int mediacodec_encode_init(AVCodecContext *avccontext) { + MediaCodecEncContext *context = avccontext->priv_data; + int fmt; + AMediaFormat* format; + enum AVPixelFormat pix_fmt; + media_status_t configure; + const char* mime_type; + + context->avctx = avccontext; + + if (avccontext->codec_id == AV_CODEC_ID_HEVC) { + mime_type = "video/hevc"; + } else if (avccontext->codec_id == AV_CODEC_ID_H264) { + mime_type = "video/avc"; + } else if (avccontext->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + mime_type = "video/mpeg2"; + } else if (avccontext->codec_id == AV_CODEC_ID_MPEG4) { + mime_type = "video/mp4v-es"; + } else if (avccontext->codec_id == AV_CODEC_ID_VP8) { + mime_type = "video/x-vnd.on2.vp8"; + } else if (avccontext->codec_id == AV_CODEC_ID_VP9) { + mime_type = "video/x-vnd.on2.vp9"; + } + + context->codec = AMediaCodec_createEncoderByType(mime_type); + + format = AMediaFormat_new(); + AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, mime_type); + AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, avccontext->height); + AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, avccontext->width); + AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, avccontext->bit_rate); + AMediaFormat_setFloat(format, AMEDIAFORMAT_KEY_FRAME_RATE, av_q2d(avccontext->framerate)); + AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, getColorFormatFromPixelFormat(avccontext->pix_fmt != AV_PIX_FMT_NONE ? avccontext->pix_fmt : avccontext->codec->pix_fmts[0])); + + av_log(avccontext, AV_LOG_ERROR, AMediaFormat_toString(format)); + +// ff_get_format(avccontext, avccontext->codec->pix_fmts); +// +// pix_fmt = AV_PIX_FMT_NONE; +// +// if (avccontext->hwaccel_context && ((MediaCodecSurfaceContext*)avccontext->hwaccel_context)->surface_object){ +// MediaCodecSurfaceContext* hwaccel_context = ((MediaCodecSurfaceContext*)avccontext->hwaccel_context); +// hwaccel_context->surface = ANativeWindow_fromSurface(hwaccel_context->env, hwaccel_context->surface_object); +// configure = AMediaCodec_configure(context->codec, format, hwaccel_context->surface, NULL, 0); +// pix_fmt = AV_PIX_FMT_MEDIACODEC; +// } else { + configure = AMediaCodec_configure(context->codec, format, NULL, NULL, AMEDIACODEC_CONFIGURE_FLAG_ENCODE); +// } + + if (configure == AMEDIA_OK) { + AMediaFormat_getInt32(AMediaCodec_getOutputFormat(context->codec), AMEDIAFORMAT_KEY_COLOR_FORMAT, &fmt); + avccontext->pix_fmt = pix_fmt != AV_PIX_FMT_NONE ? pix_fmt : getPixelFormatFromColorFormat(fmt); + av_log(avccontext, AV_LOG_DEBUG, "Encoder configured %s\n", AMediaFormat_toString(AMediaCodec_getOutputFormat(context->codec))); + return AMediaCodec_start(context->codec); + } else { + return configure; + } +} + +static int mediacodec_encode_frame(AVCodecContext *avccontext, AVPacket *avpkt, const AVFrame *frame, + int *got_packet_ptr) { + + MediaCodecEncContext *context = avccontext->priv_data; + AMediaCodec* codec = context->codec; + ssize_t index, indexOutput; + uint8_t *inputBuffer; + + size_t bufferSize; + media_status_t status; + AMediaCodecBufferInfo info; + + index = AMediaCodec_dequeueInputBuffer(codec, 200); + if (index < 0) { + return 0; + } + inputBuffer = AMediaCodec_getInputBuffer(codec, index, &bufferSize); + av_log(avccontext, AV_LOG_DEBUG, "input buffer acquired (index: %ld capacity: %ld)\n", index, bufferSize); + + if (frame->data) { + bufferSize = av_image_get_buffer_size(avccontext->pix_fmt, avccontext->width, avccontext->height, 1); + av_image_copy_to_buffer(inputBuffer, bufferSize, frame->data, frame->linesize, context->preferred_fmt, avccontext->width, avccontext->height, 1); + status = AMediaCodec_queueInputBuffer(codec, index, 0, bufferSize, 1000000LL * frame->pts * avccontext->time_base.num / avccontext->time_base.den, 0); + av_log(avccontext, AV_LOG_DEBUG, "input buffer queued (pts: %lld)\n", 1000000LL * frame->pts * avccontext->time_base.num / avccontext->time_base.den); + }else{ + status = AMediaCodec_queueInputBuffer(codec, index, 0, 0, 0, AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM); + av_log(avccontext, AV_LOG_DEBUG, "end of stream reached"); + } + + if (status != AMEDIA_OK) { + return status; + } + + indexOutput = AMediaCodec_dequeueOutputBuffer(codec, &info, 200); + if (indexOutput >= 0) { + + AMediaFormat* outputFormat; + uint8_t *outputBuffer; + + outputBuffer = AMediaCodec_getOutputBuffer(codec, indexOutput, &bufferSize); + outputFormat = AMediaCodec_getOutputFormat(codec); + av_log(avccontext, AV_LOG_DEBUG, "output buffer acquired (format: %s)\n", AMediaFormat_toString(outputFormat)); + + memcpy(avpkt->data, outputBuffer, info.size); + avpkt->size = info.size; + avpkt->pts = info.presentationTimeUs * avccontext->time_base.den / (avccontext->time_base.num * 1000000LL); + + if (info.flags) { + avpkt->flags |= AV_PKT_FLAG_KEY; + } + + status = AMediaCodec_releaseOutputBuffer(codec, indexOutput, false); + + if (status != AMEDIA_OK) { + return status; + } + + *got_packet_ptr = 1; + } else { + *got_packet_ptr = 0; + } + + return 0; + + + +} + +static int mediacodec_encode_close(AVCodecContext *avccontext) { + media_status_t status; + MediaCodecEncContext *context = avccontext->priv_data; + status = AMediaCodec_flush(context->codec); + if (status != AMEDIA_OK){ + return status; + } + status = AMediaCodec_stop(context->codec); + if (status != AMEDIA_OK){ + return status; + } + return AMediaCodec_delete(context->codec); +} + +#define ATTR(x) .x +#define CODECNAME(name) mediacodec_ ## name +#define DECLARE_ENCODER(cname, cid) \ +AVCodec ff_mediacodec_##cname##_encoder = { \ + ATTR(name) = AV_STRINGIFY(CODECNAME(cname)), \ + ATTR(long_name) = NULL_IF_CONFIG_SMALL("Android MediaCodec encoder"), \ + ATTR(type) = AVMEDIA_TYPE_VIDEO, \ + ATTR(id) = cid, \ + ATTR(priv_data_size) = sizeof (MediaCodecEncContext), \ + ATTR(init) = mediacodec_encode_init, \ + ATTR(encode2) = mediacodec_encode_frame, \ + ATTR(close) = mediacodec_encode_close, \ + ATTR(capabilities) = AV_CODEC_CAP_DELAY, \ + ATTR(pix_fmts) = (const enum AVPixelFormat[]) {AV_PIX_FMT_YUV420P, AV_PIX_FMT_NV12, AV_PIX_FMT_MEDIACODEC} \ +}; \ +\ +AVHWAccel ff_mediacodec_##cname##_hwaccel = { \ + ATTR(name) = AV_STRINGIFY(CODECNAME(cname)), \ + ATTR(type) = AVMEDIA_TYPE_VIDEO, \ + ATTR(id) = cid, \ + ATTR(pix_fmt) = AV_PIX_FMT_MEDIACODEC, \ +}; \ + + +DECLARE_ENCODER(hevc, AV_CODEC_ID_HEVC) +DECLARE_ENCODER(h264, AV_CODEC_ID_H264) +DECLARE_ENCODER(mpeg2, AV_CODEC_ID_MPEG2VIDEO) +DECLARE_ENCODER(mpeg4, AV_CODEC_ID_MPEG4) +DECLARE_ENCODER(vp8, AV_CODEC_ID_VP8) +DECLARE_ENCODER(vp9, AV_CODEC_ID_VP9) + +static void init_and_register_all_mediacodec(AVCodec* codec) { + + AMediaCodec* encoder; + + encoder = AMediaCodec_createEncoderByType("video/avc"); + if (encoder) { + AMediaCodec_delete(encoder); + avcodec_register(&ff_mediacodec_h264_encoder); + av_register_hwaccel(&ff_mediacodec_h264_hwaccel); + } + + encoder = AMediaCodec_createEncoderByType("video/hevc"); + if (encoder) { + AMediaCodec_delete(encoder); + avcodec_register(&ff_mediacodec_hevc_encoder); + av_register_hwaccel(&ff_mediacodec_hevc_hwaccel); + } + + encoder = AMediaCodec_createEncoderByType("video/mpeg2"); + if (encoder) { + AMediaCodec_delete(encoder); + avcodec_register(&ff_mediacodec_mpeg2_encoder); + av_register_hwaccel(&ff_mediacodec_mpeg2_hwaccel); + } + + encoder = AMediaCodec_createEncoderByType("video/mp4v-es"); + if (encoder) { + AMediaCodec_delete(encoder); + avcodec_register(&ff_mediacodec_mpeg4_encoder); + av_register_hwaccel(&ff_mediacodec_mpeg4_hwaccel); + } + + + encoder = AMediaCodec_createEncoderByType("video/x-vnd.on2.vp8"); + if (encoder) { + AMediaCodec_delete(encoder); + avcodec_register(&ff_mediacodec_vp8_encoder); + av_register_hwaccel(&ff_mediacodec_vp8_hwaccel); + } + + encoder = AMediaCodec_createEncoderByType("video/x-vnd.on2.vp9"); + if (encoder) { + AMediaCodec_delete(encoder); + avcodec_register(&ff_mediacodec_vp9_encoder); + av_register_hwaccel(&ff_mediacodec_vp9_hwaccel); + } + +} + +AVCodec ff_mediacodec_encoder = { + .name = "mediacodec", + .init_static_data = init_and_register_all_mediacodec +}; + diff --git a/captive/ffmpeg/csrc/libavutil/pixdesc.c b/captive/ffmpeg/csrc/libavutil/pixdesc.c index 2cfab89c030..dafb434c2d2 100644 --- a/captive/ffmpeg/csrc/libavutil/pixdesc.c +++ b/captive/ffmpeg/csrc/libavutil/pixdesc.c @@ -2037,10 +2037,6 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { .name = "qsv", .flags = AV_PIX_FMT_FLAG_HWACCEL, }, - [AV_PIX_FMT_MEDIACODEC] = { - .name = "mediacodec", - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, [AV_PIX_FMT_MMAL] = { .name = "mmal", .flags = AV_PIX_FMT_FLAG_HWACCEL, @@ -2099,146 +2095,8 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { }, .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_BE, }, - [AV_PIX_FMT_P016LE] = { - .name = "p016le", - .nb_components = 3, - .log2_chroma_w = 1, - .log2_chroma_h = 1, - .comp = { - { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ - { 1, 4, 0, 0, 16, 3, 15, 1 }, /* U */ - { 1, 4, 2, 0, 16, 3, 15, 3 }, /* V */ - }, - .flags = AV_PIX_FMT_FLAG_PLANAR, - }, - [AV_PIX_FMT_P016BE] = { - .name = "p016be", - .nb_components = 3, - .log2_chroma_w = 1, - .log2_chroma_h = 1, - .comp = { - { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ - { 1, 4, 0, 0, 16, 3, 15, 1 }, /* U */ - { 1, 4, 2, 0, 16, 3, 15, 3 }, /* V */ - }, - .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_BE, - }, - [AV_PIX_FMT_GBRAP12LE] = { - .name = "gbrap12le", - .nb_components = 4, - .log2_chroma_w = 0, - .log2_chroma_h = 0, - .comp = { - { 2, 2, 0, 0, 12, 1, 11, 1 }, /* R */ - { 0, 2, 0, 0, 12, 1, 11, 1 }, /* G */ - { 1, 2, 0, 0, 12, 1, 11, 1 }, /* B */ - { 3, 2, 0, 0, 12, 1, 11, 1 }, /* A */ - }, - .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | - AV_PIX_FMT_FLAG_ALPHA, - }, - [AV_PIX_FMT_GBRAP12BE] = { - .name = "gbrap12be", - .nb_components = 4, - .log2_chroma_w = 0, - .log2_chroma_h = 0, - .comp = { - { 2, 2, 0, 0, 12, 1, 11, 1 }, /* R */ - { 0, 2, 0, 0, 12, 1, 11, 1 }, /* G */ - { 1, 2, 0, 0, 12, 1, 11, 1 }, /* B */ - { 3, 2, 0, 0, 12, 1, 11, 1 }, /* A */ - }, - .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | - AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, - }, - [AV_PIX_FMT_GBRAP10LE] = { - .name = "gbrap10le", - .nb_components = 4, - .log2_chroma_w = 0, - .log2_chroma_h = 0, - .comp = { - { 2, 2, 0, 0, 10, 1, 9, 1 }, /* R */ - { 0, 2, 0, 0, 10, 1, 9, 1 }, /* G */ - { 1, 2, 0, 0, 10, 1, 9, 1 }, /* B */ - { 3, 2, 0, 0, 10, 1, 9, 1 }, /* A */ - }, - .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | - AV_PIX_FMT_FLAG_ALPHA, - }, - [AV_PIX_FMT_GBRAP10BE] = { - .name = "gbrap10be", - .nb_components = 4, - .log2_chroma_w = 0, - .log2_chroma_h = 0, - .comp = { - { 2, 2, 0, 0, 10, 1, 9, 1 }, /* R */ - { 0, 2, 0, 0, 10, 1, 9, 1 }, /* G */ - { 1, 2, 0, 0, 10, 1, 9, 1 }, /* B */ - { 3, 2, 0, 0, 10, 1, 9, 1 }, /* A */ - }, - .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | - AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, - }, - [AV_PIX_FMT_D3D11] = { - .name = "d3d11", - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, - [AV_PIX_FMT_GBRPF32BE] = { - .name = "gbrpf32be", - .nb_components = 3, - .log2_chroma_w = 0, - .log2_chroma_h = 0, - .comp = { - { 2, 4, 0, 0, 32, 3, 31, 1 }, /* R */ - { 0, 4, 0, 0, 32, 3, 31, 1 }, /* G */ - { 1, 4, 0, 0, 32, 3, 31, 1 }, /* B */ - }, - .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | - AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_FLOAT, - }, - [AV_PIX_FMT_GBRPF32LE] = { - .name = "gbrpf32le", - .nb_components = 3, - .log2_chroma_w = 0, - .log2_chroma_h = 0, - .comp = { - { 2, 4, 0, 0, 32, 3, 31, 1 }, /* R */ - { 0, 4, 0, 0, 32, 3, 31, 1 }, /* G */ - { 1, 4, 0, 0, 32, 3, 31, 1 }, /* B */ - }, - .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_FLOAT | AV_PIX_FMT_FLAG_RGB, - }, - [AV_PIX_FMT_GBRAPF32BE] = { - .name = "gbrapf32be", - .nb_components = 4, - .log2_chroma_w = 0, - .log2_chroma_h = 0, - .comp = { - { 2, 4, 0, 0, 32, 3, 31, 1 }, /* R */ - { 0, 4, 0, 0, 32, 3, 31, 1 }, /* G */ - { 1, 4, 0, 0, 32, 3, 31, 1 }, /* B */ - { 3, 4, 0, 0, 32, 3, 31, 1 }, /* A */ - }, - .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | - AV_PIX_FMT_FLAG_ALPHA | AV_PIX_FMT_FLAG_RGB | - AV_PIX_FMT_FLAG_FLOAT, - }, - [AV_PIX_FMT_GBRAPF32LE] = { - .name = "gbrapf32le", - .nb_components = 4, - .log2_chroma_w = 0, - .log2_chroma_h = 0, - .comp = { - { 2, 4, 0, 0, 32, 3, 31, 1 }, /* R */ - { 0, 4, 0, 0, 32, 3, 31, 1 }, /* G */ - { 1, 4, 0, 0, 32, 3, 31, 1 }, /* B */ - { 3, 4, 0, 0, 32, 3, 31, 1 }, /* A */ - }, - .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA | - AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_FLOAT, - }, - [AV_PIX_FMT_DRM_PRIME] = { - .name = "drm_prime", + [AV_PIX_FMT_MEDIACODEC] = { + .name = "mediacodec", .flags = AV_PIX_FMT_FLAG_HWACCEL, }, }; diff --git a/captive/ffmpeg/csrc/libavutil/pixfmt.h b/captive/ffmpeg/csrc/libavutil/pixfmt.h index 8a26fa874cf..58f6a0c3bfe 100644 --- a/captive/ffmpeg/csrc/libavutil/pixfmt.h +++ b/captive/ffmpeg/csrc/libavutil/pixfmt.h @@ -302,14 +302,14 @@ enum AVPixelFormat { AV_PIX_FMT_P010LE, ///< like NV12, with 10bpp per component, data in the high bits, zeros in the low bits, little-endian AV_PIX_FMT_P010BE, ///< like NV12, with 10bpp per component, data in the high bits, zeros in the low bits, big-endian + AV_PIX_FMT_MEDIACODEC, ///< HW decoding through Android Media Codec + AV_PIX_FMT_GBRAP12BE, ///< planar GBR 4:4:4:4 48bpp, big-endian AV_PIX_FMT_GBRAP12LE, ///< planar GBR 4:4:4:4 48bpp, little-endian AV_PIX_FMT_GBRAP10BE, ///< planar GBR 4:4:4:4 40bpp, big-endian AV_PIX_FMT_GBRAP10LE, ///< planar GBR 4:4:4:4 40bpp, little-endian - AV_PIX_FMT_MEDIACODEC, ///< hardware decoding through MediaCodec - AV_PIX_FMT_GRAY12BE, ///< Y , 12bpp, big-endian AV_PIX_FMT_GRAY12LE, ///< Y , 12bpp, little-endian AV_PIX_FMT_GRAY10BE, ///< Y , 10bpp, big-endian diff --git a/captive/ffmpeg/incarcerate.in b/captive/ffmpeg/incarcerate.in index 970231a4a17..759a68a9101 100755 --- a/captive/ffmpeg/incarcerate.in +++ b/captive/ffmpeg/incarcerate.in @@ -77,6 +77,15 @@ case $HOST_OS in # static linking, so we fix librtmp here. FFMPEG_OPTIONS="$FFMPEG_OPTIONS --extra-libs=-lwinmm" ;; + *linux-android*) + # ffmpeg configure doesn't handle pkg-config files correctly when + # static linking, so we fix librtmp here. + FFMPEG_OPTIONS="$FFMPEG_OPTIONS --extra-cflags=@CFLAGS@" + FFMPEG_OPTIONS="$FFMPEG_OPTIONS --enable-pthreads" + FFMPEG_OPTIONS="$FFMPEG_OPTIONS --extra-libs=-ldl" + FFMPEG_OPTIONS="$FFMPEG_OPTIONS --extra-libs=-lmediandk" + FFMPEG_OPTIONS="$FFMPEG_OPTIONS --extra-libs=-landroid" + ;; *linux*) # ffmpeg configure doesn't handle pkg-config files correctly when # static linking, so we fix librtmp here.