以 MPEG-1 为例的视频解码例子,不含封装,只解析裸流
流程:
视频数据包初始化,av_packet_alloc
查找 MPEG-1 解码器, avcodec_find_decoder
数据解析器初始化,av_parser_init
解码结构初始化,avcodec_alloc_context3
打开解码器,avcodec_open2
打开视频文件,fopen
解码视频帧初始化,av_frame_alloc
循环 读文件,fread 解析数据包,av_parser_parse2 解码视频帧,avcodec_send_packet,avcodec_receive_frame 写文件(PGM图,p5),fopen,fwrite,fclose
关闭视频文件,fclose
关闭解析器,av_parser_close
释放解码器,avcodec_free_context
释放视频帧,av_frame_free
释放视频数据包,av_packet_free
升级方案:
avcodec_find_decoder 可以调用其他解码器,解析其他裸流,如:h264、h265等解码后的输出帧,可以按 yuv 分量保存成 yuv 视频文件 //Y, U, V (YUV420P) FILE *fp = fopen(filepath_out, "wba"); for(int i=0;i<frame->height;i++){ fwrite(frame->data[0]+pFrame->linesize[0]*i,1,frame->width,fp); } for(int i=0;i<frame->height/2;i++){ fwrite(frame->data[1]+frame->linesize[1]*i,1,frame->width/2,fp); } for(int i=0;i<frame->height/2;i++){ fwrite(frame->data[2]+frame->linesize[2]*i,1,frame->width/2,fp); } flcose(fp);decode_video.c
/** * @file * video decoding with libavcodec API example * * @example decode_video.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <libavcodec/avcodec.h> #define INBUF_SIZE 4096 static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize, char *filename) { FILE *f; int i; f = fopen(filename,"w"); fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255); for (i = 0; i < ysize; i++) fwrite(buf + i * wrap, 1, xsize, f); fclose(f); } static void decode(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket *pkt, const char *filename) { char buf[1024]; int ret; ret = avcodec_send_packet(dec_ctx, pkt); if (ret < 0) { fprintf(stderr, "Error sending a packet for decoding\n"); exit(1); } while (ret >= 0) { ret = avcodec_receive_frame(dec_ctx, frame); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) return; else if (ret < 0) { fprintf(stderr, "Error during decoding\n"); exit(1); } 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), "%s-%d", filename, dec_ctx->frame_number); pgm_save(frame->data[0], frame->linesize[0], frame->width, frame->height, buf); } } int main(int argc, char **argv) { const char *filename, *outfilename; const AVCodec *codec; AVCodecParserContext *parser; AVCodecContext *c= NULL; FILE *f; AVFrame *frame; uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; uint8_t *data; size_t data_size; int ret; AVPacket *pkt; if (argc <= 2) { fprintf(stderr, "Usage: %s <input file> <output file>\n" "And check your input file is encoded by mpeg1video please.\n", argv[0]); exit(0); } filename = argv[1]; outfilename = argv[2]; pkt = av_packet_alloc(); if (!pkt) exit(1); /* set end of buffer to 0 (this ensures that no overreading happens for damaged MPEG streams) */ memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE); /* find the MPEG-1 video decoder */ codec = avcodec_find_decoder(AV_CODEC_ID_MPEG1VIDEO); if (!codec) { fprintf(stderr, "Codec not found\n"); 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); } /* For some codecs, such as msmpeg4 and mpeg4, width and height MUST be initialized there because this information is not available in the bitstream. */ /* open it */ if (avcodec_open2(c, codec, NULL) < 0) { fprintf(stderr, "Could not open codec\n"); exit(1); } f = fopen(filename, "rb"); if (!f) { fprintf(stderr, "Could not open %s\n", filename); exit(1); } frame = av_frame_alloc(); if (!frame) { fprintf(stderr, "Could not allocate video frame\n"); exit(1); } while (!feof(f)) { /* read raw data from the input file */ data_size = fread(inbuf, 1, INBUF_SIZE, f); if (!data_size) break; /* use the parser to split the data into frames */ data = inbuf; while (data_size > 0) { ret = av_parser_parse2(parser, c, &pkt->data, &pkt->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 (pkt->size) decode(c, frame, pkt, outfilename); } } /* flush the decoder */ decode(c, frame, NULL, outfilename); fclose(f); av_parser_close(parser); avcodec_free_context(&c); av_frame_free(&frame); av_packet_free(&pkt); return 0; }