lavc/mediacodecdec: switch to new decoding API

Using the new API gives the decoder the ability to produce
N frames per input packet. This is particularly useful with
mpeg2 decoders on some android devices, which automatically
deinterlace video and produce one frame per field.

Signed-off-by: Aman Gupta <aman@tmm1.net>
Signed-off-by: Matthieu Bouron <matthieu.bouron@gmail.com>
This commit is contained in:
Aman Gupta 2017-12-28 17:33:14 -08:00 committed by Matthieu Bouron
parent 8bbd8c8d52
commit 9d9835017f
1 changed files with 48 additions and 32 deletions

View File

@ -31,6 +31,7 @@
#include "libavutil/pixfmt.h"
#include "avcodec.h"
#include "decode.h"
#include "h264_parse.h"
#include "hevc_parse.h"
#include "hwaccel.h"
@ -424,29 +425,13 @@ static int mediacodec_process_data(AVCodecContext *avctx, AVFrame *frame,
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)
static int mediacodec_receive_frame(AVCodecContext *avctx, AVFrame *frame)
{
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)
return ret;
}
ret = av_packet_ref(&input_pkt, avpkt);
if (ret < 0)
return ret;
av_fifo_generic_write(s->fifo, &input_pkt, sizeof(input_pkt), NULL);
}
int got_frame = 0;
int is_eof = 0;
AVPacket pkt = { 0 };
/*
* MediaCodec.flush() discards both input and output buffers, thus we
@ -470,26 +455,57 @@ static int mediacodec_decode_frame(AVCodecContext *avctx, void *data,
*/
if (ff_mediacodec_dec_is_flushing(avctx, s->ctx)) {
if (!ff_mediacodec_dec_flush(avctx, s->ctx)) {
return avpkt->size;
return AVERROR(EAGAIN);
}
}
ret = ff_decode_get_packet(avctx, &pkt);
if (ret == AVERROR_EOF)
is_eof = 1;
else if (ret == AVERROR(EAGAIN))
; /* no input packet, but fallthrough to check for pending frames */
else if (ret < 0)
return ret;
/* buffer the input packet */
if (pkt.size) {
if (av_fifo_space(s->fifo) < sizeof(pkt)) {
ret = av_fifo_realloc2(s->fifo,
av_fifo_size(s->fifo) + sizeof(pkt));
if (ret < 0) {
av_packet_unref(&pkt);
return ret;
}
}
av_fifo_generic_write(s->fifo, &pkt, sizeof(pkt), NULL);
}
/* process buffered data */
while (!*got_frame) {
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);
AVPacket null_pkt = { 0 };
if (is_eof) {
ret = ff_mediacodec_dec_decode(avctx, s->ctx, frame,
&got_frame, &null_pkt);
if (ret < 0)
return ret;
else if (got_frame)
return 0;
else
return AVERROR_EOF;
}
return AVERROR(EAGAIN);
}
av_fifo_generic_read(s->fifo, &s->buffered_pkt, sizeof(s->buffered_pkt), NULL);
}
ret = mediacodec_process_data(avctx, frame, got_frame, &s->buffered_pkt);
ret = mediacodec_process_data(avctx, frame, &got_frame, &s->buffered_pkt);
if (ret < 0)
return ret;
@ -497,7 +513,7 @@ static int mediacodec_decode_frame(AVCodecContext *avctx, void *data,
s->buffered_pkt.data += ret;
}
return avpkt->size;
return 0;
}
static void mediacodec_decode_flush(AVCodecContext *avctx)
@ -537,7 +553,7 @@ AVCodec ff_h264_mediacodec_decoder = {
.id = AV_CODEC_ID_H264,
.priv_data_size = sizeof(MediaCodecH264DecContext),
.init = mediacodec_decode_init,
.decode = mediacodec_decode_frame,
.receive_frame = mediacodec_receive_frame,
.flush = mediacodec_decode_flush,
.close = mediacodec_decode_close,
.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE,
@ -556,7 +572,7 @@ AVCodec ff_hevc_mediacodec_decoder = {
.id = AV_CODEC_ID_HEVC,
.priv_data_size = sizeof(MediaCodecH264DecContext),
.init = mediacodec_decode_init,
.decode = mediacodec_decode_frame,
.receive_frame = mediacodec_receive_frame,
.flush = mediacodec_decode_flush,
.close = mediacodec_decode_close,
.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE,
@ -575,7 +591,7 @@ AVCodec ff_mpeg2_mediacodec_decoder = {
.id = AV_CODEC_ID_MPEG2VIDEO,
.priv_data_size = sizeof(MediaCodecH264DecContext),
.init = mediacodec_decode_init,
.decode = mediacodec_decode_frame,
.receive_frame = mediacodec_receive_frame,
.flush = mediacodec_decode_flush,
.close = mediacodec_decode_close,
.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE,
@ -593,7 +609,7 @@ AVCodec ff_mpeg4_mediacodec_decoder = {
.id = AV_CODEC_ID_MPEG4,
.priv_data_size = sizeof(MediaCodecH264DecContext),
.init = mediacodec_decode_init,
.decode = mediacodec_decode_frame,
.receive_frame = mediacodec_receive_frame,
.flush = mediacodec_decode_flush,
.close = mediacodec_decode_close,
.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE,
@ -611,7 +627,7 @@ AVCodec ff_vp8_mediacodec_decoder = {
.id = AV_CODEC_ID_VP8,
.priv_data_size = sizeof(MediaCodecH264DecContext),
.init = mediacodec_decode_init,
.decode = mediacodec_decode_frame,
.receive_frame = mediacodec_receive_frame,
.flush = mediacodec_decode_flush,
.close = mediacodec_decode_close,
.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE,
@ -629,7 +645,7 @@ AVCodec ff_vp9_mediacodec_decoder = {
.id = AV_CODEC_ID_VP9,
.priv_data_size = sizeof(MediaCodecH264DecContext),
.init = mediacodec_decode_init,
.decode = mediacodec_decode_frame,
.receive_frame = mediacodec_receive_frame,
.flush = mediacodec_decode_flush,
.close = mediacodec_decode_close,
.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE,