使用FFmpeg实现重封装及剪辑视频功能

视频封装的概述:

  • 使用场景:像素格式转换–>编码–>封装
  • 为什么要封装?
    • 指定编码格式、帧率、时长等参数
    • 视频帧索引存储,方便视频进度跳转
  • 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);
// 获取媒体流信息写入ic
3. av_read_frame
int av_read_frame(AVFormatContext *s, AVPacket *pkt);  //AVPacket 调用之后一定要进行清理,内部没有对其进行释放动作
//pkt->pts, pkt->dts and pkt->duration 会根据AVStream.time_base设置
//pkt使用结束需要用av_packet_unref()清理引用计数
//pkt.stream_index AVStream 在AVFormatContext.streams中的数组下标
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计算

// a * bq / cq
int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq,
                        enum AVRounding rnd);
AV_ROUND_ZERO = 0, // Round toward zero
AV_ROUND_INF = 1, // Round away from zero
AV_ROUND_DOWN = 2, // Round toward -infinity
AV_ROUND_UP = 3, // Round toward +infinity
AV_ROUND_NEAR_INF = 5, // Round to nearest and halfway cases away from zero

写入帧

int av_write_frame(AVFormatContext *s, AVPacket *pkt)
/*
    直接写入
    pkt
        不改变pkt引用计数 NULL刷新缓冲
        pts使用s->streams中的time_base
        stream_index 要对应s->streams
*/
int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
/*
    需要在内部缓冲数据包,以确保输出文件中的数据包按照dts增加的顺序
    pkt:
        获取数据引用,使用完引用计数减一,调用此函数后不可再访问pkt
        非引用计数则复制 传递NULL写入interleaving queues缓冲
    AVFormatContext.maxinterleave_delta
*/
// 第一步 打开文件
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
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值