ijkplayer源码分析之opengl与surface关联初始化
=====================================================
ijkplayer源码分析系列文章列表:
ijkplayer源码分析之surface与opengl es关联初始化(一)
ijkplayer源码分析之audio与opensl es初始化(二)
======================================================
audio的初始化
IjkVideoView.java
// OPT_CATEGORY_PLAYER = 4;
if (mSettings.getUsingOpenSLES())
|--ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 1);
|--_setOption(category, name, value);
goto Ijkplayer_jni.c
将键值对保存到ffp->player_opts
中
IjkMediaPlayer_setOptionLong(JNIEnv *env, jobject thiz, jint category, jobject name, jlong value)
|--ijkmp_set_option_int(mp, category, c_name, value);
|--ffp_set_option_int(mp->ffplayer, opt_category, name, value);
|--AVDictionary **dict = ffp_get_opt_dict(ffp, opt_category);
| |--&ffp->player_opts; // AVDictionary *player_opts;
|--av_dict_set_int(dict, name, value, 0); //将键值对保存到`ffp->player_opts`中
|--av_dict_set(pm, key, valuestr, flags);
//pipeline->func_open_audio_output = func_open_audio_output;
IjkMediaPlayer_prepareAsync //Ijkplayer_jni.c
|--ijkmp_prepare_async
|--ijkmp_prepare_async_l(IjkMediaPlayer *mp) //Ijkplayer.c
|--ffp_prepare_async_l(FFPlayer *ffp, const char *file_name) //Ff_ffplay.c
|--ffp->aout = ffpipeline_open_audio_output(ffp->pipeline, ffp);
|--pipeline->func_open_audio_output(pipeline, ffp); //
|--func_open_audio_output
|--if (ffp->opensles)
| |--SDL_AoutAndroid_CreateForOpenSLES();
|--else
|--SDL_AoutAndroid_CreateForAudioTrack();
这里先分析使用OpenSLES的情况
1.创建OpenSL引擎并将引擎及回调信息填充到FFPlayer->aout
中(SDL_Aout *aout;)
SDL_AoutAndroid_CreateForOpenSLES
|--SDL_Aout *aout = SDL_Aout_CreateInternal(sizeof(SDL_Aout_Opaque));
|--slCreateEngine(&slObject, 0, NULL, 0, NULL, NULL);
|--SDL_Aout_Opaque *opaque = aout->opaque;
|--opaque->slObject = slObject;
|--opaque->slEngine = slEngine;
|--opaque->slOutputMixObject = slOutputMixObject;
|--aout->free_l = aout_free_l;
|--aout->opaque_class = &g_opensles_class;
|--aout->open_audio = aout_open_audio;
|--aout->pause_audio = aout_pause_audio;
|--aout->flush_audio = aout_flush_audio;
|--aout->close_audio = aout_close_audio;
|--aout->set_volume = aout_set_volume;
|--aout->func_get_latency_seconds = aout_get_latency_seconds;
Audio Spec
typedef struct SDL_AudioSpec
{
int freq; /**< DSP frequency -- samples per second */
SDL_AudioFormat format; /**< Audio data format */
Uint8 channels; /**< Number of channels: 1 mono, 2 stereo */
Uint8 silence; /**< Audio buffer silence value (calculated) */
Uint16 samples; /**< Audio buffer size in samples (power of 2) */
Uint16 padding; /**< NOT USED. Necessary for some compile environments */
Uint32 size; /**< Audio buffer size in bytes (calculated) */
SDL_AudioCallback callback;
void *userdata;
} SDL_AudioSpec;
typedef struct SDL_Aout_Opaque {
SDL_cond *wakeup_cond;
SDL_mutex *wakeup_mutex;
SDL_Thread *audio_tid;
SDL_Thread _audio_tid;
SDL_AudioSpec spec;
SLDataFormat_PCM format_pcm;
int bytes_per_frame;
int milli_per_buffer;
int frames_per_buffer;
int bytes_per_buffer;
SLObjectItf slObject;
SLEngineItf slEngine;
SLObjectItf slOutputMixObject;
SLObjectItf slPlayerObject;
SLAndroidSimpleBufferQueueItf slBufferQueueItf;
SLVolumeItf slVolumeItf;
SLPlayItf slPlayItf;
volatile bool need_set_volume;
volatile float left_volume;
volatile float right_volume;
volatile bool abort_request;
volatile bool pause_on;
volatile bool need_flush;
volatile bool is_running;
uint8_t *buffer;
size_t buffer_capacity;
} SDL_Aout_Opaque;
2.打开音频
#define OPENSLES_BUFFERS 255 /* maximum number of buffers */
#define OPENSLES_BUFLEN 10 /* ms */
read_thread //Ff_ffplay.c
|--stream_component_open(ffp, st_index[AVMEDIA_TYPE_AUDIO]);
|--audio_open(ffp, channel_layout, nb_channels, sample_rate, &is->audio_tgt)
|--wanted_spec.format = AUDIO_S16SYS;
|--wanted_spec.silence = 0;
|--wanted_spec.callback = sdl_audio_callback;
|--wanted_spec.userdata = opaque;
|--SDL_AoutOpenAudio(ffp->aout, &wanted_spec, &spec)
|--aout->open_audio(aout, desired, obtained);
|--aout_open_audio(SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
|--SDL_Aout_Opaque *opaque = aout->opaque;
|--opaque->spec = *desired;
|--(*opaque->slBufferQueueItf)->RegisterCallback(opaque->slBufferQueueItf, aout_opensles_callback, (void*)aout); //添加音频播放完成回调
|--opaque->bytes_per_frame = format_pcm->numChannels * format_pcm->bitsPerSample / 8;
| //每一帧占用几个字节
|--opaque->milli_per_buffer = OPENSLES_BUFLEN;
| //每个buffer要占用多少毫秒
|--opaque->frames_per_buffer = opaque->milli_per_buffer * format_pcm->samplesPerSec / 1000000; // samplesPerSec is in milli
| //每个buffer有几帧
|--opaque->bytes_per_buffer = opaque->bytes_per_frame * opaque->frames_per_buffer;
|--opaque->buffer_capacity = OPENSLES_BUFFERS * opaque->bytes_per_buffer;
|--for(int i = 0; i < OPENSLES_BUFFERS; ++i)
| |--(*opaque->slBufferQueueItf)->Enqueue(opaque->slBufferQueueItf, opaque->buffer + i * opaque->bytes_per_buffer, opaque->bytes_per_buffer);
| // 将数据添加到播放队列
|--SDL_CreateThreadEx(&opaque->_audio_tid, aout_thread, aout, "ff_aout_opensles");
|--aout_thread_n(arg);
|--SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);