提交 cd58dd6b 编写于 作者: R raymondzheng

ijkplayer: support accurate seek

上级 f80a1d07
......@@ -133,6 +133,8 @@ enum media_info_type {
//100xx
MEDIA_INFO_VIDEO_ROTATION_CHANGED = 10001,
MEDIA_INFO_AUDIO_RENDERING_START = 10002,
MEDIA_INFO_MEDIA_ACCURATE_SEEK_COMPLETE = 10100,
};
typedef struct ijkmp_mediacodecinfo_context
......
......@@ -965,6 +965,10 @@ static void message_loop_n(JNIEnv *env, IjkMediaPlayer *mp)
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:
......
......@@ -42,6 +42,7 @@
#define FFP_MSG_SEEK_COMPLETE 600 /* arg1 = seek position, arg2 = error */
#define FFP_MSG_PLAYBACK_STATE_CHANGED 700
#define FFP_MSG_TIMED_TEXT 800
#define FFP_MSG_ACCURATE_SEEK_COMPLETE 900 /* arg1 = current position*/
#define FFP_MSG_VIDEO_DECODER_OPEN 10001
......
......@@ -806,7 +806,10 @@ static void stream_close(FFPlayer *ffp)
frame_queue_destory(&is->pictq);
frame_queue_destory(&is->sampq);
frame_queue_destory(&is->subpq);
SDL_DestroyCond(is->audio_accurate_seek_cond);
SDL_DestroyCond(is->video_accurate_seek_cond);
SDL_DestroyCond(is->continue_read_thread);
SDL_DestroyMutex(is->accurate_seek_mutex);
SDL_DestroyMutex(is->play_mutex);
#if !CONFIG_AVFILTER
sws_freeContext(is->img_convert_ctx);
......@@ -1268,6 +1271,59 @@ static int queue_picture(FFPlayer *ffp, AVFrame *src_frame, double pts, double d
{
VideoState *is = ffp->is;
Frame *vp;
int video_accurate_seek_fail = 0;
int64_t video_seek_pos = 0;
if (ffp->enable_accurate_seek && is->video_accurate_seek_req && !is->seek_req) {
if (!isnan(pts)) {
video_seek_pos = is->seek_pos;
if (pts * 1000 * 1000 < is->seek_pos) {
if (is->drop_vframe_count == 0) {
av_log(NULL, AV_LOG_INFO, "video accurate_seek start, is->seek_pos=%lld, pts=%lf\n", is->seek_pos, pts);
}
is->drop_vframe_count++;
if (is->drop_vframe_count < MAX_KEY_FRAME_INTERVAL) {
return 1; // drop some old frame when do accurate seek
} else {
av_log(NULL, AV_LOG_WARNING, "video accurate_seek is error, is->drop_vframe_count=%d\n", is->drop_vframe_count);
video_accurate_seek_fail = 1; // if KEY_FRAME interval too big, disable accurate seek
}
} else {
av_log(NULL, AV_LOG_INFO, "video accurate_seek is ok, is->drop_vframe_count =%d, is->seek_pos=%lld, pts=%lf\n", is->drop_vframe_count, is->seek_pos, pts);
if (video_seek_pos == is->seek_pos) {
is->drop_vframe_count = 0;
SDL_LockMutex(is->accurate_seek_mutex);
is->video_accurate_seek_req = 0;
SDL_CondSignal(is->audio_accurate_seek_cond);
if (video_seek_pos == is->seek_pos && is->audio_accurate_seek_req && !is->abort_request)
SDL_CondWait(is->video_accurate_seek_cond, is->accurate_seek_mutex);
ffp_notify_msg2(ffp, FFP_MSG_ACCURATE_SEEK_COMPLETE, (int)(pts * 1000));
if (video_seek_pos != is->seek_pos && !is->abort_request) {
is->video_accurate_seek_req = 1;
SDL_UnlockMutex(is->accurate_seek_mutex);
return 1;
}
SDL_UnlockMutex(is->accurate_seek_mutex);
}
}
} else {
video_accurate_seek_fail = 1;
}
if (video_accurate_seek_fail) {
if (!isnan(pts)) {
ffp_notify_msg2(ffp, FFP_MSG_ACCURATE_SEEK_COMPLETE, (int)(pts * 1000));
}
ffp->enable_accurate_seek = 0;
is->drop_vframe_count = 0;
SDL_LockMutex(is->accurate_seek_mutex);
is->video_accurate_seek_req = 0;
SDL_CondSignal(is->audio_accurate_seek_cond);
SDL_UnlockMutex(is->accurate_seek_mutex);
}
}
#if defined(DEBUG_SYNC)
printf("frame_type=%c pts=%0.3f\n",
......@@ -1642,6 +1698,8 @@ static int audio_thread(void *arg)
int got_frame = 0;
AVRational tb;
int ret = 0;
int audio_accurate_seek_fail = 0;
int64_t audio_seek_pos = 0;
if (!frame)
return AVERROR(ENOMEM);
......@@ -1653,6 +1711,58 @@ static int audio_thread(void *arg)
if (got_frame) {
tb = (AVRational){1, frame->sample_rate};
if (ffp->enable_accurate_seek && is->audio_accurate_seek_req && !is->seek_req) {
double frame_pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);
double audio_clock = 0;
if (!isnan(frame_pts)) {
double samples_duration = (double) frame->nb_samples / frame->sample_rate;
audio_clock = frame_pts + samples_duration;
audio_seek_pos = is->seek_pos;
if (audio_clock * 1000 * 1000 < is->seek_pos) {
if (is->drop_aframe_count == 0) {
av_log(NULL, AV_LOG_INFO, "audio accurate_seek start, is->seek_pos=%lld, audio_clock=%lf\n", is->seek_pos, audio_clock);
}
is->drop_aframe_count++;
if (is->drop_aframe_count < MAX_KEY_FRAME_INTERVAL) {
continue; // drop some old frame when do accurate seek
} else {
av_log(NULL, AV_LOG_INFO, "audio accurate_seek is error, is->drop_aframe_count=%d\n", is->drop_aframe_count);
audio_accurate_seek_fail = 1;
}
} else {
if (audio_seek_pos == is->seek_pos) {
av_log(NULL, AV_LOG_INFO, "audio accurate_seek is ok, is->drop_aframe_count=%d\n", is->drop_aframe_count);
is->drop_aframe_count = 0;
SDL_LockMutex(is->accurate_seek_mutex);
is->audio_accurate_seek_req = 0;
SDL_CondSignal(is->video_accurate_seek_cond);
if (audio_seek_pos == is->seek_pos && is->video_accurate_seek_req && !is->abort_request)
SDL_CondWait(is->audio_accurate_seek_cond, is->accurate_seek_mutex);
if (audio_seek_pos != is->seek_pos && !is->abort_request) {
is->audio_accurate_seek_req = 1;
SDL_UnlockMutex(is->accurate_seek_mutex);
continue;
}
SDL_UnlockMutex(is->accurate_seek_mutex);
}
}
} else {
audio_accurate_seek_fail = 1;
}
if (audio_accurate_seek_fail) {
if (!isnan(frame_pts)) {
ffp_notify_msg2(ffp, FFP_MSG_ACCURATE_SEEK_COMPLETE, (int)(audio_clock * 1000));
}
ffp->enable_accurate_seek = 0;
is->drop_aframe_count = 0;
SDL_LockMutex(is->accurate_seek_mutex);
is->audio_accurate_seek_req = 0;
SDL_CondSignal(is->video_accurate_seek_cond);
SDL_UnlockMutex(is->accurate_seek_mutex);
}
}
#if CONFIG_AVFILTER
dec_channel_layout = get_valid_channel_layout(frame->channel_layout, av_frame_get_channels(frame));
......@@ -2837,6 +2947,18 @@ static int read_thread(void *arg)
if (is->pause_req)
step_to_next_frame_l(ffp);
SDL_UnlockMutex(ffp->is->play_mutex);
if (ffp->enable_accurate_seek) {
is->drop_aframe_count = 0;
is->drop_vframe_count = 0;
SDL_LockMutex(is->accurate_seek_mutex);
is->audio_accurate_seek_req = 1;
is->video_accurate_seek_req = 1;
SDL_CondSignal(is->audio_accurate_seek_cond);
SDL_CondSignal(is->video_accurate_seek_cond);
SDL_UnlockMutex(is->accurate_seek_mutex);
}
ffp_notify_msg3(ffp, FFP_MSG_SEEK_COMPLETE, (int)fftime_to_milliseconds(seek_target), ret);
ffp_toggle_buffering(ffp, 1);
}
......@@ -3054,6 +3176,16 @@ static VideoState *stream_open(FFPlayer *ffp, const char *filename, AVInputForma
goto fail;
}
if (!(is->video_accurate_seek_cond = SDL_CreateCond())) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
ffp->enable_accurate_seek = 0;
}
if (!(is->audio_accurate_seek_cond = SDL_CreateCond())) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
ffp->enable_accurate_seek = 0;
}
init_clock(&is->vidclk, &is->videoq.serial);
init_clock(&is->audclk, &is->audioq.serial);
init_clock(&is->extclk, &is->extclk.serial);
......@@ -3063,6 +3195,7 @@ static VideoState *stream_open(FFPlayer *ffp, const char *filename, AVInputForma
is->av_sync_type = ffp->av_sync_type;
is->play_mutex = SDL_CreateMutex();
is->accurate_seek_mutex = SDL_CreateMutex();
ffp->is = is;
is->pause_req = !ffp->start_on_prepared;
......@@ -3681,6 +3814,15 @@ int ffp_stop_l(FFPlayer *ffp)
}
msg_queue_abort(&ffp->msg_queue);
if (ffp->enable_accurate_seek && is && is->accurate_seek_mutex
&& is->audio_accurate_seek_cond && is->video_accurate_seek_cond) {
SDL_LockMutex(is->accurate_seek_mutex);
is->audio_accurate_seek_req = 0;
is->video_accurate_seek_req = 0;
SDL_CondSignal(is->audio_accurate_seek_cond);
SDL_CondSignal(is->video_accurate_seek_cond);
SDL_UnlockMutex(is->accurate_seek_mutex);
}
return 0;
}
......
......@@ -128,6 +128,8 @@
#define MIN_PKT_DURATION 15
#define MAX_KEY_FRAME_INTERVAL 1000 // max key frame interval is 1000
#ifdef FFP_MERGE
#define CURSOR_HIDE_DELAY 1000000
......@@ -381,6 +383,14 @@ typedef struct VideoState {
volatile int latest_seek_load_serial;
volatile int64_t latest_seek_load_start_at;
int drop_aframe_count;
int drop_vframe_count;
int audio_accurate_seek_req;
int video_accurate_seek_req;
SDL_mutex *accurate_seek_mutex;
SDL_cond *video_accurate_seek_cond;
SDL_cond *audio_accurate_seek_cond;
} VideoState;
/* options specified by the user */
......@@ -665,6 +675,7 @@ typedef struct FFPlayer {
AVApplicationContext *app_ctx;
IjkIOManagerContext *ijkio_manager_ctx;
int enable_accurate_seek;
} FFPlayer;
#define fftime_to_milliseconds(ts) (av_rescale(ts, 1000, AV_TIME_BASE))
......@@ -741,6 +752,7 @@ inline static void ffp_reset_internal(FFPlayer *ffp)
ffp->start_on_prepared = 1;
ffp->first_video_frame_rendered = 0;
ffp->sync_av_start = 1;
ffp->enable_accurate_seek = 0;
ffp->playable_duration_ms = 0;
......
......@@ -147,6 +147,9 @@ static const AVOption ffp_context_options[] = {
{ "preset-5-1-center-mix-level", "preset center-mix-level for 5.1 channel",
OPTION_OFFSET(preset_5_1_center_mix_level), OPTION_DOUBLE(M_SQRT1_2, -32, 32) },
{ "enable-accurate-seek", "enable accurate seek",
OPTION_OFFSET(enable_accurate_seek), OPTION_INT(0, 0, 1) },
// iOS only options
{ "videotoolbox", "VideoToolbox: enable",
OPTION_OFFSET(videotoolbox), OPTION_INT(0, 0, 1) },
......@@ -178,7 +181,7 @@ static const AVOption ffp_context_options[] = {
OPTION_OFFSET(mediacodec_handle_resolution_change), OPTION_INT(0, 0, 1) },
{ "opensles", "OpenSL ES: enable",
OPTION_OFFSET(opensles), OPTION_INT(0, 0, 1) },
{ NULL }
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册