您的位置:首页 > 其它

SDL播放ffmpeg解码的AAC

2015-06-24 17:26 387 查看
转自雷神的博客: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[]){
	***FormatContext *pFormatCtx;
	int i,audioStream;
	***CodecContext *pCodecCtx;
	***Codec *pCodec;
	***Packet *packet;
	uint8_t *out_buffer;
	***Frame *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==***MEDIA_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 = (***Packet*)av_malloc(sizeof(***Packet));
	av_init_packet(packet);

	uint64_t out_channel_layout = ***_CH_LAYOUT_STEREO;//输出声道
	int out_nb_samples=1024;
	***SampleFormat out_sample_fmt = ***_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播放)



代码很贴心,用了很多条件……

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: