使用到的ffmpeg API
av_log_set_level()
设置日志打印的标准, 高于这个标准的将不会打印
av_log()
打印ffmpeg中的日志,当做printf用
av_dump_format()
打印流的各种信息
av_register_all()
初始化所有组件
int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options)
打开一个文件并解析,传入文件地址,输入文件的上下文会保存在 ps
主要是完成了对输入的AVFormatContext中的AVInputFormat的初始化,对AVIOContext打开输入控制,以及创建AVStream。
avformat_close_input()
传入上下文,关闭文件
av_find_best_stream()
输入流的上下文和要找的流的类型,返回最好流的索引
av_init_packet()
初始化一个包,保存了解复用(demuxer)之后,解码(decode)之前的数据(仍然是压缩后的数据)和关于这些数据的一些附加的信息
av_read_frame()
返回流的下一帧,当不再需要数据包时,必须使用av_packet_unref释放该数据包,当到文件结尾时返回负数
av_packet_unref()
取消引用数据包引用的缓冲区,并将剩余的数据包字段重置为其默认值。
avformat_alloc_context()
用来申请AVFormatContext类型变量空间并初始化默认参数,返回AVFormatContext类型上下文
av_guess_format()
根据输入的文件名生成最适合的输出容器,也可以指定文件类型,返回容器的上下文
avformat_new_stream()
创建流通道,返回AVStream
首先调用av_mallocz()为AVStream分配内存。
接着给新分配的AVStream的各个字段赋上默认值。
然后调用了另一个函数avcodec_alloc_context3()初始化AVStream中的AVCodecContext。
avcodec_parameters_copy()
拷贝avstream中的codecpar的信息,这里将输入流的参数信息拷贝到输出流中
*int av_strerror(int errnum, char errbuf, size_t errbuf_size)
errnum指错误码,errbuf返回错误的buf,错误buf的size,给错误信息赋值,为打印做准备
avformat_write_header
写输出文件流的头
av_rescale_q_rnd
计算 “a * b / c” 的值并分五种方式来取整.
av_rescale_q
av_rescale_q_rnd的特殊情况
av_interleaved_write_frame
此函数将根据需要在内部缓冲数据包,以确保输出文件中的数据包按照增加dts的顺序正确地交织在一起
av_write_trailer
将流尾随写入输出媒体文件并释放文件私有数据。只能在成功调用avformat_write_header后调用。
avio_open
创建并初始化一个AVIOContext,用于访问由url指示的资源。
avio_close
关闭
使用到的ffmpeg的数据结构
AVFormatContext(统领全局,主要存储视音频封装格式中包含的信息)
|------AVInputFormat(存储输入视音频使用的封装格式)
|------AVOutputFormat(存储输出音视频使用的封装格式)
|------AVIOContext(处在协议层)
| |---------URLContext(存储视音频使用的协议的类型以及状态)
| |--------- URLProtocol(存储输入视音频使用的封装格式)
|------AVStream(存储一个视频/音频流的相关数据)
|---------AVCondecContext(存储该视频/音频流使用解码方式的相关数据)
|---------AVCodec(视频/音频对应的解码器)
AVOutputFormat
对流(Stream)的封装和抽象,描述了视频、音频等流的编码格式等基本流信息。此外也是音频、视频、字母数据流的重要载体。
AVStream
存储每一个视频/音频流信息的结构体
AVCodecContext *codec // 已过时,使用另一个 codecpar 结构体代替。
AVRational time_base // 时间基数。
int64_t duration // 总时长。流的总时长,该参数不可靠。
AVRational avg_frame_rate // 帧率。
AVCodecParameters *codecpar; // 包含音视频参数的结构体。很重要,可以用来获取音视频参数中的宽度、高度、采样率、编码格式等信息。
AVPacket
保存了解复用(demuxer)之后,解码(decode)之前的数据(仍然是压缩后的数据)和关于这些数据的一些附加的信息
关于数据的属性有以下字段:
pts: (int64_t)显示时间,结合AVStream->time_base转换成时间戳
dts: (int64_t)解码时间,结合AVStream->time_base转换成时间戳
size: (int)data的大小
stream_index: (int)packet在stream的index位置
flags: (int)标示,结合AV_PKT_FLAG使用,其中最低为1表示该数据是一个关键帧。
#define AV_PKT_FLAG_KEY 0x0001 //关键帧
#define AV_PKT_FLAG_CORRUPT 0x0002 //损坏的数据
#define AV_PKT_FLAG_DISCARD 0x0004 /丢弃的数据
side_data_elems: (int)边缘数据元数个数
duration: (int64_t)数据的时长,以所属媒体流的时间基准为单位,未知则值为默认值0
pos: (int64_t )数据在流媒体中的位置,未知则值为默认值-1
convergence_duration:该字段已deprecated,不在使用
关于数据缓存,AVPacket本身只是个容器,不直接的包含数据,而是通过数据缓存的指针引用数据。AVPacket包含两种数据
uint8_t *data:指向保存压缩数据的指针,这就是AVPacket的实际数据。
AVPacketSideData *side_data:容器提供的一些附加数据
AVBufferRef *buf:用来管理data指针引用的数据缓存,其使用在后面介绍
第一种方式
先取出一个个音频包,然后在每个音频包前边手动的加 ADTS Header写成一个文件。
#include <stdio.h>
#define __STDC_CONSTANT_MACROS
#ifdef __cplusplus
extern "C" {
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
#include <libavutil/log.h>
#ifdef __cplusplus
};
#endif
void adts_header(char *szAdtsHeader, int dataLen)
{
int audio_object_type = 2;
int sampling_frequency_index = 7;
int channel_config = 2;
int adtsLen = dataLen + 7;
szAdtsHeader[0] = 0xff; //syncword:0xfff 高8bits
szAdtsHeader[1] = 0xf0; //syncword:0xfff 低4bits
szAdtsHeader[1] |= (0 << 3); //MPEG Version:0 for MPEG-4,1 for MPEG-2 1bit
szAdtsHeader[1] |= (0 << 1); //Layer:0 2bits
szAdtsHeader[1] |= 1; //protection absent:1 1bit
szAdtsHeader[2] = (audio_object_type - 1) << 6; //profile:audio_object_type - 1 2bits
szAdtsHeader[2] |= (sampling_frequency_index & 0x0f) << 2; //sampling frequency index:sampling_frequency_index 4bits
szAdtsHeader[2]