技术点:
- 大循环编码逻辑
- 小循环(函数内),数据的编码细节
- 哪些操作会造成AVPacket的引用计数增加?要考虑av_packet_unref()
- avcodec_receive_packet()会
- av_read_frame()亦会
- encode()第二参传入nullptr会有什么后果?积极后果,flush下缓冲,剩余的帧压缩成AVPacket
static void encode(AVCodecContext* enc_ctx,
AVFrame* p_frame,
AVPacket* p_pkt,
FILE* out_file)
{
int ret = 0;
if(p_frame)
printf("send frame to encoder, pts = %lld", p_frame->pts);
ret = avcodec_send_frame(enc_ctx, p_frame);
if(ret < 0)
{
printf("Error, Failed to send frame for encoding! \n");
exit(1);
}
while(ret >= 0)
{
// 会增加AVPacket引用计数
ret = avcodec_receive_packet(enc_ctx, p_pkt);
if(AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if(ret < 0)
{
printf("Error, Failed to encode! \n");
exit(1);
}
fwrite(p_pkt->data, 1, p_pkt->size, out_file);
av_packet_unref(p_pkt);
}
}
- 下面演示是从笔记本摄像头拿到原始数据(AVPacket NV12)
// 如下,两种方式创建一个AVPacket
// 栈上分配AVPacket,无需初始化,该对象可直接用,这个用来承接摄像头的数据
AVPacket pkt;
// 堆上分配AVPacket,供encode()函数使用的用来保存缓=缓冲的对象,这里直接拿到其指针
AVPacket* p_buf_pkt = nullptr;
p_buf_pkt = av_packet_alloc();
uint base = 0;
// av_read_frame()会增加AVPacket引用计数,从文件或视频流中读入一帧AVPacket
while(ret = av_read_frame(fmt_ctx, &pkt) == 0)
{
// AVPacket数据经过转换,成了YUV420P的AVFrame
// 没有其他设置AVFrame的操作,只设置pts时间戳
p_frame->pts = base;
++base;
encode(enc_ctx, p_frame, p_buf_pkt, out_file);
// 释放AVPacket
av_packet_unref(&pkt)
}
// 把最后的缓存刷新出来
encode(enc_ctx, nullptr, p_buf_pkt, out_file);