ffmpeg解复用解码重采样

        之前有个片源输出有吵杂的声音,然后为了和板子输出的音频比较,我就在linux PC上参照一下我们的工程和网上的一些方法,写了这么一个程序。
要开始播放是一个视频,到音频的输出,大概经历了这个几个过程:解复用(抽取视音频流)->解码音频->重采样。最终从重采样出来的数据,是可以从音频驱动直接输出的。

        重采样的话,应该不是必须的,然而我们项目是用安卓的架构,HAL层有了输出参数的设定(采样率48K,双声道,采样格式AV_SAMPLE_FMT_S16)。

  下面是代码,写得很烂,初始化和反初始化乱七八糟的,我也不想改了,反正是我自己用的demo而已,贴上来之前,我去掉了很多东西,不一定能编译过,反正是这个逻辑了。几个月前写的东西,都几乎忘光。

#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libavutil/avutil.h"
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include "stdio.h"
#include "math.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
int main(int argc ,char **argv)
{
	
	if (argc !=2)
	{
		printf("useage:%s INPUTFILE\n", argv[0]);
		return -1;
	}

	char *outdec="dec.pcm";
	int fd_out = open(outdec, O_WRONLY, 0666);
	if (fd_out < 0)
	{
		printf("open in file is failed\n");
		return -1;
		
	}
	

	
	av_register_all();

	AVFrame* frame = avcodec_alloc_frame();
	if (!frame)
	{
		printf( "Error allocating the frame" );
		return -1;
	}

	AVFormatContext* formatContext = NULL;
	if (avformat_open_input(&formatContext, argv[1], NULL, NULL) != 0)
	{
		av_free(frame);
		printf( "Error opening the file" );
		return -1;
	}

	if (avformat_find_stream_info(formatContext, NULL) < 0)
	{
		av_free(frame);
		//av_close_input_file(formatContext);
		printf( "Error finding the stream info" );
		return -1;
	}

	AVStream* audioStream = NULL;
	unsigned int i = 0;
	for (; i < formatContext->nb_streams; ++i)
	{
		if (formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)//查找音频流对应的ID
		{
				audioStream = formatContext->streams[i];
				break;
		}
	}

	if (audioStream == NULL)
	{
			av_free(frame);
			av_close_input_file(formatContext);
			printf( "Could not find any audio stream in the file" );
			return 1;
	}

	AVCodecContext* codecContext = audioStream->codec;

	codecContext->codec = avcodec_find_decoder(codecContext->codec_id);
	if (codecContext->codec == NULL)
	{
		av_free(frame);
		av_close_input_file(formatContext);
		printf( "Couldn't find a proper decoder" );
		return -1;
	}
	else if (avcodec_open2(codecContext, codecContext->codec, NULL) != 0)
	{
		av_free(frame);
		av_close_input_file(formatContext);
		printf( "Couldn't open the context with the decoder" );
		return 1;
	}
	
	/* 重采样格式初始化 */
	SwrContext* swrContext = NULL;
	printf(" bit_rate = %d \r\n", codecContext->bit_rate);
	printf(" sample_rate = %d \r\n", codecContext->sample_rate);
	printf(" channels = %d \r\n", codecContext->channels);
	printf(" channel_layout = %d \r\n", codecContext->channel_layout);
	printf(" code_name = %s \r\n", codecContext->codec->name);
	printf(" av_get_default_channel_layout(2) %d \r\n", av_get_default_channel_layout(2));
	swrContext = swr_alloc_set_opts(NULL,
				av_get_default_channel_layout(2), // out channel layout
				AV_SAMPLE_FMT_S16, // out sample format
				48000, // out sample rate
				codecContext->channel_layout, // in channel layout
				codecContext->sample_fmt, // in sample format
				codecContext->sample_rate, // in sample rate
				0, // log offset
				NULL); // log context
	if(swr_init(swrContext)<0)
	{
		printf("swr_init() for AV_SAMPLE_FMT_S16 fail");
		swr_free(&swrContext);
		av_free(frame);
		av_close_input_file(formatContext);
		return -1;
	}
	if (!swrContext)
	{
		swr_free(&swrContext);
		av_free(frame);
		avcodec_close(codecContext);
		av_close_input_file(formatContext);
		swrContext = NULL;
		printf( "Couldn't allocate and set the resampling context" );
		return -1;
	}

//	int bufSize = av_samples_get_buffer_size(NULL, codecContext->channels, codecContext->sample_rate, codecContext->sample_fmt, 0);
//	unsigned char* buf = new unsigned char[bufSize];

	AVPacket *packet=(AVPacket *)av_mallocz(sizeof(AVPacket));
	av_init_packet(packet);
		

	static unsigned char audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2]; 
	unsigned char *out[]={audio_buf};  
	unsigned char *pktdata;
	int pktsize,flush_complete=0;
	int resampled_data_size = 0;
	while (av_read_frame(formatContext, packet) == 0)
	{
			if (packet->stream_index == audioStream->index) //只处理音频
			{

					int got_frame = 0;
					int len = 0;
					while (packet->size > 0)
					{
						len = avcodec_decode_audio4(codecContext, frame, &got_frame, packet); //音频解码
						if (len < 0)
						{
							av_free_packet(packet);
							swr_free(&swrContext);
							av_free(frame);
							avcodec_close(codecContext);
							av_close_input_file(formatContext);
							swrContext = NULL;
							printf( " audio decode error ! \n" );
							return -1;
						}
						packet->data += len; //必须考虑一包解多次的情况
						packet->size -= len;

						if (got_frame)//获取一帧的音频
						{							
							//const unsigned char **in = (const unsigned char **) src_pp;
							const unsigned char **in = (const unsigned char **) frame->extended_data;
							int len2 = swr_convert(swrContext, out,
							sizeof(audio_buf)/codecContext->channels/av_get_bytes_per_sample(AV_SAMPLE_FMT_S16),
							in, frame->nb_samples);
						
							if (len2 < 0) 
							{
								fprintf(stderr, "audio_resample() failed\n");
								av_free_packet(packet);
								swr_free(&swrContext);
								av_free(frame);
								avcodec_close(codecContext);
								av_close_input_file(formatContext);
								swrContext = NULL;
								printf( " audio decode error ! \n" );
								return -1;
							}
							if (len2 == sizeof(audio_buf) / codecContext->channels / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)) 
							{
								fprintf(stderr, "warning: audio buffer is probably too small\n");
								swr_init(swrContext);
							}
							resampled_data_size = len2 * (2) * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);	
							write(fd_out, *out, resampled_data_size);
						}
					}
			}
				av_init_packet(packet);
				
	}

end:
	av_free_packet(packet);
//	delete [] buf;
	swr_free(&swrContext);
	av_free(frame);
	avcodec_close(codecContext);
	//av_close_input_file(formatContext);
	close(fd);
}


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值