ffmpeg之G711解析成pcm

ffmpeg在码流转换上面实在是强大,今天实验了一下把G711音频专成PCM的音频,并最终实验成功。

第一步:寻找解码器,若格式不支持,则无法转码

	codec = avcodec_find_decoder(AV_CODEC_ID_PCM_ALAW);
	if (!codec) {
		fprintf(stderr, "Codec not found\n");
		return false;
	}

提醒:G711A的解码ID为AV_CODEC_ID_PCM_ALAW

第二步:创建解码上下文,主要保持解码相关的信息

	c = avcodec_alloc_context3(codec);
	if (!c) {
		fprintf(stderr, "Could not allocate audio codec context\n");
		return false;
	}
	c->sample_fmt = sample_fmt;
	c->sample_rate = sample_rate;
	c->channels = channels;

需要设置3个参数,不然后面打开解码器会失败

sample_fmt:采样格式,标识含义8位,16位等采样

sample_rate:采样频率

channels:采样通道数

第三步:打开解码器

	if (avcodec_open2(c, codec, NULL) < 0) {
		fprintf(stderr, "Could not open codec\n");
		return false;
	}

第四步:输入码流

ret = avcodec_send_packet(c, packet);

第五步:输出解码结果

扫描二维码关注公众号,回复: 2618493 查看本文章
int ret = avcodec_receive_frame(c, frame);

整个过程大约分为这5个步骤。

另外通过研究,有几个重要的关于内存的发现:

由于输入解码的数据格式是AVPacket,而我拿到的数据确是字节流,需要把字节流转换成AVPacket类型。

这里作了如下处理:

	packet->size = iSize;
	packet->data = (uint8_t *)av_malloc(packet->size);
	memcpy(packet->data, pData, iSize);
	ret = av_packet_from_data(packet, packet->data, packet->size);
	if (ret <0)
	{
		fprintf(stderr, "av_packet_from_data error \n");
		av_free(packet->data);
		return;
	}
	ret = avcodec_send_packet(c, packet);
	av_packet_unref(packet);

通过函数av_packet_from_data生产了AVPacket类型数据,但是需要注意在使用完之后,需要调用av_packet_unref进行释放内存,不然会存在内存泄漏,有人会问上面的内存是通过av_malcoc生成的,我们还需要释放吗?我通过实验发现调用av_packet_unref之后,就不需要再调用av_free来进行释放了,ffmpeg好像自己已经释放了。

另外关于解码出来的音频,需要注意他的存放再uint8_t *data[AV_NUM_DATA_POINTERS];里面的,这是一个数组,每个通道一维。由于pcm保持多通道根据采样率进行顺序保持,所以保持位pcm需要处理一下:

int iCopyPos = 0;
	for(int i = 0; i < frame->nb_samples; i++)
	{
		for (int ch = 0; ch < c->channels; ch++)
		{
			memcpy(m_pOutData + iCopyPos,frame->data[ch] + data_size * i, data_size);
			iCopyPos = iCopyPos + data_size;
		}
	}

最后,为了便于大家学习和交流,我采用vs2017开发,上传示例如下连接:

https://download.csdn.net/download/g0415shenw/10584757

猜你喜欢

转载自blog.csdn.net/g0415shenw/article/details/81432854