当前位置:网站首页>Comprehensive overview of ijkplayer contour features for ijkplayer code walk through
Comprehensive overview of ijkplayer contour features for ijkplayer code walk through
2022-06-13 06:29:00 【That's right】
stay read_thread() Call in thread stream_component_open(ffp, st_index[AVMEDIA_TYPE_VIDEO]); function ,
This function decoder_start(&is->viddec, video_thread, ffp, “ff_video_dec”) Launched the video_thread Threads ,
This code is from android Program space , have a look ijkPlayer Basic contour features .
The first 1 part wideo_thread Thread source
//> Source path : libavformat/ff_ffplay.c in
static int video_thread(void *arg)
{
FFPlayer *ffp = (FFPlayer *)arg;
int ret = 0;
if (ffp->node_vdec) {
ret = ffpipenode_run_sync(ffp->node_vdec);
}
return ret;
}
//> Source path : libavformat/ff_ffpipenode.c in
int ffpipenode_run_sync(IJKFF_Pipenode *node)
{
return node->func_run_sync(node);
}
The first 2 part this func_run_sync() Is a pointer , Who the hell is he .
This pointer needs to be combed node->func_run_sync Point to the function implementation , The following contents can be found from 1 ~ 7 Look at it this way , Would be right ijkPlayer Have a clearer understanding .
//> 7. SDL_AMediaCodecJava_init() Initialize function contents
static SDL_AMediaCodec* SDL_AMediaCodecJava_init(JNIEnv *env, jobject android_media_codec)
{
SDLTRACE("%s", __func__);
jobject global_android_media_codec = (*env)->NewGlobalRef(env, android_media_codec);
if (J4A_ExceptionCheck__catchAll(env) || !global_android_media_codec) {
return NULL;
}
SDL_AMediaCodec *acodec = SDL_AMediaCodec_CreateInternal(sizeof(SDL_AMediaCodec_Opaque));
if (!acodec) {
SDL_JNI_DeleteGlobalRefP(env, &global_android_media_codec);
return NULL;
}
SDL_AMediaCodec_Opaque *opaque = acodec->opaque;
opaque->android_media_codec = global_android_media_codec;
acodec->opaque_class = &g_amediacodec_class;
acodec->func_delete = SDL_AMediaCodecJava_delete;
acodec->func_configure = NULL;
acodec->func_configure_surface = SDL_AMediaCodecJava_configure_surface;
acodec->func_start = SDL_AMediaCodecJava_start; //> The contents of the function are as follows
acodec->func_stop = SDL_AMediaCodecJava_stop;
acodec->func_flush = SDL_AMediaCodecJava_flush;
acodec->func_writeInputData = SDL_AMediaCodecJava_writeInputData;
acodec->func_dequeueInputBuffer = SDL_AMediaCodecJava_dequeueInputBuffer;
acodec->func_queueInputBuffer = SDL_AMediaCodecJava_queueInputBuffer;
acodec->func_dequeueOutputBuffer = SDL_AMediaCodecJava_dequeueOutputBuffer;
acodec->func_getOutputFormat = SDL_AMediaCodecJava_getOutputFormat;
acodec->func_releaseOutputBuffer = SDL_AMediaCodecJava_releaseOutputBuffer;
acodec->func_isInputBuffersValid = SDL_AMediaCodecJava_isInputBuffersValid;
SDL_AMediaCodec_increaseReference(acodec);
return acodec;
}
//> The function content is here
static sdl_amedia_status_t SDL_AMediaCodecJava_start(SDL_AMediaCodec* acodec)
{
SDLTRACE("%s", __func__);
JNIEnv *env = NULL;
if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
ALOGE("%s: SetupThreadEnv failed", __func__);
return SDL_AMEDIA_ERROR_UNKNOWN;
}
SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;
jobject android_media_codec = opaque->android_media_codec;
J4AC_MediaCodec__start(env, android_media_codec);
if (J4A_ExceptionCheck__catchAll(env)) {
//> This function is a callback android Program .
ALOGE("%s: start failed", __func__);
return SDL_AMEDIA_ERROR_UNKNOWN;
}
return SDL_AMEDIA_OK;
}
//> This function
static volatile int g_amediacodec_object_serial;
int SDL_AMediaCodec_create_object_serial()
{
int object_serial = __sync_add_and_fetch(&g_amediacodec_object_serial, 1);
if (object_serial == 0)
object_serial = __sync_add_and_fetch(&g_amediacodec_object_serial, 1);
return object_serial;
}
//> __sync_fetch_and_add Function function , In multithreading , Simple variable operation can ensure the correctness of the result .
//> 6. Source path :ijksdl_codec_android_mediacodec_java.c In file
SDL_AMediaCodec* SDL_AMediaCodecJava_createByCodecName(JNIEnv *env, const char *codec_name)
{
SDLTRACE("%s", __func__);
jobject android_media_codec = J4AC_MediaCodec__createByCodecName__withCString__catchAll(env, codec_name);
if (J4A_ExceptionCheck__catchAll(env) || !android_media_codec) {
return NULL;
}
SDL_AMediaCodec* acodec = SDL_AMediaCodecJava_init(env, android_media_codec); //> initialization Decoder control interface , see 7 Subsection description
acodec->object_serial = SDL_AMediaCodec_create_object_serial(); //> see 7 Subsection description
SDL_JNI_DeleteLocalRefP(env, &android_media_codec);
return acodec;
}
//> 5. Source path :pipeline/ffpipenode_androd_mediacodec_vdec.c in ,
IJKFF_Pipenode *ffpipenode_init_decoder_from_android_mediacodec(FFPlayer *ffp, IJKFF_Pipeline *pipeline, SDL_Vout *vout)
{
if (SDL_Android_GetApiLevel() < IJK_API_16_JELLY_BEAN)
return NULL;
if (!ffp || !ffp->is)
return NULL;
IJKFF_Pipenode *node = ffpipenode_alloc(sizeof(IJKFF_Pipenode_Opaque));
if (!node)
return node;
VideoState *is = ffp->is;
IJKFF_Pipenode_Opaque *opaque = node->opaque;
JNIEnv *env = NULL;
node->func_destroy = func_destroy;
if (ffp->mediacodec_sync) {
///> The initialization value of this parameter is not found
node->func_run_sync = func_run_sync_loop;
} else {
node->func_run_sync = func_run_sync; //> Point to this function , The first 1 Part of the video thread running functions
}
node->func_flush = func_flush;
opaque->pipeline = pipeline;
opaque->ffp = ffp;
opaque->decoder = &is->viddec; //> Point to is->viddec Video decoder
opaque->weak_vout = vout;
opaque->acodec_mutex = SDL_CreateMutex();
opaque->acodec_cond = SDL_CreateCond();
opaque->acodec_first_dequeue_output_mutex = SDL_CreateMutex();
opaque->acodec_first_dequeue_output_cond = SDL_CreateCond();
opaque->any_input_mutex = SDL_CreateMutex();
opaque->any_input_cond = SDL_CreateCond();
if (!opaque->acodec_cond || !opaque->acodec_cond || !opaque->acodec_first_dequeue_output_mutex || !opaque->acodec_first_dequeue_output_cond) {
ALOGE("%s:open_video_decoder: SDL_CreateCond() failed\n", __func__);
goto fail;
}
opaque->codecpar = avcodec_parameters_alloc();
if (!opaque->codecpar)
goto fail;
if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
ALOGE("%s:create: SetupThreadEnv failed\n", __func__);
goto fail;
}
ALOGI("%s:use default mediacodec name: %s\n", __func__, ffp->mediacodec_default_name);
strcpy(opaque->mcc.codec_name, ffp->mediacodec_default_name);
opaque->acodec = SDL_AMediaCodecJava_createByCodecName(env, ffp->mediacodec_default_name); //> establish android Callback interface related
if (!opaque->acodec) {
goto fail;
}
return node;
fail:
ALOGW("%s: init fail\n", __func__);
ffpipenode_free_p(&node);
return NULL;
}
//> 4. call ffpipenode_init_decoder_from_android_mediacodec() person
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;
}
//> 3. call func_init_video_decoder() person
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; //> Player volume control
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; //> Turn on the video decoder
pipeline->func_open_audio_output = func_open_audio_output; //> Turn on the audio decoder
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;
}
//> 2. call ffpipeline_create_from_android() person , Next function source code path :ijkplayer_android.c In file
IjkMediaPlayer *ijkmp_android_create(int(*msg_loop)(void*))
{
IjkMediaPlayer *mp = ijkmp_create(msg_loop); //> establish FFPlayer player , initialization ffp->msg_queue Users and android Program information exchange .
if (!mp)
goto fail;
mp->ffplayer->vout = SDL_VoutAndroid_CreateForAndroidSurface(); //> initialization vout->create_overlay = func_create_overlay
if (!mp->ffplayer->vout)
goto fail;
mp->ffplayer->pipeline = ffpipeline_create_from_android(mp->ffplayer); //> see 3 Some notes
if (!mp->ffplayer->pipeline)
goto fail;
ffpipeline_set_vout(mp->ffplayer->pipeline, mp->ffplayer->vout);//> Build a video pipeline
return mp;
fail:
ijkmp_dec_ref_p(&mp);
return NULL;
}
//> 1. call ijkmp_android_create() person , Next function source code path :ijkplayer_jni.c In file
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);
}
thus
We see that this program is used by users in android Program space through JNI Interface _native_setup() Create a player to call this program .
Let's sort out the relevant data structures in this part , In this way, we can get to the point .
struct IjkMediaPlayer {
volatile int ref_count;
pthread_mutex_t mutex;
FFPlayer *ffplayer; //> 1. FFPlayer Pointer to the player
int (*msg_loop)(void*); //> 2. msg_loop Thread used to exchange information with the player
SDL_Thread *msg_thread;
SDL_Thread _msg_thread;
int mp_state;
char *data_source; //> 3. The content of the playback source address set by the user
void *weak_thiz; //> 4. relation android Of jobject object
int restart;
int restart_from_beginning;
int seek_req;
long seek_msec;
};
typedef struct IJKFF_Pipeline_Opaque {
FFPlayer *ffp; //> Point to the player
SDL_mutex *surface_mutex;
jobject jsurface;
volatile bool is_surface_need_reconfigure;
bool (*mediacodec_select_callback)(void *opaque, ijkmp_mediacodecinfo_context *mcc);
void *mediacodec_select_callback_opaque; //> Callback interface
SDL_Vout *weak_vout;
float left_volume;
float right_volume;
} IJKFF_Pipeline_Opaque;
summary :
- The user is in android Program space through JNI Interface _native_setup() Create player ;
- IjkMediaPlayer Basic features such as structure definition , There is one FFPlayer、 Information exchange capability ;
- adopt Pipeline Add control interface ;
- Put player related events , adopt SDL_AMediaCodecJava_init() Function to implement the interface callback function ;
- User pass JNI Interface call IjkMediaPlayer_prepareAsync() function , Change the player state to the ready state ,
During this procedure, we call open_stream() function , establish read_thread() and video_thread() Threads .
thus , In combination with the previous several code walkthroughs , We are right. ijkPlayer The whole character can establish the outline cognition .
The first 3 part ijkPlayer How information is exchanged
have a look message_loop() The function is implemented as follows :
static int message_loop(void *arg)
{
MPTRACE("%s\n", __func__);
JNIEnv *env = NULL;
if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
ALOGE("%s: SetupThreadEnv failed\n", __func__);
return -1;
}
IjkMediaPlayer *mp = (IjkMediaPlayer*) arg;
JNI_CHECK_GOTO(mp, env, NULL, "mpjni: native_message_loop: null mp", LABEL_RETURN);
message_loop_n(env, mp);
LABEL_RETURN:
ijkmp_dec_ref_p(&mp);
MPTRACE("message_loop exit");
return 0;
}
//> Loop body function
static void message_loop_n(JNIEnv *env, IjkMediaPlayer *mp)
{
jobject weak_thiz = (jobject) ijkmp_get_weak_thiz(mp);
JNI_CHECK_GOTO(weak_thiz, env, NULL, "mpjni: message_loop_n: null weak_thiz", LABEL_RETURN);
while (1) {
AVMessage msg;
int retval = ijkmp_get_msg(mp, &msg, 1); //> Get the event content 、 first floor Information processing loop body
if (retval < 0)
break;
// block-get should never return 0
assert(retval > 0);
switch (msg.what) {
//> The second floor The main body of the information processing cycle
case FFP_MSG_FLUSH:
MPTRACE("FFP_MSG_FLUSH:\n");
post_event(env, weak_thiz, MEDIA_NOP, 0, 0);
break;
case FFP_MSG_ERROR:
MPTRACE("FFP_MSG_ERROR: %d\n", msg.arg1);
post_event(env, weak_thiz, MEDIA_ERROR, MEDIA_ERROR_IJK_PLAYER, msg.arg1);
break;
case FFP_MSG_PREPARED:
MPTRACE("FFP_MSG_PREPARED:\n");
post_event(env, weak_thiz, MEDIA_PREPARED, 0, 0);
break;
case FFP_MSG_COMPLETED:
MPTRACE("FFP_MSG_COMPLETED:\n");
post_event(env, weak_thiz, MEDIA_PLAYBACK_COMPLETE, 0, 0);
break;
case FFP_MSG_VIDEO_SIZE_CHANGED: //> Resolution change
MPTRACE("FFP_MSG_VIDEO_SIZE_CHANGED: %d, %d\n", msg.arg1, msg.arg2);
post_event(env, weak_thiz, MEDIA_SET_VIDEO_SIZE, msg.arg1, msg.arg2);
break;
case FFP_MSG_SAR_CHANGED:
MPTRACE("FFP_MSG_SAR_CHANGED: %d, %d\n", msg.arg1, msg.arg2);
post_event(env, weak_thiz, MEDIA_SET_VIDEO_SAR, msg.arg1, msg.arg2);
break;
case FFP_MSG_VIDEO_RENDERING_START:
MPTRACE("FFP_MSG_VIDEO_RENDERING_START:\n");
post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_VIDEO_RENDERING_START, 0);
break;
case FFP_MSG_AUDIO_RENDERING_START:
MPTRACE("FFP_MSG_AUDIO_RENDERING_START:\n");
post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_AUDIO_RENDERING_START, 0);
break;
case FFP_MSG_VIDEO_ROTATION_CHANGED: //> Horizontal and vertical screen changes
MPTRACE("FFP_MSG_VIDEO_ROTATION_CHANGED: %d\n", msg.arg1);
post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_VIDEO_ROTATION_CHANGED, msg.arg1);
break;
case FFP_MSG_AUDIO_DECODED_START:
MPTRACE("FFP_MSG_AUDIO_DECODED_START:\n");
post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_AUDIO_DECODED_START, 0);
break;
case FFP_MSG_VIDEO_DECODED_START:
MPTRACE("FFP_MSG_VIDEO_DECODED_START:\n");
post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_VIDEO_DECODED_START, 0);
break;
case FFP_MSG_OPEN_INPUT:
MPTRACE("FFP_MSG_OPEN_INPUT:\n"); //> Open input data
post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_OPEN_INPUT, 0);
break;
case FFP_MSG_FIND_STREAM_INFO:
MPTRACE("FFP_MSG_FIND_STREAM_INFO:\n"); //> Decoder matching succeeded
post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_FIND_STREAM_INFO, 0);
break;
case FFP_MSG_COMPONENT_OPEN:
MPTRACE("FFP_MSG_COMPONENT_OPEN:\n"); //> Turn on the flow
post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_COMPONENT_OPEN, 0);
break;
case FFP_MSG_BUFFERING_START:
MPTRACE("FFP_MSG_BUFFERING_START:\n");
post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_BUFFERING_START, msg.arg1);
break;
case FFP_MSG_BUFFERING_END:
MPTRACE("FFP_MSG_BUFFERING_END:\n");
post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_BUFFERING_END, msg.arg1);
break;
case FFP_MSG_BUFFERING_UPDATE:
// MPTRACE("FFP_MSG_BUFFERING_UPDATE: %d, %d", msg.arg1, msg.arg2);
post_event(env, weak_thiz, MEDIA_BUFFERING_UPDATE, msg.arg1, msg.arg2);
break;
case FFP_MSG_BUFFERING_BYTES_UPDATE:
break;
case FFP_MSG_BUFFERING_TIME_UPDATE:
break;
case FFP_MSG_SEEK_COMPLETE:
MPTRACE("FFP_MSG_SEEK_COMPLETE:\n");
post_event(env, weak_thiz, MEDIA_SEEK_COMPLETE, 0, 0);
break;
case FFP_MSG_ACCURATE_SEEK_COMPLETE:
MPTRACE("FFP_MSG_ACCURATE_SEEK_COMPLETE:\n");
post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_MEDIA_ACCURATE_SEEK_COMPLETE, msg.arg1);
break;
case FFP_MSG_PLAYBACK_STATE_CHANGED:
break;
case FFP_MSG_TIMED_TEXT:
if (msg.obj) {
jstring text = (*env)->NewStringUTF(env, (char *)msg.obj);
post_event2(env, weak_thiz, MEDIA_TIMED_TEXT, 0, 0, text);
J4A_DeleteLocalRef__p(env, &text);
}
else {
post_event2(env, weak_thiz, MEDIA_TIMED_TEXT, 0, 0, NULL);
}
break;
case FFP_MSG_GET_IMG_STATE:
if (msg.obj) {
jstring file_name = (*env)->NewStringUTF(env, (char *)msg.obj);
post_event2(env, weak_thiz, MEDIA_GET_IMG_STATE, msg.arg1, msg.arg2, file_name);
J4A_DeleteLocalRef__p(env, &file_name);
}
else {
post_event2(env, weak_thiz, MEDIA_GET_IMG_STATE, msg.arg1, msg.arg2, NULL);
}
break;
case FFP_MSG_VIDEO_SEEK_RENDERING_START:
MPTRACE("FFP_MSG_VIDEO_SEEK_RENDERING_START:\n");
post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_VIDEO_SEEK_RENDERING_START, msg.arg1);
break;
case FFP_MSG_AUDIO_SEEK_RENDERING_START:
MPTRACE("FFP_MSG_AUDIO_SEEK_RENDERING_START:\n");
post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_AUDIO_SEEK_RENDERING_START, msg.arg1);
break;
default:
ALOGE("unknown FFP_MSG_xxx(%d)\n", msg.what);
break;
}
msg_free_res(&msg);
}
LABEL_RETURN:
;
}
first floor Information circulation processing
/* need to call msg_free_res for freeing the resouce obtained in msg */
int ijkmp_get_msg(IjkMediaPlayer *mp, AVMessage *msg, int block)
{
assert(mp);
while (1) {
int continue_wait_next_msg = 0;
int retval = msg_queue_get(&mp->ffplayer->msg_queue, msg, block); //> from Get messages from the information queue of the player
if (retval <= 0)
return retval;
switch (msg->what) {
//> Control the player status according to the information content
case FFP_MSG_PREPARED: //> The player enters the ready state
MPTRACE("ijkmp_get_msg: FFP_MSG_PREPARED\n");
pthread_mutex_lock(&mp->mutex);
if (mp->mp_state == MP_STATE_ASYNC_PREPARING) {
ijkmp_change_state_l(mp, MP_STATE_PREPARED);
} else {
// FIXME: 1: onError() ?
av_log(mp->ffplayer, AV_LOG_DEBUG, "FFP_MSG_PREPARED: expecting mp_state==MP_STATE_ASYNC_PREPARING\n");
}
if (!mp->ffplayer->start_on_prepared) {
ijkmp_change_state_l(mp, MP_STATE_PAUSED);
}
pthread_mutex_unlock(&mp->mutex);
break;
case FFP_MSG_COMPLETED:
MPTRACE("ijkmp_get_msg: FFP_MSG_COMPLETED\n");
pthread_mutex_lock(&mp->mutex);
mp->restart = 1;
mp->restart_from_beginning = 1;
ijkmp_change_state_l(mp, MP_STATE_COMPLETED);
pthread_mutex_unlock(&mp->mutex);
break;
case FFP_MSG_SEEK_COMPLETE:
MPTRACE("ijkmp_get_msg: FFP_MSG_SEEK_COMPLETE\n");
pthread_mutex_lock(&mp->mutex);
mp->seek_req = 0;
mp->seek_msec = 0;
pthread_mutex_unlock(&mp->mutex);
break;
case FFP_REQ_START: //> Start the player
MPTRACE("ijkmp_get_msg: FFP_REQ_START\n");
continue_wait_next_msg = 1;
pthread_mutex_lock(&mp->mutex);
if (0 == ikjmp_chkst_start_l(mp->mp_state)) {
// FIXME: 8 check seekable
if (mp->restart) {
if (mp->restart_from_beginning) {
av_log(mp->ffplayer, AV_LOG_DEBUG, "ijkmp_get_msg: FFP_REQ_START: restart from beginning\n");
retval = ffp_start_from_l(mp->ffplayer, 0);
if (retval == 0)
ijkmp_change_state_l(mp, MP_STATE_STARTED);
} else {
av_log(mp->ffplayer, AV_LOG_DEBUG, "ijkmp_get_msg: FFP_REQ_START: restart from seek pos\n");
retval = ffp_start_l(mp->ffplayer);
if (retval == 0)
ijkmp_change_state_l(mp, MP_STATE_STARTED);
}
mp->restart = 0;
mp->restart_from_beginning = 0;
} else {
av_log(mp->ffplayer, AV_LOG_DEBUG, "ijkmp_get_msg: FFP_REQ_START: start on fly\n");
retval = ffp_start_l(mp->ffplayer);
if (retval == 0)
ijkmp_change_state_l(mp, MP_STATE_STARTED);
}
}
pthread_mutex_unlock(&mp->mutex);
break;
case FFP_REQ_PAUSE: //> Pause the player
MPTRACE("ijkmp_get_msg: FFP_REQ_PAUSE\n");
continue_wait_next_msg = 1;
pthread_mutex_lock(&mp->mutex);
if (0 == ikjmp_chkst_pause_l(mp->mp_state)) {
int pause_ret = ffp_pause_l(mp->ffplayer);
if (pause_ret == 0)
ijkmp_change_state_l(mp, MP_STATE_PAUSED);
}
pthread_mutex_unlock(&mp->mutex);
break;
case FFP_REQ_SEEK:
MPTRACE("ijkmp_get_msg: FFP_REQ_SEEK\n");
continue_wait_next_msg = 1;
pthread_mutex_lock(&mp->mutex);
if (0 == ikjmp_chkst_seek_l(mp->mp_state)) {
mp->restart_from_beginning = 0;
if (0 == ffp_seek_to_l(mp->ffplayer, msg->arg1)) {
av_log(mp->ffplayer, AV_LOG_DEBUG, "ijkmp_get_msg: FFP_REQ_SEEK: seek to %d\n", (int)msg->arg1);
}
}
pthread_mutex_unlock(&mp->mutex);
break;
}
if (continue_wait_next_msg) {
msg_free_res(msg);
continue;
}
return retval;
}
return -1;
}
//> Get the event content from the queue
/* return < 0 if aborted, 0 if no msg and > 0 if msg. */
inline static int msg_queue_get(MessageQueue *q, AVMessage *msg, int block)
{
AVMessage *msg1;
int ret;
SDL_LockMutex(q->mutex);
for (;;) {
if (q->abort_request) {
ret = -1;
break;
}
msg1 = q->first_msg;
if (msg1) {
q->first_msg = msg1->next;
if (!q->first_msg)
q->last_msg = NULL;
q->nb_messages--;
*msg = *msg1;
msg1->obj = NULL;
#ifdef FFP_MERGE
av_free(msg1);
#else
msg1->next = q->recycle_msg;
q->recycle_msg = msg1;
#endif
ret = 1;
break;
} else if (!block) {
ret = 0;
break;
} else {
SDL_CondWait(q->cond, q->mutex);
}
}
SDL_UnlockMutex(q->mutex);
return ret;
}
summary :
- Creating ijkPlayer when , hold msg_loop() Function associated with the player ;
- In message processing Two layer processing mechanism , first floor ffplay Player related event handling ,
The second layer is the message exchange processing between Android and the player .
边栏推荐
- 万能播放器 PotPlayer 的下载与安装,直播流 m3u8 导入
- Intelligent digital asset management helps enterprises win the post epidemic Era
- You should consider upgrading via
- 【新手上路常见问答】关于技术管理
- 欧姆龙平替国产大货—JY-V640半导体晶元盒读写器
- pthon 执行 pip 指令报错 You should consider upgrading via ...
- Kotlin collaboration - simple use of collaboration
- Kotlin data flow - flow
- [JS] array de duplication
- Scrcpy source code walk 2 how to connect a client to a mobile server
猜你喜欢

Echart line chart: different colors are displayed when the names of multiple line charts are the same

JVM基础

Uniapp secondary encapsulates uview components, and the parent component controls display and hiding

‘ipconfig‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

Kotlin collaboration channel

MFS explanation (V) -- MFS metadata log server installation and configuration

1+1 > 2, share creators can help you achieve

Jetpack - basic use of room

JetPack - - -WorkManger

电镀挂具RFID工序管理解决方案
随机推荐
Kotlin collaboration - start and cancel, scope
Super model logo online design and production tool
Echart histogram: echart implements stacked histogram
Wechat applet (pull-down refresh data) novice to
超有范的 logo 在线设计制作工具
Echart histogram: stacked histogram displays value
Ijkplayer compilation process record
SSM框架整合--->简单后台管理
[solution] camunda deployment process should point to a running platform rest API
Wechat applet (get location)
The boys x pubgmobile linkage is coming! Check out the latest game posters
‘ipconfig‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。
Fidde breakpoint interception
MFS详解(五)——MFS元数据日志服务器安装与配置
1+1 > 2, share creators can help you achieve
App performance test: (III) traffic monitoring
Wechat applet (function transfer parameters, transfer multiple parameters, page Jump)
【js】var、let、const
Applet Use of spaces
Dart class inherits and implements mixed operators