Revision d38c9e7a

View differences:

ffplay.c
48 48
#undef main /* We don't want SDL to override our main() */
49 49
#endif
50 50

  
51
#include <unistd.h>
52
#include <assert.h>
53

  
51 54
const char program_name[] = "FFplay";
52 55
const int program_birth_year = 2003;
53 56

  
......
66 69
/* no AV correction is done if too big error */
67 70
#define AV_NOSYNC_THRESHOLD 10.0
68 71

  
72
#define FRAME_SKIP_FACTOR 0.05
73

  
69 74
/* maximum audio speed change to get correct sync */
70 75
#define SAMPLE_CORRECTION_PERCENT_MAX 10
71 76

  
......
93 98

  
94 99
typedef struct VideoPicture {
95 100
    double pts;                                  ///<presentation time stamp for this picture
101
    double target_clock;                         ///<av_gettime() time at which this should be displayed ideally
96 102
    int64_t pos;                                 ///<byte position in file
97 103
    SDL_Overlay *bmp;
98 104
    int width, height; /* source height & width */
99 105
    int allocated;
100
    SDL_TimerID timer_id;
101 106
    enum PixelFormat pix_fmt;
102 107

  
103 108
#if CONFIG_AVFILTER
......
119 124
typedef struct VideoState {
120 125
    SDL_Thread *parse_tid;
121 126
    SDL_Thread *video_tid;
127
    SDL_Thread *refresh_tid;
122 128
    AVInputFormat *iformat;
123 129
    int no_background;
124 130
    int abort_request;
......
206 212
#if CONFIG_AVFILTER
207 213
    AVFilterContext *out_video_filter;          ///<the last filter in the video chain
208 214
#endif
215

  
216
    float skip_frames;
217
    float skip_frames_index;
218
    int refresh;
209 219
} VideoState;
210 220

  
211 221
static void show_help(void);
......
249 259
static int error_concealment = 3;
250 260
static int decoder_reorder_pts= -1;
251 261
static int autoexit;
262
static int framedrop=1;
252 263
#if CONFIG_AVFILTER
253 264
static char *vfilters = NULL;
254 265
#endif
......
999 1010
        video_image_display(is);
1000 1011
}
1001 1012

  
1002
static Uint32 sdl_refresh_timer_cb(Uint32 interval, void *opaque)
1013
static int refresh_thread(void *opaque)
1003 1014
{
1015
    VideoState *is= opaque;
1016
    while(!is->abort_request){
1004 1017
    SDL_Event event;
1005 1018
    event.type = FF_REFRESH_EVENT;
1006 1019
    event.user.data1 = opaque;
1020
        if(!is->refresh){
1021
            is->refresh=1;
1007 1022
    SDL_PushEvent(&event);
1008
    return 0; /* 0 means stop timer */
1009
}
1010

  
1011
/* schedule a video refresh in 'delay' ms */
1012
static SDL_TimerID schedule_refresh(VideoState *is, int delay)
1013
{
1014
    if(!delay) delay=1; //SDL seems to be buggy when the delay is 0
1015
    return SDL_AddTimer(delay, sdl_refresh_timer_cb, is);
1023
        }
1024
        usleep(5000); //FIXME ideally we should wait the correct time but SDLs event passing is so slow it would be silly
1025
    }
1026
    return 0;
1016 1027
}
1017 1028

  
1018 1029
/* get the current audio clock value */
......
1097 1108
    is->paused = !is->paused;
1098 1109
}
1099 1110

  
1100
static double compute_frame_delay(double frame_current_pts, VideoState *is)
1111
static double compute_target_time(double frame_current_pts, VideoState *is)
1101 1112
{
1102
    double actual_delay, delay, sync_threshold, diff;
1113
    double delay, sync_threshold, diff;
1103 1114

  
1104 1115
    /* compute nominal delay */
1105 1116
    delay = frame_current_pts - is->frame_last_pts;
......
1129 1140
                delay = 2 * delay;
1130 1141
        }
1131 1142
    }
1132

  
1133 1143
    is->frame_timer += delay;
1134
    /* compute the REAL delay (we need to do that to avoid
1135
       long term errors */
1136
    actual_delay = is->frame_timer - (av_gettime() / 1000000.0);
1137
    if (actual_delay < 0.010) {
1138
        /* XXX: should skip picture */
1139
        actual_delay = 0.010;
1140
    }
1141

  
1142 1144
#if defined(DEBUG_SYNC)
1143 1145
    printf("video: delay=%0.3f actual_delay=%0.3f pts=%0.3f A-V=%f\n",
1144 1146
            delay, actual_delay, frame_current_pts, -diff);
1145 1147
#endif
1146 1148

  
1147
    return actual_delay;
1149
    return is->frame_timer;
1148 1150
}
1149 1151

  
1150 1152
/* called to display each frame */
......
1156 1158
    SubPicture *sp, *sp2;
1157 1159

  
1158 1160
    if (is->video_st) {
1161
retry:
1159 1162
        if (is->pictq_size == 0) {
1160
            fprintf(stderr, "Internal error detected in the SDL timer\n");
1163
            //nothing to do, no picture to display in the que
1161 1164
        } else {
1165
            double time= av_gettime()/1000000.0;
1166
            double next_target;
1162 1167
            /* dequeue the picture */
1163 1168
            vp = &is->pictq[is->pictq_rindex];
1164 1169

  
1170
            if(time < vp->target_clock)
1171
                return;
1165 1172
            /* update current video pts */
1166 1173
            is->video_current_pts = vp->pts;
1167
            is->video_current_pts_drift = is->video_current_pts - av_gettime() / 1000000.0;
1174
            is->video_current_pts_drift = is->video_current_pts - time;
1168 1175
            is->video_current_pos = vp->pos;
1176
            if(is->pictq_size > 1){
1177
                VideoPicture *nextvp= &is->pictq[(is->pictq_rindex+1)%VIDEO_PICTURE_QUEUE_SIZE];
1178
                assert(nextvp->target_clock >= vp->target_clock);
1179
                next_target= nextvp->target_clock;
1180
            }else{
1181
                next_target= vp->target_clock + is->video_clock - vp->pts; //FIXME pass durations cleanly
1182
            }
1183
            if(framedrop && time > next_target){
1184
                is->skip_frames *= 1.0 + FRAME_SKIP_FACTOR;
1185
                if(is->pictq_size > 1 || time > next_target + 0.5){
1186
                    /* update queue size and signal for next picture */
1187
                    if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
1188
                        is->pictq_rindex = 0;
1189

  
1190
                    SDL_LockMutex(is->pictq_mutex);
1191
                    is->pictq_size--;
1192
                    SDL_CondSignal(is->pictq_cond);
1193
                    SDL_UnlockMutex(is->pictq_mutex);
1194
                    goto retry;
1195
                }
1196
            }
1169 1197

  
1170 1198
            if(is->subtitle_st) {
1171 1199
                if (is->subtitle_stream_changed) {
......
1219 1247
                is->pictq_rindex = 0;
1220 1248

  
1221 1249
            SDL_LockMutex(is->pictq_mutex);
1222
            vp->timer_id= 0;
1223 1250
            is->pictq_size--;
1224 1251
            SDL_CondSignal(is->pictq_cond);
1225 1252
            SDL_UnlockMutex(is->pictq_mutex);
......
1227 1254
    } else if (is->audio_st) {
1228 1255
        /* draw the next audio frame */
1229 1256

  
1230
        schedule_refresh(is, 40);
1231

  
1232 1257
        /* if only audio stream, then display the audio bars (better
1233 1258
           than nothing, just to test the implementation */
1234 1259

  
1235 1260
        /* display picture */
1236 1261
        video_display(is);
1237
    } else {
1238
        schedule_refresh(is, 100);
1239 1262
    }
1240 1263
    if (show_status) {
1241 1264
        static int64_t last_time;
......
1314 1337
#endif
1315 1338
    /* wait until we have space to put a new picture */
1316 1339
    SDL_LockMutex(is->pictq_mutex);
1340

  
1341
    if(is->pictq_size>=VIDEO_PICTURE_QUEUE_SIZE && !is->refresh)
1342
        is->skip_frames= FFMAX(1.0 - FRAME_SKIP_FACTOR, is->skip_frames * (1.0-FRAME_SKIP_FACTOR));
1343

  
1317 1344
    while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE &&
1318 1345
           !is->videoq.abort_request) {
1319 1346
        SDL_CondWait(is->pictq_cond, is->pictq_mutex);
......
1411 1438
        if (++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE)
1412 1439
            is->pictq_windex = 0;
1413 1440
        SDL_LockMutex(is->pictq_mutex);
1441
        vp->target_clock= compute_target_time(vp->pts, is);
1442

  
1414 1443
        is->pictq_size++;
1415
        //We must schedule in a mutex as we must store the timer id before the timer dies or might end up freeing a alraedy freed id
1416
        vp->timer_id= schedule_refresh(is, (int)(compute_frame_delay(vp->pts, is) * 1000 + 0.5));
1417 1444
        SDL_UnlockMutex(is->pictq_mutex);
1418 1445
    }
1419 1446
    return 0;
......
1462 1489
            SDL_LockMutex(is->pictq_mutex);
1463 1490
            //Make sure there are no long delay timers (ideally we should just flush the que but thats harder)
1464 1491
            for(i=0; i<VIDEO_PICTURE_QUEUE_SIZE; i++){
1465
                if(is->pictq[i].timer_id){
1466
                    if(SDL_RemoveTimer(is->pictq[i].timer_id)){
1467
                    is->pictq[i].timer_id=0;
1468
                    schedule_refresh(is, 1);
1469
                    }
1470
                }
1492
                is->pictq[i].target_clock= 0;
1471 1493
            }
1472 1494
            while (is->pictq_size && !is->videoq.abort_request) {
1473 1495
                SDL_CondWait(is->pictq_cond, is->pictq_mutex);
......
1480 1502
            is->frame_last_pts= AV_NOPTS_VALUE;
1481 1503
            is->frame_last_delay = 0;
1482 1504
            is->frame_timer = (double)av_gettime() / 1000000.0;
1483

  
1505
            is->skip_frames= 1;
1506
            is->skip_frames_index= 0;
1484 1507
            return 0;
1485 1508
        }
1486 1509

  
......
1514 1537

  
1515 1538
//            if (len1 < 0)
1516 1539
//                break;
1517
    if (got_picture)
1518
        return 1;
1540
    if (got_picture){
1541
        is->skip_frames_index += 1;
1542
        if(is->skip_frames_index >= is->skip_frames){
1543
            is->skip_frames_index -= FFMAX(is->skip_frames, 1.0);
1544
            return 1;
1545
        }
1546

  
1547
    }
1519 1548
    return 0;
1520 1549
}
1521 1550

  
......
2364 2393
    if (st_index[CODEC_TYPE_VIDEO] >= 0) {
2365 2394
        ret= stream_component_open(is, st_index[CODEC_TYPE_VIDEO]);
2366 2395
    }
2396
    is->refresh_tid = SDL_CreateThread(refresh_thread, is);
2367 2397
    if(ret<0) {
2368
        /* add the refresh timer to draw the picture */
2369
        schedule_refresh(is, 40);
2370

  
2371 2398
        if (!display_disable)
2372 2399
            is->show_audio = 2;
2373 2400
    }
......
2539 2566
    /* XXX: use a special url_shutdown call to abort parse cleanly */
2540 2567
    is->abort_request = 1;
2541 2568
    SDL_WaitThread(is->parse_tid, NULL);
2569
    SDL_WaitThread(is->refresh_tid, NULL);
2542 2570

  
2543 2571
    /* free all pictures */
2544 2572
    for(i=0;i<VIDEO_PICTURE_QUEUE_SIZE; i++) {
......
2805 2833
            break;
2806 2834
        case FF_REFRESH_EVENT:
2807 2835
            video_refresh_timer(event.user.data1);
2836
            cur_stream->refresh=0;
2808 2837
            break;
2809 2838
        default:
2810 2839
            break;
......
2926 2955
    { "sync", HAS_ARG | OPT_FUNC2 | OPT_EXPERT, {(void*)opt_sync}, "set audio-video sync. type (type=audio/video/ext)", "type" },
2927 2956
    { "threads", HAS_ARG | OPT_FUNC2 | OPT_EXPERT, {(void*)opt_thread_count}, "thread count", "count" },
2928 2957
    { "autoexit", OPT_BOOL | OPT_EXPERT, {(void*)&autoexit}, "exit at the end", "" },
2958
    { "framedrop", OPT_BOOL | OPT_EXPERT, {(void*)&framedrop}, "drop frames when cpu is too slow", "" },
2929 2959
#if CONFIG_AVFILTER
2930 2960
    { "vfilters", OPT_STRING | HAS_ARG, {(void*)&vfilters}, "video filters", "filter list" },
2931 2961
#endif

Also available in: Unified diff