我使用的ffmpeg是3.4版本 对应的帮助文档是api文档是

ffmpeg 3.4api文档 <http://ffmpeg.org/doxygen/3.4/index.html>

AVFormatContext:容器相关结构体,比如MP4,flv等。
AVCodecContext:编解码器相关结构体。
AVCodec:编解码器参数相关结构体。
AVStream 对流的抽象
AVOutputFormat:对输出文件格式的抽象
AvFrame:用来存原始帧数据,比如编码前的yuv数据,或者解码后的yuv数据。
AvPacket:用来存编码后的包数据,或者解码前的包数据,比如h264的帧数据I,P,B帧数据。

av_register_all();

注册相关编解码器,和混合器(视频和音频混合),和分流器(将视频和音频分流)


avformat_network_init();

网络相关的注册,如果还没有做网络相关的播放可以不用注册,比如你使用了rtmp相关的操作就需要注册。

result = avformat_open_input(&afc, path, 0, 0);
注意 :要先将afc = NULL ,不然会有异常发生。
这个是打开输入流


打开输入流并且读取文件头,比如MP4的头部信息,一般会有音频,视频相关的参数信息。
记得用avformat_close_input关闭。

result = avformat_find_stream_info(afc, 0);

这个获取输入的相关信息,上面已经打开了,现在我们就是要使用里面的相关信息,比如视频一般有视频流,或者音频流,甚至还有字幕流,今天我们就解码视频我们就关系视频就行了。

afc->nb_streams
这个是告诉我们这个文件一共有几个流(音频视频等)
for (int i = 0; i < afc->nb_streams; ++i) { AVStream *avStream =
afc->streams[i]; if (avStream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
//视频 video_index = i; videoCode =
avcodec_find_decoder(avStream->codecpar->codec_id); if
(avStream->codecpar->format != AV_PIX_FMT_YUV420P) {
cj->callStr("目前只支持yuv420p的格式"); return RESULT_FAILD; } if (!videoCode) {
LOGE("VIDEO avcodec_find_decoder FAILD!"); return RESULT_FAILD; } } else if
(avStream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { //音频 audio_index = i;
this->simpleRate = avStream->codecpar->sample_rate; LOGE("audio samplerate %d
", avStream->codecpar->sample_rate); audioCode =
avcodec_find_decoder(avStream->codecpar->codec_id); if (!audioCode) {
LOGE("audio avcodec_find_decoder FAILD!"); return RESULT_FAILD; } } }
遍历的方式拿到音频,视频的流对应的index也可以说轨道,顺便也把他的解码code找到。

vc = avcodec_alloc_context3(videoCode);
申请一个AVCodecContext
用来解码使用的

avcodec_parameters_to_context(vc, afc->streams[video_index]->codecpar);
记得把对应的参数copy过去,不然解码器不知道容器中的视频是怎么样的。比如帧率,分辨率等。

result = avcodec_open2(vc, NULL, NULL);
初始化解码器。

result = av_read_frame(afc, pkt_);
这个是从容器中读取avpacket这个还是编码状态的packet
读取容器中的packet我是单独使用的线程,读取后分别根据是音频还是视频再分发出去,使用观察者模式。

result = avcodec_send_packet(vc, pck);
然后送入解码

result = avcodec_receive_frame(vc, vframe);
这个是解码后的数据

vframe->pts
就是当前帧的显示时间

还有关于avframe相关的参数
vframe->data[0]
vframe->data[1]
vframe->data[2]

如果我们数据是yuv420p相关的数据
那么data[0]指向的就是y的,data[1]指向的就是u,data[2]指向的就是v。

音频的pcm,如果是双声道的并且是平面存储的那么data[0]指向一个声道,data[1]指向一个声道。

比如双声道存储方式有: lrlrlrlrlr 也有llll rrrr.
l对应是左声道,r对应右声道
前者是直接存储在data[0]中,后者是分开成data[0]存储左声道,data[1]存储右声道。

vframe->linesize[0]
vframe->linesize[1]
vframe->linesize[2]


Linesize:视频的话就是一个图像横向有多少个字节(那不就是图像的宽度么?不全是),因为为了读写速度的原因,会有cpu相关的补齐措施,有可能是比width大的。

如果是对应yuv420p
Linesize[0]: y对应的字节数
Linesize[1]:u对应的字节数,一般是y的一半
Linesize[2]:v对应的字节数,同上

如果是音频的话就是对应的声道占多少个字节。

frame->nb_samples
:这个是一帧音频有多少个采样(1024比较多),当然也只是我们这样叫,并不是1024就是一帧,这个不和视频一样,视频是一个画面就是一帧。

对应项目
myffmpeg <https://blog.csdn.net/u010339039/article/details/88719382>
这是一个整体的app,现在只是将其中的小模块分解,记录下。

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信