1.由于快开学了,将这个摄像头开发的问题记录一下
1.线程问题 将play和init放在两条不同的线程,导致av_read_frame无法访问
2.api接口的新旧问题 ,释放avformat 要用av_format_input_close ,不可以用avformat_free_context,在4.0版本
3.线程的退出问题,如何优雅的退出
旧的接口尽量不要用
4.每次重新打开摄像头,必须先释放之前的参数,否则摄像头会被占用
gop 两个关键帧之间的间隔
i bbb p
b帧
H264编码,把帧分为3种,i帧,p帧 b帧
i帧有完整的图像,而其他两种没有,所以一个视频的i帧越小,视频越小
举例,当年在b站看视频的时候,往回拉,但是不一定完全回到那个地方
很有可能是那个地方没有关键帧
h265对移动端来说性能开销过大
gop_size是什么,是一组连续的画面
帧率:每秒编码进视频文件的帧数目
码率就是比特率,和音频质量有关
DTS 和PTS,前者是解码的时间,后者是显示的时间
avframe:pts,该帧什么时候被显示,avpacket:dts:该包什么时候被解码
2个i 帧形成一个gop_size
帧率:每秒显示25帧
[图片]
所以,时间基简单来说,就是决定了一个帧占用的时间,那么一个帧的duartion应该等于pts乘以time_base.
视频的一个packet就对应了一个帧,音频的一个packet可能就对应了不止一个帧
num_pkt=采样率除以nb_samples
nb_streams->采样数
一般情况下,音频的时间基和采样率成倒数 1/sample_rate
所以pts=n*nbstreams
pts->显示时间戳
dts->解码时间戳
:
决定视频输出时封装方式的函数,写任何一个函数,都会自动匹配相应的封装方式
quantizer
timebase是一个单位,比如说在ffmpeg中是以秒为单位的
如果说是1:1000很容易理解成毫秒,但是如果是1:25呢,这样用常用的单位就无法解释,所以提出了时间基的概念
分数
分母
demux出来的帧的time:是相对于源AVStream的timebase
编码器出来的帧的time:是相对于源AVCodecContext的timebase
mux存入文件等容器的time:是相对于目的AVStream的timebase
这里的Time指的是pts显示时间
只是初始化,需要用av_frame_get_buffer为像素分配内存空间
av_frame_get_buffer的第四个参数的意思是设定内存对齐的对齐数
所以给像素设定内存大小的方式是1.先计算所需内存大小,根据像素类型,款,高,内存 av_frame_get_buffer_size 2.根据计算出来的内存大小对内存进行分配,av_malloc 3.格式化内存空间,av_image_fill_array
cpu的寻址是通过地址总线来访问内存的,32位的cpu一次可以处理4个字节,所以cpu实际寻址的步长就是4个字节,换个说法,就是只对编号是4的倍数的内存地址进行寻址
字长,是cpu一次可以处理的数据的位数
[图片]
[图片]
[图片]
转化成unicode编码
.tolatin1 转化成ascall
编码大概流程
1.初始化各个结构体,给各个结构体分配内存大小,avformat avframe avpacket,
2.找到根据文件格式找到编码器,如H264,设置编码器上下文参数,如gop_SIZE,bitrate,宽高等,找到编码器
3.初始化avframe ,并给单个像素大小分配内存空间,注意(用两个不同的api),设置音视频缓冲区大小,(pframebuf),给它分配大小并格式化av_image_fill_array
简单理解下,av_frame_get_buffer应该是为指针数组avframe->data分配32个字节空间,一个指针占8个字节,之后再给真实的pframebuf分配内存空间,先前已经malloc好了,最后再调用av_image_fill_array对这个pframebuf进行格式化,(底层来说应该是调用了一个av_image_fill_pointer完成指针指向内存块的操作)
到这里,初始化工作就完成了
接着开始编码操作
1,把解码器解出来的yuv420的帧里面的data指针指向的数据分别赋给另外初始化的pframe的数据指针 , 调用avcodec_send_frame,再调用avcodec_recieve_pkt,将拿到的压缩pkt保存到文件里面
[图片]
根据文件格式找到编码器
今天出现的问题,想要实现点一下录制,再点一下,录制完毕,功能
fwrite返回的是元素的个数
在执行过程中更改图标用icon类
通过更改播放器的文件名
音视频同步开发总结
1.解码器和编码器都有一个叫缓冲区的地方 2.av_read_frame()读出来的是av_packet3.读取管道数据的同步问题,可能出现的情况是主线程中的av_fifo_read和采集线程中的av_fifo_write同时对fifo操作时会发生同步问题。所以要用到消费者,生产者模型。4,音视频同步的问题,打时间戳,av_compare_ts比较时间戳,如果音频帧在前面,则至少需要编码一个视频帧,如果视频帧在前面,则至少需要编码多个音视频。5.不是同时上锁时会发生死锁,那么这时候就需要用c++11的方法,进行同时上述上锁。6,最后一定要记得清除编码器的缓冲区。