avplay.c 96.3 KB
Newer Older
Fabrice Bellard's avatar
Fabrice Bellard committed
1
/*
Anton Khirnov's avatar
Anton Khirnov committed
2
 * avplay : Simple Media Player based on the Libav libraries
Fabrice Bellard's avatar
Fabrice Bellard committed
3 4
 * Copyright (c) 2003 Fabrice Bellard
 *
5
 * This file is part of Libav.
6
 *
7
 * Libav is free software; you can redistribute it and/or
Fabrice Bellard's avatar
Fabrice Bellard committed
8 9
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
Fabrice Bellard's avatar
Fabrice Bellard committed
11
 *
12
 * Libav is distributed in the hope that it will be useful,
Fabrice Bellard's avatar
Fabrice Bellard committed
13 14 15 16 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with Libav; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Fabrice Bellard's avatar
Fabrice Bellard committed
20
 */
21

22
#include "config.h"
23
#include <inttypes.h>
24 25
#include <math.h>
#include <limits.h>
26
#include "libavutil/avstring.h"
27
#include "libavutil/colorspace.h"
28
#include "libavutil/mathematics.h"
29
#include "libavutil/pixdesc.h"
30
#include "libavutil/imgutils.h"
31
#include "libavutil/dict.h"
32 33
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
34
#include "libavutil/time.h"
35 36 37
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
38
#include "libavresample/avresample.h"
39
#include "libavutil/opt.h"
40
#include "libavcodec/avfft.h"
Fabrice Bellard's avatar
Fabrice Bellard committed
41

42 43
#if CONFIG_AVFILTER
# include "libavfilter/avfilter.h"
44
# include "libavfilter/buffersink.h"
45
# include "libavfilter/buffersrc.h"
46 47
#endif

Fabrice Bellard's avatar
Fabrice Bellard committed
48 49 50 51 52
#include "cmdutils.h"

#include <SDL.h>
#include <SDL_thread.h>

53
#ifdef __MINGW32__
54 55 56
#undef main /* We don't want SDL to override our main() */
#endif

57 58
#include <assert.h>

Anton Khirnov's avatar
Anton Khirnov committed
59
const char program_name[] = "avplay";
60
const int program_birth_year = 2003;
61

62 63 64
#define MAX_QUEUE_SIZE (15 * 1024 * 1024)
#define MIN_AUDIOQ_SIZE (20 * 16 * 1024)
#define MIN_FRAMES 5
Fabrice Bellard's avatar
Fabrice Bellard committed
65

66 67 68 69 70
/* SDL audio buffer size, in samples. Should be small to have precise
   A/V sync as SDL does not have hardware buffer fullness info. */
#define SDL_AUDIO_BUFFER_SIZE 1024

/* no AV sync correction is done if below the AV sync threshold */
71
#define AV_SYNC_THRESHOLD 0.01
72 73 74
/* no AV correction is done if too big error */
#define AV_NOSYNC_THRESHOLD 10.0

75 76
#define FRAME_SKIP_FACTOR 0.05

77 78 79 80 81 82
/* maximum audio speed change to get correct sync */
#define SAMPLE_CORRECTION_PERCENT_MAX 10

/* we use about AUDIO_DIFF_AVG_NB A-V differences to make the average */
#define AUDIO_DIFF_AVG_NB   20

Fabrice Bellard's avatar
Fabrice Bellard committed
83
/* NOTE: the size must be big enough to compensate the hardware audio buffersize size */
Aneesh Dogra's avatar
Aneesh Dogra committed
84
#define SAMPLE_ARRAY_SIZE (2 * 65536)
Fabrice Bellard's avatar
Fabrice Bellard committed
85

86
static int64_t sws_flags = SWS_BICUBIC;
87

Fabrice Bellard's avatar
Fabrice Bellard committed
88 89 90 91 92 93 94 95 96
typedef struct PacketQueue {
    AVPacketList *first_pkt, *last_pkt;
    int nb_packets;
    int size;
    int abort_request;
    SDL_mutex *mutex;
    SDL_cond *cond;
} PacketQueue;

97
#define VIDEO_PICTURE_QUEUE_SIZE 2
98
#define SUBPICTURE_QUEUE_SIZE 4
Fabrice Bellard's avatar
Fabrice Bellard committed
99 100

typedef struct VideoPicture {
101 102 103
    double pts;             // presentation timestamp for this picture
    double target_clock;    // av_gettime() time at which this should be displayed ideally
    int64_t pos;            // byte position in file
Fabrice Bellard's avatar
Fabrice Bellard committed
104 105 106
    SDL_Overlay *bmp;
    int width, height; /* source height & width */
    int allocated;
107
    int reallocate;
108
    enum AVPixelFormat pix_fmt;
109

110
    AVRational sar;
Fabrice Bellard's avatar
Fabrice Bellard committed
111 112
} VideoPicture;

113 114 115 116 117
typedef struct SubPicture {
    double pts; /* presentation time stamp for this picture */
    AVSubtitle sub;
} SubPicture;

Fabrice Bellard's avatar
Fabrice Bellard committed
118 119 120
enum {
    AV_SYNC_AUDIO_MASTER, /* default choice */
    AV_SYNC_VIDEO_MASTER,
121
    AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */
Fabrice Bellard's avatar
Fabrice Bellard committed
122 123 124 125 126
};

typedef struct VideoState {
    SDL_Thread *parse_tid;
    SDL_Thread *video_tid;
127
    SDL_Thread *refresh_tid;
128
    AVInputFormat *iformat;
Fabrice Bellard's avatar
Fabrice Bellard committed
129 130 131
    int no_background;
    int abort_request;
    int paused;
132
    int last_paused;
Fabrice Bellard's avatar
Fabrice Bellard committed
133
    int seek_req;
134
    int seek_flags;
Fabrice Bellard's avatar
Fabrice Bellard committed
135
    int64_t seek_pos;
136
    int64_t seek_rel;
137
    int read_pause_return;
Fabrice Bellard's avatar
Fabrice Bellard committed
138 139 140
    AVFormatContext *ic;

    int audio_stream;
141

Fabrice Bellard's avatar
Fabrice Bellard committed
142
    int av_sync_type;
143 144
    double external_clock; /* external clock base */
    int64_t external_clock_time;
145

146 147 148 149 150
    double audio_clock;
    double audio_diff_cum; /* used for AV difference average computation */
    double audio_diff_avg_coef;
    double audio_diff_threshold;
    int audio_diff_avg_count;
Fabrice Bellard's avatar
Fabrice Bellard committed
151 152 153
    AVStream *audio_st;
    PacketQueue audioq;
    int audio_hw_buf_size;
154
    uint8_t silence_buf[SDL_AUDIO_BUFFER_SIZE];
155
    uint8_t *audio_buf;
156
    uint8_t *audio_buf1;
157
    unsigned int audio_buf_size; /* in bytes */
Fabrice Bellard's avatar
Fabrice Bellard committed
158
    int audio_buf_index; /* in bytes */
159
    AVPacket audio_pkt_temp;
Fabrice Bellard's avatar
Fabrice Bellard committed
160
    AVPacket audio_pkt;
161 162 163
    enum AVSampleFormat sdl_sample_fmt;
    uint64_t sdl_channel_layout;
    int sdl_channels;
164
    int sdl_sample_rate;
165 166
    enum AVSampleFormat resample_sample_fmt;
    uint64_t resample_channel_layout;
167
    int resample_sample_rate;
168
    AVAudioResampleContext *avr;
169
    AVFrame *frame;
170

Fabrice Bellard's avatar
Fabrice Bellard committed
171 172 173
    int show_audio; /* if true, display audio samples */
    int16_t sample_array[SAMPLE_ARRAY_SIZE];
    int sample_array_index;
174
    int last_i_start;
175
    RDFTContext *rdft;
176
    int rdft_bits;
Måns Rullgård's avatar
Måns Rullgård committed
177
    FFTSample *rdft_data;
178
    int xpos;
179

180 181 182 183 184 185 186 187 188
    SDL_Thread *subtitle_tid;
    int subtitle_stream;
    int subtitle_stream_changed;
    AVStream *subtitle_st;
    PacketQueue subtitleq;
    SubPicture subpq[SUBPICTURE_QUEUE_SIZE];
    int subpq_size, subpq_rindex, subpq_windex;
    SDL_mutex *subpq_mutex;
    SDL_cond *subpq_cond;
189

190 191 192
    double frame_timer;
    double frame_last_pts;
    double frame_last_delay;
193
    double video_clock;             // pts of last decoded frame / predicted pts of next decoded frame
Fabrice Bellard's avatar
Fabrice Bellard committed
194 195 196
    int video_stream;
    AVStream *video_st;
    PacketQueue videoq;
197 198 199
    double video_current_pts;       // current displayed pts (different from video_clock if frame fifos are used)
    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
Fabrice Bellard's avatar
Fabrice Bellard committed
200 201 202 203
    VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE];
    int pictq_size, pictq_rindex, pictq_windex;
    SDL_mutex *pictq_mutex;
    SDL_cond *pictq_cond;
204
#if !CONFIG_AVFILTER
205
    struct SwsContext *img_convert_ctx;
206
#endif
207

Fabrice Bellard's avatar
Fabrice Bellard committed
208 209 210
    //    QETimer *video_timer;
    char filename[1024];
    int width, height, xleft, ytop;
211

212
    PtsCorrectionContext pts_ctx;
213

214
#if CONFIG_AVFILTER
215 216
    AVFilterContext *in_video_filter;   // the first filter in the video chain
    AVFilterContext *out_video_filter;  // the last filter in the video chain
217
#endif
218 219 220 221

    float skip_frames;
    float skip_frames_index;
    int refresh;
Fabrice Bellard's avatar
Fabrice Bellard committed
222 223 224 225 226
} VideoState;

/* options specified by the user */
static AVInputFormat *file_iformat;
static const char *input_filename;
227
static const char *window_title;
Fabrice Bellard's avatar
Fabrice Bellard committed
228 229
static int fs_screen_width;
static int fs_screen_height;
Aneesh Dogra's avatar
Aneesh Dogra committed
230
static int screen_width  = 0;
231
static int screen_height = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
232 233
static int audio_disable;
static int video_disable;
Aneesh Dogra's avatar
Aneesh Dogra committed
234 235 236 237
static int wanted_stream[AVMEDIA_TYPE_NB] = {
    [AVMEDIA_TYPE_AUDIO]    = -1,
    [AVMEDIA_TYPE_VIDEO]    = -1,
    [AVMEDIA_TYPE_SUBTITLE] = -1,
238
};
Aneesh Dogra's avatar
Aneesh Dogra committed
239
static int seek_by_bytes = -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
240
static int display_disable;
241
static int show_status = 1;
242
static int av_sync_type = AV_SYNC_AUDIO_MASTER;
Fabrice Bellard's avatar
Fabrice Bellard committed
243
static int64_t start_time = AV_NOPTS_VALUE;
244
static int64_t duration = AV_NOPTS_VALUE;
245
static int debug_mv = 0;
246
static int step = 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
247
static int workaround_bugs = 1;
248
static int fast = 0;
249
static int genpts = 0;
250
static int idct = FF_IDCT_AUTO;
Aneesh Dogra's avatar
Aneesh Dogra committed
251 252 253
static enum AVDiscard skip_frame       = AVDISCARD_DEFAULT;
static enum AVDiscard skip_idct        = AVDISCARD_DEFAULT;
static enum AVDiscard skip_loop_filter = AVDISCARD_DEFAULT;
254
static int error_concealment = 3;
Aneesh Dogra's avatar
Aneesh Dogra committed
255
static int decoder_reorder_pts = -1;
Michael Niedermayer's avatar
Michael Niedermayer committed
256
static int autoexit;
257 258
static int exit_on_keydown;
static int exit_on_mousedown;
Aneesh Dogra's avatar
Aneesh Dogra committed
259 260
static int loop = 1;
static int framedrop = 1;
261
static int infinite_buffer = 0;
262

Aneesh Dogra's avatar
Aneesh Dogra committed
263
static int rdftspeed = 20;
264 265 266
#if CONFIG_AVFILTER
static char *vfilters = NULL;
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
267 268 269 270

/* current context */
static int is_full_screen;
static VideoState *cur_stream;
271
static int64_t audio_callback_time;
Fabrice Bellard's avatar
Fabrice Bellard committed
272

273
static AVPacket flush_pkt;
274

Fabrice Bellard's avatar
Fabrice Bellard committed
275 276
#define FF_ALLOC_EVENT   (SDL_USEREVENT)
#define FF_REFRESH_EVENT (SDL_USEREVENT + 1)
277
#define FF_QUIT_EVENT    (SDL_USEREVENT + 2)
Fabrice Bellard's avatar
Fabrice Bellard committed
278

279
static SDL_Surface *screen;
Fabrice Bellard's avatar
Fabrice Bellard committed
280

281 282
static int packet_queue_put(PacketQueue *q, AVPacket *pkt);

Fabrice Bellard's avatar
Fabrice Bellard committed
283 284 285 286 287 288
/* packet queue handling */
static void packet_queue_init(PacketQueue *q)
{
    memset(q, 0, sizeof(PacketQueue));
    q->mutex = SDL_CreateMutex();
    q->cond = SDL_CreateCond();
289
    packet_queue_put(q, &flush_pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
290 291
}

Fabrice Bellard's avatar
Fabrice Bellard committed
292
static void packet_queue_flush(PacketQueue *q)
Fabrice Bellard's avatar
Fabrice Bellard committed
293 294 295
{
    AVPacketList *pkt, *pkt1;

296
    SDL_LockMutex(q->mutex);
Aneesh Dogra's avatar
Aneesh Dogra committed
297
    for (pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {
Fabrice Bellard's avatar
Fabrice Bellard committed
298 299
        pkt1 = pkt->next;
        av_free_packet(&pkt->pkt);
300
        av_freep(&pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
301
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
302 303 304 305
    q->last_pkt = NULL;
    q->first_pkt = NULL;
    q->nb_packets = 0;
    q->size = 0;
306
    SDL_UnlockMutex(q->mutex);
Fabrice Bellard's avatar
Fabrice Bellard committed
307 308 309 310 311
}

static void packet_queue_end(PacketQueue *q)
{
    packet_queue_flush(q);
Fabrice Bellard's avatar
Fabrice Bellard committed
312 313 314 315 316 317 318 319
    SDL_DestroyMutex(q->mutex);
    SDL_DestroyCond(q->cond);
}

static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
{
    AVPacketList *pkt1;

Fabrice Bellard's avatar
Fabrice Bellard committed
320
    /* duplicate the packet */
Aneesh Dogra's avatar
Aneesh Dogra committed
321
    if (pkt != &flush_pkt && av_dup_packet(pkt) < 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
322
        return -1;
323

Fabrice Bellard's avatar
Fabrice Bellard committed
324 325 326 327 328 329
    pkt1 = av_malloc(sizeof(AVPacketList));
    if (!pkt1)
        return -1;
    pkt1->pkt = *pkt;
    pkt1->next = NULL;

Fabrice Bellard's avatar
Fabrice Bellard committed
330

Fabrice Bellard's avatar
Fabrice Bellard committed
331 332 333 334 335 336 337 338 339
    SDL_LockMutex(q->mutex);

    if (!q->last_pkt)

        q->first_pkt = pkt1;
    else
        q->last_pkt->next = pkt1;
    q->last_pkt = pkt1;
    q->nb_packets++;
340
    q->size += pkt1->pkt.size + sizeof(*pkt1);
Fabrice Bellard's avatar
Fabrice Bellard committed
341 342 343 344 345 346 347 348 349 350 351 352
    /* XXX: should duplicate packet data in DV case */
    SDL_CondSignal(q->cond);

    SDL_UnlockMutex(q->mutex);
    return 0;
}

static void packet_queue_abort(PacketQueue *q)
{
    SDL_LockMutex(q->mutex);

    q->abort_request = 1;
353

Fabrice Bellard's avatar
Fabrice Bellard committed
354 355 356 357 358 359 360 361 362 363 364 365 366
    SDL_CondSignal(q->cond);

    SDL_UnlockMutex(q->mutex);
}

/* return < 0 if aborted, 0 if no packet and > 0 if packet.  */
static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
{
    AVPacketList *pkt1;
    int ret;

    SDL_LockMutex(q->mutex);

Aneesh Dogra's avatar
Aneesh Dogra committed
367
    for (;;) {
Fabrice Bellard's avatar
Fabrice Bellard committed
368 369 370 371
        if (q->abort_request) {
            ret = -1;
            break;
        }
372

Fabrice Bellard's avatar
Fabrice Bellard committed
373 374 375 376 377 378
        pkt1 = q->first_pkt;
        if (pkt1) {
            q->first_pkt = pkt1->next;
            if (!q->first_pkt)
                q->last_pkt = NULL;
            q->nb_packets--;
379
            q->size -= pkt1->pkt.size + sizeof(*pkt1);
Fabrice Bellard's avatar
Fabrice Bellard committed
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
            *pkt = pkt1->pkt;
            av_free(pkt1);
            ret = 1;
            break;
        } else if (!block) {
            ret = 0;
            break;
        } else {
            SDL_CondWait(q->cond, q->mutex);
        }
    }
    SDL_UnlockMutex(q->mutex);
    return ret;
}

395
static inline void fill_rectangle(SDL_Surface *screen,
Fabrice Bellard's avatar
Fabrice Bellard committed
396 397 398 399 400 401 402 403 404 405
                                  int x, int y, int w, int h, int color)
{
    SDL_Rect rect;
    rect.x = x;
    rect.y = y;
    rect.w = w;
    rect.h = h;
    SDL_FillRect(screen, &rect, color);
}

406 407 408 409 410 411 412 413 414 415 416 417 418 419
#define ALPHA_BLEND(a, oldp, newp, s)\
((((oldp << s) * (255 - (a))) + (newp * (a))) / (255 << s))

#define RGBA_IN(r, g, b, a, s)\
{\
    unsigned int v = ((const uint32_t *)(s))[0];\
    a = (v >> 24) & 0xff;\
    r = (v >> 16) & 0xff;\
    g = (v >> 8) & 0xff;\
    b = v & 0xff;\
}

#define YUVA_IN(y, u, v, a, s, pal)\
{\
420
    unsigned int val = ((const uint32_t *)(pal))[*(const uint8_t*)(s)];\
421 422 423 424 425 426 427 428 429 430 431 432 433 434
    a = (val >> 24) & 0xff;\
    y = (val >> 16) & 0xff;\
    u = (val >> 8) & 0xff;\
    v = val & 0xff;\
}

#define YUVA_OUT(d, y, u, v, a)\
{\
    ((uint32_t *)(d))[0] = (a << 24) | (y << 16) | (u << 8) | v;\
}


#define BPP 1

435
static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, int imgh)
436 437 438 439 440 441
{
    int wrap, wrap3, width2, skip2;
    int y, u, v, a, u1, v1, a1, w, h;
    uint8_t *lum, *cb, *cr;
    const uint8_t *p;
    const uint32_t *pal;
442 443
    int dstx, dsty, dstw, dsth;

444 445 446 447
    dstw = av_clip(rect->w, 0, imgw);
    dsth = av_clip(rect->h, 0, imgh);
    dstx = av_clip(rect->x, 0, imgw - dstw);
    dsty = av_clip(rect->y, 0, imgh - dsth);
448
    lum = dst->data[0] + dsty * dst->linesize[0];
Aneesh Dogra's avatar
Aneesh Dogra committed
449 450
    cb  = dst->data[1] + (dsty >> 1) * dst->linesize[1];
    cr  = dst->data[2] + (dsty >> 1) * dst->linesize[2];
451

452
    width2 = ((dstw + 1) >> 1) + (dstx & ~dstw & 1);
453
    skip2 = dstx >> 1;
454
    wrap = dst->linesize[0];
455 456 457
    wrap3 = rect->pict.linesize[0];
    p = rect->pict.data[0];
    pal = (const uint32_t *)rect->pict.data[1];  /* Now in YCrCb! */
458

459 460
    if (dsty & 1) {
        lum += dstx;
461 462
        cb += skip2;
        cr += skip2;
463

464
        if (dstx & 1) {
465 466 467 468 469 470 471 472 473
            YUVA_IN(y, u, v, a, p, pal);
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
            cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
            cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
            cb++;
            cr++;
            lum++;
            p += BPP;
        }
Aneesh Dogra's avatar
Aneesh Dogra committed
474
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
            YUVA_IN(y, u, v, a, p, pal);
            u1 = u;
            v1 = v;
            a1 = a;
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);

            YUVA_IN(y, u, v, a, p + BPP, pal);
            u1 += u;
            v1 += v;
            a1 += a;
            lum[1] = ALPHA_BLEND(a, lum[1], y, 0);
            cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1);
            cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1);
            cb++;
            cr++;
            p += 2 * BPP;
            lum += 2;
        }
        if (w) {
            YUVA_IN(y, u, v, a, p, pal);
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
            cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
            cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
498 499
            p++;
            lum++;
500
        }
501 502
        p += wrap3 - dstw * BPP;
        lum += wrap - dstw - dstx;
503 504 505
        cb += dst->linesize[1] - width2 - skip2;
        cr += dst->linesize[2] - width2 - skip2;
    }
Aneesh Dogra's avatar
Aneesh Dogra committed
506
    for (h = dsth - (dsty & 1); h >= 2; h -= 2) {
507
        lum += dstx;
508 509
        cb += skip2;
        cr += skip2;
510

511
        if (dstx & 1) {
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
            YUVA_IN(y, u, v, a, p, pal);
            u1 = u;
            v1 = v;
            a1 = a;
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
            p += wrap3;
            lum += wrap;
            YUVA_IN(y, u, v, a, p, pal);
            u1 += u;
            v1 += v;
            a1 += a;
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
            cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1);
            cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1);
            cb++;
            cr++;
            p += -wrap3 + BPP;
            lum += -wrap + 1;
        }
Aneesh Dogra's avatar
Aneesh Dogra committed
531
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
532 533 534 535 536 537
            YUVA_IN(y, u, v, a, p, pal);
            u1 = u;
            v1 = v;
            a1 = a;
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);

538
            YUVA_IN(y, u, v, a, p + BPP, pal);
539 540 541 542 543 544 545 546 547 548 549 550 551
            u1 += u;
            v1 += v;
            a1 += a;
            lum[1] = ALPHA_BLEND(a, lum[1], y, 0);
            p += wrap3;
            lum += wrap;

            YUVA_IN(y, u, v, a, p, pal);
            u1 += u;
            v1 += v;
            a1 += a;
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);

552
            YUVA_IN(y, u, v, a, p + BPP, pal);
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
            u1 += u;
            v1 += v;
            a1 += a;
            lum[1] = ALPHA_BLEND(a, lum[1], y, 0);

            cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 2);
            cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 2);

            cb++;
            cr++;
            p += -wrap3 + 2 * BPP;
            lum += -wrap + 2;
        }
        if (w) {
            YUVA_IN(y, u, v, a, p, pal);
            u1 = u;
            v1 = v;
            a1 = a;
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
            p += wrap3;
            lum += wrap;
            YUVA_IN(y, u, v, a, p, pal);
            u1 += u;
            v1 += v;
            a1 += a;
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
            cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1);
            cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1);
            cb++;
            cr++;
            p += -wrap3 + BPP;
            lum += -wrap + 1;
        }
586 587
        p += wrap3 + (wrap3 - dstw * BPP);
        lum += wrap + (wrap - dstw - dstx);
588 589 590 591 592
        cb += dst->linesize[1] - width2 - skip2;
        cr += dst->linesize[2] - width2 - skip2;
    }
    /* handle odd height */
    if (h) {
593
        lum += dstx;
594 595
        cb += skip2;
        cr += skip2;
596

597
        if (dstx & 1) {
598 599 600 601 602 603 604 605 606
            YUVA_IN(y, u, v, a, p, pal);
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
            cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
            cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
            cb++;
            cr++;
            lum++;
            p += BPP;
        }
Aneesh Dogra's avatar
Aneesh Dogra committed
607
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
            YUVA_IN(y, u, v, a, p, pal);
            u1 = u;
            v1 = v;
            a1 = a;
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);

            YUVA_IN(y, u, v, a, p + BPP, pal);
            u1 += u;
            v1 += v;
            a1 += a;
            lum[1] = ALPHA_BLEND(a, lum[1], y, 0);
            cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u, 1);
            cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v, 1);
            cb++;
            cr++;
            p += 2 * BPP;
            lum += 2;
        }
        if (w) {
            YUVA_IN(y, u, v, a, p, pal);
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
            cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
            cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
        }
    }
}

static void free_subpicture(SubPicture *sp)
{
637
    avsubtitle_free(&sp->sub);
638 639
}

Fabrice Bellard's avatar
Fabrice Bellard committed
640 641 642
static void video_image_display(VideoState *is)
{
    VideoPicture *vp;
643 644
    SubPicture *sp;
    AVPicture pict;
Fabrice Bellard's avatar
Fabrice Bellard committed
645 646 647
    float aspect_ratio;
    int width, height, x, y;
    SDL_Rect rect;
648
    int i;
Fabrice Bellard's avatar
Fabrice Bellard committed
649 650 651

    vp = &is->pictq[is->pictq_rindex];
    if (vp->bmp) {
652
#if CONFIG_AVFILTER
653
         if (!vp->sar.num)
654 655
             aspect_ratio = 0;
         else
656
             aspect_ratio = av_q2d(vp->sar);
657 658
#else

Fabrice Bellard's avatar
Fabrice Bellard committed
659
        /* XXX: use variable in the frame */
660 661 662 663
        if (is->video_st->sample_aspect_ratio.num)
            aspect_ratio = av_q2d(is->video_st->sample_aspect_ratio);
        else if (is->video_st->codec->sample_aspect_ratio.num)
            aspect_ratio = av_q2d(is->video_st->codec->sample_aspect_ratio);
Fabrice Bellard's avatar
Fabrice Bellard committed
664
        else
665
            aspect_ratio = 0;
666
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
667
        if (aspect_ratio <= 0.0)
668
            aspect_ratio = 1.0;
669
        aspect_ratio *= (float)vp->width / (float)vp->height;
Fabrice Bellard's avatar
Fabrice Bellard committed
670

671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
        if (is->subtitle_st)
        {
            if (is->subpq_size > 0)
            {
                sp = &is->subpq[is->subpq_rindex];

                if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000))
                {
                    SDL_LockYUVOverlay (vp->bmp);

                    pict.data[0] = vp->bmp->pixels[0];
                    pict.data[1] = vp->bmp->pixels[2];
                    pict.data[2] = vp->bmp->pixels[1];

                    pict.linesize[0] = vp->bmp->pitches[0];
                    pict.linesize[1] = vp->bmp->pitches[2];
                    pict.linesize[2] = vp->bmp->pitches[1];

                    for (i = 0; i < sp->sub.num_rects; i++)
690
                        blend_subrect(&pict, sp->sub.rects[i],
691
                                      vp->bmp->w, vp->bmp->h);
692 693 694 695 696 697 698

                    SDL_UnlockYUVOverlay (vp->bmp);
                }
            }
        }


Fabrice Bellard's avatar
Fabrice Bellard committed
699 700
        /* XXX: we suppose the screen has a 1.0 pixel ratio */
        height = is->height;
701
        width = ((int)rint(height * aspect_ratio)) & ~1;
Fabrice Bellard's avatar
Fabrice Bellard committed
702 703
        if (width > is->width) {
            width = is->width;
704
            height = ((int)rint(width / aspect_ratio)) & ~1;
Fabrice Bellard's avatar
Fabrice Bellard committed
705 706 707
        }
        x = (is->width - width) / 2;
        y = (is->height - height) / 2;
708
        is->no_background = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
709
        rect.x = is->xleft + x;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
710
        rect.y = is->ytop  + y;
Fabrice Bellard's avatar
Fabrice Bellard committed
711 712 713 714 715 716
        rect.w = width;
        rect.h = height;
        SDL_DisplayYUVOverlay(vp->bmp, &rect);
    }
}

717 718 719 720 721 722 723
/* get the current audio output buffer size, in samples. With SDL, we
   cannot have a precise information */
static int audio_write_get_buf_size(VideoState *is)
{
    return is->audio_buf_size - is->audio_buf_index;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
724 725 726
static inline int compute_mod(int a, int b)
{
    a = a % b;
727
    if (a >= 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
728 729 730 731 732 733 734 735 736 737
        return a;
    else
        return a + b;
}

static void video_audio_display(VideoState *s)
{
    int i, i_start, x, y1, y, ys, delay, n, nb_display_channels;
    int ch, channels, h, h2, bgcolor, fgcolor;
    int16_t time_diff;
738 739
    int rdft_bits, nb_freq;

Aneesh Dogra's avatar
Aneesh Dogra committed
740
    for (rdft_bits = 1; (1 << rdft_bits) < 2 * s->height; rdft_bits++)
741
        ;
Aneesh Dogra's avatar
Aneesh Dogra committed
742
    nb_freq = 1 << (rdft_bits - 1);
743

Fabrice Bellard's avatar
Fabrice Bellard committed
744
    /* compute display index : center on currently output samples */
745
    channels = s->sdl_channels;
Fabrice Bellard's avatar
Fabrice Bellard committed
746
    nb_display_channels = channels;
747
    if (!s->paused) {
Aneesh Dogra's avatar
Aneesh Dogra committed
748
        int data_used = s->show_audio == 1 ? s->width : (2 * nb_freq);
749 750 751
        n = 2 * channels;
        delay = audio_write_get_buf_size(s);
        delay /= n;
752

753 754 755 756
        /* to be more precise, we take into account the time spent since
           the last buffer computation */
        if (audio_callback_time) {
            time_diff = av_gettime() - audio_callback_time;
757
            delay -= (time_diff * s->sdl_sample_rate) / 1000000;
758
        }
759

Aneesh Dogra's avatar
Aneesh Dogra committed
760
        delay += 2 * data_used;
761 762
        if (delay < data_used)
            delay = data_used;
763 764

        i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
Aneesh Dogra's avatar
Aneesh Dogra committed
765 766 767 768 769 770 771 772 773 774 775 776
        if (s->show_audio == 1) {
            h = INT_MIN;
            for (i = 0; i < 1000; i += channels) {
                int idx = (SAMPLE_ARRAY_SIZE + x - i) % SAMPLE_ARRAY_SIZE;
                int a = s->sample_array[idx];
                int b = s->sample_array[(idx + 4 * channels) % SAMPLE_ARRAY_SIZE];
                int c = s->sample_array[(idx + 5 * channels) % SAMPLE_ARRAY_SIZE];
                int d = s->sample_array[(idx + 9 * channels) % SAMPLE_ARRAY_SIZE];
                int score = a - d;
                if (h < score && (b ^ c) < 0) {
                    h = score;
                    i_start = idx;
777
                }
778 779 780
            }
        }

781 782 783
        s->last_i_start = i_start;
    } else {
        i_start = s->last_i_start;
Fabrice Bellard's avatar
Fabrice Bellard committed
784 785 786
    }

    bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
Aneesh Dogra's avatar
Aneesh Dogra committed
787
    if (s->show_audio == 1) {
788 789 790 791 792 793 794 795 796 797
        fill_rectangle(screen,
                       s->xleft, s->ytop, s->width, s->height,
                       bgcolor);

        fgcolor = SDL_MapRGB(screen->format, 0xff, 0xff, 0xff);

        /* total height for one channel */
        h = s->height / nb_display_channels;
        /* graph height / 2 */
        h2 = (h * 9) / 20;
Aneesh Dogra's avatar
Aneesh Dogra committed
798
        for (ch = 0; ch < nb_display_channels; ch++) {
799 800
            i = i_start + ch;
            y1 = s->ytop + ch * h + (h / 2); /* position of center line */
Aneesh Dogra's avatar
Aneesh Dogra committed
801
            for (x = 0; x < s->width; x++) {
802 803 804 805 806 807 808 809 810 811 812 813 814
                y = (s->sample_array[i] * h2) >> 15;
                if (y < 0) {
                    y = -y;
                    ys = y1 - y;
                } else {
                    ys = y1;
                }
                fill_rectangle(screen,
                               s->xleft + x, ys, 1, y,
                               fgcolor);
                i += channels;
                if (i >= SAMPLE_ARRAY_SIZE)
                    i -= SAMPLE_ARRAY_SIZE;
Fabrice Bellard's avatar
Fabrice Bellard committed
815 816 817
            }
        }

818
        fgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0xff);
Fabrice Bellard's avatar
Fabrice Bellard committed
819

Aneesh Dogra's avatar
Aneesh Dogra committed
820
        for (ch = 1; ch < nb_display_channels; ch++) {
821 822 823 824 825 826
            y = s->ytop + ch * h;
            fill_rectangle(screen,
                           s->xleft, y, s->width, 1,
                           fgcolor);
        }
        SDL_UpdateRect(screen, s->xleft, s->ytop, s->width, s->height);
Aneesh Dogra's avatar
Aneesh Dogra committed
827
    } else {
828
        nb_display_channels= FFMIN(nb_display_channels, 2);
Aneesh Dogra's avatar
Aneesh Dogra committed
829
        if (rdft_bits != s->rdft_bits) {
830
            av_rdft_end(s->rdft);
Måns Rullgård's avatar
Måns Rullgård committed
831
            av_free(s->rdft_data);
832
            s->rdft = av_rdft_init(rdft_bits, DFT_R2C);
Aneesh Dogra's avatar
Aneesh Dogra committed
833 834
            s->rdft_bits = rdft_bits;
            s->rdft_data = av_malloc(4 * nb_freq * sizeof(*s->rdft_data));
835 836
        }
        {
Måns Rullgård's avatar
Måns Rullgård committed
837
            FFTSample *data[2];
Aneesh Dogra's avatar
Aneesh Dogra committed
838 839
            for (ch = 0; ch < nb_display_channels; ch++) {
                data[ch] = s->rdft_data + 2 * nb_freq * ch;
840
                i = i_start + ch;
Aneesh Dogra's avatar
Aneesh Dogra committed
841 842 843
                for (x = 0; x < 2 * nb_freq; x++) {
                    double w = (x-nb_freq) * (1.0 / nb_freq);
                    data[ch][x] = s->sample_array[i] * (1.0 - w * w);
844 845 846 847
                    i += channels;
                    if (i >= SAMPLE_ARRAY_SIZE)
                        i -= SAMPLE_ARRAY_SIZE;
                }
848
                av_rdft_calc(s->rdft, data[ch]);
849
            }
Aneesh Dogra's avatar
Aneesh Dogra committed
850 851 852 853 854 855 856 857 858
            // least efficient way to do this, we should of course directly access it but its more than fast enough
            for (y = 0; y < s->height; y++) {
                double w = 1 / sqrt(nb_freq);
                int a = sqrt(w * sqrt(data[0][2 * y + 0] * data[0][2 * y + 0] + data[0][2 * y + 1] * data[0][2 * y + 1]));
                int b = (nb_display_channels == 2 ) ? sqrt(w * sqrt(data[1][2 * y + 0] * data[1][2 * y + 0]
                       + data[1][2 * y + 1] * data[1][2 * y + 1])) : a;
                a = FFMIN(a, 255);
                b = FFMIN(b, 255);
                fgcolor = SDL_MapRGB(screen->format, a, b, (a + b) / 2);
859 860 861 862 863 864 865 866

                fill_rectangle(screen,
                            s->xpos, s->height-y, 1, 1,
                            fgcolor);
            }
        }
        SDL_UpdateRect(screen, s->xpos, s->ytop, 1, s->height);
        s->xpos++;
Aneesh Dogra's avatar
Aneesh Dogra committed
867
        if (s->xpos >= s->width)
868 869
            s->xpos= s->xleft;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
870 871
}

Aneesh Dogra's avatar
Aneesh Dogra committed
872 873 874
static int video_open(VideoState *is)
{
    int flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
875 876
    int w,h;

Aneesh Dogra's avatar
Aneesh Dogra committed
877 878
    if (is_full_screen) flags |= SDL_FULLSCREEN;
    else                flags |= SDL_RESIZABLE;
879

880 881 882
    if (is_full_screen && fs_screen_width) {
        w = fs_screen_width;
        h = fs_screen_height;
Aneesh Dogra's avatar
Aneesh Dogra committed
883
    } else if (!is_full_screen && screen_width) {
884 885
        w = screen_width;
        h = screen_height;
886
#if CONFIG_AVFILTER
Aneesh Dogra's avatar
Aneesh Dogra committed
887
    } else if (is->out_video_filter && is->out_video_filter->inputs[0]) {
888 889 890
        w = is->out_video_filter->inputs[0]->w;
        h = is->out_video_filter->inputs[0]->h;
#else
Aneesh Dogra's avatar
Aneesh Dogra committed
891
    } else if (is->video_st && is->video_st->codec->width) {
892 893
        w = is->video_st->codec->width;
        h = is->video_st->codec->height;
894
#endif
895
    } else {
896 897
        w = 640;
        h = 480;
898
    }
Aneesh Dogra's avatar
Aneesh Dogra committed
899
    if (screen && is->width == screen->w && screen->w == w
900 901 902
       && is->height== screen->h && screen->h == h)
        return 0;

903 904
#if defined(__APPLE__) && !SDL_VERSION_ATLEAST(1, 2, 14)
    /* setting bits_per_pixel = 0 or 32 causes blank video on OS X and older SDL */
905
    screen = SDL_SetVideoMode(w, h, 24, flags);
906 907
#else
    screen = SDL_SetVideoMode(w, h, 0, flags);
908 909 910 911 912
#endif
    if (!screen) {
        fprintf(stderr, "SDL: could not set video mode - exiting\n");
        return -1;
    }
913 914 915
    if (!window_title)
        window_title = input_filename;
    SDL_WM_SetCaption(window_title, window_title);
916

Aneesh Dogra's avatar
Aneesh Dogra committed
917
    is->width  = screen->w;
918 919 920 921
    is->height = screen->h;

    return 0;
}
922

Fabrice Bellard's avatar
Fabrice Bellard committed
923 924 925
/* display the current picture, if any */
static void video_display(VideoState *is)
{
Aneesh Dogra's avatar
Aneesh Dogra committed
926
    if (!screen)
927
        video_open(cur_stream);
928
    if (is->audio_st && is->show_audio)
Fabrice Bellard's avatar
Fabrice Bellard committed
929 930 931 932 933
        video_audio_display(is);
    else if (is->video_st)
        video_image_display(is);
}

934
static int refresh_thread(void *opaque)
Fabrice Bellard's avatar
Fabrice Bellard committed
935
{
936
    VideoState *is= opaque;
Aneesh Dogra's avatar
Aneesh Dogra committed
937
    while (!is->abort_request) {
938 939 940
        SDL_Event event;
        event.type = FF_REFRESH_EVENT;
        event.user.data1 = opaque;
Aneesh Dogra's avatar
Aneesh Dogra committed
941 942
        if (!is->refresh) {
            is->refresh = 1;
943
            SDL_PushEvent(&event);
944
        }
945
        av_usleep(is->audio_st && is->show_audio ? rdftspeed * 1000 : 5000); // FIXME ideally we should wait the correct time but SDLs event passing is so slow it would be silly
946 947
    }
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
948 949
}

950 951 952 953 954 955 956 957 958
/* get the current audio clock value */
static double get_audio_clock(VideoState *is)
{
    double pts;
    int hw_buf_size, bytes_per_sec;
    pts = is->audio_clock;
    hw_buf_size = audio_write_get_buf_size(is);
    bytes_per_sec = 0;
    if (is->audio_st) {
959
        bytes_per_sec = is->sdl_sample_rate * is->sdl_channels *
960
                        av_get_bytes_per_sample(is->sdl_sample_fmt);
961 962 963 964 965 966 967 968 969
    }
    if (bytes_per_sec)
        pts -= (double)hw_buf_size / bytes_per_sec;
    return pts;
}

/* get the current video clock value */
static double get_video_clock(VideoState *is)
{
Michael Niedermayer's avatar
Michael Niedermayer committed
970
    if (is->paused) {
971
        return is->video_current_pts;
Fabrice Bellard's avatar
Fabrice Bellard committed
972
    } else {
973
        return is->video_current_pts_drift + av_gettime() / 1000000.0;
Fabrice Bellard's avatar
Fabrice Bellard committed
974
    }
975 976 977 978 979 980 981 982 983 984 985 986 987 988 989
}

/* get the current external clock value */
static double get_external_clock(VideoState *is)
{
    int64_t ti;
    ti = av_gettime();
    return is->external_clock + ((ti - is->external_clock_time) * 1e-6);
}

/* get the current master clock value */
static double get_master_clock(VideoState *is)
{
    double val;

Fabrice Bellard's avatar
Fabrice Bellard committed
990 991 992 993 994 995 996 997 998 999 1000
    if (is->av_sync_type == AV_SYNC_VIDEO_MASTER) {
        if (is->video_st)
            val = get_video_clock(is);
        else
            val = get_audio_clock(is);
    } else if (is->av_sync_type == AV_SYNC_AUDIO_MASTER) {
        if (is->audio_st)
            val = get_audio_clock(is);
        else
            val = get_video_clock(is);
    } else {
1001
        val = get_external_clock(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
1002
    }
1003 1004 1005
    return val;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
1006
/* seek in the stream */
1007
static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_bytes)
Fabrice Bellard's avatar
Fabrice Bellard committed
1008
{
1009 1010
    if (!is->seek_req) {
        is->seek_pos = pos;
1011
        is->seek_rel = rel;
Michael Niedermayer's avatar
Michael Niedermayer committed
1012
        is->seek_flags &= ~AVSEEK_FLAG_BYTE;
1013 1014
        if (seek_by_bytes)
            is->seek_flags |= AVSEEK_FLAG_BYTE;
1015 1016
        is->seek_req = 1;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
1017 1018 1019 1020 1021
}

/* pause or resume the video */
static void stream_pause(VideoState *is)
{
1022 1023
    if (is->paused) {
        is->frame_timer += av_gettime() / 1000000.0 + is->video_current_pts_drift - is->video_current_pts;
Aneesh Dogra's avatar
Aneesh Dogra committed
1024
        if (is->read_pause_return != AVERROR(ENOSYS)) {
1025
            is->video_current_pts = is->video_current_pts_drift + av_gettime() / 1000000.0;
1026
        }
1027
        is->video_current_pts_drift = is->video_current_pts - av_gettime() / 1000000.0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1028
    }
1029
    is->paused = !is->paused;
Fabrice Bellard's avatar
Fabrice Bellard committed
1030 1031
}

1032
static double compute_target_time(double frame_current_pts, VideoState *is)
1033
{
1034
    double delay, sync_threshold, diff;
1035 1036 1037 1038 1039 1040

    /* compute nominal delay */
    delay = frame_current_pts - is->frame_last_pts;
    if (delay <= 0 || delay >= 10.0) {
        /* if incorrect delay, use previous one */
        delay = is->frame_last_delay;
1041
    } else {
1042
        is->frame_last_delay = delay;
1043
    }
1044 1045 1046 1047 1048 1049 1050
    is->frame_last_pts = frame_current_pts;

    /* update delay to follow master synchronisation source */
    if (((is->av_sync_type == AV_SYNC_AUDIO_MASTER && is->audio_st) ||
         is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {
        /* if video is slave, we try to correct big delays by
           duplicating or deleting a frame */
1051
        diff = get_video_clock(is) - get_master_clock(is);
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064

        /* skip or repeat frame. We take into account the
           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 (diff <= -sync_threshold)
                delay = 0;
            else if (diff >= sync_threshold)
                delay = 2 * delay;
        }
    }
    is->frame_timer += delay;
1065 1066 1067

    av_dlog(NULL, "video: delay=%0.3f pts=%0.3f A-V=%f\n",
            delay, frame_current_pts, -diff);
1068

1069
    return is->frame_timer;
1070 1071
}

Fabrice Bellard's avatar
Fabrice Bellard committed
1072 1073 1074 1075 1076
/* called to display each frame */
static void video_refresh_timer(void *opaque)
{
    VideoState *is = opaque;
    VideoPicture *vp;
1077

1078
    SubPicture *sp, *sp2;
Fabrice Bellard's avatar
Fabrice Bellard committed
1079 1080

    if (is->video_st) {
1081
retry:
Fabrice Bellard's avatar
Fabrice Bellard committed
1082
        if (is->pictq_size == 0) {
Aneesh Dogra's avatar
Aneesh Dogra committed
1083
            // nothing to do, no picture to display in the que
Fabrice Bellard's avatar
Fabrice Bellard committed
1084
        } else {
Aneesh Dogra's avatar
Aneesh Dogra committed
1085
            double time = av_gettime() / 1000000.0;
1086
            double next_target;
1087
            /* dequeue the picture */
Fabrice Bellard's avatar
Fabrice Bellard committed
1088
            vp = &is->pictq[is->pictq_rindex];
1089

Aneesh Dogra's avatar
Aneesh Dogra committed
1090
            if (time < vp->target_clock)
1091
                return;
1092 1093
            /* update current video pts */
            is->video_current_pts = vp->pts;
1094
            is->video_current_pts_drift = is->video_current_pts - time;
1095
            is->video_current_pos = vp->pos;
Aneesh Dogra's avatar
Aneesh Dogra committed
1096 1097
            if (is->pictq_size > 1) {
                VideoPicture *nextvp = &is->pictq[(is->pictq_rindex + 1) % VIDEO_PICTURE_QUEUE_SIZE];
1098 1099
                assert(nextvp->target_clock >= vp->target_clock);
                next_target= nextvp->target_clock;
Aneesh Dogra's avatar
Aneesh Dogra committed
1100 1101
            } else {
                next_target = vp->target_clock + is->video_clock - vp->pts; // FIXME pass durations cleanly
1102
            }
Aneesh Dogra's avatar
Aneesh Dogra committed
1103
            if (framedrop && time > next_target) {
1104
                is->skip_frames *= 1.0 + FRAME_SKIP_FACTOR;
Aneesh Dogra's avatar
Aneesh Dogra committed
1105
                if (is->pictq_size > 1 || time > next_target + 0.5) {
1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116
                    /* update queue size and signal for next picture */
                    if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
                        is->pictq_rindex = 0;

                    SDL_LockMutex(is->pictq_mutex);
                    is->pictq_size--;
                    SDL_CondSignal(is->pictq_cond);
                    SDL_UnlockMutex(is->pictq_mutex);
                    goto retry;
                }
            }
1117

Aneesh Dogra's avatar
Aneesh Dogra committed
1118
            if (is->subtitle_st) {
1119 1120
                if (is->subtitle_stream_changed) {
                    SDL_LockMutex(is->subpq_mutex);
1121

1122 1123
                    while (is->subpq_size) {
                        free_subpicture(&is->subpq[is->subpq_rindex]);
1124

1125 1126 1127
                        /* update queue size and signal for next picture */
                        if (++is->subpq_rindex == SUBPICTURE_QUEUE_SIZE)
                            is->subpq_rindex = 0;
1128

1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161
                        is->subpq_size--;
                    }
                    is->subtitle_stream_changed = 0;

                    SDL_CondSignal(is->subpq_cond);
                    SDL_UnlockMutex(is->subpq_mutex);
                } else {
                    if (is->subpq_size > 0) {
                        sp = &is->subpq[is->subpq_rindex];

                        if (is->subpq_size > 1)
                            sp2 = &is->subpq[(is->subpq_rindex + 1) % SUBPICTURE_QUEUE_SIZE];
                        else
                            sp2 = NULL;

                        if ((is->video_current_pts > (sp->pts + ((float) sp->sub.end_display_time / 1000)))
                                || (sp2 && is->video_current_pts > (sp2->pts + ((float) sp2->sub.start_display_time / 1000))))
                        {
                            free_subpicture(sp);

                            /* update queue size and signal for next picture */
                            if (++is->subpq_rindex == SUBPICTURE_QUEUE_SIZE)
                                is->subpq_rindex = 0;

                            SDL_LockMutex(is->subpq_mutex);
                            is->subpq_size--;
                            SDL_CondSignal(is->subpq_cond);
                            SDL_UnlockMutex(is->subpq_mutex);
                        }
                    }
                }
            }

Fabrice Bellard's avatar
Fabrice Bellard committed
1162
            /* display picture */
1163
            if (!display_disable)
1164
                video_display(is);
1165

Fabrice Bellard's avatar
Fabrice Bellard committed
1166 1167 1168
            /* update queue size and signal for next picture */
            if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
                is->pictq_rindex = 0;
1169

Fabrice Bellard's avatar
Fabrice Bellard committed
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179
            SDL_LockMutex(is->pictq_mutex);
            is->pictq_size--;
            SDL_CondSignal(is->pictq_cond);
            SDL_UnlockMutex(is->pictq_mutex);
        }
    } else if (is->audio_st) {
        /* draw the next audio frame */

        /* if only audio stream, then display the audio bars (better
           than nothing, just to test the implementation */
1180

Fabrice Bellard's avatar
Fabrice Bellard committed
1181
        /* display picture */
1182
        if (!display_disable)
1183
            video_display(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
1184 1185 1186 1187
    }
    if (show_status) {
        static int64_t last_time;
        int64_t cur_time;
1188
        int aqsize, vqsize, sqsize;
1189
        double av_diff;
1190

Fabrice Bellard's avatar
Fabrice Bellard committed
1191
        cur_time = av_gettime();
1192
        if (!last_time || (cur_time - last_time) >= 30000) {
Fabrice Bellard's avatar
Fabrice Bellard committed
1193 1194
            aqsize = 0;
            vqsize = 0;
1195
            sqsize = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1196 1197 1198 1199
            if (is->audio_st)
                aqsize = is->audioq.size;
            if (is->video_st)
                vqsize = is->videoq.size;
1200 1201
            if (is->subtitle_st)
                sqsize = is->subtitleq.size;
1202 1203 1204
            av_diff = 0;
            if (is->audio_st && is->video_st)
                av_diff = get_audio_clock(is) - get_video_clock(is);
1205
            printf("%7.2f A-V:%7.3f s:%3.1f aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64"   \r",
Aneesh Dogra's avatar
Aneesh Dogra committed
1206 1207
                   get_master_clock(is), av_diff, FFMAX(is->skip_frames - 1, 0), aqsize / 1024,
                   vqsize / 1024, sqsize, is->pts_ctx.num_faulty_dts, is->pts_ctx.num_faulty_pts);
Fabrice Bellard's avatar
Fabrice Bellard committed
1208 1209 1210 1211 1212 1213
            fflush(stdout);
            last_time = cur_time;
        }
    }
}

1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
static void stream_close(VideoState *is)
{
    VideoPicture *vp;
    int i;
    /* XXX: use a special url_shutdown call to abort parse cleanly */
    is->abort_request = 1;
    SDL_WaitThread(is->parse_tid, NULL);
    SDL_WaitThread(is->refresh_tid, NULL);

    /* free all pictures */
Aneesh Dogra's avatar
Aneesh Dogra committed
1224
    for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247
        vp = &is->pictq[i];
        if (vp->bmp) {
            SDL_FreeYUVOverlay(vp->bmp);
            vp->bmp = NULL;
        }
    }
    SDL_DestroyMutex(is->pictq_mutex);
    SDL_DestroyCond(is->pictq_cond);
    SDL_DestroyMutex(is->subpq_mutex);
    SDL_DestroyCond(is->subpq_cond);
#if !CONFIG_AVFILTER
    if (is->img_convert_ctx)
        sws_freeContext(is->img_convert_ctx);
#endif
    av_free(is);
}

static void do_exit(void)
{
    if (cur_stream) {
        stream_close(cur_stream);
        cur_stream = NULL;
    }
1248
    uninit_opts();
1249
    avformat_network_deinit();
1250 1251 1252
    if (show_status)
        printf("\n");
    SDL_Quit();
1253
    av_log(NULL, AV_LOG_QUIET, "");
1254 1255 1256
    exit(0);
}

Fabrice Bellard's avatar
Fabrice Bellard committed
1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
/* allocate a picture (needs to do that in main thread to avoid
   potential locking problems */
static void alloc_picture(void *opaque)
{
    VideoState *is = opaque;
    VideoPicture *vp;

    vp = &is->pictq[is->pictq_windex];

    if (vp->bmp)
        SDL_FreeYUVOverlay(vp->bmp);

1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279
#if CONFIG_AVFILTER
    vp->width   = is->out_video_filter->