]> git.sesse.net Git - ffmpeg/blobdiff - ffplay.c
dirac: enable diracdsp_mmx
[ffmpeg] / ffplay.c
index b41820c51bd854826da93e887a2036a7316eba92..5a32d4e5dcbd4a71ff8c4dd04f9ddce6217026db 100644 (file)
--- a/ffplay.c
+++ b/ffplay.c
@@ -102,6 +102,7 @@ typedef struct VideoPicture {
     SDL_Overlay *bmp;
     int width, height; /* source height & width */
     int allocated;
+    int reallocate;
     enum PixelFormat pix_fmt;
 
 #if CONFIG_AVFILTER
@@ -171,6 +172,8 @@ typedef struct VideoState {
     struct SwrContext *swr_ctx;
     double audio_current_pts;
     double audio_current_pts_drift;
+    int frame_drops_early;
+    int frame_drops_late;
 
     enum ShowMode {
         SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB
@@ -196,6 +199,10 @@ typedef struct VideoState {
     double frame_timer;
     double frame_last_pts;
     double frame_last_duration;
+    double frame_last_dropped_pts;
+    double frame_last_returned_time;
+    double frame_last_filter_delay;
+    int64_t frame_last_dropped_pos;
     double video_clock;                          ///<pts of last decoded frame / predicted pts of next decoded frame
     int video_stream;
     AVStream *video_st;
@@ -1101,20 +1108,35 @@ static void pictq_next_picture(VideoState *is) {
     SDL_UnlockMutex(is->pictq_mutex);
 }
 
+static void update_video_pts(VideoState *is, double pts, int64_t pos) {
+    double time = av_gettime() / 1000000.0;
+    /* update current video pts */
+    is->video_current_pts = pts;
+    is->video_current_pts_drift = is->video_current_pts - time;
+    is->video_current_pos = pos;
+    is->frame_last_pts = pts;
+}
+
 /* called to display each frame */
 static void video_refresh(void *opaque)
 {
     VideoState *is = opaque;
     VideoPicture *vp;
+    double time;
 
     SubPicture *sp, *sp2;
 
     if (is->video_st) {
 retry:
         if (is->pictq_size == 0) {
+            SDL_LockMutex(is->pictq_mutex);
+            if (is->frame_last_dropped_pts != AV_NOPTS_VALUE && is->frame_last_dropped_pts > is->frame_last_pts) {
+                update_video_pts(is, is->frame_last_dropped_pts, is->frame_last_dropped_pos);
+                is->frame_last_dropped_pts = AV_NOPTS_VALUE;
+            }
+            SDL_UnlockMutex(is->pictq_mutex);
             //nothing to do, no picture to display in the que
         } else {
-            double time= av_gettime()/1000000.0;
             double last_duration, duration, delay;
             /* dequeue the picture */
             vp = &is->pictq[is->pictq_rindex];
@@ -1132,17 +1154,16 @@ retry:
             }
             delay = compute_target_delay(is->frame_last_duration, is);
 
+            time= av_gettime()/1000000.0;
             if(time < is->frame_timer + delay)
                 return;
 
-            is->frame_last_pts = vp->pts;
             if (delay > 0)
                 is->frame_timer += delay * FFMAX(1, floor((time-is->frame_timer) / delay));
 
-            /* update current video pts */
-            is->video_current_pts = vp->pts;
-            is->video_current_pts_drift = is->video_current_pts - time;
-            is->video_current_pos = vp->pos;
+            SDL_LockMutex(is->pictq_mutex);
+            update_video_pts(is, vp->pts, vp->pos);
+            SDL_UnlockMutex(is->pictq_mutex);
 
             if(is->pictq_size > 1) {
                  VideoPicture *nextvp= &is->pictq[(is->pictq_rindex+1)%VIDEO_PICTURE_QUEUE_SIZE];
@@ -1153,6 +1174,7 @@ retry:
 
             if((framedrop>0 || (framedrop && is->audio_st)) && time > is->frame_timer + duration){
                 if(is->pictq_size > 1){
+                    is->frame_drops_late++;
                     pictq_next_picture(is);
                     goto retry;
                 }
@@ -1238,9 +1260,10 @@ retry:
             av_diff = 0;
             if (is->audio_st && is->video_st)
                 av_diff = get_audio_clock(is) - get_video_clock(is);
-            printf("%7.2f A-V:%7.3f aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64"   \r",
+            printf("%7.2f A-V:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64"   \r",
                    get_master_clock(is),
                    av_diff,
+                   is->frame_drops_early + is->frame_drops_late,
                    aqsize / 1024,
                    vqsize / 1024,
                    sqsize,
@@ -1338,7 +1361,7 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts1, int64_
     vp->duration = frame_delay;
 
     /* alloc or resize hardware picture buffer */
-    if (!vp->bmp ||
+    if (!vp->bmp || vp->reallocate ||
 #if CONFIG_AVFILTER
         vp->width  != is->out_video_filter->inputs[0]->w ||
         vp->height != is->out_video_filter->inputs[0]->h) {
@@ -1348,7 +1371,8 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts1, int64_
 #endif
         SDL_Event event;
 
-        vp->allocated = 0;
+        vp->allocated  = 0;
+        vp->reallocate = 0;
 
         /* the allocation must be done in the main thread to avoid
            locking problems */
@@ -1446,17 +1470,20 @@ static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacke
             SDL_CondWait(is->pictq_cond, is->pictq_mutex);
         }
         is->video_current_pos = -1;
-        SDL_UnlockMutex(is->pictq_mutex);
-
         is->frame_last_pts = AV_NOPTS_VALUE;
         is->frame_last_duration = 0;
         is->frame_timer = (double)av_gettime() / 1000000.0;
+        is->frame_last_dropped_pts = AV_NOPTS_VALUE;
+        SDL_UnlockMutex(is->pictq_mutex);
+
         return 0;
     }
 
     avcodec_decode_video2(is->video_st->codec, frame, &got_picture, pkt);
 
     if (got_picture) {
+        int ret = 1;
+
         if (decoder_reorder_pts == -1) {
             *pts = frame->best_effort_timestamp;
         } else if (decoder_reorder_pts) {
@@ -1469,8 +1496,29 @@ static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacke
             *pts = 0;
         }
 
-        return 1;
+        if (((is->av_sync_type == AV_SYNC_AUDIO_MASTER && is->audio_st) || is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK) &&
+             (framedrop>0 || (framedrop && is->audio_st))) {
+            SDL_LockMutex(is->pictq_mutex);
+            if (is->frame_last_pts != AV_NOPTS_VALUE && *pts) {
+                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 &&
+                     ptsdiff > 0 && ptsdiff < AV_NOSYNC_THRESHOLD &&
+                     clockdiff + ptsdiff - is->frame_last_filter_delay < 0) {
+                    is->frame_last_dropped_pos = pkt->pos;
+                    is->frame_last_dropped_pts = dpts;
+                    is->frame_drops_early++;
+                    ret = 0;
+                }
+            }
+            SDL_UnlockMutex(is->pictq_mutex);
+        }
+
+        if (ret)
+            is->frame_last_returned_time = av_gettime() / 1000000.0;
 
+        return ret;
     }
     return 0;
 }
@@ -1794,6 +1842,10 @@ static int video_thread(void *arg)
 
         if (ret < 0) goto the_end;
 
+        is->frame_last_filter_delay = av_gettime() / 1000000.0 - is->frame_last_returned_time;
+        if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0)
+            is->frame_last_filter_delay = 0;
+
 #if CONFIG_AVFILTER
         if (!picref)
             continue;
@@ -2703,6 +2755,12 @@ static void stream_cycle_channel(VideoState *is, int codec_type)
 static void toggle_full_screen(VideoState *is)
 {
     is_full_screen = !is_full_screen;
+#if defined(__APPLE__) && SDL_VERSION_ATLEAST(1, 2, 14)
+    /* OSX needs to reallocate the SDL overlays */
+    for (int i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
+        is->pictq[i].reallocate = 1;
+    }
+#endif
     video_open(is);
 }