android 音频播放插件,Android 音视频学习基础Android最简单的音频播放器| 神农笔记...

/*

*最简单的基于FFmpeg的音频播放器

*Simplest FFmpeg Audio Player

*本程序实现了音频的解码和播放。

*

*/

#include

#include

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;

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值