|
|
|
@ -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); |
|
|
|
|
|
|
|
|
|