From 4be7d578a3cf03a77a277c78d6cf1420f87a7593 Mon Sep 17 00:00:00 2001 From: Marton Balint Date: Sat, 16 Feb 2013 20:21:13 +0100 Subject: [PATCH 1/9] ffplay: signal seek event to read thread Improves seek delay. Signed-off-by: Marton Balint --- ffplay.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ffplay.c b/ffplay.c index 5a3d1b24a1..d5a9dc362c 100644 --- a/ffplay.c +++ b/ffplay.c @@ -1184,6 +1184,7 @@ static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_by if (seek_by_bytes) is->seek_flags |= AVSEEK_FLAG_BYTE; is->seek_req = 1; + SDL_CondSignal(is->continue_read_thread); } } From 48e43a1999fb47c0afb1b5c148e48262c84ec5ad Mon Sep 17 00:00:00 2001 From: Marton Balint Date: Sat, 16 Feb 2013 20:53:07 +0100 Subject: [PATCH 2/9] ffplay: drop remaining frames in current audio avpacket when seeking Fixes ticket #1928. Signed-off-by: Marton Balint --- ffplay.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ffplay.c b/ffplay.c index d5a9dc362c..ed53023854 100644 --- a/ffplay.c +++ b/ffplay.c @@ -2090,6 +2090,9 @@ static int audio_decode_frame(VideoState *is) } else avcodec_get_frame_defaults(is->frame); + if (is->audioq.serial != is->audio_pkt_temp_serial) + break; + if (is->paused) return -1; From 3070600d9b14b2e48637eb252a48b388195fda58 Mon Sep 17 00:00:00 2001 From: Marton Balint Date: Sat, 16 Feb 2013 20:56:19 +0100 Subject: [PATCH 3/9] ffplay: only quit from audio_decode_frame before decoding when paused This way the audio clock is updated to a proper value even when the video is paused. Signed-off-by: Marton Balint --- ffplay.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ffplay.c b/ffplay.c index ed53023854..4f24a32fe9 100644 --- a/ffplay.c +++ b/ffplay.c @@ -2196,7 +2196,7 @@ static int audio_decode_frame(VideoState *is) av_free_packet(pkt); memset(pkt_temp, 0, sizeof(*pkt_temp)); - if (is->paused || is->audioq.abort_request) { + if (is->audioq.abort_request) { return -1; } From 36dc476f83f7e5c4849e1c37f1cc9dc7ef75079d Mon Sep 17 00:00:00 2001 From: Marton Balint Date: Sun, 10 Feb 2013 00:29:29 +0100 Subject: [PATCH 4/9] ffplay: return true for pictq_prev_picture if it was successful Signed-off-by: Marton Balint --- ffplay.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ffplay.c b/ffplay.c index 4f24a32fe9..0d4fde6344 100644 --- a/ffplay.c +++ b/ffplay.c @@ -1255,8 +1255,9 @@ static void pictq_next_picture(VideoState *is) { SDL_UnlockMutex(is->pictq_mutex); } -static void pictq_prev_picture(VideoState *is) { +static int pictq_prev_picture(VideoState *is) { VideoPicture *prevvp; + int ret = 0; /* update queue size and signal for the previous picture */ prevvp = &is->pictq[(is->pictq_rindex + VIDEO_PICTURE_QUEUE_SIZE - 1) % VIDEO_PICTURE_QUEUE_SIZE]; if (prevvp->allocated && prevvp->serial == is->videoq.serial) { @@ -1265,10 +1266,12 @@ static void pictq_prev_picture(VideoState *is) { if (--is->pictq_rindex == -1) is->pictq_rindex = VIDEO_PICTURE_QUEUE_SIZE - 1; is->pictq_size++; + ret = 1; } SDL_CondSignal(is->pictq_cond); SDL_UnlockMutex(is->pictq_mutex); } + return ret; } static void update_video_pts(VideoState *is, double pts, int64_t pos, int serial) { From 38f649662c12c0d23d1be6f066c6ca597f6c1cbb Mon Sep 17 00:00:00 2001 From: Marton Balint Date: Sat, 16 Feb 2013 14:24:34 +0100 Subject: [PATCH 5/9] ffplay: allow frame dropping if we redisplay an already displayed frame Signed-off-by: Marton Balint --- ffplay.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ffplay.c b/ffplay.c index 0d4fde6344..b4394e3619 100644 --- a/ffplay.c +++ b/ffplay.c @@ -1307,8 +1307,9 @@ static void video_refresh(void *opaque, double *remaining_time) } if (is->video_st) { + int redisplay = 0; if (is->force_refresh) - pictq_prev_picture(is); + redisplay = pictq_prev_picture(is); retry: if (is->pictq_size == 0) { SDL_LockMutex(is->pictq_mutex); @@ -1325,6 +1326,7 @@ retry: if (vp->serial != is->videoq.serial) { pictq_next_picture(is); + redisplay = 0; goto retry; } @@ -1355,9 +1357,11 @@ retry: if (is->pictq_size > 1) { VideoPicture *nextvp = &is->pictq[(is->pictq_rindex + 1) % VIDEO_PICTURE_QUEUE_SIZE]; duration = nextvp->pts - vp->pts; - if(!is->step && (framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) && time > is->frame_timer + duration){ - is->frame_drops_late++; + if(!is->step && (redisplay || framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) && time > is->frame_timer + duration){ + if (!redisplay) + is->frame_drops_late++; pictq_next_picture(is); + redisplay = 0; goto retry; } } From 26c208cf0ff59efd7786528884a64d35fc42e9bf Mon Sep 17 00:00:00 2001 From: Marton Balint Date: Sat, 16 Feb 2013 23:36:07 +0100 Subject: [PATCH 6/9] ffplay: if audio or video clock is invalid return NAN This helps us not to make bad decision (frame dropping, audio compensation) right after seeking when we do not know yet the recent audio or video clock. Signed-off-by: Marton Balint --- ffplay.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/ffplay.c b/ffplay.c index b4394e3619..ad3e36cb06 100644 --- a/ffplay.c +++ b/ffplay.c @@ -176,6 +176,7 @@ typedef struct VideoState { double external_clock_speed; ///< speed of the external clock double audio_clock; + int audio_clock_serial; double audio_diff_cum; /* used for AV difference average computation */ double audio_diff_avg_coef; double audio_diff_threshold; @@ -238,6 +239,7 @@ typedef struct VideoState { double video_current_pts_drift; // video_current_pts - time (av_gettime) at which we updated video_current_pts - used to have running video pts int64_t video_current_pos; // current displayed file pos double max_frame_duration; // maximum duration of a frame - above this, we consider the jump a timestamp discontinuity + int video_clock_serial; VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE]; int pictq_size, pictq_rindex, pictq_windex; SDL_mutex *pictq_mutex; @@ -1079,6 +1081,8 @@ static void video_display(VideoState *is) /* get the current audio clock value */ static double get_audio_clock(VideoState *is) { + if (is->audio_clock_serial != is->audioq.serial) + return NAN; if (is->paused) { return is->audio_current_pts; } else { @@ -1089,6 +1093,8 @@ static double get_audio_clock(VideoState *is) /* get the current video clock value */ static double get_video_clock(VideoState *is) { + if (is->video_clock_serial != is->videoq.serial) + return NAN; if (is->paused) { return is->video_current_pts; } else { @@ -1230,7 +1236,7 @@ static double compute_target_delay(double delay, VideoState *is) delay to compute the threshold. I still don't know if it is the best guess */ sync_threshold = FFMAX(AV_SYNC_THRESHOLD, delay); - if (fabs(diff) < AV_NOSYNC_THRESHOLD) { + if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) { if (diff <= -sync_threshold) delay = 0; else if (diff >= sync_threshold) @@ -1281,6 +1287,7 @@ static void update_video_pts(VideoState *is, double pts, int64_t pos, int serial is->video_current_pts_drift = is->video_current_pts - time; is->video_current_pos = pos; is->frame_last_pts = pts; + is->video_clock_serial = serial; if (is->videoq.serial == serial) check_external_clock_sync(is, is->video_current_pts); } @@ -1677,7 +1684,7 @@ static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacke double clockdiff = get_video_clock(is) - get_master_clock(is); double dpts = av_q2d(is->video_st->time_base) * *pts; double ptsdiff = dpts - is->frame_last_pts; - if (fabs(clockdiff) < AV_NOSYNC_THRESHOLD && + if (!isnan(clockdiff) && fabs(clockdiff) < AV_NOSYNC_THRESHOLD && ptsdiff > 0 && ptsdiff < AV_NOSYNC_THRESHOLD && clockdiff + ptsdiff - is->frame_last_filter_delay < 0) { is->frame_last_dropped_pos = pkt->pos; @@ -2038,7 +2045,7 @@ static int synchronize_audio(VideoState *is, int nb_samples) diff = get_audio_clock(is) - get_master_clock(is); - if (fabs(diff) < AV_NOSYNC_THRESHOLD) { + if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) { is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum; if (is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) { /* not enough measures to have a correct estimate */ @@ -2224,6 +2231,7 @@ static int audio_decode_frame(VideoState *is) /* if update the audio clock with the pts */ if (pkt->pts != AV_NOPTS_VALUE) { is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts; + is->audio_clock_serial = is->audio_pkt_temp_serial; } } } @@ -2265,7 +2273,7 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len) /* Let's assume the audio driver that is used by SDL has two periods. */ is->audio_current_pts = is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / bytes_per_sec; is->audio_current_pts_drift = is->audio_current_pts - audio_callback_time / 1000000.0; - if (is->audioq.serial == is->audio_pkt_temp_serial) + if (is->audioq.serial == is->audio_clock_serial) check_external_clock_sync(is, is->audio_current_pts); } @@ -2851,6 +2859,8 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat) update_external_clock_speed(is, 1.0); is->audio_current_pts_drift = -av_gettime() / 1000000.0; is->video_current_pts_drift = is->audio_current_pts_drift; + is->audio_clock_serial = -1; + is->video_clock_serial = -1; is->av_sync_type = av_sync_type; is->read_tid = SDL_CreateThread(read_thread, is); if (!is->read_tid) { @@ -3033,6 +3043,8 @@ static void event_loop(VideoState *cur_stream) stream_seek(cur_stream, pos, incr, 1); } else { pos = get_master_clock(cur_stream); + if (isnan(pos)) + pos = (double)cur_stream->seek_pos / AV_TIME_BASE; pos += incr; if (cur_stream->ic->start_time != AV_NOPTS_VALUE && pos < cur_stream->ic->start_time / (double)AV_TIME_BASE) pos = cur_stream->ic->start_time / (double)AV_TIME_BASE; From daece4c6745b42e8b1e171fb4bf485d5d64fc53f Mon Sep 17 00:00:00 2001 From: Marton Balint Date: Fri, 22 Feb 2013 18:18:00 +0100 Subject: [PATCH 7/9] ffplay: use NAN to signal invalid external clock Signed-off-by: Marton Balint --- ffplay.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ffplay.c b/ffplay.c index ad3e36cb06..e0b113c9db 100644 --- a/ffplay.c +++ b/ffplay.c @@ -1156,7 +1156,8 @@ static void update_external_clock_pts(VideoState *is, double pts) } static void check_external_clock_sync(VideoState *is, double pts) { - if (fabs(get_external_clock(is) - pts) > AV_NOSYNC_THRESHOLD) { + double ext_clock = get_external_clock(is); + if (isnan(ext_clock) || fabs(ext_clock - pts) > AV_NOSYNC_THRESHOLD) { update_external_clock_pts(is, pts); } } @@ -2717,8 +2718,7 @@ static int read_thread(void *arg) packet_queue_put(&is->videoq, &flush_pkt); } if (is->seek_flags & AVSEEK_FLAG_BYTE) { - //FIXME: use a cleaner way to signal obsolete external clock... - update_external_clock_pts(is, (double)AV_NOPTS_VALUE); + update_external_clock_pts(is, NAN); } else { update_external_clock_pts(is, seek_target / (double)AV_TIME_BASE); } @@ -2854,8 +2854,7 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat) is->continue_read_thread = SDL_CreateCond(); - //FIXME: use a cleaner way to signal obsolete external clock... - update_external_clock_pts(is, (double)AV_NOPTS_VALUE); + update_external_clock_pts(is, NAN); update_external_clock_speed(is, 1.0); is->audio_current_pts_drift = -av_gettime() / 1000000.0; is->video_current_pts_drift = is->audio_current_pts_drift; From d0c6ed7da01d3c99448512da722a03604b937048 Mon Sep 17 00:00:00 2001 From: Marton Balint Date: Sat, 23 Feb 2013 01:52:23 +0100 Subject: [PATCH 8/9] ffplay: add option to disable subtitling Fixes ticket #2201. Signed-off-by: Marton Balint --- ffplay.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ffplay.c b/ffplay.c index e0b113c9db..ca1fb9eb89 100644 --- a/ffplay.c +++ b/ffplay.c @@ -277,6 +277,7 @@ static int screen_width = 0; static int screen_height = 0; static int audio_disable; static int video_disable; +static int subtitle_disable; static int wanted_stream[AVMEDIA_TYPE_NB] = { [AVMEDIA_TYPE_AUDIO] = -1, [AVMEDIA_TYPE_VIDEO] = -1, @@ -2635,7 +2636,7 @@ static int read_thread(void *arg) wanted_stream[AVMEDIA_TYPE_AUDIO], st_index[AVMEDIA_TYPE_VIDEO], NULL, 0); - if (!video_disable) + if (!video_disable && !subtitle_disable) st_index[AVMEDIA_TYPE_SUBTITLE] = av_find_best_stream(ic, AVMEDIA_TYPE_SUBTITLE, wanted_stream[AVMEDIA_TYPE_SUBTITLE], @@ -3231,6 +3232,7 @@ static const OptionDef options[] = { { "fs", OPT_BOOL, { &is_full_screen }, "force full screen" }, { "an", OPT_BOOL, { &audio_disable }, "disable audio" }, { "vn", OPT_BOOL, { &video_disable }, "disable video" }, + { "sn", OPT_BOOL, { &subtitle_disable }, "disable subtitling" }, { "ast", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_AUDIO] }, "select desired audio stream", "stream_number" }, { "vst", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_VIDEO] }, "select desired video stream", "stream_number" }, { "sst", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_SUBTITLE] }, "select desired subtitle stream", "stream_number" }, From ac37d21f496438f6c8694025744287b60bdd9ba6 Mon Sep 17 00:00:00 2001 From: Marton Balint Date: Sat, 23 Feb 2013 02:15:06 +0100 Subject: [PATCH 9/9] ffplay: do not cycle through unavailable show modes Fixes ticket #2200. Signed-off-by: Marton Balint --- ffplay.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/ffplay.c b/ffplay.c index ca1fb9eb89..01ee15e65c 100644 --- a/ffplay.c +++ b/ffplay.c @@ -2943,10 +2943,17 @@ static void toggle_full_screen(VideoState *is) static void toggle_audio_display(VideoState *is) { int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00); - is->show_mode = (is->show_mode + 1) % SHOW_MODE_NB; - fill_rectangle(screen, - is->xleft, is->ytop, is->width, is->height, - bgcolor, 1); + int next = is->show_mode; + do { + next = (next + 1) % SHOW_MODE_NB; + } while (next != is->show_mode && (next == SHOW_MODE_VIDEO && !is->video_st || next != SHOW_MODE_VIDEO && !is->audio_st)); + if (is->show_mode != next) { + fill_rectangle(screen, + is->xleft, is->ytop, is->width, is->height, + bgcolor, 1); + is->force_refresh = 1; + is->show_mode = next; + } } static void refresh_loop_wait_event(VideoState *is, SDL_Event *event) { @@ -3008,7 +3015,6 @@ static void event_loop(VideoState *cur_stream) break; case SDLK_w: toggle_audio_display(cur_stream); - cur_stream->force_refresh = 1; break; case SDLK_PAGEUP: incr = 600.0;