视频封装的概述:
- 使用场景:像素格式转换–>编码–>封装
- 为什么要封装?
- 指定编码格式、帧率、时长等参数
- 视频帧索引存储,方便视频进度跳转
- MP4文件格式分析:
解封装流程:
相关API:
1. avformat_open_input:
int avformat_open_input(AVFormatContext **ps,
const char *url,
const AVInputFormat *fmt,
AVDictionary **options);
2. avformat_find_stream_info
int avforamt_find_stream_info(AVFormatContext *ic, AVDictionary **options);
3. av_read_frame
int av_read_frame(AVFormatContext *s, AVPacket *pkt);
4.avformat_close_input
void avformat_close_input(AVFormatContext **s);
相关结构体:
AvFormatContext:
unsigned int nb_stream;
流信息的个数
AVStream **strames;
指针数组,通过索引来访问对应的流信息
void *priv_data;
//AVOptions
AVIOContext *pb;
// I/O 写入和输出
int64_t duration;
// Duration of the stream Demuxing only
int64_t bit_rate;
// 这个媒体文件的比特率
char *url;
// 文件地址,支持rtsp, http
AVStream
int index;
AVRational time_base;
// 音频和视频的时间基数不一定一致, 音频是离散的
AVRational avg_frame_rate;
// 显示帧率
AVCodecParameters *codecpar;
// 配置信息以及解码配置用到的参数
AVCodecParameters
AVMediaType codec_type;
//视频、音频或者字幕
AVCodecID codec_id;
//编解码器的ID号
int format;
// video: the pixel format audio: the sample format
int64_t bit_rate;
// 比特率
int width;
int height
- // 音频数据
uint64_t channel_layout;
int channels;
int sample_rate;
int frame_size;
封装视频:
- 创建上下文
- 添加音频视频流
- 打开输出IO
- 写入文件头
- 写入帧数据(需要考虑写入次序)
- 写入尾部数据(pts索引)
- 案例:重封装mp4文件,截断10s
FFmpeg相关接口:
int avformat_alloc_output_context2(AVFormatContext **ctx,
const AVOutputFormat *oformat,
const char *format_name,
const char *filename);
AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c);
int avio_open(AVIOContext **s, const char *url, int flags);
#define AVIO_FLAG_READ 1
#define AVIO_FLAG_WRITE 2
#define AVIO_FLAG_READ_WRITE (AVIO_FLAG_READ|AVIO_FLAG_WRITE)
#define AVIO_FLAG_NONBLOCK 8
PTS计算
int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq,
enum AVRounding rnd);
AV_ROUND_ZERO = 0,
AV_ROUND_INF = 1,
AV_ROUND_DOWN = 2,
AV_ROUND_UP = 3,
AV_ROUND_NEAR_INF = 5,
写入帧
int av_write_frame(AVFormatContext *s, AVPacket *pkt)
int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
// 第一步 打开文件
avio_open(&c->pb, url, AVIO_FLAG_WRITE);
// 第二步 写入头
int avformat_write_header(AVFormatContext *s, AVDictionary **options);
// 第三步 写入帧
int av_write_frame(AVFormatContext *s, AVPacket *pkt);
// 第四步 写入尾
int av_write_trailer(AVFormatContext *s);
int avio_closep(AVIOContext *s);
控制播放进度
int av_seek_frame(AVFormatContext *s, int stre