Hi,
On 07/07/2016 17:43, Matthieu Bouron wrote:
[...]
0001-lavc-add-mediacodec-hwaccel-support.patch
From 9bb86990f0f7a26d25878a771f5977ae83d14769 Mon Sep 17 00:00:00 2001
From: Matthieu Bouron<matthieu.bou...@stupeflix.com>
Date: Fri, 11 Mar 2016 17:21:04 +0100
Subject: [PATCH] lavc: add mediacodec hwaccel support
---
configure | 1 +
libavcodec/Makefile | 6 +-
libavcodec/allcodecs.c | 1 +
libavcodec/mediacodec.c | 133 ++++++++++++++++++++
libavcodec/mediacodec.h | 88 +++++++++++++
libavcodec/mediacodec_surface.c | 66 ++++++++++
libavcodec/mediacodec_surface.h | 31 +++++
libavcodec/mediacodec_wrapper.c | 5 +-
libavcodec/mediacodecdec.c | 270 +++++++++++++++++++++++++++++++++-------
libavcodec/mediacodecdec.h | 17 +++
libavcodec/mediacodecdec_h264.c | 44 ++++++-
libavcodec/version.h | 2 +-
libavutil/pixdesc.c | 4 +
libavutil/pixfmt.h | 2 +
14 files changed, 611 insertions(+), 59 deletions(-)
create mode 100644 libavcodec/mediacodec.c
create mode 100644 libavcodec/mediacodec.h
create mode 100644 libavcodec/mediacodec_surface.c
create mode 100644 libavcodec/mediacodec_surface.h
[...]
diff --git a/libavcodec/mediacodec.c b/libavcodec/mediacodec.c
new file mode 100644
index 0000000..5b79798
--- /dev/null
+++ b/libavcodec/mediacodec.c
@@ -0,0 +1,133 @@
+/*
+ * Android MediaCodec public API functions
+ *
+ * Copyright (c) 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 "config.h"
+
+#if CONFIG_H264_MEDIACODEC_HWACCEL
+
+#include <jni.h>
+
+#include "libavcodec/avcodec.h"
+#include "libavutil/atomic.h"
+#include "libavutil/mem.h"
+
+#include "ffjni.h"
+#include "mediacodec.h"
+#include "mediacodecdec.h"
+
+AVMediaCodecContext *av_mediacodec_alloc_context(void)
+{
+ return av_mallocz(sizeof(AVMediaCodecContext));
+}
+
+int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext
*ctx, void *surface)
+{
+ int ret = 0;
+ JNIEnv *env = NULL;
+ int attached = 0;
+
nit: env and attached don't need to be initialized
+ env = ff_jni_attach_env(&attached, avctx);
+ if (!env) {
+ return AVERROR_EXTERNAL;
+ }
+
+ ctx->surface = (*env)->NewGlobalRef(env, surface);
+ if (ctx->surface) {
+ avctx->hwaccel_context = ctx;
+ } else {
+ av_log(avctx, AV_LOG_ERROR, "Could not create new global reference\n");
+ ret = AVERROR_EXTERNAL;
+ }
+
+ if (attached) {
+ ff_jni_detach_env(avctx);
+ }
+
+ return ret;
+}
+
+void av_mediacodec_default_free(AVCodecContext *avctx)
+{
+ JNIEnv *env = NULL;
+ int attached = 0;
+
ditto
[...]
diff --git a/libavcodec/mediacodec.h b/libavcodec/mediacodec.h
new file mode 100644
index 0000000..f755bd1
--- /dev/null
+++ b/libavcodec/mediacodec.h
@@ -0,0 +1,88 @@
+/*
+ * Android MediaCodec public API
+ *
+ * Copyright (c) 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_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);
+
+/**
+ * Opaque structure representing a MediaCodec buffer to render.
+ */
+typedef struct MediaCodecBuffer AVMediaCodecBuffer;
+
+/**
+ * Release a MediaCodec buffer and render it on the surface that is associated
nit: "render to the surface"
same below
+ * 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 on the surface or 0 to
+ * only release the buffer
+ * @return 0 on success, < 0 otherwise
+ */
+int av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render);
+
+#endif /* AVCODEC_MEDIACODEC_H */
diff --git a/libavcodec/mediacodec_surface.c b/libavcodec/mediacodec_surface.c
new file mode 100644
index 0000000..903ebe4
--- /dev/null
+++ b/libavcodec/mediacodec_surface.c
@@ -0,0 +1,66 @@
+/*
+ * Android MediaCodec Surface functions
+ *
+ * Copyright (c) 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 "ffjni.h"
+#include "mediacodec_surface.h"
+
+void *ff_mediacodec_surface_ref(void *surface, void *log_ctx)
+{
+ int attached = 0;
+ JNIEnv *env = NULL;
+
+ void *reference = NULL;
+
nit: unneeded initializations
+ env = ff_jni_attach_env(&attached, log_ctx);
+ if (!env) {
+ return NULL;
+ }
+
+ reference = (*env)->NewGlobalRef(env, surface);
+
+ if (attached) {
+ ff_jni_detach_env(log_ctx);
+ }
+
+ return reference;
+}
+
+int ff_mediacodec_surface_unref(void *surface, void *log_ctx)
+{
+ int attached = 0;
+ JNIEnv *env = NULL;
+
ditto
[...]
diff --git a/libavcodec/mediacodecdec.c b/libavcodec/mediacodecdec.c
index e29637e..aa5ab24 100644
--- a/libavcodec/mediacodecdec.c
+++ b/libavcodec/mediacodecdec.c
@@ -23,6 +23,7 @@
#include <string.h>
#include <sys/types.h>
+#include "libavutil/atomic.h"
#include "libavutil/common.h"
#include "libavutil/mem.h"
#include "libavutil/log.h"
@@ -33,6 +34,8 @@
#include "avcodec.h"
#include "internal.h"
+#include "mediacodec.h"
+#include "mediacodec_surface.h"
#include "mediacodec_sw_buffer.h"
#include "mediacodec_wrapper.h"
#include "mediacodecdec.h"
@@ -118,6 +121,10 @@ static enum AVPixelFormat
mcdec_map_color_format(AVCodecContext *avctx,
int i;
enum AVPixelFormat ret = AV_PIX_FMT_NONE;
+ if (s->surface) {
+ return AV_PIX_FMT_MEDIACODEC;
+ }
+
if (!strcmp(s->codec_name, "OMX.k3.video.decoder.avc") && color_format ==
COLOR_FormatYCbYCr) {
s->color_format = color_format =
COLOR_TI_FormatYUV420PackedSemiPlanar;
}
@@ -134,7 +141,117 @@ static enum AVPixelFormat
mcdec_map_color_format(AVCodecContext *avctx,
return ret;
}
-static int mediacodec_wrap_buffer(AVCodecContext *avctx,
+static void ff_mediacodec_dec_ref(MediaCodecDecContext *s)
+{
+ avpriv_atomic_int_add_and_fetch(&s->refcount, 1);
+}
+
+static void ff_mediacodec_dec_unref(MediaCodecDecContext *s)
+{
+ if (!s)
+ return;
+
+ if (!avpriv_atomic_int_add_and_fetch(&s->refcount, -1)) {
+ if (s->codec) {
+ ff_AMediaCodec_delete(s->codec);
+ s->codec = NULL;
+ }
+
+ if (s->format) {
+ ff_AMediaFormat_delete(s->format);
+ s->format = NULL;
+ }
+
+ if (s->surface) {
+ ff_mediacodec_surface_unref(s->surface, NULL);
+ s->surface = NULL;
+ }
+
+ av_freep(&s->codec_name);
+ av_freep(&s);
+ }
+}
+
+static void mediacodec_buffer_release(void *opaque, uint8_t *data)
+{
+ AVMediaCodecBuffer *buffer = opaque;
+ MediaCodecDecContext *ctx = buffer->ctx;
+ int released = avpriv_atomic_int_get(&buffer->released);
+
+ if (!released) {
+ ff_AMediaCodec_releaseOutputBuffer(ctx->codec, buffer->index, 0);
+ }
+
+ ff_mediacodec_dec_unref(ctx);
+ av_freep(&buffer);
+}
+
+static int mediacodec_wrap_hw_buffer(AVCodecContext *avctx,
+ MediaCodecDecContext *s,
+ ssize_t index,
+ FFAMediaCodecBufferInfo *info,
+ AVFrame *frame)
+{
+ int ret = 0;
+ int status = 0;
+ AVMediaCodecBuffer *buffer = NULL;
+
+ frame->buf[0] = NULL;
+ frame->width = avctx->width;
+ frame->height = avctx->height;
+ frame->format = avctx->pix_fmt;
+
+ if (avctx->pkt_timebase.num && avctx->pkt_timebase.den) {
+ frame->pkt_pts = av_rescale_q(info->presentationTimeUs,
+ av_make_q(1, 1000000),
+ avctx->pkt_timebase);
+ } else {
+ frame->pkt_pts = info->presentationTimeUs;
+ }
+ frame->pkt_dts = AV_NOPTS_VALUE;
+
+ buffer = av_mallocz(sizeof(AVMediaCodecBuffer));
+ if (!buffer) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ buffer->released = 0;
+
+ frame->buf[0] = av_buffer_create(NULL,
+ 0,
+ mediacodec_buffer_release,
+ buffer,
+ AV_BUFFER_FLAG_READONLY);
+
+ if (!frame->buf[0]) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+
+ }
+
+ buffer->ctx = s;
+ ff_mediacodec_dec_ref(s);
+
+ buffer->index = index;
+ buffer->pts = info->presentationTimeUs;
+
+ frame->data[3] = (uint8_t *)buffer;
+
+ return 0;
+fail:
+ av_freep(buffer);
+ av_buffer_unref(&frame->buf[0]);
+ status = ff_AMediaCodec_releaseOutputBuffer(s->codec, index, 0);
+ if (status < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to release output buffer\n");
+ ret = AVERROR_EXTERNAL;
+ }
+
+ return ret;
+}
+
+static int mediacodec_wrap_sw_buffer(AVCodecContext *avctx,
MediaCodecDecContext *s,
uint8_t *data,
size_t size,
@@ -304,6 +421,30 @@ static int mediacodec_dec_parse_format(AVCodecContext
*avctx, MediaCodecDecConte
return ff_set_dimensions(avctx, width, height);
}
+
+static int mediacodec_dec_flush_codec(AVCodecContext *avctx,
MediaCodecDecContext *s)
+{
+ FFAMediaCodec *codec = s->codec;
+ int status;
+
+ s->dequeued_buffer_nb = 0;
+
+ s->draining = 0;
+ s->flushing = 0;
+ s->eos = 0;
+
+ status = ff_AMediaCodec_flush(codec);
+ if (status < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to flush codec\n");
+ return AVERROR_EXTERNAL;
+ }
+
+ s->first_buffer = 0;
+ s->first_buffer_at = av_gettime();
+
+ return 0;
+}
+
int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s,
const char *mime, FFAMediaFormat *format)
{
@@ -311,7 +452,24 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx,
MediaCodecDecContext *s,
int status;
int profile;
+ enum AVPixelFormat pix_fmt;
+ enum AVPixelFormat pix_fmts[3] = {
nit: 2
+ AV_PIX_FMT_MEDIACODEC,
+ AV_PIX_FMT_NONE,
+ };
+
s->first_buffer_at = av_gettime();
+ s->refcount = 1;
+
+ pix_fmt = ff_get_format(avctx, pix_fmts);
+ if (pix_fmt == AV_PIX_FMT_MEDIACODEC) {
+ AVMediaCodecContext *user_ctx = avctx->hwaccel_context;
+
+ if (user_ctx && user_ctx->surface) {
+ s->surface = ff_mediacodec_surface_ref(user_ctx->surface, avctx);
+ av_log(avctx, AV_LOG_INFO, "Using surface %p\n", s->surface);
+ }
+ }
profile = ff_AMediaCodecProfile_getProfileFromAVCodecContext(avctx);
if (profile < 0) {
@@ -332,7 +490,7 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx,
MediaCodecDecContext *s,
goto fail;
}
- status = ff_AMediaCodec_configure(s->codec, format, NULL, NULL, 0);
+ status = ff_AMediaCodec_configure(s->codec, format, s->surface, NULL, 0);
if (status < 0) {
char *desc = ff_AMediaFormat_toString(format);
av_log(avctx, AV_LOG_ERROR,
@@ -380,7 +538,7 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx,
MediaCodecDecContext *s,
{
int ret;
int offset = 0;
- int need_flushing = 0;
+ int need_draining = 0;
uint8_t *data;
ssize_t index;
size_t size;
@@ -392,15 +550,21 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx,
MediaCodecDecContext *s,
int64_t input_dequeue_timeout_us = INPUT_DEQUEUE_TIMEOUT_US;
int64_t output_dequeue_timeout_us = OUTPUT_DEQUEUE_TIMEOUT_US;
+ if (s->flushing) {
+ av_log(avctx, AV_LOG_ERROR, "Decoder is flushing and cannot accept new
buffer "
+ "until all output buffers have been
released\n");
+ return AVERROR_EXTERNAL;
+ }
+
if (pkt->size == 0) {
- need_flushing = 1;
+ need_draining = 1;
}
- if (s->flushing && s->eos) {
+ if (s->draining && s->eos) {
return 0;
}
- while (offset < pkt->size || (need_flushing && !s->flushing)) {
+ while (offset < pkt->size || (need_draining && !s->draining)) {
int size;
index = ff_AMediaCodec_dequeueInputBuffer(codec, input_dequeue_timeout_us);
@@ -419,26 +583,37 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx,
MediaCodecDecContext *s,
return AVERROR_EXTERNAL;
}
- if (need_flushing) {
+ if (need_draining) {
+ int64_t pts = pkt->pts;
uint32_t flags = ff_AMediaCodec_getBufferFlagEndOfStream(codec);
+ if (s->surface) {
+ pts = av_rescale_q(pts, avctx->pkt_timebase, av_make_q(1,
1000000));
+ }
+
av_log(avctx, AV_LOG_DEBUG, "Sending End Of Stream signal\n");
- status = ff_AMediaCodec_queueInputBuffer(codec, index, 0, 0, pkt->pts, flags);
+ status = ff_AMediaCodec_queueInputBuffer(codec, index, 0, 0, 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;
+ s->draining = 1;
break;
} else {
+ int64_t pts = pkt->pts;
+
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 (s->surface && avctx->pkt_timebase.num &&
avctx->pkt_timebase.den) {
+ pts = av_rescale_q(pts, avctx->pkt_timebase, av_make_q(1,
1000000));
+ }
+
+ status = ff_AMediaCodec_queueInputBuffer(codec, index, 0, size,
pts, 0);
if (status < 0) {
av_log(avctx, AV_LOG_ERROR, "Failed to queue input buffer (status
= %d)\n", status);
return AVERROR_EXTERNAL;
@@ -446,7 +621,7 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx,
MediaCodecDecContext *s,
}
}
- if (need_flushing || s->flushing) {
+ if (need_draining || s->draining) {
/* If the codec is flushing or need to be flushed, block for a fair
* amount of time to ensure we got a frame */
output_dequeue_timeout_us = OUTPUT_DEQUEUE_BLOCK_TIMEOUT_US;
@@ -475,15 +650,22 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx,
MediaCodecDecContext *s,
}
if (info.size) {
- 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;
+ if (s->surface) {
+ if ((ret = mediacodec_wrap_hw_buffer(avctx, s, index, &info,
frame)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to wrap MediaCodec
buffer\n");
+ return ret;
+ }
+ } else {
+ 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_sw_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;
@@ -525,9 +707,9 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx,
MediaCodecDecContext *s,
} else if (ff_AMediaCodec_infoOutputBuffersChanged(codec, index)) {
ff_AMediaCodec_cleanOutputBuffers(codec);
} else if (ff_AMediaCodec_infoTryAgainLater(codec, index)) {
- if (s->flushing) {
+ if (s->draining) {
av_log(avctx, AV_LOG_ERROR, "Failed to dequeue output buffer within %"
PRIi64 "ms "
- "while flushing remaining frames, output
will probably lack frames\n",
+ "while draining remaining frames, output
will probably lack frames\n",
output_dequeue_timeout_us / 1000);
} else {
av_log(avctx, AV_LOG_DEBUG, "No output buffer available, try again
later\n");
@@ -542,39 +724,35 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx,
MediaCodecDecContext *s,
int ff_mediacodec_dec_flush(AVCodecContext *avctx, MediaCodecDecContext *s)
{
- FFAMediaCodec *codec = s->codec;
- int status;
-
- s->dequeued_buffer_nb = 0;
+ if (!s->surface || avpriv_atomic_int_get(&s->refcount) == 1) {
+ int ret;
- s->flushing = 0;
- s->eos = 0;
+ if ((ret = mediacodec_dec_flush_codec(avctx, s)) < 0) {
+ return ret;
+ }
nit:
int ret = flush();
if (ret < 0) ...
- status = ff_AMediaCodec_flush(codec);
- if (status < 0) {
- av_log(avctx, AV_LOG_ERROR, "Failed to flush codec\n");
- return AVERROR_EXTERNAL;
+ return 1;
Stating that returning 1 here is to state the flush is possible could be
cool
}
- s->first_buffer = 0;
- s->first_buffer_at = av_gettime();
-
+ s->flushing = 1;
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;
- }
-
- av_freep(&s->codec_name);
+ ff_mediacodec_dec_unref(s);
return 0;
}
+
+int ff_mediacodec_dec_is_flushing(AVCodecContext *avctx, MediaCodecDecContext
*s)
+{
+ return s->flushing;
+}
+
+AVHWAccel ff_h264_mediacodec_hwaccel = {
+ .name = "mediacodec",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_H264,
+ .pix_fmt = AV_PIX_FMT_MEDIACODEC,
+};
diff --git a/libavcodec/mediacodecdec.h b/libavcodec/mediacodecdec.h
index 646b628..8613352 100644
--- a/libavcodec/mediacodecdec.h
+++ b/libavcodec/mediacodecdec.h
@@ -34,12 +34,17 @@
typedef struct MediaCodecDecContext {
+ volatile int refcount;
+
I don't think this needs to be marked volatile
char *codec_name;
FFAMediaCodec *codec;
FFAMediaFormat *format;
+ void *surface;
+
int started;
+ int draining;
int flushing;
int eos;
@@ -78,4 +83,16 @@ int ff_mediacodec_dec_flush(AVCodecContext *avctx,
int ff_mediacodec_dec_close(AVCodecContext *avctx,
MediaCodecDecContext *s);
+int ff_mediacodec_dec_is_flushing(AVCodecContext *avctx,
+ MediaCodecDecContext *s);
+
+typedef struct MediaCodecBuffer {
+
+ MediaCodecDecContext *ctx;
+ ssize_t index;
+ int64_t pts;
+ volatile int released;
+
same here
+} MediaCodecBuffer;
+
#endif /* AVCODEC_MEDIACODECDEC_H */
diff --git a/libavcodec/mediacodecdec_h264.c b/libavcodec/mediacodecdec_h264.c
index 11fb677..e63943d 100644
--- a/libavcodec/mediacodecdec_h264.c
+++ b/libavcodec/mediacodecdec_h264.c
@@ -41,7 +41,7 @@
typedef struct MediaCodecH264DecContext {
- MediaCodecDecContext ctx;
+ MediaCodecDecContext *ctx;
AVBSFContext *bsf;
@@ -55,7 +55,8 @@ static av_cold int mediacodec_decode_close(AVCodecContext *avctx)
{
MediaCodecH264DecContext *s = avctx->priv_data;
- ff_mediacodec_dec_close(avctx, &s->ctx);
+ ff_mediacodec_dec_close(avctx, s->ctx);
+ s->ctx = NULL;
av_fifo_free(s->fifo);
@@ -184,7 +185,15 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx)
goto done;
}
- if ((ret = ff_mediacodec_dec_init(avctx, &s->ctx, CODEC_MIME, format)) < 0) {
+ 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 ((ret = ff_mediacodec_dec_init(avctx, s->ctx, CODEC_MIME, format)) < 0)
{
+ s->ctx = NULL;
goto done;
}
@@ -233,7 +242,7 @@ static int mediacodec_process_data(AVCodecContext *avctx, AVFrame *frame,
{
MediaCodecH264DecContext *s = avctx->priv_data;
- return ff_mediacodec_dec_decode(avctx, &s->ctx, frame, got_frame, pkt);
+ return ff_mediacodec_dec_decode(avctx, s->ctx, frame, got_frame, pkt);
}
static int mediacodec_decode_frame(AVCodecContext *avctx, void *data,
@@ -260,6 +269,29 @@ static int mediacodec_decode_frame(AVCodecContext *avctx,
void *data,
av_fifo_generic_write(s->fifo, &input_pkt, sizeof(input_pkt), NULL);
}
+ /*
+ * 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.
+ *
+ */
+ if (ff_mediacodec_dec_is_flushing(avctx, s->ctx)) {
+ if (!ff_mediacodec_dec_flush(avctx, s->ctx)) {
+ return avpkt->size;
This is not describing the case when ff_mediacodec_dec_flush() returns
an error.
+ }
+ }
+
/* process buffered data */
while (!*got_frame) {
/* prepare the input data -- convert to Annex B if needed */
@@ -271,7 +303,7 @@ static int mediacodec_decode_frame(AVCodecContext *avctx,
void *data,
/* 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);
+ ff_mediacodec_dec_decode(avctx, s->ctx, frame, got_frame,
avpkt);
}
av_fifo_generic_read(s->fifo, &input_pkt, sizeof(input_pkt), NULL);
@@ -318,7 +350,7 @@ static void mediacodec_decode_flush(AVCodecContext *avctx)
av_packet_unref(&s->filtered_pkt);
- ff_mediacodec_dec_flush(avctx, &s->ctx);
+ ff_mediacodec_dec_flush(avctx, s->ctx);
}
AVCodec ff_h264_mediacodec_decoder = {
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 5e04754..33d4b06 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -28,7 +28,7 @@
#include "libavutil/version.h"
#define LIBAVCODEC_VERSION_MAJOR 57
-#define LIBAVCODEC_VERSION_MINOR 48
+#define LIBAVCODEC_VERSION_MINOR 49
#define LIBAVCODEC_VERSION_MICRO 102
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c
index 0dffa4d..d88aaf7 100644
--- a/libavutil/pixdesc.c
+++ b/libavutil/pixdesc.c
@@ -1974,6 +1974,10 @@ 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,
diff --git a/libavutil/pixfmt.h b/libavutil/pixfmt.h
index 0ed01c4..6f71ac0 100644
--- a/libavutil/pixfmt.h
+++ b/libavutil/pixfmt.h
@@ -303,6 +303,8 @@ enum AVPixelFormat {
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_NB, ///< number of pixel formats, DO NOT USE THIS if
you want to link with shared libav* because the number of formats might differ
between versions
};
-- 2.9.0
--
Ben
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel