avcodec_send_frame和avcodec_receive_packet

编码器和解码器都维护了一个缓冲区,在刚开始输入数据时,需要多输入几帧,等缓冲区被填充满后,才会在receive端接收到编码或解码后的数据。
另一方面因为存在AVPacket中的数据不一定是一帧(比如音频的数据可能1个AVPacket包含1s的数据,帧率为25的话,就包含25帧),但存在AVFrame中的是一帧数据,所以avcodec_send_packet和avcodec_receive_frame不一定一一对应,调用一次avcodec_send_packet后,可能需要多次调用avcodec_receive_frame,另一篇文章讨论av_read_frame每次返回的视频和音频帧数

解码接口:
avcodec_send_packet和avcodec_receive_frame
内存:frame只需要分配对象本身空间就好,frame->data的空间并不需要分配。函数会判断是否已经给frame->data分配空间,如果没有分配会在函数内部为frame->data分配合适的空间。另一篇文章,AVFrame内存讨论,AVFrame相关api
。举例如下:

int re = avcodec_send_packet(codec_ctx, pkt);
if (re != 0)
{
    return;
}
while( avcodec_receive_frame(codec_ctx, frame) >= 0)
{
    //处理接收后的帧
}

avcodec_receive_frame:send端只把数据放入缓冲区,recive端才是解码并获得数据的函数,如果receive发现已有解码后的数据则直接获取,如果没有则开始解码。

编码接口
数据遗留:在最后应该向avcodec_send_frame(enc_ctx, NULL)传入NULL数据,这样编码器知道后面不会再有数据,就把放在缓冲区中的数据,全部编码并通过avcodec_receive_packet输出出来。

返回值:EAGAIN,意思是需要输入更多的数据,才会有新的数据编码后的数据返回。AVERROR_EOF在从文件中读取数据推流时,出现这个错误是因为文件内的数据读完了。

参数内存:newpkt->data并不需要分配数据空间,只需要给newpkt本身结构体分配空间就好。另一篇文章,关于AVPacket内存与avcodec_receive_packet的关系,AVPacket相关api

func()
{
	avcodec_send_frame(enc_ctx, frame);
	if(ret < 0)
	{
		//Error
	}
	while(ret >= 0)
	{
		ret = avcodec_receive_packet(enc_ctx, newpkt);
		if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)	{return;}
		else if(ret < 0){//Error}
	}

}

在ubuntu虚拟机中采集pc摄像头,并推流实测编解码的四个函数是否一一对应关系,帧率为30:
解码
avcodec_send_packet
avcodec_receive_frame
记录:s1518 r1518 s2754 r2754
s发送的次数,r成功接收的次数
第一次调用avcodec_send_packet,avcodec_receive_frame就成功接收到数据了。并且以后每次也都一一对应调用两个函数。

编码
avcodec_send_frame
avcodec_receive_packet
//s1336 r1286 s867 r817 保持50帧
avcodec_send_frame连续调用50次后,avcodec_receive_packet才成功接收到一次数据,以后每次都一一对应。

在ubuntu虚拟机中采集pc声卡,并推流实测编解码的三个函数是否一一对应关系:
解码
avcodec_send_packet
avcodec_receive_frame
av_interleaved_write_frame
实测当分别送进去128,1024,940个音频采样到avcodec_send_frame时,avcodec_receive_packet一对一返回,开始并没有几帧缓存,av_interleaved_write_frame也一对一执行,也没有一开始缓存几帧。也就是三者总是保持一对一执行,后两者都有返回,并且一开始没有缓存。音频涉及到字节的处理,见另一篇博客:libfdk_aac音频采样数和编码字节数注意

ffmpeg是音视频必备,笔者VX:YQW1163720468,加入ffmpeg群讨论。备注:ffmpeg爱好者

附录:
libavcodec\encode.c

int attribute_align_arg avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
{
    av_packet_unref(avpkt);
 
    if (!avcodec_is_open(avctx) || !av_codec_is_encoder(avctx->codec))
        return AVERROR(EINVAL);
 
    if (avctx->codec->receive_packet) {
        if (avctx->internal->draining && !(avctx->codec->capabilities & AV_CODEC_CAP_DELAY))
            return AVERROR_EOF;
        return avctx->codec->receive_packet(avctx, avpkt);
    }
 
    // Emulation via old API.
 
    if (!avctx->internal->buffer_pkt_valid) {
        int got_packet;
        int ret;
        if (!avctx->internal->draining)
            return AVERROR(EAGAIN);
        ret = do_encode(avctx, NULL, &got_packet);
        if (ret < 0)
            return ret;
        if (ret >= 0 && !got_packet)
            return AVERROR_EOF;
    }
 
    av_packet_move_ref(avpkt, avctx->internal->buffer_pkt);
    avctx->internal->buffer_pkt_valid = 0;
    return 0;
}
void av_packet_unref(AVPacket *pkt)
{
    av_packet_free_side_data(pkt);
    av_buffer_unref(&pkt->buf);
    av_init_packet(pkt);
    pkt->data = NULL;
    pkt->size = 0;
}
  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

、、、、南山小雨、、、、

分享对你有帮助,打赏一下吧!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值