avplay.c 96.9 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 27
#include <stdint.h>

28
#include "libavutil/avstring.h"
29
#include "libavutil/colorspace.h"
30
#include "libavutil/mathematics.h"
31
#include "libavutil/pixdesc.h"
32
#include "libavutil/imgutils.h"
33
#include "libavutil/dict.h"
34 35
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
36
#include "libavutil/time.h"
37 38 39
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
40
#include "libavresample/avresample.h"
41
#include "libavutil/opt.h"
42
#include "libavcodec/avfft.h"
Fabrice Bellard's avatar
Fabrice Bellard committed
43

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

Fabrice Bellard's avatar
Fabrice Bellard committed
50 51 52 53 54
#include "cmdutils.h"

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

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

59 60
#include <assert.h>

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

64 65 66
#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
67

68 69 70 71 72
/* 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 */
73
#define AV_SYNC_THRESHOLD 0.01
74 75 76
/* no AV correction is done if too big error */
#define AV_NOSYNC_THRESHOLD 10.0

77 78
#define FRAME_SKIP_FACTOR 0.05

79 80 81 82 83 84
/* 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
85
/* NOTE: the size must be big enough to compensate the hardware audio buffersize size */
Aneesh Dogra's avatar
Aneesh Dogra committed
86
#define SAMPLE_ARRAY_SIZE (2 * 65536)
Fabrice Bellard's avatar
Fabrice Bellard committed
87

88
static int64_t sws_flags = SWS_BICUBIC;
89

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

99
#define VIDEO_PICTURE_QUEUE_SIZE 2
100
#define SUBPICTURE_QUEUE_SIZE 4
Fabrice Bellard's avatar
Fabrice Bellard committed
101 102

typedef struct VideoPicture {
103 104 105
    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
106 107 108
    SDL_Overlay *bmp;
    int width, height; /* source height & width */
    int allocated;
109
    int reallocate;
110
    enum AVPixelFormat pix_fmt;
111

112
    AVRational sar;
Fabrice Bellard's avatar
Fabrice Bellard committed
113 114
} VideoPicture;

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

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

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

    int audio_stream;
143

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

148 149 150 151 152
    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
153 154 155
    AVStream *audio_st;
    PacketQueue audioq;
    int audio_hw_buf_size;
156
    uint8_t silence_buf[SDL_AUDIO_BUFFER_SIZE];
157
    uint8_t *audio_buf;
158
    uint8_t *audio_buf1;
159
    unsigned int audio_buf_size; /* in bytes */
Fabrice Bellard's avatar
Fabrice Bellard committed
160
    int audio_buf_index; /* in bytes */
161
    AVPacket audio_pkt_temp;
Fabrice Bellard's avatar
Fabrice Bellard committed
162
    AVPacket audio_pkt;
163 164 165
    enum AVSampleFormat sdl_sample_fmt;
    uint64_t sdl_channel_layout;
    int sdl_channels;
166
    int sdl_sample_rate;
167 168
    enum AVSampleFormat resample_sample_fmt;
    uint64_t resample_channel_layout;
169
    int resample_sample_rate;
170
    AVAudioResampleContext *avr;
171
    AVFrame *frame;
172

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

182 183 184 185 186 187 188 189 190
    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;
191

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

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

214
    PtsCorrectionContext pts_ctx;
215

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

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

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

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

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

274
static AVPacket flush_pkt;
275

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

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

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

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

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

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

static void packet_queue_end(PacketQueue *q)
{
    packet_queue_flush(q);
Fabrice Bellard's avatar
Fabrice Bellard committed
313 314 315 316 317 318 319 320
    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
321
    /* duplicate the packet */
Aneesh Dogra's avatar
Aneesh Dogra committed
322
    if (pkt != &flush_pkt && av_dup_packet(pkt) < 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
323
        return -1;
324

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

Fabrice Bellard's avatar
Fabrice Bellard committed
331

Fabrice Bellard's avatar
Fabrice Bellard committed
332 333 334 335 336 337 338 339 340
    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++;
341
    q->size += pkt1->pkt.size + sizeof(*pkt1);
Fabrice Bellard's avatar
Fabrice Bellard committed
342 343 344 345 346 347 348 349 350 351 352 353
    /* 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;
354

Fabrice Bellard's avatar
Fabrice Bellard committed
355 356 357 358 359 360 361 362 363 364 365 366 367
    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
368
    for (;;) {
Fabrice Bellard's avatar
Fabrice Bellard committed
369 370 371 372
        if (q->abort_request) {
            ret = -1;
            break;
        }
373

Fabrice Bellard's avatar
Fabrice Bellard committed
374 375 376 377 378 379
        pkt1 = q->first_pkt;
        if (pkt1) {
            q->first_pkt = pkt1->next;
            if (!q->first_pkt)
                q->last_pkt = NULL;
            q->nb_packets--;
380
            q->size -= pkt1->pkt.size + sizeof(*pkt1);
Fabrice Bellard's avatar
Fabrice Bellard committed
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
            *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;
}

396
static inline void fill_rectangle(SDL_Surface *screen,
Fabrice Bellard's avatar
Fabrice Bellard committed
397 398 399 400 401 402 403 404 405 406
                                  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);
}

407 408 409 410 411 412 413 414 415 416 417 418 419 420
#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)\
{\
421
    unsigned int val = ((const uint32_t *)(pal))[*(const uint8_t*)(s)];\
422 423 424 425 426 427 428 429 430 431 432 433 434 435
    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

436
static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, int imgh)
437 438 439 440 441 442
{
    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;
443 444
    int dstx, dsty, dstw, dsth;

445 446 447 448
    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);
449
    lum = dst->data[0] + dsty * dst->linesize[0];
Aneesh Dogra's avatar
Aneesh Dogra committed
450 451
    cb  = dst->data[1] + (dsty >> 1) * dst->linesize[1];
    cr  = dst->data[2] + (dsty >> 1) * dst->linesize[2];
452

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

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

465
        if (dstx & 1) {
466 467 468 469 470 471 472 473 474
            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
475
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
            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);
499 500
            p++;
            lum++;
501
        }
502 503
        p += wrap3 - dstw * BPP;
        lum += wrap - dstw - dstx;
504 505 506
        cb += dst->linesize[1] - width2 - skip2;
        cr += dst->linesize[2] - width2 - skip2;
    }
Aneesh Dogra's avatar
Aneesh Dogra committed
507
    for (h = dsth - (dsty & 1); h >= 2; h -= 2) {
508
        lum += dstx;
509 510
        cb += skip2;
        cr += skip2;
511

512
        if (dstx & 1) {
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
            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
532
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
533 534 535 536 537 538
            YUVA_IN(y, u, v, a, p, pal);
            u1 = u;
            v1 = v;
            a1 = a;
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);

539
            YUVA_IN(y, u, v, a, p + BPP, pal);
540 541 542 543 544 545 546 547 548 549 550 551 552
            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);

553
            YUVA_IN(y, u, v, a, p + BPP, pal);
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 586
            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;
        }
587 588
        p += wrap3 + (wrap3 - dstw * BPP);
        lum += wrap + (wrap - dstw - dstx);
589 590 591 592 593
        cb += dst->linesize[1] - width2 - skip2;
        cr += dst->linesize[2] - width2 - skip2;
    }
    /* handle odd height */
    if (h) {
594
        lum += dstx;
595 596
        cb += skip2;
        cr += skip2;
597

598
        if (dstx & 1) {
599 600 601 602 603 604 605 606 607
            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
608
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
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 637
            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)
{
638
    avsubtitle_free(&sp->sub);
639 640
}

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

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

Fabrice Bellard's avatar
Fabrice Bellard committed
660
        /* XXX: use variable in the frame */
661 662 663 664
        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
665
        else
666
            aspect_ratio = 0;
667
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
668
        if (aspect_ratio <= 0.0)
669
            aspect_ratio = 1.0;
670
        aspect_ratio *= (float)vp->width / (float)vp->height;
Fabrice Bellard's avatar
Fabrice Bellard committed
671

672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
        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++)
691
                        blend_subrect(&pict, sp->sub.rects[i],
692
                                      vp->bmp->w, vp->bmp->h);
693 694 695 696 697 698 699

                    SDL_UnlockYUVOverlay (vp->bmp);
                }
            }
        }


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

718 719 720 721 722 723 724
/* 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
725 726 727
static inline int compute_mod(int a, int b)
{
    a = a % b;
728
    if (a >= 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
729 730 731 732 733 734 735 736 737 738
        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;
739 740
    int rdft_bits, nb_freq;

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

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

754 755 756 757
        /* 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;
758
            delay -= (time_diff * s->sdl_sample_rate) / 1000000;
759
        }
760

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

        i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
Aneesh Dogra's avatar
Aneesh Dogra committed
766 767 768 769 770 771 772 773 774 775 776 777
        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;
778
                }
779 780 781
            }
        }

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

    bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
Aneesh Dogra's avatar
Aneesh Dogra committed
788
    if (s->show_audio == 1) {
789 790 791 792 793 794 795 796 797 798
        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
799
        for (ch = 0; ch < nb_display_channels; ch++) {
800 801
            i = i_start + ch;
            y1 = s->ytop + ch * h + (h / 2); /* position of center line */
Aneesh Dogra's avatar
Aneesh Dogra committed
802
            for (x = 0; x < s->width; x++) {
803 804 805 806 807 808 809 810 811 812 813 814 815
                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
816 817 818
            }
        }

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

Aneesh Dogra's avatar
Aneesh Dogra committed
821
        for (ch = 1; ch < nb_display_channels; ch++) {
822 823 824 825 826 827
            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
828
    } else {
829
        nb_display_channels= FFMIN(nb_display_channels, 2);
Aneesh Dogra's avatar
Aneesh Dogra committed
830
        if (rdft_bits != s->rdft_bits) {
831
            av_rdft_end(s->rdft);
Måns Rullgård's avatar
Måns Rullgård committed
832
            av_free(s->rdft_data);
833
            s->rdft = av_rdft_init(rdft_bits, DFT_R2C);
Aneesh Dogra's avatar
Aneesh Dogra committed
834 835
            s->rdft_bits = rdft_bits;
            s->rdft_data = av_malloc(4 * nb_freq * sizeof(*s->rdft_data));
836 837
        }
        {
Måns Rullgård's avatar
Måns Rullgård committed
838
            FFTSample *data[2];
Aneesh Dogra's avatar
Aneesh Dogra committed
839 840
            for (ch = 0; ch < nb_display_channels; ch++) {
                data[ch] = s->rdft_data + 2 * nb_freq * ch;
841
                i = i_start + ch;
Aneesh Dogra's avatar
Aneesh Dogra committed
842 843 844
                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);
845 846 847 848
                    i += channels;
                    if (i >= SAMPLE_ARRAY_SIZE)
                        i -= SAMPLE_ARRAY_SIZE;
                }
849
                av_rdft_calc(s->rdft, data[ch]);
850
            }
Diego Biurrun's avatar
Diego Biurrun committed
851 852
            /* Least efficient way to do this, we should of course
             * directly access it but it is more than fast enough. */
Aneesh Dogra's avatar
Aneesh Dogra committed
853 854 855 856 857 858 859 860
            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);
861 862 863 864 865 866 867 868

                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
869
        if (s->xpos >= s->width)
870 871
            s->xpos= s->xleft;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
872 873
}

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

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

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

905 906
#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 */
907
    screen = SDL_SetVideoMode(w, h, 24, flags);
908 909
#else
    screen = SDL_SetVideoMode(w, h, 0, flags);
910 911 912 913 914
#endif
    if (!screen) {
        fprintf(stderr, "SDL: could not set video mode - exiting\n");
        return -1;
    }
915 916 917
    if (!window_title)
        window_title = input_filename;
    SDL_WM_SetCaption(window_title, window_title);
918

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

    return 0;
}
924

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

936
static int refresh_thread(void *opaque)
Fabrice Bellard's avatar
Fabrice Bellard committed
937
{
938
    VideoState *is= opaque;
Aneesh Dogra's avatar
Aneesh Dogra committed
939
    while (!is->abort_request) {
940 941 942
        SDL_Event event;
        event.type = FF_REFRESH_EVENT;
        event.user.data1 = opaque;
Aneesh Dogra's avatar
Aneesh Dogra committed
943 944
        if (!is->refresh) {
            is->refresh = 1;
945
            SDL_PushEvent(&event);
946
        }
947
        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
948 949
    }
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
950 951
}

952 953 954 955 956 957 958 959 960
/* 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) {
961
        bytes_per_sec = is->sdl_sample_rate * is->sdl_channels *
962
                        av_get_bytes_per_sample(is->sdl_sample_fmt);
963 964 965 966 967 968 969 970 971
    }
    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
972
    if (is->paused) {
973
        return is->video_current_pts;
Fabrice Bellard's avatar
Fabrice Bellard committed
974
    } else {
975
        return is->video_current_pts_drift + av_gettime() / 1000000.0;
Fabrice Bellard's avatar
Fabrice Bellard committed
976
    }
977 978 979 980 981 982 983 984 985 986 987 988 989 990 991
}

/* 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
992 993 994 995 996 997 998 999 1000 1001 1002
    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 {
1003
        val = get_external_clock(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
1004
    }
1005 1006 1007
    return val;
}

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

/* pause or resume the video */
static void stream_pause(VideoState *is)
{
1024 1025
    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
1026
        if (is->read_pause_return != AVERROR(ENOSYS)) {
1027
            is->video_current_pts = is->video_current_pts_drift + av_gettime() / 1000000.0;
1028
        }
1029
        is->video_current_pts_drift = is->video_current_pts - av_gettime() / 1000000.0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1030
    }
1031
    is->paused = !is->paused;
Fabrice Bellard's avatar
Fabrice Bellard committed
1032 1033
}

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

    /* 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;
1043
    } else {
1044
        is->frame_last_delay = delay;
1045
    }
1046 1047 1048 1049 1050 1051 1052
    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 */
1053
        diff = get_video_clock(is) - get_master_clock(is);
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066

        /* 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;
1067 1068 1069

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

1071
    return is->frame_timer;
1072 1073
}

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

1080
    SubPicture *sp, *sp2;
Fabrice Bellard's avatar
Fabrice Bellard committed
1081 1082

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

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

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

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

1127 1128 1129
                        /* update queue size and signal for next picture */
                        if (++is->subpq_rindex == SUBPICTURE_QUEUE_SIZE)
                            is->subpq_rindex = 0;
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 1162 1163
                        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
1164
            /* display picture */
1165
            if (!display_disable)
1166
                video_display(is);
1167

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

Fabrice Bellard's avatar
Fabrice Bellard committed
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181
            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 */
1182

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

Fabrice Bellard's avatar
Fabrice Bellard committed
1193
        cur_time = av_gettime();
1194
        if (!last_time || (cur_time - last_time) >= 30000) {
Fabrice Bellard's avatar
Fabrice Bellard committed
1195 1196
            aqsize = 0;
            vqsize = 0;
1197
            sqsize = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1198 1199 1200 1201
            if (is->audio_st)
                aqsize = is->audioq.size;
            if (is->video_st)
                vqsize = is->videoq.size;
1202 1203
            if (is->subtitle_st)
                sqsize = is->subtitleq.size;
1204 1205 1206
            av_diff = 0;
            if (is->audio_st && is->video_st)
                av_diff = get_audio_clock(is) - get_video_clock(is);
1207
            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
1208 1209
                   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
1210 1211 1212 1213 1214 1215
            fflush(stdout);
            last_time = cur_time;
        }
    }
}

1216 1217 1218 1219 1220 1221 1222 1223 1224 1225
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
1226
    for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249
        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;
    }
1250
    uninit_opts();
1251
    avformat_network_deinit();
1252 1253 1254
    if (show_status)
        printf("\n");
    SDL_Quit();
1255
    av_log(NULL, AV_LOG_QUIET, "");
1256 1257 1258
    exit(0);
}

Fabrice Bellard's avatar
Fabrice Bellard committed
1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270
/* 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);

1271 1272 1273 1274