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) {
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. */
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);