一. 解码
1. 注册ffmpeg 所有编码/解码器
av_register_all();
avdevice_register_all();
2. 打开一个输入格式上下文: AVFormatContext
avformat_open_input()
3. 从输入格式上下文读取流,并分析出流信息
avformat_find_stream_info()
4. 从格式上下文信息中,通过流ID,获取到解码器上下文 :AVCodecContext
pCodecCtx_Video = pFormatCtx_Video->streams[x]->codec;
5. 从解码器上下文信息的解码ID查找解码器:AVCodec
avcodec_find_decoder ()
6. 通过解码器上下文AVCodecContext与解码器AVCodec打开解码器:
avcodec_open2()
7.循环读出数据包:通过格式信息读出包
av_read_frame(pFormatCtx_Video, packet)
8. 通过解码器上下文件AVCodecContext 解码包:
if (avcodec_decode_video2(pCodecCtx_Video, pFrame, &got_picture, packet) < 0)
9. 数据写入队列: AVFifoBuffer
二. 编码并保存文件:
1. 通过文件名,打开一个输出格式上下文:AVFormatContext * pFormatCtx_Out
avformat_alloc_output_context2()
2. 通过输出格式AVFormatContext,打开一个流: AVStream
avformat_new_stream()
3. 通过一中的格式信息:格式上下文件AVFormatContext,初始化2中的流信息
包括:
pVideoStream->codec->codec = avcodec_find_encoder(AV_CODEC_ID_MPEG4);
pVideoStream->codec->height = pFormatCtx_Video->streams[0]->codec->height;
pVideoStream->codec->width = pFormatCtx_Video->streams[0]->codec->width;
pVideoStream->codec->time_base = pFormatCtx_Video->streams[0]->codec->time_base;
pVideoStream->codec->sample_aspect_ratio = pFormatCtx_Video->streams[0]->codec->sample_aspect_ratio;
// take first format from list of supported formats
pVideoStream->codec->pix_fmt = pFormatCtx_Out->streams[VideoIndex]->codec->codec->pix_fmts[0];
4. 打开编码器:从流中的编码上下文件,下ID
avcodec_open2()
5. 打开IO,也即初始化,输出格式中的AVIOContext
avio_open(&pFormatCtx_Out->pb, outFileName, AVIO_FLAG_WRITE)
6. 写入文件格式头:
avformat_write_header(pFormatCtx_Out, NULL)
7. 循环从队列读出数据:
av_fifo_generic_read(fifo_video, picture_buf, size, NULL);
8. 初始化数据到 AVFrame:
avpicture_fill((AVPicture *)picture, picture_buf,
pFormatCtx_Out->streams[VideoIndex]->codec->pix_fmt,
pFormatCtx_Out->streams[VideoIndex]->codec->width,
pFormatCtx_Out->streams[VideoIndex]->codec->height);
9. 计算avframe的PTS:
picture->pts = VideoFrameIndex * ((pFormatCtx_Video->streams[0]->time_base.den / pFormatCtx_Video->streams[0]->time_base.num) / 15);
10 编码成PACKET;
int ret = avcodec_encode_video2(pFormatCtx_Out->streams[VideoIndex]->codec, &pkt, picture, &got_picture);
11. 计算pakcet的pts pps,
pkt.stream_index = VideoIndex;
pkt.pts = av_rescale_q_rnd(pkt.pts, pFormatCtx_Video->streams[0]->time_base,
pFormatCtx_Out->streams[VideoIndex]->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.dts = av_rescale_q_rnd(pkt.dts, pFormatCtx_Video->streams[0]->time_base,
pFormatCtx_Out->streams[VideoIndex]->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.duration = ((pFormatCtx_Out->streams[0]->time_base.den / pFormatCtx_Out->streams[0]->time_base.num) / 15);
cur_pts_v = pkt.pts;
12. 写入文件 :
ret = av_interleaved_write_frame(pFormatCtx_Out, &pkt);
13. 循环结束后写文件尾
av_write_trailer(pFormatCtx_Out);