ijkplayer源代码文章索引_qq_15255121的专栏-CSDN博客
struct IJKFF_Pipeline *pipeline;
struct IJKFF_Pipeline {
SDL_Class *opaque_class;
IJKFF_Pipeline_Opaque *opaque;
void (*func_destroy) (IJKFF_Pipeline *pipeline);
IJKFF_Pipenode *(*func_open_video_decoder) (IJKFF_Pipeline *pipeline, FFPlayer *ffp);
SDL_Aout *(*func_open_audio_output) (IJKFF_Pipeline *pipeline, FFPlayer *ffp);
IJKFF_Pipenode *(*func_init_video_decoder) (IJKFF_Pipeline *pipeline, FFPlayer *ffp);
int (*func_config_video_decoder) (IJKFF_Pipeline *pipeline, FFPlayer *ffp);
};
opaque_class
我们先看下?? SDL_Class ? ? ? ? ? ? *opaque_class;
我们看到
static SDL_Class g_pipeline_class = {
.name = "ffpipeline_android_media",
};
IJKFF_Pipeline *ffpipeline_create_from_android(FFPlayer *ffp)
{
ALOGD("ffpipeline_create_from_android()\n");
IJKFF_Pipeline *pipeline = ffpipeline_alloc(&g_pipeline_class, sizeof(IJKFF_Pipeline_Opaque));
if (!pipeline)
return pipeline;
IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;
opaque->ffp = ffp;
opaque->surface_mutex = SDL_CreateMutex();
opaque->left_volume = 1.0f;
opaque->right_volume = 1.0f;
if (!opaque->surface_mutex) {
ALOGE("ffpipeline-android:create SDL_CreateMutex failed\n");
goto fail;
}
pipeline->func_destroy = func_destroy;
pipeline->func_open_video_decoder = func_open_video_decoder;
pipeline->func_open_audio_output = func_open_audio_output;
pipeline->func_init_video_decoder = func_init_video_decoder;
pipeline->func_config_video_decoder = func_config_video_decoder;
return pipeline;
fail:
ffpipeline_free_p(&pipeline);
return NULL;
}
IJKFF_Pipeline *ffpipeline_alloc(SDL_Class *opaque_class, size_t opaque_size)
{
IJKFF_Pipeline *pipeline = (IJKFF_Pipeline*) calloc(1, sizeof(IJKFF_Pipeline));
if (!pipeline)
return NULL;
pipeline->opaque_class = opaque_class;
pipeline->opaque = calloc(1, opaque_size);
if (!pipeline->opaque) {
free(pipeline);
return NULL;
}
return pipeline;
}
可以知道是ffpipeline_android_media
IJKFF_Pipeline_Opaque
IJKFF_Pipeline_Opaque *opaque;
typedef struct IJKFF_Pipeline_Opaque {
FFPlayer *ffp; //最上层的FFPlayer
SDL_mutex *surface_mutex; //surface锁
jobject jsurface; //surface
volatile bool is_surface_need_reconfigure;//是否需要重新设置
bool (*mediacodec_select_callback)(void *opaque, ijkmp_mediacodecinfo_context *mcc);
void *mediacodec_select_callback_opaque;
SDL_Vout *weak_vout; //视频输出 弱引用
float left_volume; //最小音量
float right_volume; //最高音量
} IJKFF_Pipeline_Opaque;
mediacodec_select_callback是什么呢?
static void
IjkMediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
MPTRACE("%s\n", __func__);
IjkMediaPlayer *mp = ijkmp_android_create(message_loop);
JNI_CHECK_GOTO(mp, env, "java/lang/OutOfMemoryError", "mpjni: native_setup: ijkmp_create() failed", LABEL_RETURN);
jni_set_media_player(env, thiz, mp);
ijkmp_set_weak_thiz(mp, (*env)->NewGlobalRef(env, weak_this));
ijkmp_set_inject_opaque(mp, ijkmp_get_weak_thiz(mp));
ijkmp_set_ijkio_inject_opaque(mp, ijkmp_get_weak_thiz(mp));
ijkmp_android_set_mediacodec_select_callback(mp, mediacodec_select_callback, ijkmp_get_weak_thiz(mp));
LABEL_RETURN:
ijkmp_dec_ref_p(&mp);
}
void ijkmp_android_set_mediacodec_select_callback(IjkMediaPlayer *mp, bool (*callback)(void *opaque, ijkmp_mediacodecinfo_context *mcc), void *opaque)
{
if (!mp)
return;
MPTRACE("ijkmp_android_set_mediacodec_select_callback()");
pthread_mutex_lock(&mp->mutex);
if (mp && mp->ffplayer && mp->ffplayer->pipeline) {
ffpipeline_set_mediacodec_select_callback(mp->ffplayer->pipeline, callback, opaque);
}
pthread_mutex_unlock(&mp->mutex);
MPTRACE("ijkmp_android_set_mediacodec_select_callback()=void");
}
void ffpipeline_set_mediacodec_select_callback(IJKFF_Pipeline* pipeline, bool (*callback)(void *opaque, ijkmp_mediacodecinfo_context *mcc), void *opaque)
{
ALOGD("%s\n", __func__);
if (!check_ffpipeline(pipeline, __func__))
return;
pipeline->opaque->mediacodec_select_callback = callback;
pipeline->opaque->mediacodec_select_callback_opaque = opaque;
}
我们看到mediacodec_select_callback是ijkplayer/android/ijkplayer_jni.c中的
static bool mediacodec_select_callback(void *opaque, ijkmp_mediacodecinfo_context *mcc)
{
JNIEnv *env = NULL;
jobject weak_this = (jobject) opaque;
const char *found_codec_name = NULL;
if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
ALOGE("%s: SetupThreadEnv failed\n", __func__);
return -1;
}
found_codec_name = J4AC_IjkMediaPlayer__onSelectCodec__withCString__asCBuffer(env, weak_this, mcc->mime_type, mcc->profile, mcc->level, mcc->codec_name, sizeof(mcc->codec_name));
if (J4A_ExceptionCheck__catchAll(env) || !found_codec_name) {
ALOGE("%s: onSelectCodec failed\n", __func__);
goto fail;
}
fail:
return found_codec_name;
}
通过上面代码可以知道最后调用了IjkMediaPlayer.java的
@CalledByNative
private static String onSelectCodec(Object weakThiz, String mimeType, int profile, int level) {
if (weakThiz == null || !(weakThiz instanceof WeakReference<?>))
return null;
@SuppressWarnings("unchecked")
WeakReference<IjkMediaPlayer> weakPlayer = (WeakReference<IjkMediaPlayer>) weakThiz;
IjkMediaPlayer player = weakPlayer.get();
if (player == null)
return null;
OnMediaCodecSelectListener listener = player.mOnMediaCodecSelectListener;
if (listener == null)
listener = DefaultMediaCodecSelector.sInstance;
return listener.onMediaCodecSelect(player, mimeType, profile, level);
}
public static class DefaultMediaCodecSelector implements OnMediaCodecSelectListener {
public static final DefaultMediaCodecSelector sInstance = new DefaultMediaCodecSelector();
@SuppressWarnings("deprecation")
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public String onMediaCodecSelect(IMediaPlayer mp, String mimeType, int profile, int level) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
return null;
if (TextUtils.isEmpty(mimeType))
return null;
Log.i(TAG, String.format(Locale.US, "onSelectCodec: mime=%s, profile=%d, level=%d", mimeType, profile, level));
ArrayList<IjkMediaCodecInfo> candidateCodecList = new ArrayList<IjkMediaCodecInfo>();
int numCodecs = MediaCodecList.getCodecCount();
for (int i = 0; i < numCodecs; i++) {
MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
Log.d(TAG, String.format(Locale.US, " found codec: %s", codecInfo.getName()));
if (codecInfo.isEncoder())
continue;
String[] types = codecInfo.getSupportedTypes();
if (types == null)
continue;
for(String type: types) {
if (TextUtils.isEmpty(type))
continue;
Log.d(TAG, String.format(Locale.US, " mime: %s", type));
if (!type.equalsIgnoreCase(mimeType))
continue;
IjkMediaCodecInfo candidate = IjkMediaCodecInfo.setupCandidate(codecInfo, mimeType);
if (candidate == null)
continue;
candidateCodecList.add(candidate);
Log.i(TAG, String.format(Locale.US, "candidate codec: %s rank=%d", codecInfo.getName(), candidate.mRank));
candidate.dumpProfileLevels(mimeType);
}
}
if (candidateCodecList.isEmpty()) {
return null;
}
IjkMediaCodecInfo bestCodec = candidateCodecList.get(0);
for (IjkMediaCodecInfo codec : candidateCodecList) {
if (codec.mRank > bestCodec.mRank) {
bestCodec = codec;
}
}
if (bestCodec.mRank < IjkMediaCodecInfo.RANK_LAST_CHANCE) {
Log.w(TAG, String.format(Locale.US, "unaccetable codec: %s", bestCodec.mCodecInfo.getName()));
return null;
}
Log.i(TAG, String.format(Locale.US, "selected codec: %s rank=%d", bestCodec.mCodecInfo.getName(), bestCodec.mRank));
return bestCodec.mCodecInfo.getName();
}
}
返回的是解码器的名字,进而最后如果有名字返回true,没名字返回false。
? ? ijkmp_android_set_mediacodec_select_callback(mp, mediacodec_select_callback, ijkmp_get_weak_thiz(mp));
这句话同时告诉我们mediacodec_select_callback_opaque是java层的
IjkMediaPlayer
func_init_video_decoder
static IJKFF_Pipenode *func_init_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp)
{
IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;
IJKFF_Pipenode *node = NULL;
if (ffp->mediacodec_all_videos || ffp->mediacodec_avc || ffp->mediacodec_hevc || ffp->mediacodec_mpeg2)
node = ffpipenode_init_decoder_from_android_mediacodec(ffp, pipeline, opaque->weak_vout);
return node;
}
创建decoder解码器
func_config_video_decoder
static int func_config_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp)
{
IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;
int ret = NULL;
if (ffp->node_vdec) {
ret = ffpipenode_config_from_android_mediacodec(ffp, pipeline, opaque->weak_vout, ffp->node_vdec);
}
return ret;
}
设置解码器参数
func_open_video_decoder
static IJKFF_Pipenode *func_open_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp)
{
IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;
IJKFF_Pipenode *node = NULL;
if (ffp->mediacodec_all_videos || ffp->mediacodec_avc || ffp->mediacodec_hevc || ffp->mediacodec_mpeg2)
node = ffpipenode_create_video_decoder_from_android_mediacodec(ffp, pipeline, opaque->weak_vout);
if (!node) {
node = ffpipenode_create_video_decoder_from_ffplay(ffp);
}
return node;
}
打开解码器,并开始工作
func_open_audio_output
static SDL_Aout *func_open_audio_output(IJKFF_Pipeline *pipeline, FFPlayer *ffp)
{
SDL_Aout *aout = NULL;
if (ffp->opensles) {
aout = SDL_AoutAndroid_CreateForOpenSLES();
} else {
aout = SDL_AoutAndroid_CreateForAudioTrack();
}
if (aout)
SDL_AoutSetStereoVolume(aout, pipeline->opaque->left_volume, pipeline->opaque->right_volume);
return aout;
}
下面两篇文章对理解,上面方法的调用以及硬解码有帮组。
Android解码API
Android手机直播(四)Android Media API - 简书
硬解码使用的
ijkplayer 解码实现分析——硬解篇 - 知乎
|