Android media ---- 1.7.ffmpeg 简单音频播放器

哎,喜欢偷懒,这边直接抄袭下雷神的代码。雷神是个值得敬佩的程序员。

vs代码下载链接:
https://pan.baidu.com/s/1c2dIuYk 密码:ld4b

/* 
 *最简单的基于FFmpeg的音频播放器
 *Simplest FFmpeg Audio Player
 *
 *雷霄骅 Lei Xiaohua
 *leixiaohua1020@126.com
 *中国传媒大学/数字电视技术
 *Communication University of China / Digital TV Technology
 *http://blog.csdn.net/leixiaohua1020
 *
 *本程序实现了音频的解码和播放。
 *
 */
#include <stdlib.h>
#include <string.h>
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"
//SDL
#include "sdl/SDL.h"
#include "sdl/SDL_thread.h"
};
#include "decoder.h"

//#define _WAVE_

//全局变量---------------------
	static  Uint8  *audio_chunk; 
	static  Uint32  audio_len; 
	static  Uint8  *audio_pos; 
//-----------------
	/*  The audio function callback takes the following parameters: 
	stream: A pointer to the audio buffer to be filled 
	len: The length (in bytes) of the audio buffer (这是固定的4096?)
	回调函数
	注意:mp3为什么播放不顺畅?
	len=4096;audio_len=4608;两个相差512!为了这512,还得再调用一次回调函数。。。
	m4a,aac就不存在此问题(都是4096)!
	*/ 
	void  fill_audio(void *udata,Uint8 *stream,int len){ 
		/*  Only  play  if  we  have  data  left  */ 
	if(audio_len==0) 
			return; 
		/*  Mix  as  much  data  as  possible  */ 
	len=(len>audio_len?audio_len:len); 
	SDL_MixAudio(stream,audio_pos,len,SDL_MIX_MAXVOLUME);
	audio_pos += len; 
	audio_len -= len; 
	} 
//-----------------


int decode_audio(char* no_use)
{
	AVFormatContext	*pFormatCtx;
	int				i, audioStream;
	AVCodecContext	*pCodecCtx;
	AVCodec			*pCodec;


	
	char url[300]={0};
	strcpy(url,no_use);

	av_register_all();
	//支持网络流输入ff
	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;
	}
	// Retrieve stream information
	if(av_find_stream_info(pFormatCtx)<0)
	{
		printf("Couldn't find stream information.\n");
		return -1;
	}
	// Dump valid information onto standard error
	av_dump_format(pFormatCtx, 0, url, false);

	// Find the first audio stream
	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("Didn't find a audio stream.\n");
		return -1;
	}

	// Get a pointer to the codec context for the audio stream
	pCodecCtx=pFormatCtx->streams[audioStream]->codec;

	// Find the decoder for the audio stream
	pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
	if(pCodec==NULL)
	{
		printf("Codec not found.\n");
		return -1;
	}

	// Open codec
	if(avcodec_open2(pCodecCtx, pCodec,NULL)<0)
	{
		printf("Could not open codec.\n");
		return -1;
	}

	FILE *pFile;
#ifdef _WAVE_
	pFile=fopen("output.wav", "wb");
	fseek(pFile, 44, SEEK_SET); //预留文件头的位置
#else
	pFile=fopen("output1.pcm", "wb");
#endif

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

	AVFrame	*pFrame;
	pFrame=avcodec_alloc_frame();
	//输出音频数据大小,一定小于输出内存。
	int out_linesize;
	//输出内存大小
	int out_buffer_size=av_samples_get_buffer_size(&out_linesize, pCodecCtx->channels,pCodecCtx->frame_size,pCodecCtx->sample_fmt, 1);
	uint8_t *out_buffer=new uint8_t[out_buffer_size];
	//---------SDL--------------------------------------
	//初始化
	if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {  
		printf( "Could not initialize SDL - %s\n", SDL_GetError()); 
		exit(1);
	}

	//结构体,包含PCM数据的相关信息
	SDL_AudioSpec wanted_spec;
	wanted_spec.freq = pCodecCtx->sample_rate; 
	wanted_spec.format = AUDIO_S16SYS; 
	wanted_spec.channels = pCodecCtx->channels; 
	wanted_spec.silence = 0; 
	//wanted_spec.samples = 1024; //播放AAC,M4a,缓冲区的大小
	wanted_spec.samples = 1152; //播放MP3,WMA时候用
	wanted_spec.callback = fill_audio; 
	wanted_spec.userdata = pCodecCtx; 

	if (SDL_OpenAudio(&wanted_spec, NULL)<0)//步骤(2)打开音频设备 
	{ 
		printf("can't open audio.\n"); 
		return 0; 
	} 
	//-----------------------------------------------------
	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);

	uint32_t ret,len = 0;
	int got_picture;
	int index = 0;
	struct SwrContext *au_convert_ctx;
	au_convert_ctx = swr_alloc();
	au_convert_ctx=swr_alloc_set_opts(au_convert_ctx,AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, 44100,
		pCodecCtx->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");
                exit(0);
            }
			if ( got_picture > 0 )
			{
#if 1
				swr_convert(au_convert_ctx,&out_buffer, out_linesize,(const uint8_t **)pFrame->data , pFrame->nb_samples);

				printf("index:%5d\t pts %5d\n", index,packet->pts);
#endif
				//直接写入
#if 1
				fwrite(out_buffer, 1, out_linesize, pFile);
#endif
				index++;
			}
#if 1
			//---------------------------------------
			//printf("begin....\n"); 
			//设置音频数据缓冲,PCM数据
			audio_chunk = (Uint8 *) out_buffer; 
			//设置音频数据长度
			audio_len = out_linesize;
			audio_len = 4096;
			//播放mp3的时候改为audio_len = 4096
			//则会比较流畅,但是声音会变调!MP3一帧长度4608
			//使用一次回调函数(4096字节缓冲)播放不完,所以还要使用一次回调函数,导致播放缓慢。。。
			//设置初始播放位置
			audio_pos = audio_chunk;
			//回放音频数据 
			SDL_PauseAudio(0);
			//printf("don't close, audio playing...\n"); 
			while(audio_len>0)//等待直到音频数据播放完毕! 
				SDL_Delay(1); 
			//---------------------------------------
#endif
		}
		av_free_packet(packet);
	}

#ifdef _WAVE_
	fseek(pFile, 0, SEEK_SET);
	struct WAVE_HEADER wh;

	memcpy(wh.header.RiffID, "RIFF", 4);
	wh.header.RiffSize = 36 + len;
	memcpy(wh.header.RiffFormat, "WAVE", 4);

	memcpy(wh.format.FmtID, "fmt ", 4);
	wh.format.FmtSize = 16;
	wh.format.wavFormat.FormatTag = 1;
	wh.format.wavFormat.Channels = pCodecCtx->channels;
	wh.format.wavFormat.SamplesRate = pCodecCtx->sample_rate;
	wh.format.wavFormat.BitsPerSample = 16;
	calformat(wh.format.wavFormat); //Calculate AvgBytesRate and BlockAlign

	memcpy(wh.data.DataID, "data", 4);
	wh.data.DataSize = len;

	fwrite(&wh, 1, sizeof(wh), pFile);
#endif
	SDL_CloseAudio();//关闭音频设备 
	// Close file
	fclose(pFile);
	// Close the codec
	avcodec_close(pCodecCtx);
	// Close the video file
	av_close_input_file(pFormatCtx);

	return 0;
}

相关文章

Android 音视频学习基础–1.1 音视频基础知识
Android 音视频学习基础–1.2 需要认识的一些工具
Android 音视频学习基础–1.3 主流的开源项目
Android 音视频学习基础–1.4 ffmpeg pcm输出
Android 音视频学习基础–1.5 ffmpeg yuv输出
Android 音视频学习基础–1.6 ffmpeg 简单视频播放器
Android 音视频学习基础–1.7 Android最简单的音频播放器
Android 音视频学习基础–1.8 Android最简单的音频播放器
Android 音视频学习基础–1.9 Android最简单的视频播放器
Android 音视频学习基础–1.10 Android自制简单音视频播放器

欢迎大家批评指正

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值