#include#include #include #include #include #include #include #define LOG_TAG "FFMPEG_WZP_AUDIO" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) //用于保存ffmpeg变的信息 struct ffmpeg_info_t{ AVFormatContext *fmt_ctx; AVCodecContext *dec_ctx; int audio_stream_index ; }ffmpeg_info; struct openslgs_info_t{ // engine interfaces SLObjectItf engineObject ; SLEngineItf engineEngine; // output mix interfaces SLObjectItf outputMixObject ; SLEnvironmentalReverbItf outputMixEnvironmentalReverb ; // buffer queue player interfaces SLObjectItf bqPlayerObject ; SLPlayItf bqPlayerPlay; SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue; SLEffectSendItf bqPlayerEffectSend; SLMuteSoloItf bqPlayerMuteSolo; SLVolumeItf bqPlayerVolume; }openslgs; typedef struct PacketQueue { AVPacketList * first_pkt, *last_pkt; int nb_packets; int size; }PacketQueue; PacketQueue audio_queue; void packet_queue_init(PacketQueue *q) { memset(q, 0, sizeof(PacketQueue)); } int packet_queue_put(PacketQueue *q, AVPacket *pkt) { AVPacketList *pkt1; if(av_dup_packet(pkt) < 0) return -1; pkt1 = av_malloc(sizeof(AVPacketList)); if (!pkt1) return -1; pkt1->pkt = *pkt; pkt1->next = NULL; if (!q->last_pkt) q->first_pkt = pkt1; else q->last_pkt->next = pkt1; q->last_pkt = pkt1; q->nb_packets++; q->size += pkt1->pkt.size; return 0; } int quit = 0; static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) { AVPacketList *pkt1; int ret; if(quit) { ret = -1; return -1; } pkt1 = q->first_pkt; if (pkt1) { q->first_pkt = pkt1->next; if (!q->first_pkt) q->last_pkt = NULL; q->nb_packets--; q->size -= pkt1->pkt.size; *pkt = pkt1->pkt; av_free(pkt1); ret = 1; return ret; } else if (!block) { ret = 0; return ret; } return ret; } AVPacket packet; AVFrame *frame; int decode_frame(uint8_t *stream){ int len, data_size, got_frame; for(;;){ while(packet.size>0){ if(!frame) { if (!(frame = avcodec_alloc_frame())) return AVERROR(ENOMEM); } else { avcodec_get_frame_defaults(frame); } len = avcodec_decode_audio4(ffmpeg_info.dec_ctx, frame, &got_frame, &packet); if(len < 0) { /* if error, skip frame */ packet.size = 0; break; } packet.data += len; packet.size -= len; if(got_frame <= 0) /* No data yet, get more frames */ continue; data_size = av_samples_get_buffer_size(NULL, ffmpeg_info.dec_ctx->channels, frame->nb_samples, ffmpeg_info.dec_ctx->sample_fmt, 1); memcpy(stream, frame->data[0], data_size); return data_size; } packet_queue_get(&audio_queue,&packet,1); } } uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2]; // this callback handler is called every time a buffer finishes playing void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context){ int len=decode_frame(audio_buf); (*openslgs.bqPlayerBufferQueue)->Enqueue(openslgs.bqPlayerBufferQueue,audio_buf,len); } //打开文件,初化化ffmpeg信息 static int open_input_file(const char *filename) { ffmpeg_info.audio_stream_index =-1; int ret; AVCodec *dec; if ((ret = avformat_open_input(&ffmpeg_info.fmt_ctx, filename, NULL, NULL)) < 0) { LOGE("Cannot open input file\n"); return ret; } if ((ret = avformat_find_stream_info(ffmpeg_info.fmt_ctx, NULL)) < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n"); return ret; } /* select the audio stream */ ret = av_find_best_stream(ffmpeg_info.fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0); if (ret < 0) { LOGE("Cannot find a audio stream in the input file\n"); return ret; } ffmpeg_info.audio_stream_index = ret; ffmpeg_info.dec_ctx = ffmpeg_info.fmt_ctx->streams[ffmpeg_info.audio_stream_index]->codec; /* init the audio decoder */ if ((ret = avcodec_open2(ffmpeg_info.dec_ctx, dec, NULL)) < 0) { LOGE("Cannot open audio decoder\n"); return ret; } return 0; } void createEngine(){ SLresult result; // create engine result = slCreateEngine(&openslgs.engineObject, 0, NULL, 0, NULL, NULL); assert(SL_RESULT_SUCCESS == result); // realize the engine result = (*openslgs.engineObject)->Realize(openslgs.engineObject, SL_BOOLEAN_FALSE); assert(SL_RESULT_SUCCESS == result); // get the engine interface result = (*openslgs.engineObject)->GetInterface(openslgs.engineObject, SL_IID_ENGINE, &openslgs.engineEngine); assert(SL_RESULT_SUCCESS == result); // create output mix const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB}; const SLboolean req[1] = {SL_BOOLEAN_FALSE}; result = (*openslgs.engineEngine)->CreateOutputMix(openslgs.engineEngine, &openslgs.outputMixObject, 1, ids, req); assert(SL_RESULT_SUCCESS == result); // realize the output mix result = (*openslgs.outputMixObject)->Realize(openslgs.outputMixObject, SL_BOOLEAN_FALSE); assert(SL_RESULT_SUCCESS == result); #if 0 // get the environmental reverb interface result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB, &outputMixEnvironmentalReverb); if (SL_RESULT_SUCCESS == result) { result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(outputMixEnvironmentalReverb, &reverbSettings); } #endif // ignore unsuccessful result codes for env reverb } void createBufferQueueAudioPlayer(){ SLresult result; // configure audio source SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; /* SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_16, SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, SL_SPEAKER_FRONT_CENTER, SL_BYTEORDER_LITTLEENDIAN}; format_pcm.samplesPerSec=ffmpeg_info.dec_ctx->sample_rate*1000; SLDataSource audioSrc = {&loc_bufq, &format_pcm}; */ SLDataFormat_PCM pcm; pcm.formatType = SL_DATAFORMAT_PCM; pcm.numChannels = ffmpeg_info.dec_ctx->channels;//跟下面的channelMask 要配对 不会会报错 pcm.samplesPerSec = ffmpeg_info.dec_ctx->sample_rate*1000; pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; pcm.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16; pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; //立体声 这是参照audiotrack CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT)得到的 pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; SLDataSource audioSrc = {&loc_bufq, &pcm}; // configure audio sink SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, openslgs.outputMixObject}; SLDataSink audioSnk = {&loc_outmix, NULL}; // create audio player const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND, /*SL_IID_MUTESOLO,*/ SL_IID_VOLUME}; const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, /*SL_BOOLEAN_TRUE,*/ SL_BOOLEAN_TRUE}; result = (*openslgs.engineEngine)->CreateAudioPlayer(openslgs.engineEngine, &openslgs.bqPlayerObject, &audioSrc, &audioSnk, 3, ids, req); assert(SL_RESULT_SUCCESS == result); // realize the player result = (*openslgs.bqPlayerObject)->Realize(openslgs.bqPlayerObject, SL_BOOLEAN_FALSE); assert(SL_RESULT_SUCCESS == result); // get the play interface result = (*openslgs.bqPlayerObject)->GetInterface(openslgs.bqPlayerObject, SL_IID_PLAY, &openslgs.bqPlayerPlay); assert(SL_RESULT_SUCCESS == result); // get the buffer queue interface result = (*openslgs.bqPlayerObject)->GetInterface(openslgs.bqPlayerObject, SL_IID_BUFFERQUEUE, &openslgs.bqPlayerBufferQueue); assert(SL_RESULT_SUCCESS == result); // register callback on the buffer queue result = (*openslgs.bqPlayerBufferQueue)->RegisterCallback(openslgs.bqPlayerBufferQueue, bqPlayerCallback, NULL); assert(SL_RESULT_SUCCESS == result); assert(SL_RESULT_SUCCESS == result); #if 0 // mute/solo is not supported for sources that are known to be mono, as this is // get the mute/solo interface result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_MUTESOLO, &bqPlayerMuteSolo); assert(SL_RESULT_SUCCESS == result); #endif // get the volume interface result = (*openslgs.bqPlayerObject)->GetInterface(openslgs.bqPlayerObject, SL_IID_VOLUME, &openslgs.bqPlayerVolume); assert(SL_RESULT_SUCCESS == result); // set the player's state to playing result = (*openslgs.bqPlayerPlay)->SetPlayState(openslgs.bqPlayerPlay, SL_PLAYSTATE_PLAYING); assert(SL_RESULT_SUCCESS == result); } void put_packet_intoqueue(){ AVPacket packet; while(1){ if(av_read_frame(ffmpeg_info.fmt_ctx,&packet)<0){ break; } if(packet.stream_index==ffmpeg_info.audio_stream_index){ packet_queue_put(&audio_queue,&packet); }else av_free_packet(&packet); } LOGI("audio_queue.size=%d\n",audio_queue.size); } int main(int argc, char **argv){ avcodec_register_all(); av_register_all(); open_input_file(argv[1]); packet_queue_init(&audio_queue); put_packet_intoqueue(); createEngine(); createBufferQueueAudioPlayer(); bqPlayerCallback(NULL,NULL); for(;;){ getchar(); } }