From: Anton Khirnov Date: Wed, 19 Oct 2016 19:56:22 +0000 (+0200) Subject: examples/decode_video: use a parser for splitting the input X-Git-Tag: android-x86-7.1-r1~252^2~257 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=f78d360bba6dcfb585847a49a84e89c25950fbdb;p=android-x86%2Fexternal-ffmpeg.git examples/decode_video: use a parser for splitting the input Do not rely on the decoder handling this, as it's not guaranteed to work. --- diff --git a/doc/examples/decode_video.c b/doc/examples/decode_video.c index 43819ecc6c..4c1068bef3 100644 --- a/doc/examples/decode_video.c +++ b/doc/examples/decode_video.c @@ -50,16 +50,45 @@ static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize, fclose(f); } +static void decode(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket *pkt, + const char *filename) +{ + char buf[1024]; + int ret, got_picture; + + while (pkt->size > 0) { + ret = avcodec_decode_video2(dec_ctx, frame, &got_picture, pkt); + if (ret < 0) { + fprintf(stderr, "Error while decoding frame %d\n", dec_ctx->frame_number); + exit(1); + } + if (got_picture) { + printf("saving frame %3d\n", dec_ctx->frame_number); + fflush(stdout); + + /* the picture is allocated by the decoder. no need to + free it */ + snprintf(buf, sizeof(buf), filename, dec_ctx->frame_number); + pgm_save(frame->data[0], frame->linesize[0], + frame->width, frame->height, buf); + } + pkt->size -= ret; + pkt->data += ret; + } +} + int main(int argc, char **argv) { const char *filename, *outfilename; const AVCodec *codec; + AVCodecParserContext *parser; AVCodecContext *c= NULL; - int frame, got_picture, len; FILE *f; AVFrame *picture; uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; - char buf[1024]; + uint8_t *data; + size_t data_size; + int ret; AVPacket avpkt; if (argc <= 2) { @@ -83,12 +112,15 @@ 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); picture = av_frame_alloc(); - if (codec->capabilities & AV_CODEC_CAP_TRUNCATED) - c->flags |= AV_CODEC_FLAG_TRUNCATED; // we do not send complete frames - /* For some codecs, such as msmpeg4 and mpeg4, width and height MUST be initialized there because this information is not available in the bitstream. */ @@ -105,70 +137,37 @@ int main(int argc, char **argv) exit(1); } - frame = 0; - for(;;) { - avpkt.size = fread(inbuf, 1, INBUF_SIZE, f); - if (avpkt.size == 0) + while (!feof(f)) { + /* read raw data from the input file */ + data_size = fread(inbuf, 1, INBUF_SIZE, f); + if (!data_size) break; - /* NOTE1: some codecs are stream based (mpegvideo, mpegaudio) - and this is the only method to use them because you cannot - know the compressed data size before analysing it. - - BUT some other codecs (msmpeg4, mpeg4) are inherently frame - based, so you must call them with all the data for one - frame exactly. You must also initialize 'width' and - 'height' before initializing them. */ - - /* NOTE2: some codecs allow the raw parameters (frame size, - sample rate) to be changed at any frame. We handle this, so - you should also take care of it */ - - /* here, we use a stream based decoder (mpeg1video), so we - feed decoder and see if it could decode a frame */ - avpkt.data = inbuf; - while (avpkt.size > 0) { - len = avcodec_decode_video2(c, picture, &got_picture, &avpkt); - if (len < 0) { - fprintf(stderr, "Error while decoding frame %d\n", frame); + /* use the parser to split the data into frames */ + data = inbuf; + while (data_size > 0) { + 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_picture) { - printf("saving frame %3d\n", frame); - fflush(stdout); - - /* the picture is allocated by the decoder. no need to - free it */ - snprintf(buf, sizeof(buf), outfilename, frame); - pgm_save(picture->data[0], picture->linesize[0], - c->width, c->height, buf); - frame++; - } - avpkt.size -= len; - avpkt.data += len; + data += ret; + data_size -= ret; + + if (avpkt.size) + decode(c, picture, &avpkt, outfilename); } } - /* Some codecs, such as MPEG, transmit the I- and P-frame with a - latency of one frame. You must do the following to have a - chance to get the last frame of the video. */ + /* flush the decoder */ avpkt.data = NULL; avpkt.size = 0; - len = avcodec_decode_video2(c, picture, &got_picture, &avpkt); - if (got_picture) { - printf("saving last frame %3d\n", frame); - fflush(stdout); - - /* the picture is allocated by the decoder. no need to - free it */ - snprintf(buf, sizeof(buf), outfilename, frame); - pgm_save(picture->data[0], picture->linesize[0], - c->width, c->height, buf); - frame++; - } + decode(c, picture, &avpkt, outfilename); fclose(f); + av_parser_close(parser); avcodec_free_context(&c); av_frame_free(&picture);