转自雷神的博客:http://blog.csdn.net/leixiaohua1020/article/details/38979615
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stdafx.h"
#define __STDC_CONSTANT_MACROS
#ifdef _WIN32
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"
#include "SDL/SDL.h"
};
#endif
#define MAX_AUDIO_FRAME_SIZE 19200
#define OUTPUT_PCM 0
#define USE_SDL 1
static Uint8 *audio_chunk;
static Uint32 audio_len;
static Uint8 *audio_pos;
void fill_audio(void *udata,Uint8 *stream,int len){
SDL_memset(stream,0,len);
if(audio_len ==0){
return;
}
len=(len>audio_len?audio_len:len);
SDL_MixAudio(stream,audio_pos,len,SDL_MIX_MAXVOLUME);
audio_pos+=len;
audio_len-=len;
}
int _tmain(int argc, _TCHAR* argv[]){
AVFormatContext *pFormatCtx;
int i,audioStream;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVPacket *packet;
uint8_t *out_buffer;
AVFrame *pFrame;
SDL_AudioSpec wanted_spec;
int ret;
int m=1;
uint32_t len=0;
int got_picture;
int index=0;
int64_t in_channel_layout;
struct SwrContext *au_convert_ctx;
FILE *pFile=NULL;
char url[]="test1.aac";
av_register_all();
avformat_network_init();
pFormatCtx= avformat_alloc_context();
if(avformat_open_input(&pFormatCtx,url,NULL,NULL)!=0){
printf("Couldn't open input stream\n");
return -1;
}
if(avformat_find_stream_info(pFormatCtx,NULL)<0){
printf("Couldn't find the info of stream\n");
return -1;
}
av_dump_format(pFormatCtx,0,url,false);
audioStream =-1;
for(i=0;i < pFormatCtx->nb_streams;i++){
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO){
audioStream=i;
break;
}
}
if(audioStream==-1){
printf("Couldn't find a audio stream\n");
return -1;
}
pCodecCtx= pFormatCtx->streams[audioStream]->codec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==NULL){
printf("Codec not found\n");
return -1;
}
if(avcodec_open2(pCodecCtx,pCodec,NULL)<0){
printf("Could not open codec \n");
return -1;
}
#if OUTPUT_PCM
pFile = fopen("output.pcm","wb");
#endif
packet = (AVPacket*)av_malloc(sizeof(AVPacket));
av_init_packet(packet);
uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO;//输出声道
int out_nb_samples=1024;
AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;//输出格式S16
int out_sample_rate = 44100;
int out_channels =av_get_channel_layout_nb_channels(out_channel_layout);
int out_buffer_size = av_samples_get_buffer_size(NULL,out_channels,out_nb_samples,out_sample_fmt,1);
out_buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE*2);
pFrame = av_frame_alloc();
#if USE_SDL
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)){
printf("Could not initialize SDL - %s\n",SDL_GetError());
return -1;
}
wanted_spec.freq = out_sample_rate;
wanted_spec.format = AUDIO_S16SYS;
wanted_spec.channels=out_channels;
wanted_spec.silence =0;
wanted_spec.samples = out_nb_samples;
wanted_spec.callback =fill_audio;
wanted_spec.userdata = pCodecCtx;
if(SDL_OpenAudio(&wanted_spec,NULL)<0){
printf("cann't open audio\n");
return -1;
}else{
printf("whether loop in SDL_OpenAudio()\n");
}
#endif
printf("Bitrate:\t %3d\n",pFormatCtx->bit_rate);
printf("Decoder Name:\t %s\n",pCodecCtx->codec->long_name);
printf("Channels:\t %d\n",pCodecCtx->channels);
printf("Sample per Second \t %d \n",pCodecCtx->sample_rate);
in_channel_layout = av_get_default_channel_layout(pCodecCtx->channels);
printf("in_channel_layout --->%d\n",in_channel_layout);
au_convert_ctx = swr_alloc();
au_convert_ctx= swr_alloc_set_opts(au_convert_ctx,out_channel_layout,out_sample_fmt,out_sample_rate,
in_channel_layout,pCodecCtx->sample_fmt,pCodecCtx->sample_rate,0,NULL);
swr_init(au_convert_ctx);
while(av_read_frame(pFormatCtx,packet)>=0){
if(packet->stream_index==audioStream){
ret = avcodec_decode_audio4(pCodecCtx,pFrame,&got_picture,packet);
if(ret < 0){
printf("Error in decoding audio frame\n");
return -1;
}
if(got_picture > 0){
swr_convert(au_convert_ctx,&out_buffer,MAX_AUDIO_FRAME_SIZE,(const uint8_t **)pFrame->data,pFrame->nb_samples);
printf("index:%5d\t pts:%12d\t packet size:%d\n",index,packet->pts,packet->size);
#if USE_SDL
if(wanted_spec.samples!=pFrame->nb_samples){//MP3、AAC不同的samples,重定位
SDL_CloseAudio();
out_nb_samples = pFrame->nb_samples;
out_buffer_size=av_samples_get_buffer_size(NULL,out_channels,out_nb_samples,out_sample_fmt,1);
wanted_spec.samples=out_nb_samples;
SDL_OpenAudio(&wanted_spec,NULL);
}
#endif
#if OUTPUT_PCM
fwrite(out_buffer,1,out_buffer_size,pFile);
#endif
index++;
}
#if USE_SDL
audio_chunk = (Uint8 *)out_buffer;
audio_len = out_buffer_size;
audio_pos =audio_chunk;
/*
*SDL_PauseAudio(1); // audio callback is stopped when this returns.
SDL_Delay(5000); // audio device plays silence for 5 seconds
SDL_PauseAudio(0); // audio callback starts running again.
*/
SDL_PauseAudio(0); //将解码并转换过的数据装在SDL中
while(audio_len>0){
SDL_Delay(1);//播放
}
#endif
}
av_free_packet(packet);
}
swr_free(&au_convert_ctx);
#if USE_SDL
SDL_CloseAudio();
SDL_Quit();
#endif
#if OUTPUT_PCM
fclose(pFile);
#endif
av_free(out_buffer);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
return 0;
}
雷神的这篇博客,从本地读取AAC文件avformat_open_input() ------>
av_read_frame()(读一个packet)-------->
avcodec_decode_audio4()(解码)------------->
swr_convert()(转换S16)--------->
SDL_PauseAudio(0)(通过回调函数装在SDL中)------------>
SDL_Delay(1)(SDL播放)
代码很贴心,用了很多条件……