花了好几天研究的下ffmpeg,不知是人太笨还是怎么了,学习效率好低,现在把总结做下记录。
ffmpeg视频编码过程:
1.设置编码器的参数
AVCodecContext *c;
c->codec_id = codec_id;
对于解码输出, code_id 可以根据你的保存文件名猜测 fmt = av_guess_format(NULL, filename, NULL) ,默认为mpeg
c->codec_type = AVMEDIA_TYPE_VIDEO;
/* put sample parameters */
c->bit_rate = 400000;(for example)
c->width = width;
c->height = height;
还有其他参数,不一一列出,将c指向流的AVCodecContext的地址, c = st->c;
查找编码器 codec = avcodec_find_encoder(c->codec_id);
打开编码器 avcodec_open(c, codec);
2.对于编码拿到的当然是一张原始的图片(raw picture),图片像素格式可能是YUV420P或其它。为了下一步的编码,你可能还要把原始图片的格式改变一下(比如mpeg视频编码要求原始图像格式是YUV420p),
①struct SwsContext *sws_getContext(int srcW, int srcH, enum PixelFormat srcFormat,
int dstW, int dstH, enum PixelFormat dstFormat,
int flags, SwsFilter *srcFilter,
SwsFilter *dstFilter, const double *param);
②int sws_scale(struct SwsContext *context, const uint8_t* const srcSlice[], const int srcStride[],
int srcSliceY, int srcSliceH, uint8_t* const dst[], const int dstStride[]);
当然改变后的图片还是没有经过编码的(raw picture)。
3.接着就可以对这副图编码了
int avcodec_encode_video(AVCodecContext *avctx, uint8_t *buf, int buf_size,
const AVFrame *pict);
编码后的一桢是放在一个包里的,这个包里的数据就是经过编码压缩的(mpeg或者H.263之类的),这个压缩量是非常可观的,大大减少数据量,这也是ffmpeg编码的核心吧(个人认为)。返回值即包的大小
4.然后就是把这个包写入视频流中
int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt);
对于要保存视频文件(如avi格式)什么的,要把流写入文件中,就要申请一个流
av_new_stream(oc, 0);
。。。。
ffmpeg视频解码过程大致逆过程:
1.查看解码器信息(不是必须,但对调试有好处)
av_find_stream_info(pFormatCtx);
ffmpeg会帮我们浏览要打开的是个视频容器(即视频文件如avi格式)的流信息
dump_format(pFormatCtx,0,argv[1],0);
抛出信息。
2.查找解码器
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
打开解码器 avcodec_open(pCodecCtx,pCodec)
3.从视频流中读取一个包,这个包可能包含了两帧图片的边界
av_read_packet(pFormatCtx, &packet)
4. 对获取的包解码
原始数据会解码到图像帧中
bytesDecoded=avcodec_decode_video(pCodecCtx, pFrame,
&frameFinished, rawData, bytesRemaining);
一个包解码不一定会获得一个完整帧,所以要判断framFinished标志,该标志有上面函数返回。
继续取包解码直到获得完整帧,获得的数据会放在pFrame中。
4.将这帧图像(pframe)转化为想要的图像格式
利用上述sws_getContext,sws_scale