之前有个片源输出有吵杂的声音,然后为了和板子输出的音频比较,我就在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);
}