From 0946c754d99c05413e813ee515039adcf0f9232a Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 19 Oct 2016 21:56:22 +0200 Subject: [PATCH] examples/decode_audio: use a parser for splitting the input Do not rely on the decoder handling this, as it's not guaranteed to work. --- doc/examples/decode_audio.c | 82 ++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 28 deletions(-) diff --git a/doc/examples/decode_audio.c b/doc/examples/decode_audio.c index b56a5ee7f2..d2150a67c1 100644 --- a/doc/examples/decode_audio.c +++ b/doc/examples/decode_audio.c @@ -37,14 +37,40 @@ #define AUDIO_INBUF_SIZE 20480 #define AUDIO_REFILL_THRESH 4096 +static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame, + FILE *outfile) +{ + int len, got_frame; + + while (pkt->size > 0) { + len = avcodec_decode_audio4(dec_ctx, frame, &got_frame, pkt); + if (len < 0) { + fprintf(stderr, "Error while decoding\n"); + exit(1); + } + if (got_frame) { + /* if a frame has been decoded, output it */ + int data_size = av_samples_get_buffer_size(NULL, dec_ctx->channels, + frame->nb_samples, + dec_ctx->sample_fmt, 1); + fwrite(frame->data[0], 1, data_size, outfile); + } + pkt->size -= len; + pkt->data += len; + } +} + int main(int argc, char **argv) { const char *outfilename, *filename; const AVCodec *codec; AVCodecContext *c= NULL; - int len; + AVCodecParserContext *parser = NULL; + int len, ret; FILE *f, *outfile; uint8_t inbuf[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; + uint8_t *data; + size_t data_size; AVPacket avpkt; AVFrame *decoded_frame = NULL; @@ -67,6 +93,12 @@ int main(int argc, char **argv) exit(1); } + parser = av_parser_init(codec->id); + if (!parser) { + fprintf(stderr, "parser not found\n"); + exit(1); + } + c = avcodec_alloc_context3(codec); /* open it */ @@ -87,12 +119,10 @@ int main(int argc, char **argv) } /* decode until eof */ - avpkt.data = inbuf; - avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f); - - while (avpkt.size > 0) { - int got_frame = 0; + data = inbuf; + data_size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f); + while (data_size > 0) { if (!decoded_frame) { if (!(decoded_frame = av_frame_alloc())) { fprintf(stderr, "out of memory\n"); @@ -100,31 +130,26 @@ int main(int argc, char **argv) } } - len = avcodec_decode_audio4(c, decoded_frame, &got_frame, &avpkt); - if (len < 0) { - fprintf(stderr, "Error while decoding\n"); + ret = av_parser_parse2(parser, c, &avpkt.data, &avpkt.size, + data, data_size, + AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0); + if (ret < 0) { + fprintf(stderr, "Error while parsing\n"); exit(1); } - if (got_frame) { - /* if a frame has been decoded, output it */ - int data_size = av_samples_get_buffer_size(NULL, c->channels, - decoded_frame->nb_samples, - c->sample_fmt, 1); - fwrite(decoded_frame->data[0], 1, data_size, outfile); - } - avpkt.size -= len; - avpkt.data += len; - if (avpkt.size < AUDIO_REFILL_THRESH) { - /* Refill the input buffer, to avoid trying to decode - * incomplete frames. Instead of this, one could also use - * a parser, or use a proper container format through - * libavformat. */ - memmove(inbuf, avpkt.data, avpkt.size); - avpkt.data = inbuf; - len = fread(avpkt.data + avpkt.size, 1, - AUDIO_INBUF_SIZE - avpkt.size, f); + data += ret; + data_size -= ret; + + if (avpkt.size) + decode(c, &avpkt, decoded_frame, outfile); + + if (data_size < AUDIO_REFILL_THRESH) { + memmove(inbuf, data, data_size); + data = inbuf; + len = fread(data + data_size, 1, + AUDIO_INBUF_SIZE - data_size, f); if (len > 0) - avpkt.size += len; + data_size += len; } } @@ -132,6 +157,7 @@ int main(int argc, char **argv) fclose(f); avcodec_free_context(&c); + av_parser_close(parser); av_frame_free(&decoded_frame); return 0;