iOS ijkplayer 消息循环
_mediaPlayer = ijkmp_ios_create(media_player_msg_loop);//开始消息循环
int media_player_msg_loop(void* arg)
{
@autoreleasepool {
IjkMediaPlayer *mp = (IjkMediaPlayer*)arg;
__weak IJKFFMoviePlayerController *ffpController = ffplayerRetain(ijkmp_set_weak_thiz(mp, NULL));
while (ffpController) {
@autoreleasepool {
IJKFFMoviePlayerMessage *msg = [ffpController obtainMessage];
if (!msg)
break;
int retval = ijkmp_get_msg(mp, &msg->_msg, 1);
if (retval < 0)
break;
// block-get should never return 0
assert(retval > 0);
//此处发送消息
[ffpController performSelectorOnMainThread:@selector(postEvent:) withObject:msg waitUntilDone:NO];
}
}
// retained in prepare_async, before SDL_CreateThreadEx
ijkmp_dec_ref_p(&mp);
return 0;
}
}
//消息循环处理函数
在消息循环处理函数中有两个关键地方
ijkmp_get_msg(mp, &msg->_msg, 1);//获取到消息并对消息做初步处理
[ffpController performSelectorOnMainThread:@selector(postEvent:) withObject:msg waitUntilDone:NO];//将消息通过postEvent函数发出并做消息处理
//获取消息并对消息做初步处理
/* 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);
if (retval <= 0)
return retval;
switch (msg->what) {
case FFP_MSG_PREPARED:
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: one rror() ?
av_log(mp->ffplayer, AV_LOG_DEBUG, "FFP_MSG_PREPARED: expecting mp_state==MP_STATE_ASYNC_PREPARING\n");
}
if (ffp_is_paused_l(mp->ffplayer)) {
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:
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:
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;
}
//通过此函数将消息发出并对消息做出处理
- (void)postEvent: (IJKFFMoviePlayerMessage *)msg
{
if (!msg)
return;
AVMessage *avmsg = &msg->_msg;
switch (avmsg->what) {
case FFP_MSG_FLUSH:
break;
case FFP_MSG_ERROR: {
NSLog(@"FFP_MSG_ERROR: %d\n", avmsg->arg1);
[self setScreenOn:NO];
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMPMoviePlayerPlaybackStateDidChangeNotification
object:self];
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMPMoviePlayerPlaybackDidFinishNotification
object:self
userInfo:@{
IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey: @(IJKMPMovieFinishReasonPlaybackError),
@"error": @(avmsg->arg1)}];
break;
}
case FFP_MSG_PREPARED: {
NSLog(@"FFP_MSG_PREPARED:\n");
_monitor.prepareDuration = (int64_t)SDL_GetTickHR() - _monitor.prepareStartTick;
int64_t vdec = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_VIDEO_DECODER, FFP_PROPV_DECODER_UNKNOWN);
switch (vdec) {
case FFP_PROPV_DECODER_VIDEOTOOLBOX:
_monitor.vdecoder = @"VideoToolbox";
break;
case FFP_PROPV_DECODER_AVCODEC:
_monitor.vdecoder = [NSString stringWithFormat:@"avcodec %d.%d.%d",
LIBAVCODEC_VERSION_MAJOR,
LIBAVCODEC_VERSION_MINOR,
LIBAVCODEC_VERSION_MICRO];
break;
default:
_monitor.vdecoder = @"Unknown";
break;
}
IjkMediaMeta *rawMeta = ijkmp_get_meta_l(_mediaPlayer);
if (rawMeta) {
ijkmeta_lock(rawMeta);
NSMutableDictionary *newMediaMeta = [[NSMutableDictionary alloc] init];
fillMetaInternal(newMediaMeta, rawMeta, IJKM_KEY_FORMAT, nil);
fillMetaInternal(newMediaMeta, rawMeta, IJKM_KEY_DURATION_US, nil);
fillMetaInternal(newMediaMeta, rawMeta, IJKM_KEY_START_US, nil);
fillMetaInternal(newMediaMeta, rawMeta, IJKM_KEY_BITRATE, nil);
fillMetaInternal(newMediaMeta, rawMeta, IJKM_KEY_VIDEO_STREAM, nil);
fillMetaInternal(newMediaMeta, rawMeta, IJKM_KEY_AUDIO_STREAM, nil);
int64_t video_stream = ijkmeta_get_int64_l(rawMeta, IJKM_KEY_VIDEO_STREAM, -1);
int64_t audio_stream = ijkmeta_get_int64_l(rawMeta, IJKM_KEY_AUDIO_STREAM, -1);
NSMutableArray *streams = [[NSMutableArray alloc] init];
size_t count = ijkmeta_get_children_count_l(rawMeta);
for(size_t i = 0; i < count; ++i) {
IjkMediaMeta *streamRawMeta = ijkmeta_get_child_l(rawMeta, i);
NSMutableDictionary *streamMeta = [[NSMutableDictionary alloc] init];
if (streamRawMeta) {
fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_TYPE, k_IJKM_VAL_TYPE__UNKNOWN);
const char *type = ijkmeta_get_string_l(streamRawMeta, IJKM_KEY_TYPE);
if (type) {
fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_CODEC_NAME, nil);
fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_CODEC_PROFILE, nil);
fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_CODEC_LONG_NAME, nil);
fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_BITRATE, nil);
if (0 == strcmp(type, IJKM_VAL_TYPE__VIDEO)) {
fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_WIDTH, nil);
fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_HEIGHT, nil);
fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_FPS_NUM, nil);
fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_FPS_DEN, nil);
fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_TBR_NUM, nil);
fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_TBR_DEN, nil);
fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_SAR_NUM, nil);
fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_SAR_DEN, nil);
if (video_stream == i) {
_monitor.videoMeta = streamMeta;
int64_t fps_num = ijkmeta_get_int64_l(streamRawMeta, IJKM_KEY_FPS_NUM, 0);
int64_t fps_den = ijkmeta_get_int64_l(streamRawMeta, IJKM_KEY_FPS_DEN, 0);
if (fps_num > 0 && fps_den > 0) {
_fpsInMeta = ((CGFloat)(fps_num)) / fps_den;
NSLog(@"fps in meta %f\n", _fpsInMeta);
}
}
} else if (0 == strcmp(type, IJKM_VAL_TYPE__AUDIO)) {
fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_SAMPLE_RATE, nil);
fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_CHANNEL_LAYOUT, nil);
if (audio_stream == i) {
_monitor.audioMeta = streamMeta;
}
}
}
}
[streams addObject:streamMeta];
}
[newMediaMeta setObject:streams forKey:kk_IJKM_KEY_STREAMS];
ijkmeta_unlock(rawMeta);
_monitor.mediaMeta = newMediaMeta;
}
ijkmp_set_playback_rate(_mediaPlayer, [self playbackRate]);
ijkmp_set_playback_volume(_mediaPlayer, [self playbackVolume]);
[self startHudTimer];
_isPreparedToPlay = YES;
[[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification object:self];
_loadState = IJKMPMovieLoadStatePlayable | IJKMPMovieLoadStatePlaythroughOK;
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMPMoviePlayerLoadStateDidChangeNotification
object:self];
break;
}
case FFP_MSG_COMPLETED: {
[self setScreenOn:NO];
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMPMoviePlayerPlaybackStateDidChangeNotification
object:self];
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMPMoviePlayerPlaybackDidFinishNotification
object:self
userInfo:@{IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey: @(IJKMPMovieFinishReasonPlaybackEnded)}];
break;
}
case FFP_MSG_VIDEO_SIZE_CHANGED:
NSLog(@"FFP_MSG_VIDEO_SIZE_CHANGED: %d, %d\n", avmsg->arg1, avmsg->arg2);
if (avmsg->arg1 > 0)
_videoWidth = avmsg->arg1;
if (avmsg->arg2 > 0)
_videoHeight = avmsg->arg2;
[self changeNaturalSize];
break;
case FFP_MSG_SAR_CHANGED:
NSLog(@"FFP_MSG_SAR_CHANGED: %d, %d\n", avmsg->arg1, avmsg->arg2);
if (avmsg->arg1 > 0)
_sampleAspectRatioNumerator = avmsg->arg1;
if (avmsg->arg2 > 0)
_sampleAspectRatioDenominator = avmsg->arg2;
[self changeNaturalSize];
break;
case FFP_MSG_BUFFERING_START: {
NSLog(@"FFP_MSG_BUFFERING_START:\n");
_monitor.lastPrerollStartTick = (int64_t)SDL_GetTickHR();
_loadState = IJKMPMovieLoadStateStalled;
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMPMoviePlayerLoadStateDidChangeNotification
object:self];
break;
}
case FFP_MSG_BUFFERING_END: {
NSLog(@"FFP_MSG_BUFFERING_END:\n");
_monitor.lastPrerollDuration = (int64_t)SDL_GetTickHR() - _monitor.lastPrerollStartTick;
_loadState = IJKMPMovieLoadStatePlayable | IJKMPMovieLoadStatePlaythroughOK;
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMPMoviePlayerLoadStateDidChangeNotification
object:self];
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMPMoviePlayerPlaybackStateDidChangeNotification
object:self];
break;
}
case FFP_MSG_BUFFERING_UPDATE:
_bufferingPosition = avmsg->arg1;
_bufferingProgress = avmsg->arg2;
// NSLog(@"FFP_MSG_BUFFERING_UPDATE: %d, %%%d\n", _bufferingPosition, _bufferingProgress);
break;
case FFP_MSG_BUFFERING_BYTES_UPDATE:
// NSLog(@"FFP_MSG_BUFFERING_BYTES_UPDATE: %d\n", avmsg->arg1);
break;
case FFP_MSG_BUFFERING_TIME_UPDATE:
_bufferingTime = avmsg->arg1;
// NSLog(@"FFP_MSG_BUFFERING_TIME_UPDATE: %d\n", avmsg->arg1);
break;
case FFP_MSG_PLAYBACK_STATE_CHANGED:
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMPMoviePlayerPlaybackStateDidChangeNotification
object:self];
break;
case FFP_MSG_SEEK_COMPLETE: {
NSLog(@"FFP_MSG_SEEK_COMPLETE:\n");
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMPMoviePlayerDidSeekCompleteNotification
object:self
userInfo:@{IJKMPMoviePlayerDidSeekCompleteTargetKey: @(avmsg->arg1),
IJKMPMoviePlayerDidSeekCompleteErrorKey: @(avmsg->arg2)}];
_seeking = NO;
break;
}
case FFP_MSG_VIDEO_DECODER_OPEN: {
_isVideoToolboxOpen = avmsg->arg1;
NSLog(@"FFP_MSG_VIDEO_DECODER_OPEN: %@\n", _isVideoToolboxOpen ? @"true" : @"false");
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMPMoviePlayerVideoDecoderOpenNotification
object:self];
break;
}
case FFP_MSG_VIDEO_RENDERING_START: {
NSLog(@"FFP_MSG_VIDEO_RENDERING_START:\n");
_monitor.firstVideoFrameLatency = (int64_t)SDL_GetTickHR() - _monitor.prepareStartTick;
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMPMoviePlayerFirstVideoFrameRenderedNotification
object:self];
break;
}
case FFP_MSG_AUDIO_RENDERING_START: {
NSLog(@"FFP_MSG_AUDIO_RENDERING_START:\n");
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMPMoviePlayerFirstAudioFrameRenderedNotification
object:self];
break;
}
case FFP_MSG_ACCURATE_SEEK_COMPLETE: {
NSLog(@"FFP_MSG_ACCURATE_SEEK_COMPLETE:\n");
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMPMoviePlayerAccurateSeekCompleteNotification
object:self
userInfo:@{IJKMPMoviePlayerDidAccurateSeekCompleteCurPos: @(avmsg->arg1)}];
break;
}
default:
// NSLog(@"unknown FFP_MSG_xxx(%d)\n", avmsg->what);
break;
}
[_msgPool recycle:msg];
}