`
CheshireCat
  • 浏览: 9521 次
社区版块
存档分类
最新评论

opensl ES 播放ffmpeg解码后音频数据 (未完待续)

 
阅读更多
#include <unistd.h>
#include <assert.h>

#include <android/log.h>

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>

#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>

#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();
	}

}

 

 

0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics