一、编译
1. 编译前的修改
1). apiexample.c LINE 19
#include "avcodec.h"
改成:
#include "libavcodec/avcodec.h"
2). apiexample.c LINE 145
len = avcodec_decode_audio(c, (short *)outbuf, &out_size,
改成:
len = avcodec_decode_audio2(c, (short *)outbuf, &out_size,
2. 编译生成
# gcc apiexample.c -g -o apiexample -I/opt/.../include -L/opt/.../lib
-lavformat -lavdevice -lavcodec -lavutil -lavfilter -pthread -ldl -lswscale -lbz2 -lasound -lz -lm
3. 运行
# apiexample xxx.mpg
输出文件存储在 /tmp/test%d.mpg
二、 主函数源码与分析
001 int main(int argc, char **argv){
002 const char *filename;
/* must be called before using avcodec lib */
003 avcodec_init();
/* register all the codecs (you can also register only the codec
you wish to have smaller code */
004 avcodec_register_all();
005 if (argc <= 1) {
006 audio_encode_example("/tmp/test.mp2");
007 audio_decode_example("/tmp/test.sw", "/tmp/test.mp2");
008 video_encode_example("/tmp/test.mpg");
009 filename = "/tmp/test.mpg";
010 } else {
011 filename = argv[1];
012 }
// audio_decode_example("/tmp/test.sw", filename);
013 video_decode_example("/tmp/test%d.pgm", filename);
014 return 0;
015 }
分析:
003: 初始化codec库
004: 注册编解码器
005: 命令行输入参数个数判断
006~009: 如果未输入参数,则先编码生成音频文件 /tmp/test.mp2, 再解码输出 /tmp/test.sw
并编码生成视频文件 /tmp/test.mpg
011: 如果有输入参数,则用这个参数作为要解码的文件名;
013: 视频解码,并生成输出文件 /tmp/test%d.pgm;
014: 主函数结束并返回;
三. video_decode_example()函数源码与分析
001 void video_decode_example(const char *outfilename, const char *filename){
002 AVCodec *codec;
003 AVCodecContext *c= NULL;
004 int frame, size, got_picture, len;
005 FILE *f;
006 AVFrame *picture;
007 uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE], *inbuf_ptr;
008 char buf[1024];
/* set end of buffer to 0 (this ensures that no overreading happens for damaged mpeg streams) */
009 memset(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE);
010 printf("Video decoding\n");
/* find the mpeg1 video decoder */
011 codec = avcodec_find_decoder(CODEC_ID_MPEG1VIDEO);
012 if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
013 c= avcodec_alloc_context();
014 picture= avcodec_alloc_frame();
015 if(codec->capabilities&CODEC_CAP_TRUNCATED)
016 c->flags|= CODEC_FLAG_TRUNCATED; /* we dont send complete frames */
/* for some codecs, such as msmpeg4 and mpeg4, width and height
MUST be initialized there because these info are not available
in the bitstream */
/* open it */
017 if (avcodec_open(c, codec) < 0) {
fprintf(stderr, "could not open codec\n");
exit(1);
}
/* the codec gives us the frame size, in samples */
018 f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "could not open %s\n", filename);
exit(1);
}
019 frame = 0;
020 for(;;) {
021 size = fread(inbuf, 1, INBUF_SIZE, f);
022 if (size == 0)
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 */
023 inbuf_ptr = inbuf;
024 while (size > 0) {
025 len = avcodec_decode_video(c, picture, &got_picture,
inbuf_ptr, size);
026 if (len < 0) {
fprintf(stderr, "Error while decoding frame %d\n", frame);
exit(1);
}
027 if (got_picture) {
028 printf("saving frame %3d\n", frame);
029 fflush(stdout);
/* the picture is allocated by the decoder. no need to free it */
030 snprintf(buf, sizeof(buf), outfilename, frame);
031 pgm_save(picture->data[0], picture->linesize[0], c->width, c->height, buf);
032 frame++;
033 }
034 size -= len;
035 inbuf_ptr += len;
036 }
037 }
/* 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 */
038 len = avcodec_decode_video(c, picture, &got_picture, NULL, 0);
039 if (got_picture) {
040 printf("saving last frame %3d\n", frame);
041 fflush(stdout);
/* the picture is allocated by the decoder. no need to free it */
042 snprintf(buf, sizeof(buf), outfilename, frame);
043 pgm_save(picture->data[0], picture->linesize[0],
c->width, c->height, buf);
044 frame++;
045 }
046 fclose(f);
047 avcodec_close(c);
048 av_free(c);
049 av_free(picture);
050 printf("\n");
051 }
分析:
002~008: 变量定义,最重要的是 AVCodec,AVCodecContext 这两个;
009: 将输入Buffer的尾部置零,以防止被破坏的mpeg流造成写越界;
011~012: 遍历编解码器链表,查找解码器,找到对应的功能函数;
013: 分配编解码器上下文的内存,清零后,部分参数赋初值;
014: 分配一个AVFrame , 并设置默认值;
015~016: 对CODEC处理流的能力进行标识;
#define CODEC_FLAG_TRUNCATED 0x00010000 /** Input bitstream might be truncated at a random
location instead of only at frame boundaries. */
017: 打开编解码器,分配具体编解码器使用的上下文,简单变量赋初值,
并调用初始化函数初始化编解码器;
018: 打开输入文件;
019: 初始化帧序号,从零开始;
020: for循环,处理输入文件直到结尾;
021~023: 每次从输入文件读入 INBUF_SIZE 字节进行处理,遇到文件结束则结束处理;
代码的注释部分是说:
有的Codec是基于流的,如mpegvideo, mpegaudio,
因此,逐字节读入,分析后再处理是唯一的办法;
有的Codec是基于帧的,如msmpeg4, mpeg4,
所以需要逐帧准确读入才能正确处理,所以要初始化“宽和高”;
还有的Codec允许帧大小,采样率可变,这种情况更要小心处理;
本例是基于流的解码器--mpeg1video, 所以需要填充好解码器后再看是否能解码了;
024: 如果输入buffer中有数据,则一直处理这些数据;
025~026: 视频解码
027~033: 如果解码得到了一帧数据,
则将这帧数据写到输出Buffer,将它的PGM数据按宽高比写到文件,帧序号加一;
034~035: 将输入buffer的指针向前推进;
038~045: 有的Codec, 如 MPEG, 会读进第二帧后再开始第一帧的处理,所以最后会留下一帧需要处理;
这里就是处理最后一帧;
046~049: 处理完毕后的相应关闭和回收;
三、audio_decode_example()函数源码与分析
001 void audio_decode_example(const char *outfilename, const char *filename){
002 AVCodec *codec;
003 AVCodecContext *c= NULL;
004 int out_size, size, len;
005 FILE *f, *outfile;
006 uint8_t *outbuf;
007 uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE], *inbuf_ptr;
printf("Audio decoding\n");
/* set end of buffer to 0 (this ensures that no overreading happens for damaged mpeg streams) */
memset(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE);
/* find the mpeg audio decoder */
008 codec = avcodec_find_decoder(CODEC_ID_MP2);
009 if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
010 c= avcodec_alloc_context();
/* open it */
011 if (avcodec_open(c, codec) < 0) {
fprintf(stderr, "could not open codec\n");
exit(1);
}
012 outbuf = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
013 f = fopen(filename, "rb");
014 if (!f) {
fprintf(stderr, "could not open %s\n", filename);
exit(1);
}
015 outfile = fopen(outfilename, "wb");
016 if (!outfile) {
av_free(c);
exit(1);
}
/* decode until eof */
017 inbuf_ptr = inbuf;
018 for(;;) {
019 size = fread(inbuf, 1, INBUF_SIZE, f);
020 if (size == 0)
021 break;
022 inbuf_ptr = inbuf;
023 while (size > 0) {
024 len = avcodec_decode_audio2(c, (short *)outbuf, &out_size, inbuf_ptr, size);
025 if (len < 0) {
fprintf(stderr, "Error while decoding\n");
exit(1);
}
026 if (out_size > 0) {
/* if a frame has been decoded, output it */
027 fwrite(outbuf, 1, out_size, outfile);
028 }
029 size -= len;
030 inbuf_ptr += len;
031 }
032 }
033 fclose(outfile);
034 fclose(f);
035 free(outbuf);
036 avcodec_close(c);
037 av_free(c);
038 }
分析:
和上面的视频解码示例类同,就不再做详解分析;
相关代码可以在这里下载:
阅读(2636) | 评论(0) | 转发(0) |