|
|
|
@@ -48,43 +48,47 @@ static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize, |
|
|
|
fclose(f); |
|
|
|
} |
|
|
|
|
|
|
|
static int decode_write_frame(const char *outfilename, AVCodecContext *avctx, |
|
|
|
AVFrame *frame, int *frame_count, AVPacket *pkt, int last) |
|
|
|
static void decode(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket *pkt, |
|
|
|
const char *filename) |
|
|
|
{ |
|
|
|
int len, got_frame; |
|
|
|
char buf[1024]; |
|
|
|
|
|
|
|
len = avcodec_decode_video2(avctx, frame, &got_frame, pkt); |
|
|
|
if (len < 0) { |
|
|
|
fprintf(stderr, "Error while decoding frame %d\n", *frame_count); |
|
|
|
return len; |
|
|
|
} |
|
|
|
if (got_frame) { |
|
|
|
printf("Saving %sframe %3d\n", last ? "last " : "", *frame_count); |
|
|
|
fflush(stdout); |
|
|
|
|
|
|
|
/* the picture is allocated by the decoder, no need to free it */ |
|
|
|
snprintf(buf, sizeof(buf), outfilename, *frame_count); |
|
|
|
pgm_save(frame->data[0], frame->linesize[0], |
|
|
|
frame->width, frame->height, buf); |
|
|
|
(*frame_count)++; |
|
|
|
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); |
|
|
|
} |
|
|
|
if (pkt->data) { |
|
|
|
pkt->size -= ret; |
|
|
|
pkt->data += ret; |
|
|
|
} |
|
|
|
} |
|
|
|
if (pkt->data) { |
|
|
|
pkt->size -= len; |
|
|
|
pkt->data += len; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int main(int argc, char **argv) |
|
|
|
{ |
|
|
|
const char *filename, *outfilename; |
|
|
|
const AVCodec *codec; |
|
|
|
AVCodecParserContext *parser; |
|
|
|
AVCodecContext *c= NULL; |
|
|
|
int frame_count; |
|
|
|
FILE *f; |
|
|
|
AVFrame *frame; |
|
|
|
uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; |
|
|
|
uint8_t *data; |
|
|
|
size_t data_size; |
|
|
|
int ret; |
|
|
|
AVPacket avpkt; |
|
|
|
|
|
|
|
if (argc <= 2) { |
|
|
|
@@ -108,15 +112,18 @@ 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); |
|
|
|
if (!c) { |
|
|
|
fprintf(stderr, "Could not allocate video codec context\n"); |
|
|
|
exit(1); |
|
|
|
} |
|
|
|
|
|
|
|
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. */ |
|
|
|
@@ -139,42 +146,37 @@ int main(int argc, char **argv) |
|
|
|
exit(1); |
|
|
|
} |
|
|
|
|
|
|
|
frame_count = 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) |
|
|
|
if (decode_write_frame(outfilename, c, frame, &frame_count, &avpkt, 0) < 0) |
|
|
|
/* 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); |
|
|
|
} |
|
|
|
} |
|
|
|
data += ret; |
|
|
|
data_size -= ret; |
|
|
|
|
|
|
|
if (avpkt.size) |
|
|
|
decode(c, frame, &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; |
|
|
|
decode_write_frame(outfilename, c, frame, &frame_count, &avpkt, 1); |
|
|
|
decode(c, frame, &avpkt, outfilename); |
|
|
|
|
|
|
|
fclose(f); |
|
|
|
|
|
|
|
av_parser_close(parser); |
|
|
|
avcodec_free_context(&c); |
|
|
|
av_frame_free(&frame); |
|
|
|
|
|
|
|
|