ffplay.c 111 KB
Newer Older
Fabrice Bellard's avatar
Fabrice Bellard committed
1 2 3
/*
 * Copyright (c) 2003 Fabrice Bellard
 *
4 5 6
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
Fabrice Bellard's avatar
Fabrice Bellard committed
7 8
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
Fabrice Bellard's avatar
Fabrice Bellard committed
10
 *
11
 * FFmpeg is distributed in the hope that it will be useful,
Fabrice Bellard's avatar
Fabrice Bellard committed
12 13 14 15 16
 * 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
17
 * License along with FFmpeg; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Fabrice Bellard's avatar
Fabrice Bellard committed
19
 */
20

21 22 23 24 25
/**
 * @file
 * simple media player based on the FFmpeg libraries
 */

26
#include "config.h"
27
#include <inttypes.h>
28 29
#include <math.h>
#include <limits.h>
30
#include <signal.h>
31
#include "libavutil/avstring.h"
32
#include "libavutil/colorspace.h"
33
#include "libavutil/mathematics.h"
34
#include "libavutil/pixdesc.h"
35
#include "libavutil/imgutils.h"
36
#include "libavutil/dict.h"
37 38
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
39
#include "libavutil/avassert.h"
40
#include "libavutil/time.h"
41 42 43
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
44
#include "libavutil/opt.h"
45
#include "libavcodec/avfft.h"
46
#include "libswresample/swresample.h"
Fabrice Bellard's avatar
Fabrice Bellard committed
47

48
#if CONFIG_AVFILTER
49
# include "libavfilter/avcodec.h"
50 51
# include "libavfilter/avfilter.h"
# include "libavfilter/avfiltergraph.h"
52
# include "libavfilter/buffersink.h"
53
# include "libavfilter/buffersrc.h"
54 55
#endif

Fabrice Bellard's avatar
Fabrice Bellard committed
56 57 58
#include <SDL.h>
#include <SDL_thread.h>

59
#include "cmdutils.h"
60

61 62
#include <assert.h>

63
const char program_name[] = "ffplay";
64
const int program_birth_year = 2003;
65

66 67
#define MAX_QUEUE_SIZE (15 * 1024 * 1024)
#define MIN_FRAMES 5
Fabrice Bellard's avatar
Fabrice Bellard committed
68

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

/* maximum audio speed change to get correct sync */
#define SAMPLE_CORRECTION_PERCENT_MAX 10

81 82 83 84 85
/* external clock speed adjustment constants for realtime sources based on buffer fullness */
#define EXTERNAL_CLOCK_SPEED_MIN  0.900
#define EXTERNAL_CLOCK_SPEED_MAX  1.010
#define EXTERNAL_CLOCK_SPEED_STEP 0.001

86 87 88
/* 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
89
/* NOTE: the size must be big enough to compensate the hardware audio buffersize size */
90 91
/* TODO: We assume that a decoded and resampled frame fits into this buffer */
#define SAMPLE_ARRAY_SIZE (8 * 65536)
Fabrice Bellard's avatar
Fabrice Bellard committed
92

93 94
static int sws_flags = SWS_BICUBIC;

95 96 97 98 99 100
typedef struct MyAVPacketList {
    AVPacket pkt;
    struct MyAVPacketList *next;
    int serial;
} MyAVPacketList;

Fabrice Bellard's avatar
Fabrice Bellard committed
101
typedef struct PacketQueue {
102
    MyAVPacketList *first_pkt, *last_pkt;
Fabrice Bellard's avatar
Fabrice Bellard committed
103 104 105
    int nb_packets;
    int size;
    int abort_request;
106
    int serial;
Fabrice Bellard's avatar
Fabrice Bellard committed
107 108 109 110
    SDL_mutex *mutex;
    SDL_cond *cond;
} PacketQueue;

111
#define VIDEO_PICTURE_QUEUE_SIZE 4
112
#define SUBPICTURE_QUEUE_SIZE 4
Fabrice Bellard's avatar
Fabrice Bellard committed
113 114

typedef struct VideoPicture {
115 116
    double pts;             // presentation timestamp for this picture
    int64_t pos;            // byte position in file
117
    int skip;
Fabrice Bellard's avatar
Fabrice Bellard committed
118 119
    SDL_Overlay *bmp;
    int width, height; /* source height & width */
120
    AVRational sample_aspect_ratio;
Fabrice Bellard's avatar
Fabrice Bellard committed
121
    int allocated;
122
    int reallocate;
123
    int serial;
124 125

#if CONFIG_AVFILTER
126
    AVFilterBufferRef *picref;
127
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
128 129
} VideoPicture;

130 131 132 133 134
typedef struct SubPicture {
    double pts; /* presentation time stamp for this picture */
    AVSubtitle sub;
} SubPicture;

135 136 137 138 139 140 141
typedef struct AudioParams {
    int freq;
    int channels;
    int channel_layout;
    enum AVSampleFormat fmt;
} AudioParams;

Fabrice Bellard's avatar
Fabrice Bellard committed
142 143 144
enum {
    AV_SYNC_AUDIO_MASTER, /* default choice */
    AV_SYNC_VIDEO_MASTER,
145
    AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */
Fabrice Bellard's avatar
Fabrice Bellard committed
146 147 148
};

typedef struct VideoState {
149
    SDL_Thread *read_tid;
Fabrice Bellard's avatar
Fabrice Bellard committed
150
    SDL_Thread *video_tid;
151
    SDL_Thread *refresh_tid;
152
    AVInputFormat *iformat;
Fabrice Bellard's avatar
Fabrice Bellard committed
153 154
    int no_background;
    int abort_request;
155
    int force_refresh;
Fabrice Bellard's avatar
Fabrice Bellard committed
156
    int paused;
157
    int last_paused;
158
    int que_attachments_req;
Fabrice Bellard's avatar
Fabrice Bellard committed
159
    int seek_req;
160
    int seek_flags;
Fabrice Bellard's avatar
Fabrice Bellard committed
161
    int64_t seek_pos;
162
    int64_t seek_rel;
163
    int read_pause_return;
Fabrice Bellard's avatar
Fabrice Bellard committed
164
    AVFormatContext *ic;
165
    int realtime;
Fabrice Bellard's avatar
Fabrice Bellard committed
166 167

    int audio_stream;
168

Fabrice Bellard's avatar
Fabrice Bellard committed
169
    int av_sync_type;
170 171 172
    double external_clock;                   ///< external clock base
    double external_clock_drift;             ///< external clock base - time (av_gettime) at which we updated external_clock
    int64_t external_clock_time;             ///< last reference time
173
    double external_clock_speed;             ///< speed of the external clock
174

175 176 177 178 179
    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
180 181 182
    AVStream *audio_st;
    PacketQueue audioq;
    int audio_hw_buf_size;
183
    DECLARE_ALIGNED(16,uint8_t,audio_buf2)[AVCODEC_MAX_AUDIO_FRAME_SIZE * 4];
184
    uint8_t silence_buf[SDL_AUDIO_BUFFER_SIZE];
185
    uint8_t *audio_buf;
186
    uint8_t *audio_buf1;
187
    unsigned int audio_buf_size; /* in bytes */
Fabrice Bellard's avatar
Fabrice Bellard committed
188
    int audio_buf_index; /* in bytes */
189
    int audio_write_buf_size;
190
    AVPacket audio_pkt_temp;
Fabrice Bellard's avatar
Fabrice Bellard committed
191
    AVPacket audio_pkt;
192
    int audio_pkt_temp_serial;
193 194
    struct AudioParams audio_src;
    struct AudioParams audio_tgt;
195
    struct SwrContext *swr_ctx;
196 197
    double audio_current_pts;
    double audio_current_pts_drift;
198 199
    int frame_drops_early;
    int frame_drops_late;
200
    AVFrame *frame;
201

202
    enum ShowMode {
203
        SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB
204
    } show_mode;
Fabrice Bellard's avatar
Fabrice Bellard committed
205 206
    int16_t sample_array[SAMPLE_ARRAY_SIZE];
    int sample_array_index;
207
    int last_i_start;
208
    RDFTContext *rdft;
209
    int rdft_bits;
Måns Rullgård's avatar
Måns Rullgård committed
210
    FFTSample *rdft_data;
211
    int xpos;
212

213 214 215 216 217 218 219 220 221
    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;
222

223 224
    double frame_timer;
    double frame_last_pts;
225
    double frame_last_duration;
226
    double frame_last_dropped_pts;
227 228
    double frame_last_returned_time;
    double frame_last_filter_delay;
229
    int64_t frame_last_dropped_pos;
230
    double video_clock;             // pts of last decoded frame / predicted pts of next decoded frame
Fabrice Bellard's avatar
Fabrice Bellard committed
231 232 233
    int video_stream;
    AVStream *video_st;
    PacketQueue videoq;
234 235 236
    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
237 238 239 240
    VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE];
    int pictq_size, pictq_rindex, pictq_windex;
    SDL_mutex *pictq_mutex;
    SDL_cond *pictq_cond;
241
#if !CONFIG_AVFILTER
242
    struct SwsContext *img_convert_ctx;
243
#endif
244
    SDL_Rect last_display_rect;
245

Fabrice Bellard's avatar
Fabrice Bellard committed
246 247
    char filename[1024];
    int width, height, xleft, ytop;
248
    int step;
249

250
#if CONFIG_AVFILTER
251 252
    AVFilterContext *in_video_filter;   // the first filter in the video chain
    AVFilterContext *out_video_filter;  // the last filter in the video chain
253 254
    int use_dr1;
    FrameBuffer *buffer_pool;
255
#endif
256 257

    int refresh;
258
    int last_video_stream, last_audio_stream, last_subtitle_stream;
259 260

    SDL_cond *continue_read_thread;
Fabrice Bellard's avatar
Fabrice Bellard committed
261 262 263 264 265
} VideoState;

/* options specified by the user */
static AVInputFormat *file_iformat;
static const char *input_filename;
266
static const char *window_title;
Fabrice Bellard's avatar
Fabrice Bellard committed
267 268
static int fs_screen_width;
static int fs_screen_height;
Aneesh Dogra's avatar
Aneesh Dogra committed
269
static int screen_width  = 0;
270
static int screen_height = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
271 272
static int audio_disable;
static int video_disable;
Aneesh Dogra's avatar
Aneesh Dogra committed
273 274 275 276
static int wanted_stream[AVMEDIA_TYPE_NB] = {
    [AVMEDIA_TYPE_AUDIO]    = -1,
    [AVMEDIA_TYPE_VIDEO]    = -1,
    [AVMEDIA_TYPE_SUBTITLE] = -1,
277
};
Aneesh Dogra's avatar
Aneesh Dogra committed
278
static int seek_by_bytes = -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
279
static int display_disable;
280
static int show_status = 1;
281
static int av_sync_type = AV_SYNC_AUDIO_MASTER;
Fabrice Bellard's avatar
Fabrice Bellard committed
282
static int64_t start_time = AV_NOPTS_VALUE;
283
static int64_t duration = AV_NOPTS_VALUE;
Michael Niedermayer's avatar
Michael Niedermayer committed
284
static int workaround_bugs = 1;
285
static int fast = 0;
286
static int genpts = 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
287
static int lowres = 0;
288
static int idct = FF_IDCT_AUTO;
Aneesh Dogra's avatar
Aneesh Dogra committed
289 290 291
static enum AVDiscard skip_frame       = AVDISCARD_DEFAULT;
static enum AVDiscard skip_idct        = AVDISCARD_DEFAULT;
static enum AVDiscard skip_loop_filter = AVDISCARD_DEFAULT;
292
static int error_concealment = 3;
Aneesh Dogra's avatar
Aneesh Dogra committed
293
static int decoder_reorder_pts = -1;
Michael Niedermayer's avatar
Michael Niedermayer committed
294
static int autoexit;
295 296
static int exit_on_keydown;
static int exit_on_mousedown;
Aneesh Dogra's avatar
Aneesh Dogra committed
297
static int loop = 1;
298
static int framedrop = -1;
299
static int infinite_buffer = -1;
300
static enum ShowMode show_mode = SHOW_MODE_NONE;
301 302 303
static const char *audio_codec_name;
static const char *subtitle_codec_name;
static const char *video_codec_name;
Aneesh Dogra's avatar
Aneesh Dogra committed
304
static int rdftspeed = 20;
305 306 307
#if CONFIG_AVFILTER
static char *vfilters = NULL;
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
308 309 310

/* current context */
static int is_full_screen;
311
static int64_t audio_callback_time;
Fabrice Bellard's avatar
Fabrice Bellard committed
312

313
static AVPacket flush_pkt;
314

Fabrice Bellard's avatar
Fabrice Bellard committed
315 316
#define FF_ALLOC_EVENT   (SDL_USEREVENT)
#define FF_REFRESH_EVENT (SDL_USEREVENT + 1)
317
#define FF_QUIT_EVENT    (SDL_USEREVENT + 2)
Fabrice Bellard's avatar
Fabrice Bellard committed
318

319
static SDL_Surface *screen;
Fabrice Bellard's avatar
Fabrice Bellard committed
320

321
static int packet_queue_put(PacketQueue *q, AVPacket *pkt);
322

323
static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)
324
{
325
    MyAVPacketList *pkt1;
326

327 328
    if (q->abort_request)
       return -1;
329

330
    pkt1 = av_malloc(sizeof(MyAVPacketList));
331 332 333 334
    if (!pkt1)
        return -1;
    pkt1->pkt = *pkt;
    pkt1->next = NULL;
335 336 337
    if (pkt == &flush_pkt)
        q->serial++;
    pkt1->serial = q->serial;
338 339 340 341 342 343 344 345 346 347

    if (!q->last_pkt)
        q->first_pkt = pkt1;
    else
        q->last_pkt->next = pkt1;
    q->last_pkt = pkt1;
    q->nb_packets++;
    q->size += pkt1->pkt.size + sizeof(*pkt1);
    /* XXX: should duplicate packet data in DV case */
    SDL_CondSignal(q->cond);
348 349 350 351 352 353
    return 0;
}

static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
{
    int ret;
354

355 356 357 358 359 360
    /* duplicate the packet */
    if (pkt != &flush_pkt && av_dup_packet(pkt) < 0)
        return -1;

    SDL_LockMutex(q->mutex);
    ret = packet_queue_put_private(q, pkt);
361
    SDL_UnlockMutex(q->mutex);
362 363 364 365 366

    if (pkt != &flush_pkt && ret < 0)
        av_free_packet(pkt);

    return ret;
367
}
368

Fabrice Bellard's avatar
Fabrice Bellard committed
369 370 371 372 373 374
/* packet queue handling */
static void packet_queue_init(PacketQueue *q)
{
    memset(q, 0, sizeof(PacketQueue));
    q->mutex = SDL_CreateMutex();
    q->cond = SDL_CreateCond();
375
    q->abort_request = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
376 377
}

Fabrice Bellard's avatar
Fabrice Bellard committed
378
static void packet_queue_flush(PacketQueue *q)
Fabrice Bellard's avatar
Fabrice Bellard committed
379
{
380
    MyAVPacketList *pkt, *pkt1;
Fabrice Bellard's avatar
Fabrice Bellard committed
381

382
    SDL_LockMutex(q->mutex);
Aneesh Dogra's avatar
Aneesh Dogra committed
383
    for (pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {
Fabrice Bellard's avatar
Fabrice Bellard committed
384 385
        pkt1 = pkt->next;
        av_free_packet(&pkt->pkt);
386
        av_freep(&pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
387
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
388 389 390 391
    q->last_pkt = NULL;
    q->first_pkt = NULL;
    q->nb_packets = 0;
    q->size = 0;
392
    SDL_UnlockMutex(q->mutex);
Fabrice Bellard's avatar
Fabrice Bellard committed
393 394
}

395
static void packet_queue_destroy(PacketQueue *q)
Fabrice Bellard's avatar
Fabrice Bellard committed
396 397
{
    packet_queue_flush(q);
Fabrice Bellard's avatar
Fabrice Bellard committed
398 399 400 401 402 403 404 405 406
    SDL_DestroyMutex(q->mutex);
    SDL_DestroyCond(q->cond);
}

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

    q->abort_request = 1;
407

Fabrice Bellard's avatar
Fabrice Bellard committed
408 409 410 411 412
    SDL_CondSignal(q->cond);

    SDL_UnlockMutex(q->mutex);
}

413 414 415 416 417 418 419 420
static void packet_queue_start(PacketQueue *q)
{
    SDL_LockMutex(q->mutex);
    q->abort_request = 0;
    packet_queue_put_private(q, &flush_pkt);
    SDL_UnlockMutex(q->mutex);
}

Fabrice Bellard's avatar
Fabrice Bellard committed
421
/* return < 0 if aborted, 0 if no packet and > 0 if packet.  */
422
static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial)
Fabrice Bellard's avatar
Fabrice Bellard committed
423
{
424
    MyAVPacketList *pkt1;
Fabrice Bellard's avatar
Fabrice Bellard committed
425 426 427 428
    int ret;

    SDL_LockMutex(q->mutex);

Aneesh Dogra's avatar
Aneesh Dogra committed
429
    for (;;) {
Fabrice Bellard's avatar
Fabrice Bellard committed
430 431 432 433
        if (q->abort_request) {
            ret = -1;
            break;
        }
434

Fabrice Bellard's avatar
Fabrice Bellard committed
435 436 437 438 439 440
        pkt1 = q->first_pkt;
        if (pkt1) {
            q->first_pkt = pkt1->next;
            if (!q->first_pkt)
                q->last_pkt = NULL;
            q->nb_packets--;
441
            q->size -= pkt1->pkt.size + sizeof(*pkt1);
Fabrice Bellard's avatar
Fabrice Bellard committed
442
            *pkt = pkt1->pkt;
443 444
            if (serial)
                *serial = pkt1->serial;
Fabrice Bellard's avatar
Fabrice Bellard committed
445 446 447 448 449 450 451 452 453 454 455 456 457 458
            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;
}

459
static inline void fill_rectangle(SDL_Surface *screen,
460
                                  int x, int y, int w, int h, int color, int update)
Fabrice Bellard's avatar
Fabrice Bellard committed
461 462 463 464 465 466 467
{
    SDL_Rect rect;
    rect.x = x;
    rect.y = y;
    rect.w = w;
    rect.h = h;
    SDL_FillRect(screen, &rect, color);
468 469
    if (update && w > 0 && h > 0)
        SDL_UpdateRect(screen, x, y, w, h);
Fabrice Bellard's avatar
Fabrice Bellard committed
470 471
}

472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
/* draw only the border of a rectangle */
static void fill_border(int xleft, int ytop, int width, int height, int x, int y, int w, int h, int color, int update)
{
    int w1, w2, h1, h2;

    /* fill the background */
    w1 = x;
    if (w1 < 0)
        w1 = 0;
    w2 = width - (x + w);
    if (w2 < 0)
        w2 = 0;
    h1 = y;
    if (h1 < 0)
        h1 = 0;
    h2 = height - (y + h);
    if (h2 < 0)
        h2 = 0;
    fill_rectangle(screen,
                   xleft, ytop,
                   w1, height,
                   color, update);
    fill_rectangle(screen,
                   xleft + width - w2, ytop,
                   w2, height,
                   color, update);
    fill_rectangle(screen,
                   xleft + w1, ytop,
                   width - w1 - w2, h1,
                   color, update);
    fill_rectangle(screen,
                   xleft + w1, ytop + height - h2,
                   width - w1 - w2, h2,
                   color, update);
}

508 509 510 511 512 513 514 515 516 517 518 519 520 521
#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)\
{\
522
    unsigned int val = ((const uint32_t *)(pal))[*(const uint8_t*)(s)];\
523 524 525 526 527 528 529 530 531 532 533 534 535 536
    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

537
static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, int imgh)
538 539 540 541 542 543
{
    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;
544 545
    int dstx, dsty, dstw, dsth;

546 547 548 549
    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);
550
    lum = dst->data[0] + dsty * dst->linesize[0];
Aneesh Dogra's avatar
Aneesh Dogra committed
551 552
    cb  = dst->data[1] + (dsty >> 1) * dst->linesize[1];
    cr  = dst->data[2] + (dsty >> 1) * dst->linesize[2];
553

554
    width2 = ((dstw + 1) >> 1) + (dstx & ~dstw & 1);
555
    skip2 = dstx >> 1;
556
    wrap = dst->linesize[0];
557 558 559
    wrap3 = rect->pict.linesize[0];
    p = rect->pict.data[0];
    pal = (const uint32_t *)rect->pict.data[1];  /* Now in YCrCb! */
560

561 562
    if (dsty & 1) {
        lum += dstx;
563 564
        cb += skip2;
        cr += skip2;
565

566
        if (dstx & 1) {
567 568 569 570 571 572 573 574 575
            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
576
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
            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);
600 601
            p++;
            lum++;
602
        }
603 604
        p += wrap3 - dstw * BPP;
        lum += wrap - dstw - dstx;
605 606 607
        cb += dst->linesize[1] - width2 - skip2;
        cr += dst->linesize[2] - width2 - skip2;
    }
Aneesh Dogra's avatar
Aneesh Dogra committed
608
    for (h = dsth - (dsty & 1); h >= 2; h -= 2) {
609
        lum += dstx;
610 611
        cb += skip2;
        cr += skip2;
612

613
        if (dstx & 1) {
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632
            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
633
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
634 635 636 637 638 639
            YUVA_IN(y, u, v, a, p, pal);
            u1 = u;
            v1 = v;
            a1 = a;
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);

640
            YUVA_IN(y, u, v, a, p + BPP, pal);
641 642 643 644 645 646 647 648 649 650 651 652 653
            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);

654
            YUVA_IN(y, u, v, a, p + BPP, pal);
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
            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;
        }
688 689
        p += wrap3 + (wrap3 - dstw * BPP);
        lum += wrap + (wrap - dstw - dstx);
690 691 692 693 694
        cb += dst->linesize[1] - width2 - skip2;
        cr += dst->linesize[2] - width2 - skip2;
    }
    /* handle odd height */
    if (h) {
695
        lum += dstx;
696 697
        cb += skip2;
        cr += skip2;
698

699
        if (dstx & 1) {
700 701 702 703 704 705 706 707 708
            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
709
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
            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)
{
739
    avsubtitle_free(&sp->sub);
740 741
}

742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770
static void calculate_display_rect(SDL_Rect *rect, int scr_xleft, int scr_ytop, int scr_width, int scr_height, VideoPicture *vp)
{
    float aspect_ratio;
    int width, height, x, y;

    if (vp->sample_aspect_ratio.num == 0)
        aspect_ratio = 0;
    else
        aspect_ratio = av_q2d(vp->sample_aspect_ratio);

    if (aspect_ratio <= 0.0)
        aspect_ratio = 1.0;
    aspect_ratio *= (float)vp->width / (float)vp->height;

    /* XXX: we suppose the screen has a 1.0 pixel ratio */
    height = scr_height;
    width = ((int)rint(height * aspect_ratio)) & ~1;
    if (width > scr_width) {
        width = scr_width;
        height = ((int)rint(width / aspect_ratio)) & ~1;
    }
    x = (scr_width - width) / 2;
    y = (scr_height - height) / 2;
    rect->x = scr_xleft + x;
    rect->y = scr_ytop  + y;
    rect->w = FFMAX(width,  1);
    rect->h = FFMAX(height, 1);
}

Fabrice Bellard's avatar
Fabrice Bellard committed
771 772 773
static void video_image_display(VideoState *is)
{
    VideoPicture *vp;
774 775
    SubPicture *sp;
    AVPicture pict;
Fabrice Bellard's avatar
Fabrice Bellard committed
776
    SDL_Rect rect;
777
    int i;
Fabrice Bellard's avatar
Fabrice Bellard committed
778 779 780

    vp = &is->pictq[is->pictq_rindex];
    if (vp->bmp) {
781 782
        if (is->subtitle_st) {
            if (is->subpq_size > 0) {
783 784
                sp = &is->subpq[is->subpq_rindex];

785
                if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) {
786 787 788 789 790 791 792 793 794 795 796
                    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++)
797
                        blend_subrect(&pict, sp->sub.rects[i],
798
                                      vp->bmp->w, vp->bmp->h);
799 800 801 802 803 804

                    SDL_UnlockYUVOverlay (vp->bmp);
                }
            }
        }

805
        calculate_display_rect(&rect, is->xleft, is->ytop, is->width, is->height, vp);
806

Fabrice Bellard's avatar
Fabrice Bellard committed
807
        SDL_DisplayYUVOverlay(vp->bmp, &rect);
808 809 810 811 812 813

        if (rect.x != is->last_display_rect.x || rect.y != is->last_display_rect.y || rect.w != is->last_display_rect.w || rect.h != is->last_display_rect.h || is->force_refresh) {
            int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
            fill_border(is->xleft, is->ytop, is->width, is->height, rect.x, rect.y, rect.w, rect.h, bgcolor, 1);
            is->last_display_rect = rect;
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
814 815 816 817 818
    }
}

static inline int compute_mod(int a, int b)
{
819
    return a < 0 ? a%b + b : a%b;
Fabrice Bellard's avatar
Fabrice Bellard committed
820 821 822 823 824 825 826
}

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;
827 828
    int rdft_bits, nb_freq;

Aneesh Dogra's avatar
Aneesh Dogra committed
829
    for (rdft_bits = 1; (1 << rdft_bits) < 2 * s->height; rdft_bits++)
830
        ;
Aneesh Dogra's avatar
Aneesh Dogra committed
831
    nb_freq = 1 << (rdft_bits - 1);
832

Fabrice Bellard's avatar
Fabrice Bellard committed
833
    /* compute display index : center on currently output samples */
834
    channels = s->audio_tgt.channels;
Fabrice Bellard's avatar
Fabrice Bellard committed
835
    nb_display_channels = channels;
836
    if (!s->paused) {
837
        int data_used= s->show_mode == SHOW_MODE_WAVES ? s->width : (2*nb_freq);
838
        n = 2 * channels;
839
        delay = s->audio_write_buf_size;
840
        delay /= n;
841

842 843 844 845
        /* 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;
846
            delay -= (time_diff * s->audio_tgt.freq) / 1000000;
847
        }
848

Aneesh Dogra's avatar
Aneesh Dogra committed
849
        delay += 2 * data_used;
850 851
        if (delay < data_used)
            delay = data_used;
852 853

        i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
854
        if (s->show_mode == SHOW_MODE_WAVES) {
Aneesh Dogra's avatar
Aneesh Dogra committed
855 856 857 858 859 860 861 862 863 864 865
            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;
866
                }
867 868 869
            }
        }

870 871 872
        s->last_i_start = i_start;
    } else {
        i_start = s->last_i_start;
Fabrice Bellard's avatar
Fabrice Bellard committed
873 874 875
    }

    bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
876
    if (s->show_mode == SHOW_MODE_WAVES) {
877 878
        fill_rectangle(screen,
                       s->xleft, s->ytop, s->width, s->height,
879
                       bgcolor, 0);
880 881 882 883 884 885 886

        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
887
        for (ch = 0; ch < nb_display_channels; ch++) {
888 889
            i = i_start + ch;
            y1 = s->ytop + ch * h + (h / 2); /* position of center line */
Aneesh Dogra's avatar
Aneesh Dogra committed
890
            for (x = 0; x < s->width; x++) {
891 892 893 894 895 896 897 898 899
                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,
900
                               fgcolor, 0);
901 902 903
                i += channels;
                if (i >= SAMPLE_ARRAY_SIZE)
                    i -= SAMPLE_ARRAY_SIZE;
Fabrice Bellard's avatar
Fabrice Bellard committed
904 905 906
            }
        }

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

Aneesh Dogra's avatar
Aneesh Dogra committed
909
        for (ch = 1; ch < nb_display_channels; ch++) {
910 911 912
            y = s->ytop + ch * h;
            fill_rectangle(screen,
                           s->xleft, y, s->width, 1,
913
                           fgcolor, 0);
914 915
        }
        SDL_UpdateRect(screen, s->xleft, s->ytop, s->width, s->height);
Aneesh Dogra's avatar
Aneesh Dogra committed
916
    } else {
917
        nb_display_channels= FFMIN(nb_display_channels, 2);
Aneesh Dogra's avatar
Aneesh Dogra committed
918
        if (rdft_bits != s->rdft_bits) {
919
            av_rdft_end(s->rdft);
Måns Rullgård's avatar
Måns Rullgård committed
920
            av_free(s->rdft_data);
921
            s->rdft = av_rdft_init(rdft_bits, DFT_R2C);
Aneesh Dogra's avatar
Aneesh Dogra committed
922 923
            s->rdft_bits = rdft_bits;
            s->rdft_data = av_malloc(4 * nb_freq * sizeof(*s->rdft_data));
924 925
        }
        {
Måns Rullgård's avatar
Måns Rullgård committed
926
            FFTSample *data[2];
Aneesh Dogra's avatar
Aneesh Dogra committed
927 928
            for (ch = 0; ch < nb_display_channels; ch++) {
                data[ch] = s->rdft_data + 2 * nb_freq * ch;
929
                i = i_start + ch;
Aneesh Dogra's avatar
Aneesh Dogra committed
930 931 932
                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);
933 934 935 936
                    i += channels;
                    if (i >= SAMPLE_ARRAY_SIZE)
                        i -= SAMPLE_ARRAY_SIZE;
                }
937
                av_rdft_calc(s->rdft, data[ch]);
938
            }
Aneesh Dogra's avatar
Aneesh Dogra committed
939 940 941 942 943 944 945 946 947
            // 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);
948 949 950

                fill_rectangle(screen,
                            s->xpos, s->height-y, 1, 1,
951
                            fgcolor, 0);
952 953 954
            }
        }
        SDL_UpdateRect(screen, s->xpos, s->ytop, 1, s->height);
955 956
        if (!s->paused)
            s->xpos++;
Aneesh Dogra's avatar
Aneesh Dogra committed
957
        if (s->xpos >= s->width)
958 959
            s->xpos= s->xleft;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
960 961
}

962 963 964 965 966 967 968 969
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->read_tid, NULL);
    SDL_WaitThread(is->refresh_tid, NULL);
970 971 972
    packet_queue_destroy(&is->videoq);
    packet_queue_destroy(&is->audioq);
    packet_queue_destroy(&is->subtitleq);
973 974

    /* free all pictures */
975
    for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
976 977
        vp = &is->pictq[i];
#if CONFIG_AVFILTER
978
        avfilter_unref_bufferp(&vp->picref);
979 980 981 982 983 984 985 986 987 988
#endif
        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);
989
    SDL_DestroyCond(is->continue_read_thread);
990 991 992 993 994 995 996
#if !CONFIG_AVFILTER
    if (is->img_convert_ctx)
        sws_freeContext(is->img_convert_ctx);
#endif
    av_free(is);
}

997
static void do_exit(VideoState *is)
998
{
999 1000
    if (is) {
        stream_close(is);
1001
    }
1002
    av_lockmgr_register(NULL);
1003 1004 1005
    uninit_opts();
#if CONFIG_AVFILTER
    avfilter_uninit();
1006
    av_freep(&vfilters);
1007
#endif
1008
    avformat_network_deinit();
1009 1010 1011
    if (show_status)
        printf("\n");
    SDL_Quit();
1012
    av_log(NULL, AV_LOG_QUIET, "%s", "");
1013 1014 1015
    exit(0);
}

1016 1017 1018 1019 1020
static void sigterm_handler(int sig)
{
    exit(123);
}

1021
static int video_open(VideoState *is, int force_set_video_mode)
Aneesh Dogra's avatar
Aneesh Dogra committed
1022 1023
{
    int flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
1024
    int w,h;
1025
    VideoPicture *vp = &is->pictq[is->pictq_rindex];
1026
    SDL_Rect rect;
1027

Aneesh Dogra's avatar
Aneesh Dogra committed
1028 1029
    if (is_full_screen) flags |= SDL_FULLSCREEN;
    else                flags |= SDL_RESIZABLE;
1030

1031 1032 1033
    if (is_full_screen && fs_screen_width) {
        w = fs_screen_width;
        h = fs_screen_height;
Aneesh Dogra's avatar
Aneesh Dogra committed
1034
    } else if (!is_full_screen && screen_width) {
1035 1036
        w = screen_width;
        h = screen_height;
1037
    } else if (vp->width) {
1038 1039 1040
        calculate_display_rect(&rect, 0, 0, INT_MAX, vp->height, vp);
        w = rect.w;
        h = rect.h;
1041
    } else {
1042 1043
        w = 640;
        h = 480;
1044
    }
Aneesh Dogra's avatar
Aneesh Dogra committed
1045
    if (screen && is->width == screen->w && screen->w == w
1046
       && is->height== screen->h && screen->h == h && !force_set_video_mode)
1047
        return 0;
1048 1049 1050
    screen = SDL_SetVideoMode(w, h, 0, flags);
    if (!screen) {
        fprintf(stderr, "SDL: could not set video mode - exiting\n");
1051
        do_exit(is);
1052
    }
1053 1054 1055
    if (!window_title)
        window_title = input_filename;
    SDL_WM_SetCaption(window_title, window_title);
1056

Aneesh Dogra's avatar
Aneesh Dogra committed
1057
    is->width  = screen->w;
1058 1059 1060 1061
    is->height = screen->h;

    return 0;
}
1062

Fabrice Bellard's avatar
Fabrice Bellard committed
1063 1064 1065
/* display the current picture, if any */
static void video_display(VideoState *is)
{
Aneesh Dogra's avatar
Aneesh Dogra committed
1066
    if (!screen)
1067
        video_open(is, 0);
1068
    if (is->audio_st && is->show_mode != SHOW_MODE_VIDEO)
Fabrice Bellard's avatar
Fabrice Bellard committed
1069 1070 1071 1072 1073
        video_audio_display(is);
    else if (is->video_st)
        video_image_display(is);
}

1074
static int refresh_thread(void *opaque)
Fabrice Bellard's avatar
Fabrice Bellard committed
1075
{
1076
    VideoState *is= opaque;
Aneesh Dogra's avatar
Aneesh Dogra committed
1077
    while (!is->abort_request) {
1078 1079 1080
        SDL_Event event;
        event.type = FF_REFRESH_EVENT;
        event.user.data1 = opaque;
1081
        if (!is->refresh && (!is->paused || is->force_refresh)) {
Aneesh Dogra's avatar
Aneesh Dogra committed
1082
            is->refresh = 1;
1083
            SDL_PushEvent(&event);
1084
        }
1085
        //FIXME ideally we should wait the correct time but SDLs event passing is so slow it would be silly
1086
        av_usleep(is->audio_st && is->show_mode != SHOW_MODE_VIDEO ? rdftspeed*1000 : 5000);
1087 1088
    }
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1089 1090
}

1091 1092 1093
/* get the current audio clock value */
static double get_audio_clock(VideoState *is)
{
1094 1095 1096 1097
    if (is->paused) {
        return is->audio_current_pts;
    } else {
        return is->audio_current_pts_drift + av_gettime() / 1000000.0;
1098 1099 1100 1101 1102 1103
    }
}

/* get the current video clock value */
static double get_video_clock(VideoState *is)
{
Michael Niedermayer's avatar
Michael Niedermayer committed
1104
    if (is->paused) {
1105
        return is->video_current_pts;
Fabrice Bellard's avatar
Fabrice Bellard committed
1106
    } else {
1107
        return is->video_current_pts_drift + av_gettime() / 1000000.0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1108
    }
1109 1110 1111 1112 1113
}

/* get the current external clock value */
static double get_external_clock(VideoState *is)
{
1114 1115 1116
    if (is->paused) {
        return is->external_clock;
    } else {
1117 1118
        double time = av_gettime() / 1000000.0;
        return is->external_clock_drift + time - (time - is->external_clock_time / 1000000.0) * (1.0 - is->external_clock_speed);
1119
    }
1120 1121
}

1122
static int get_master_sync_type(VideoState *is) {
Fabrice Bellard's avatar
Fabrice Bellard committed
1123 1124
    if (is->av_sync_type == AV_SYNC_VIDEO_MASTER) {
        if (is->video_st)
1125
            return AV_SYNC_VIDEO_MASTER;
Fabrice Bellard's avatar
Fabrice Bellard committed
1126
        else
1127
            return AV_SYNC_AUDIO_MASTER;
Fabrice Bellard's avatar
Fabrice Bellard committed
1128 1129
    } else if (is->av_sync_type == AV_SYNC_AUDIO_MASTER) {
        if (is->audio_st)
1130
            return AV_SYNC_AUDIO_MASTER;
Fabrice Bellard's avatar
Fabrice Bellard committed
1131
        else
1132
            return AV_SYNC_EXTERNAL_CLOCK;
Fabrice Bellard's avatar
Fabrice Bellard committed
1133
    } else {
1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
        return AV_SYNC_EXTERNAL_CLOCK;
    }
}

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

    switch (get_master_sync_type(is)) {
        case AV_SYNC_VIDEO_MASTER:
            val = get_video_clock(is);
            break;
        case AV_SYNC_AUDIO_MASTER:
            val = get_audio_clock(is);
            break;
        default:
            val = get_external_clock(is);
            break;
Fabrice Bellard's avatar
Fabrice Bellard committed
1153
    }
1154 1155 1156
    return val;
}

1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169
static void update_external_clock_pts(VideoState *is, double pts)
{
   is->external_clock_time = av_gettime();
   is->external_clock = pts;
   is->external_clock_drift = pts - is->external_clock_time / 1000000.0;
}

static void check_external_clock_sync(VideoState *is, double pts) {
    if (fabs(get_external_clock(is) - pts) > AV_NOSYNC_THRESHOLD) {
        update_external_clock_pts(is, pts);
    }
}

1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
static void update_external_clock_speed(VideoState *is, double speed) {
    update_external_clock_pts(is, get_external_clock(is));
    is->external_clock_speed = speed;
}

static void check_external_clock_speed(VideoState *is) {
   if (is->video_stream >= 0 && is->videoq.nb_packets <= MIN_FRAMES / 2 ||
       is->audio_stream >= 0 && is->audioq.nb_packets <= MIN_FRAMES / 2) {
       update_external_clock_speed(is, FFMAX(EXTERNAL_CLOCK_SPEED_MIN, is->external_clock_speed - EXTERNAL_CLOCK_SPEED_STEP));
   } else if ((is->video_stream < 0 || is->videoq.nb_packets > MIN_FRAMES * 2) &&
              (is->audio_stream < 0 || is->audioq.nb_packets > MIN_FRAMES * 2)) {
       update_external_clock_speed(is, FFMIN(EXTERNAL_CLOCK_SPEED_MAX, is->external_clock_speed + EXTERNAL_CLOCK_SPEED_STEP));
   } else {
       double speed = is->external_clock_speed;
       if (speed != 1.0)
           update_external_clock_speed(is, speed + EXTERNAL_CLOCK_SPEED_STEP * (1.0 - speed) / fabs(1.0 - speed));
   }
}

Fabrice Bellard's avatar
Fabrice Bellard committed
1189
/* seek in the stream */
1190
static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_bytes)
Fabrice Bellard's avatar
Fabrice Bellard committed
1191
{
1192 1193
    if (!is->seek_req) {
        is->seek_pos = pos;
1194
        is->seek_rel = rel;
Michael Niedermayer's avatar
Michael Niedermayer committed
1195
        is->seek_flags &= ~AVSEEK_FLAG_BYTE;
1196 1197
        if (seek_by_bytes)
            is->seek_flags |= AVSEEK_FLAG_BYTE;
1198 1199
        is->seek_req = 1;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
1200 1201 1202
}

/* pause or resume the video */
1203
static void stream_toggle_pause(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
1204
{
1205 1206
    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
1207
        if (is->read_pause_return != AVERROR(ENOSYS)) {
1208
            is->video_current_pts = is->video_current_pts_drift + av_gettime() / 1000000.0;
1209
        }
1210
        is->video_current_pts_drift = is->video_current_pts - av_gettime() / 1000000.0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1211
    }
1212
    update_external_clock_pts(is, get_external_clock(is));
1213
    is->paused = !is->paused;
Fabrice Bellard's avatar
Fabrice Bellard committed
1214 1215
}

1216
static double compute_target_delay(double delay, VideoState *is)
1217
{
1218
    double sync_threshold, diff;
1219 1220

    /* update delay to follow master synchronisation source */
1221
    if (get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER) {
1222 1223
        /* if video is slave, we try to correct big delays by
           duplicating or deleting a frame */
1224
        diff = get_video_clock(is) - get_master_clock(is);
1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236

        /* 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;
        }
    }
1237

1238 1239 1240 1241 1242 1243 1244 1245 1246 1247
    av_dlog(NULL, "video: delay=%0.3f A-V=%f\n",
            delay, -diff);

    return delay;
}

static void pictq_next_picture(VideoState *is) {
    /* update queue size and signal for next picture */
    if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
        is->pictq_rindex = 0;
1248

1249 1250 1251 1252
    SDL_LockMutex(is->pictq_mutex);
    is->pictq_size--;
    SDL_CondSignal(is->pictq_cond);
    SDL_UnlockMutex(is->pictq_mutex);
1253 1254
}

1255 1256 1257 1258 1259 1260
static void pictq_prev_picture(VideoState *is) {
    VideoPicture *prevvp;
    /* update queue size and signal for the previous picture */
    prevvp = &is->pictq[(is->pictq_rindex + VIDEO_PICTURE_QUEUE_SIZE - 1) % VIDEO_PICTURE_QUEUE_SIZE];
    if (prevvp->allocated && !prevvp->skip) {
        SDL_LockMutex(is->pictq_mutex);
1261
        if (is->pictq_size < VIDEO_PICTURE_QUEUE_SIZE - 1) {
1262 1263 1264 1265 1266 1267 1268 1269 1270
            if (--is->pictq_rindex == -1)
                is->pictq_rindex = VIDEO_PICTURE_QUEUE_SIZE - 1;
            is->pictq_size++;
        }
        SDL_CondSignal(is->pictq_cond);
        SDL_UnlockMutex(is->pictq_mutex);
    }
}

1271
static void update_video_pts(VideoState *is, double pts, int64_t pos, int serial) {
1272 1273 1274 1275 1276 1277
    double time = av_gettime() / 1000000.0;
    /* update current video pts */
    is->video_current_pts = pts;
    is->video_current_pts_drift = is->video_current_pts - time;
    is->video_current_pos = pos;
    is->frame_last_pts = pts;
1278 1279
    if (is->videoq.serial == serial)
        check_external_clock_sync(is, is->video_current_pts);
1280 1281
}

Fabrice Bellard's avatar
Fabrice Bellard committed
1282
/* called to display each frame */
1283
static void video_refresh(void *opaque)
Fabrice Bellard's avatar
Fabrice Bellard committed
1284 1285 1286
{
    VideoState *is = opaque;
    VideoPicture *vp;
1287
    double time;
1288

1289
    SubPicture *sp, *sp2;
Fabrice Bellard's avatar
Fabrice Bellard committed
1290

1291 1292 1293
    if (!is->paused && get_master_sync_type(is) == AV_SYNC_EXTERNAL_CLOCK && is->realtime)
        check_external_clock_speed(is);

Fabrice Bellard's avatar
Fabrice Bellard committed
1294
    if (is->video_st) {
1295 1296
        if (is->force_refresh)
            pictq_prev_picture(is);
1297
retry:
Fabrice Bellard's avatar
Fabrice Bellard committed
1298
        if (is->pictq_size == 0) {
1299 1300
            SDL_LockMutex(is->pictq_mutex);
            if (is->frame_last_dropped_pts != AV_NOPTS_VALUE && is->frame_last_dropped_pts > is->frame_last_pts) {
1301
                update_video_pts(is, is->frame_last_dropped_pts, is->frame_last_dropped_pos, 0);
1302 1303 1304
                is->frame_last_dropped_pts = AV_NOPTS_VALUE;
            }
            SDL_UnlockMutex(is->pictq_mutex);
Aneesh Dogra's avatar
Aneesh Dogra committed
1305
            // nothing to do, no picture to display in the que
Fabrice Bellard's avatar
Fabrice Bellard committed
1306
        } else {
1307
            double last_duration, duration, delay;
1308
            /* dequeue the picture */
Fabrice Bellard's avatar
Fabrice Bellard committed
1309
            vp = &is->pictq[is->pictq_rindex];
1310

1311 1312 1313 1314 1315
            if (vp->skip) {
                pictq_next_picture(is);
                goto retry;
            }

1316 1317 1318
            if (is->paused)
                goto display;

1319 1320 1321 1322 1323 1324 1325 1326
            /* compute nominal last_duration */
            last_duration = vp->pts - is->frame_last_pts;
            if (last_duration > 0 && last_duration < 10.0) {
                /* if duration of the last frame was sane, update last_duration in video state */
                is->frame_last_duration = last_duration;
            }
            delay = compute_target_delay(is->frame_last_duration, is);

1327
            time= av_gettime()/1000000.0;
1328
            if (time < is->frame_timer + delay)
1329
                return;
1330

1331 1332
            if (delay > 0)
                is->frame_timer += delay * FFMAX(1, floor((time-is->frame_timer) / delay));
1333

1334
            SDL_LockMutex(is->pictq_mutex);
1335
            update_video_pts(is, vp->pts, vp->pos, vp->serial);
1336
            SDL_UnlockMutex(is->pictq_mutex);
1337

Aneesh Dogra's avatar
Aneesh Dogra committed
1338 1339
            if (is->pictq_size > 1) {
                VideoPicture *nextvp = &is->pictq[(is->pictq_rindex + 1) % VIDEO_PICTURE_QUEUE_SIZE];
1340
                duration = nextvp->pts - vp->pts;
1341
                if((framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) && time > is->frame_timer + duration){
1342
                    is->frame_drops_late++;
1343
                    pictq_next_picture(is);
1344 1345 1346
                    goto retry;
                }
            }
1347

Aneesh Dogra's avatar
Aneesh Dogra committed
1348
            if (is->subtitle_st) {
1349 1350
                if (is->subtitle_stream_changed) {
                    SDL_LockMutex(is->subpq_mutex);
1351

1352 1353
                    while (is->subpq_size) {
                        free_subpicture(&is->subpq[is->subpq_rindex]);
1354

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

1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391
                        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);
                        }
                    }
                }
            }

1392
display:
Fabrice Bellard's avatar
Fabrice Bellard committed
1393
            /* display picture */
1394
            if (!display_disable)
1395
                video_display(is);
1396

1397
            pictq_next_picture(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
1398 1399 1400 1401 1402 1403
        }
    } 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 */
1404

Fabrice Bellard's avatar
Fabrice Bellard committed
1405
        /* display picture */
1406
        if (!display_disable)
1407
            video_display(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
1408
    }
1409
    is->force_refresh = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1410 1411 1412
    if (show_status) {
        static int64_t last_time;
        int64_t cur_time;
1413
        int aqsize, vqsize, sqsize;
1414
        double av_diff;
1415

Fabrice Bellard's avatar
Fabrice Bellard committed
1416
        cur_time = av_gettime();
1417
        if (!last_time || (cur_time - last_time) >= 30000) {
Fabrice Bellard's avatar
Fabrice Bellard committed
1418 1419
            aqsize = 0;
            vqsize = 0;
1420
            sqsize = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1421 1422 1423 1424
            if (is->audio_st)
                aqsize = is->audioq.size;
            if (is->video_st)
                vqsize = is->videoq.size;
1425 1426
            if (is->subtitle_st)
                sqsize = is->subtitleq.size;
1427 1428 1429
            av_diff = 0;
            if (is->audio_st && is->video_st)
                av_diff = get_audio_clock(is) - get_video_clock(is);
1430
            printf("%7.2f A-V:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64"   \r",
1431 1432
                   get_master_clock(is),
                   av_diff,
1433
                   is->frame_drops_early + is->frame_drops_late,
1434 1435 1436 1437 1438
                   aqsize / 1024,
                   vqsize / 1024,
                   sqsize,
                   is->video_st ? is->video_st->codec->pts_correction_num_faulty_dts : 0,
                   is->video_st ? is->video_st->codec->pts_correction_num_faulty_pts : 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
1439 1440 1441 1442 1443 1444 1445 1446
            fflush(stdout);
            last_time = cur_time;
        }
    }
}

/* allocate a picture (needs to do that in main thread to avoid
   potential locking problems */
1447
static void alloc_picture(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
1448 1449 1450 1451 1452 1453 1454 1455
{
    VideoPicture *vp;

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

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

1456
#if CONFIG_AVFILTER
1457
    avfilter_unref_bufferp(&vp->picref);
1458 1459
#endif

1460
    video_open(is, 0);
1461

1462
    vp->bmp = SDL_CreateYUVOverlay(vp->width, vp->height,
1463
                                   SDL_YV12_OVERLAY,
1464
                                   screen);
1465 1466 1467 1468
    if (!vp->bmp || vp->bmp->pitches[0] < vp->width) {
        /* SDL allocates a buffer smaller than requested if the video
         * overlay hardware is unable to support the requested size. */
        fprintf(stderr, "Error: the video system does not support an image\n"
Michael Niedermayer's avatar
Michael Niedermayer committed
1469
                        "size of %dx%d pixels. Try using -lowres or -vf \"scale=w:h\"\n"
1470
                        "to reduce the image size.\n", vp->width, vp->height );
1471
        do_exit(is);
1472
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
1473 1474 1475 1476 1477 1478 1479

    SDL_LockMutex(is->pictq_mutex);
    vp->allocated = 1;
    SDL_CondSignal(is->pictq_cond);
    SDL_UnlockMutex(is->pictq_mutex);
}

1480
static int queue_picture(VideoState *is, AVFrame *src_frame, double pts1, int64_t pos, int serial)
Fabrice Bellard's avatar
Fabrice Bellard committed
1481 1482
{
    VideoPicture *vp;
1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501
    double frame_delay, pts = pts1;

    /* compute the exact PTS for the picture if it is omitted in the stream
     * pts1 is the dts of the pkt / pts of the frame */
    if (pts != 0) {
        /* update video clock with pts, if present */
        is->video_clock = pts;
    } else {
        pts = is->video_clock;
    }
    /* update video clock for next frame */
    frame_delay = av_q2d(is->video_st->codec->time_base);
    /* for MPEG2, the frame can be repeated, so we update the
       clock accordingly */
    frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);
    is->video_clock += frame_delay;

#if defined(DEBUG_SYNC) && 0
    printf("frame_type=%c clock=%0.3f pts=%0.3f\n",
1502
           av_get_picture_type_char(src_frame->pict_type), pts, pts1);
1503
#endif
1504

Fabrice Bellard's avatar
Fabrice Bellard committed
1505 1506
    /* wait until we have space to put a new picture */
    SDL_LockMutex(is->pictq_mutex);
1507

1508
    /* keep the last already displayed picture in the queue */
1509
    while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE - 2 &&
Fabrice Bellard's avatar
Fabrice Bellard committed
1510 1511 1512 1513
           !is->videoq.abort_request) {
        SDL_CondWait(is->pictq_cond, is->pictq_mutex);
    }
    SDL_UnlockMutex(is->pictq_mutex);
1514

Fabrice Bellard's avatar
Fabrice Bellard committed
1515 1516 1517 1518 1519
    if (is->videoq.abort_request)
        return -1;

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

1520 1521 1522 1523 1524 1525
#if CONFIG_AVFILTER
    vp->sample_aspect_ratio = ((AVFilterBufferRef *)src_frame->opaque)->video->sample_aspect_ratio;
#else
    vp->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, src_frame);
#endif

Fabrice Bellard's avatar
Fabrice Bellard committed
1526
    /* alloc or resize hardware picture buffer */
1527
    if (!vp->bmp || vp->reallocate || !vp->allocated ||
1528 1529
        vp->width  != src_frame->width ||
        vp->height != src_frame->height) {
Fabrice Bellard's avatar
Fabrice Bellard committed
1530 1531
        SDL_Event event;

1532
        vp->allocated  = 0;
1533
        vp->reallocate = 0;
1534 1535
        vp->width = src_frame->width;
        vp->height = src_frame->height;
Fabrice Bellard's avatar
Fabrice Bellard committed
1536 1537

        /* the allocation must be done in the main thread to avoid
1538
           locking problems. */
Fabrice Bellard's avatar
Fabrice Bellard committed
1539
        event.type = FF_ALLOC_EVENT;
1540
        event.user.data1 = is;
Fabrice Bellard's avatar
Fabrice Bellard committed
1541
        SDL_PushEvent(&event);
1542

Fabrice Bellard's avatar
Fabrice Bellard committed
1543 1544 1545 1546 1547
        /* wait until the picture is allocated */
        SDL_LockMutex(is->pictq_mutex);
        while (!vp->allocated && !is->videoq.abort_request) {
            SDL_CondWait(is->pictq_cond, is->pictq_mutex);
        }
1548 1549 1550 1551 1552 1553
        /* if the queue is aborted, we have to pop the pending ALLOC event or wait for the allocation to complete */
        if (is->videoq.abort_request && SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_EVENTMASK(FF_ALLOC_EVENT)) != 1) {
            while (!vp->allocated) {
                SDL_CondWait(is->pictq_cond, is->pictq_mutex);
            }
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
1554 1555 1556 1557 1558 1559
        SDL_UnlockMutex(is->pictq_mutex);

        if (is->videoq.abort_request)
            return -1;
    }

1560
    /* if the frame is not skipped, then display it */
Fabrice Bellard's avatar
Fabrice Bellard committed
1561
    if (vp->bmp) {
1562
        AVPicture pict = { { 0 } };
1563
#if CONFIG_AVFILTER
1564
        avfilter_unref_bufferp(&vp->picref);
1565 1566
        vp->picref = src_frame->opaque;
#endif
1567

Fabrice Bellard's avatar
Fabrice Bellard committed
1568 1569 1570 1571 1572 1573 1574 1575 1576 1577
        /* get a pointer on the bitmap */
        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];
1578 1579

#if CONFIG_AVFILTER
Aneesh Dogra's avatar
Aneesh Dogra committed
1580
        // FIXME use direct rendering
1581
        av_picture_copy(&pict, (AVPicture *)src_frame,
1582
                        src_frame->format, vp->width, vp->height);
1583
#else
1584
        sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
1585
        is->img_convert_ctx = sws_getCachedContext(is->img_convert_ctx,
1586
            vp->width, vp->height, src_frame->format, vp->width, vp->height,
1587
            AV_PIX_FMT_YUV420P, sws_flags, NULL, NULL, NULL);
1588
        if (is->img_convert_ctx == NULL) {
1589 1590 1591
            fprintf(stderr, "Cannot initialize the conversion context\n");
            exit(1);
        }
1592
        sws_scale(is->img_convert_ctx, src_frame->data, src_frame->linesize,
1593 1594
                  0, vp->height, pict.data, pict.linesize);
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
1595 1596 1597
        /* update the bitmap content */
        SDL_UnlockYUVOverlay(vp->bmp);

1598
        vp->pts = pts;
1599
        vp->pos = pos;
1600
        vp->skip = 0;
1601
        vp->serial = serial;
Fabrice Bellard's avatar
Fabrice Bellard committed
1602 1603 1604 1605 1606 1607 1608 1609

        /* now we can update the picture count */
        if (++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE)
            is->pictq_windex = 0;
        SDL_LockMutex(is->pictq_mutex);
        is->pictq_size++;
        SDL_UnlockMutex(is->pictq_mutex);
    }
1610 1611 1612
    return 0;
}

1613
static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacket *pkt, int *serial)
Fabrice Bellard's avatar
Fabrice Bellard committed
1614
{
1615
    int got_picture, i;
Fabrice Bellard's avatar
Fabrice Bellard committed
1616

1617
    if (packet_queue_get(&is->videoq, pkt, 1, serial) < 0)
1618
        return -1;
1619

1620 1621
    if (pkt->data == flush_pkt.data) {
        avcodec_flush_buffers(is->video_st->codec);
1622

1623
        SDL_LockMutex(is->pictq_mutex);
Aneesh Dogra's avatar
Aneesh Dogra committed
1624
        // Make sure there are no long delay timers (ideally we should just flush the que but thats harder)
1625
        for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
1626
            is->pictq[i].skip = 1;
1627 1628 1629
        }
        while (is->pictq_size && !is->videoq.abort_request) {
            SDL_CondWait(is->pictq_cond, is->pictq_mutex);
1630
        }
1631 1632
        is->video_current_pos = -1;
        is->frame_last_pts = AV_NOPTS_VALUE;
1633
        is->frame_last_duration = 0;
1634
        is->frame_timer = (double)av_gettime() / 1000000.0;
1635 1636 1637
        is->frame_last_dropped_pts = AV_NOPTS_VALUE;
        SDL_UnlockMutex(is->pictq_mutex);

1638 1639
        return 0;
    }
1640

1641
    if(avcodec_decode_video2(is->video_st->codec, frame, &got_picture, pkt) < 0)
1642
        return 0;
1643 1644

    if (got_picture) {
1645 1646
        int ret = 1;

1647
        if (decoder_reorder_pts == -1) {
1648
            *pts = av_frame_get_best_effort_timestamp(frame);
1649
        } else if (decoder_reorder_pts) {
1650
            *pts = frame->pkt_pts;
1651
        } else {
1652
            *pts = frame->pkt_dts;
1653 1654 1655 1656
        }

        if (*pts == AV_NOPTS_VALUE) {
            *pts = 0;
1657
        }
1658

1659
        if (framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) {
1660 1661 1662 1663 1664 1665 1666
            SDL_LockMutex(is->pictq_mutex);
            if (is->frame_last_pts != AV_NOPTS_VALUE && *pts) {
                double clockdiff = get_video_clock(is) - get_master_clock(is);
                double dpts = av_q2d(is->video_st->time_base) * *pts;
                double ptsdiff = dpts - is->frame_last_pts;
                if (fabs(clockdiff) < AV_NOSYNC_THRESHOLD &&
                     ptsdiff > 0 && ptsdiff < AV_NOSYNC_THRESHOLD &&
1667
                     clockdiff + ptsdiff - is->frame_last_filter_delay < 0) {
1668 1669
                    is->frame_last_dropped_pos = pkt->pos;
                    is->frame_last_dropped_pts = dpts;
1670
                    is->frame_drops_early++;
1671 1672 1673 1674 1675
                    ret = 0;
                }
            }
            SDL_UnlockMutex(is->pictq_mutex);
        }
1676

1677
        return ret;
1678
    }
1679 1680 1681 1682
    return 0;
}

#if CONFIG_AVFILTER
1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713
static int configure_filtergraph(AVFilterGraph *graph, const char *filtergraph,
                                 AVFilterContext *source_ctx, AVFilterContext *sink_ctx)
{
    int ret;
    AVFilterInOut *outputs = NULL, *inputs = NULL;

    if (filtergraph) {
        outputs = avfilter_inout_alloc();
        inputs  = avfilter_inout_alloc();
        if (!outputs || !inputs) {
            ret = AVERROR(ENOMEM);
            goto fail;
        }

        outputs->name       = av_strdup("in");
        outputs->filter_ctx = source_ctx;
        outputs->pad_idx    = 0;
        outputs->next       = NULL;

        inputs->name        = av_strdup("out");
        inputs->filter_ctx  = sink_ctx;
        inputs->pad_idx     = 0;
        inputs->next        = NULL;

        if ((ret = avfilter_graph_parse(graph, filtergraph, &inputs, &outputs, NULL)) < 0)
            goto fail;
    } else {
        if ((ret = avfilter_link(source_ctx, 0, sink_ctx, 0)) < 0)
            goto fail;
    }

1714
    ret = avfilter_graph_config(graph, NULL);
1715 1716 1717 1718 1719 1720
fail:
    avfilter_inout_free(&outputs);
    avfilter_inout_free(&inputs);
    return ret;
}

1721
static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters)
1722
{
1723
    static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };
Stefano Sabatini's avatar
Stefano Sabatini committed
1724
    char sws_flags_str[128];
1725
    char buffersrc_args[256];
1726
    int ret;
1727
    AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc();
1728
    AVFilterContext *filt_src = NULL, *filt_out = NULL, *filt_crop;
1729 1730
    AVCodecContext *codec = is->video_st->codec;

1731 1732 1733
    if (!buffersink_params)
        return AVERROR(ENOMEM);

Stefano Sabatini's avatar
Stefano Sabatini committed
1734 1735
    snprintf(sws_flags_str, sizeof(sws_flags_str), "flags=%d", sws_flags);
    graph->scale_sws_opts = av_strdup(sws_flags_str);
1736

1737 1738
    snprintf(buffersrc_args, sizeof(buffersrc_args),
             "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
1739 1740
             codec->width, codec->height, codec->pix_fmt,
             is->video_st->time_base.num, is->video_st->time_base.den,
1741
             codec->sample_aspect_ratio.num, FFMAX(codec->sample_aspect_ratio.den, 1));
1742 1743 1744

    if ((ret = avfilter_graph_create_filter(&filt_src,
                                            avfilter_get_by_name("buffer"),
1745
                                            "ffplay_buffer", buffersrc_args, NULL,
1746
                                            graph)) < 0)
1747
        goto fail;
1748

1749
    buffersink_params->pixel_fmts = pix_fmts;
1750
    ret = avfilter_graph_create_filter(&filt_out,
1751
                                       avfilter_get_by_name("ffbuffersink"),
1752
                                       "ffplay_buffersink", NULL, buffersink_params, graph);
1753
    if (ret < 0)
1754
        goto fail;
1755

1756 1757 1758 1759 1760
    /* SDL YUV code is not handling odd width/height for some driver
     * combinations, therefore we crop the picture to an even width/height. */
    if ((ret = avfilter_graph_create_filter(&filt_crop,
                                            avfilter_get_by_name("crop"),
                                            "ffplay_crop", "floor(in_w/2)*2:floor(in_h/2)*2", NULL, graph)) < 0)
1761
        goto fail;
1762
    if ((ret = avfilter_link(filt_crop, 0, filt_out, 0)) < 0)
1763
        goto fail;
1764

1765
    if ((ret = configure_filtergraph(graph, vfilters, filt_src, filt_crop)) < 0)
1766
        goto fail;
1767

1768
    is->in_video_filter  = filt_src;
1769
    is->out_video_filter = filt_out;
1770

1771 1772
fail:
    av_freep(&buffersink_params);
1773 1774 1775 1776 1777 1778 1779
    return ret;
}

#endif  /* CONFIG_AVFILTER */

static int video_thread(void *arg)
{
1780
    AVPacket pkt = { 0 };
1781
    VideoState *is = arg;
Aneesh Dogra's avatar
Aneesh Dogra committed
1782
    AVFrame *frame = avcodec_alloc_frame();
1783
    int64_t pts_int = AV_NOPTS_VALUE, pos = -1;
1784 1785
    double pts;
    int ret;
1786
    int serial = 0;
1787 1788

#if CONFIG_AVFILTER
1789
    AVCodecContext *codec = is->video_st->codec;
1790
    AVFilterGraph *graph = avfilter_graph_alloc();
1791
    AVFilterContext *filt_out = NULL, *filt_in = NULL;
1792 1793
    int last_w = 0;
    int last_h = 0;
1794
    enum AVPixelFormat last_format = -2;
1795

1796 1797 1798 1799 1800
    if (codec->codec->capabilities & CODEC_CAP_DR1) {
        is->use_dr1 = 1;
        codec->get_buffer     = codec_get_buffer;
        codec->release_buffer = codec_release_buffer;
        codec->opaque         = &is->buffer_pool;
1801
    }
1802 1803
#endif

Aneesh Dogra's avatar
Aneesh Dogra committed
1804
    for (;;) {
1805
#if CONFIG_AVFILTER
1806
        AVFilterBufferRef *picref;
1807
        AVRational tb;
1808 1809 1810
#endif
        while (is->paused && !is->videoq.abort_request)
            SDL_Delay(10);
1811

1812
        avcodec_get_frame_defaults(frame);
1813 1814
        av_free_packet(&pkt);

1815
        ret = get_video_frame(is, frame, &pts_int, &pkt, &serial);
1816 1817 1818 1819 1820 1821
        if (ret < 0)
            goto the_end;

        if (!ret)
            continue;

1822
#if CONFIG_AVFILTER
1823
        if (   last_w != is->video_st->codec->width
1824 1825
            || last_h != is->video_st->codec->height
            || last_format != is->video_st->codec->pix_fmt) {
1826 1827
            av_log(NULL, AV_LOG_INFO, "Frame changed from size:%dx%d to size:%dx%d\n",
                   last_w, last_h, is->video_st->codec->width, is->video_st->codec->height);
1828 1829
            avfilter_graph_free(&graph);
            graph = avfilter_graph_alloc();
1830
            if ((ret = configure_video_filters(graph, is, vfilters)) < 0) {
1831 1832 1833 1834
                SDL_Event event;
                event.type = FF_QUIT_EVENT;
                event.user.data1 = is;
                SDL_PushEvent(&event);
1835
                av_free_packet(&pkt);
1836
                goto the_end;
1837
            }
1838
            filt_in  = is->in_video_filter;
1839 1840 1841
            filt_out = is->out_video_filter;
            last_w = is->video_st->codec->width;
            last_h = is->video_st->codec->height;
1842
            last_format = is->video_st->codec->pix_fmt;
1843
        }
1844 1845

        frame->pts = pts_int;
1846
        frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, frame);
1847
        if (is->use_dr1 && frame->opaque) {
1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859
            FrameBuffer      *buf = frame->opaque;
            AVFilterBufferRef *fb = avfilter_get_video_buffer_ref_from_arrays(
                                        frame->data, frame->linesize,
                                        AV_PERM_READ | AV_PERM_PRESERVE,
                                        frame->width, frame->height,
                                        frame->format);

            avfilter_copy_frame_props(fb, frame);
            fb->buf->priv           = buf;
            fb->buf->free           = filter_release_buffer;

            buf->refcount++;
1860
            av_buffersrc_add_ref(filt_in, fb, AV_BUFFERSRC_FLAG_NO_COPY);
1861 1862 1863 1864

        } else
            av_buffersrc_write_frame(filt_in, frame);

1865 1866
        av_free_packet(&pkt);

1867
        while (ret >= 0) {
1868 1869
            is->frame_last_returned_time = av_gettime() / 1000000.0;

1870
            ret = av_buffersink_get_buffer_ref(filt_out, &picref, 0);
1871 1872 1873 1874 1875
            if (ret < 0) {
                ret = 0;
                break;
            }

1876 1877 1878 1879
            is->frame_last_filter_delay = av_gettime() / 1000000.0 - is->frame_last_returned_time;
            if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0)
                is->frame_last_filter_delay = 0;

1880
            avfilter_copy_buf_props(frame, picref);
1881

1882
            pts_int = picref->pts;
1883
            tb      = filt_out->inputs[0]->time_base;
1884 1885
            pos     = picref->pos;
            frame->opaque = picref;
1886

1887 1888 1889 1890 1891 1892 1893 1894 1895
            if (av_cmp_q(tb, is->video_st->time_base)) {
                av_unused int64_t pts1 = pts_int;
                pts_int = av_rescale_q(pts_int, tb, is->video_st->time_base);
                av_dlog(NULL, "video_thread(): "
                        "tb:%d/%d pts:%"PRId64" -> tb:%d/%d pts:%"PRId64"\n",
                        tb.num, tb.den, pts1,
                        is->video_st->time_base.num, is->video_st->time_base.den, pts_int);
            }
            pts = pts_int * av_q2d(is->video_st->time_base);
1896
            ret = queue_picture(is, frame, pts, pos, serial);
1897
        }
1898
#else
Aneesh Dogra's avatar
Aneesh Dogra committed
1899
        pts = pts_int * av_q2d(is->video_st->time_base);
1900
        ret = queue_picture(is, frame, pts, pkt.pos, serial);
1901
#endif
1902

1903 1904 1905
        if (ret < 0)
            goto the_end;

1906 1907
        if (is->step)
            stream_toggle_pause(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
1908 1909
    }
 the_end:
1910
    avcodec_flush_buffers(is->video_st->codec);
1911
#if CONFIG_AVFILTER
1912
    avfilter_graph_free(&graph);
1913
#endif
1914
    av_free_packet(&pkt);
1915
    avcodec_free_frame(&frame);
Fabrice Bellard's avatar
Fabrice Bellard committed
1916 1917 1918
    return 0;
}

1919 1920 1921 1922 1923
static int subtitle_thread(void *arg)
{
    VideoState *is = arg;
    SubPicture *sp;
    AVPacket pkt1, *pkt = &pkt1;
1924
    int got_subtitle;
1925 1926 1927 1928
    double pts;
    int i, j;
    int r, g, b, y, u, v, a;

Aneesh Dogra's avatar
Aneesh Dogra committed
1929
    for (;;) {
1930 1931 1932
        while (is->paused && !is->subtitleq.abort_request) {
            SDL_Delay(10);
        }
1933
        if (packet_queue_get(&is->subtitleq, pkt, 1, NULL) < 0)
1934
            break;
1935

Aneesh Dogra's avatar
Aneesh Dogra committed
1936
        if (pkt->data == flush_pkt.data) {
1937 1938 1939
            avcodec_flush_buffers(is->subtitle_st->codec);
            continue;
        }
1940 1941 1942 1943 1944 1945
        SDL_LockMutex(is->subpq_mutex);
        while (is->subpq_size >= SUBPICTURE_QUEUE_SIZE &&
               !is->subtitleq.abort_request) {
            SDL_CondWait(is->subpq_cond, is->subpq_mutex);
        }
        SDL_UnlockMutex(is->subpq_mutex);
1946

1947
        if (is->subtitleq.abort_request)
1948
            return 0;
1949

1950 1951 1952 1953 1954 1955
        sp = &is->subpq[is->subpq_windex];

       /* NOTE: ipts is the PTS of the _first_ picture beginning in
           this packet, if any */
        pts = 0;
        if (pkt->pts != AV_NOPTS_VALUE)
Aneesh Dogra's avatar
Aneesh Dogra committed
1956
            pts = av_q2d(is->subtitle_st->time_base) * pkt->pts;
1957

1958 1959
        avcodec_decode_subtitle2(is->subtitle_st->codec, &sp->sub,
                                 &got_subtitle, pkt);
1960
        if (got_subtitle && sp->sub.format == 0) {
1961 1962
            if (sp->sub.pts != AV_NOPTS_VALUE)
                pts = sp->sub.pts / (double)AV_TIME_BASE;
1963
            sp->pts = pts;
1964

1965 1966
            for (i = 0; i < sp->sub.num_rects; i++)
            {
1967
                for (j = 0; j < sp->sub.rects[i]->nb_colors; j++)
1968
                {
1969
                    RGBA_IN(r, g, b, a, (uint32_t*)sp->sub.rects[i]->pict.data[1] + j);
1970 1971 1972
                    y = RGB_TO_Y_CCIR(r, g, b);
                    u = RGB_TO_U_CCIR(r, g, b, 0);
                    v = RGB_TO_V_CCIR(r, g, b, 0);
1973
                    YUVA_OUT((uint32_t*)sp->sub.rects[i]->pict.data[1] + j, y, u, v, a);
1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988
                }
            }

            /* now we can update the picture count */
            if (++is->subpq_windex == SUBPICTURE_QUEUE_SIZE)
                is->subpq_windex = 0;
            SDL_LockMutex(is->subpq_mutex);
            is->subpq_size++;
            SDL_UnlockMutex(is->subpq_mutex);
        }
        av_free_packet(pkt);
    }
    return 0;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
1989 1990 1991
/* copy samples for viewing in editor window */
static void update_sample_display(VideoState *is, short *samples, int samples_size)
{
1992
    int size, len;
Fabrice Bellard's avatar
Fabrice Bellard committed
1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007

    size = samples_size / sizeof(short);
    while (size > 0) {
        len = SAMPLE_ARRAY_SIZE - is->sample_array_index;
        if (len > size)
            len = size;
        memcpy(is->sample_array + is->sample_array_index, samples, len * sizeof(short));
        samples += len;
        is->sample_array_index += len;
        if (is->sample_array_index >= SAMPLE_ARRAY_SIZE)
            is->sample_array_index = 0;
        size -= len;
    }
}

2008 2009 2010
/* return the wanted number of samples to get better sync if sync_type is video
 * or external master clock */
static int synchronize_audio(VideoState *is, int nb_samples)
Fabrice Bellard's avatar
Fabrice Bellard committed
2011
{
2012
    int wanted_nb_samples = nb_samples;
Fabrice Bellard's avatar
Fabrice Bellard committed
2013 2014

    /* if not master, then we try to remove or add samples to correct the clock */
2015
    if (get_master_sync_type(is) != AV_SYNC_AUDIO_MASTER) {
2016
        double diff, avg_diff;
2017
        int min_nb_samples, max_nb_samples;
2018

2019
        diff = get_audio_clock(is) - get_master_clock(is);
2020

2021
        if (fabs(diff) < AV_NOSYNC_THRESHOLD) {
2022 2023 2024 2025 2026 2027 2028 2029 2030
            is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum;
            if (is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) {
                /* not enough measures to have a correct estimate */
                is->audio_diff_avg_count++;
            } else {
                /* estimate the A-V difference */
                avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef);

                if (fabs(avg_diff) >= is->audio_diff_threshold) {
2031
                    wanted_nb_samples = nb_samples + (int)(diff * is->audio_src.freq);
2032 2033 2034
                    min_nb_samples = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100));
                    max_nb_samples = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100));
                    wanted_nb_samples = FFMIN(FFMAX(wanted_nb_samples, min_nb_samples), max_nb_samples);
2035
                }
2036
                av_dlog(NULL, "diff=%f adiff=%f sample_diff=%d apts=%0.3f vpts=%0.3f %f\n",
2037
                        diff, avg_diff, wanted_nb_samples - nb_samples,
2038
                        is->audio_clock, is->video_clock, is->audio_diff_threshold);
Fabrice Bellard's avatar
Fabrice Bellard committed
2039
            }
2040 2041 2042 2043
        } else {
            /* too big difference : may be initial PTS errors, so
               reset A-V filter */
            is->audio_diff_avg_count = 0;
Aneesh Dogra's avatar
Aneesh Dogra committed
2044
            is->audio_diff_cum       = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2045 2046 2047
        }
    }

2048
    return wanted_nb_samples;
Fabrice Bellard's avatar
Fabrice Bellard committed
2049 2050 2051
}

/* decode one audio frame and returns its uncompressed size */
2052
static int audio_decode_frame(VideoState *is, double *pts_ptr)
Fabrice Bellard's avatar
Fabrice Bellard committed
2053
{
2054
    AVPacket *pkt_temp = &is->audio_pkt_temp;
Fabrice Bellard's avatar
Fabrice Bellard committed
2055
    AVPacket *pkt = &is->audio_pkt;
Aneesh Dogra's avatar
Aneesh Dogra committed
2056
    AVCodecContext *dec = is->audio_st->codec;
2057
    int len1, len2, data_size, resampled_data_size;
2058 2059
    int64_t dec_channel_layout;
    int got_frame;
Fabrice Bellard's avatar
Fabrice Bellard committed
2060
    double pts;
2061 2062
    int new_packet = 0;
    int flush_complete = 0;
2063
    int wanted_nb_samples;
Fabrice Bellard's avatar
Fabrice Bellard committed
2064

Aneesh Dogra's avatar
Aneesh Dogra committed
2065
    for (;;) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2066
        /* NOTE: the audio packet can contain several frames */
2067
        while (pkt_temp->size > 0 || (!pkt_temp->data && new_packet)) {
2068 2069 2070 2071 2072 2073
            if (!is->frame) {
                if (!(is->frame = avcodec_alloc_frame()))
                    return AVERROR(ENOMEM);
            } else
                avcodec_get_frame_defaults(is->frame);

2074 2075 2076
            if (is->paused)
                return -1;

2077 2078 2079
            if (flush_complete)
                break;
            new_packet = 0;
2080
            len1 = avcodec_decode_audio4(dec, is->frame, &got_frame, pkt_temp);
Fabrice Bellard's avatar
Fabrice Bellard committed
2081 2082
            if (len1 < 0) {
                /* if error, we skip the frame */
2083
                pkt_temp->size = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2084
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2085
            }
2086

2087 2088
            pkt_temp->data += len1;
            pkt_temp->size -= len1;
2089

2090
            if (!got_frame) {
2091 2092 2093
                /* stop sending empty packets if the decoder is finished */
                if (!pkt_temp->data && dec->codec->capabilities & CODEC_CAP_DELAY)
                    flush_complete = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2094
                continue;
2095
            }
2096
            data_size = av_samples_get_buffer_size(NULL, is->frame->channels,
2097
                                                   is->frame->nb_samples,
2098
                                                   is->frame->format, 1);
2099

2100
            dec_channel_layout =
2101 2102
                (is->frame->channel_layout && is->frame->channels == av_get_channel_layout_nb_channels(is->frame->channel_layout)) ?
                is->frame->channel_layout : av_get_default_channel_layout(is->frame->channels);
2103
            wanted_nb_samples = synchronize_audio(is, is->frame->nb_samples);
2104

2105 2106 2107 2108
            if (is->frame->format        != is->audio_src.fmt            ||
                dec_channel_layout       != is->audio_src.channel_layout ||
                is->frame->sample_rate   != is->audio_src.freq           ||
                (wanted_nb_samples       != is->frame->nb_samples && !is->swr_ctx)) {
2109
                swr_free(&is->swr_ctx);
2110
                is->swr_ctx = swr_alloc_set_opts(NULL,
2111
                                                 is->audio_tgt.channel_layout, is->audio_tgt.fmt, is->audio_tgt.freq,
2112
                                                 dec_channel_layout,           is->frame->format, is->frame->sample_rate,
2113
                                                 0, NULL);
2114 2115
                if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) {
                    fprintf(stderr, "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",
2116
                        is->frame->sample_rate,   av_get_sample_fmt_name(is->frame->format), (int)is->frame->channels,
2117
                        is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels);
2118
                    break;
2119
                }
2120
                is->audio_src.channel_layout = dec_channel_layout;
2121 2122 2123
                is->audio_src.channels = is->frame->channels;
                is->audio_src.freq = is->frame->sample_rate;
                is->audio_src.fmt = is->frame->format;
2124 2125
            }

2126
            if (is->swr_ctx) {
2127
                const uint8_t **in = (const uint8_t **)is->frame->extended_data;
2128
                uint8_t *out[] = {is->audio_buf2};
2129
                int out_count = sizeof(is->audio_buf2) / is->audio_tgt.channels / av_get_bytes_per_sample(is->audio_tgt.fmt);
2130
                if (wanted_nb_samples != is->frame->nb_samples) {
2131 2132
                    if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - is->frame->nb_samples) * is->audio_tgt.freq / is->frame->sample_rate,
                                                wanted_nb_samples * is->audio_tgt.freq / is->frame->sample_rate) < 0) {
2133 2134 2135 2136
                        fprintf(stderr, "swr_set_compensation() failed\n");
                        break;
                    }
                }
2137
                len2 = swr_convert(is->swr_ctx, out, out_count, in, is->frame->nb_samples);
2138
                if (len2 < 0) {
2139
                    fprintf(stderr, "swr_convert() failed\n");
2140 2141
                    break;
                }
2142
                if (len2 == out_count) {
2143 2144 2145 2146
                    fprintf(stderr, "warning: audio buffer is probably too small\n");
                    swr_init(is->swr_ctx);
                }
                is->audio_buf = is->audio_buf2;
2147
                resampled_data_size = len2 * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt);
2148
            } else {
2149
                is->audio_buf = is->frame->data[0];
2150
                resampled_data_size = data_size;
2151 2152
            }

Fabrice Bellard's avatar
Fabrice Bellard committed
2153 2154 2155
            /* if no pts, then compute it */
            pts = is->audio_clock;
            *pts_ptr = pts;
2156
            is->audio_clock += (double)data_size /
2157
                (is->frame->channels * is->frame->sample_rate * av_get_bytes_per_sample(is->frame->format));
2158
#ifdef DEBUG
Fabrice Bellard's avatar
Fabrice Bellard committed
2159 2160 2161 2162 2163 2164
            {
                static double last_clock;
                printf("audio: delay=%0.3f clock=%0.3f pts=%0.3f\n",
                       is->audio_clock - last_clock,
                       is->audio_clock, pts);
                last_clock = is->audio_clock;
Fabrice Bellard's avatar
Fabrice Bellard committed
2165
            }
Fabrice Bellard's avatar
Fabrice Bellard committed
2166
#endif
2167
            return resampled_data_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
2168 2169
        }

Fabrice Bellard's avatar
Fabrice Bellard committed
2170 2171
        /* free the current packet */
        if (pkt->data)
Fabrice Bellard's avatar
Fabrice Bellard committed
2172
            av_free_packet(pkt);
2173
        memset(pkt_temp, 0, sizeof(*pkt_temp));
2174

Fabrice Bellard's avatar
Fabrice Bellard committed
2175 2176 2177
        if (is->paused || is->audioq.abort_request) {
            return -1;
        }
2178

2179 2180 2181
        if (is->audioq.nb_packets == 0)
            SDL_CondSignal(is->continue_read_thread);

Fabrice Bellard's avatar
Fabrice Bellard committed
2182
        /* read next packet */
2183
        if ((new_packet = packet_queue_get(&is->audioq, pkt, 1, &is->audio_pkt_temp_serial)) < 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
2184
            return -1;
2185

2186
        if (pkt->data == flush_pkt.data) {
2187
            avcodec_flush_buffers(dec);
2188 2189
            flush_complete = 0;
        }
2190

2191
        *pkt_temp = *pkt;
2192

Fabrice Bellard's avatar
Fabrice Bellard committed
2193 2194
        /* if update the audio clock with the pts */
        if (pkt->pts != AV_NOPTS_VALUE) {
2195
            is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts;
Fabrice Bellard's avatar
Fabrice Bellard committed
2196
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
2197 2198 2199 2200
    }
}

/* prepare a new audio buffer */
2201
static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
Fabrice Bellard's avatar
Fabrice Bellard committed
2202 2203 2204
{
    VideoState *is = opaque;
    int audio_size, len1;
2205
    int bytes_per_sec;
2206
    int frame_size = av_samples_get_buffer_size(NULL, is->audio_tgt.channels, 1, is->audio_tgt.fmt, 1);
Fabrice Bellard's avatar
Fabrice Bellard committed
2207 2208 2209
    double pts;

    audio_callback_time = av_gettime();
2210

Fabrice Bellard's avatar
Fabrice Bellard committed
2211 2212
    while (len > 0) {
        if (is->audio_buf_index >= is->audio_buf_size) {
2213
           audio_size = audio_decode_frame(is, &pts);
Fabrice Bellard's avatar
Fabrice Bellard committed
2214 2215
           if (audio_size < 0) {
                /* if error, just output silence */
2216
               is->audio_buf      = is->silence_buf;
2217
               is->audio_buf_size = sizeof(is->silence_buf) / frame_size * frame_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
2218
           } else {
2219
               if (is->show_mode != SHOW_MODE_VIDEO)
Fabrice Bellard's avatar
Fabrice Bellard committed
2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232
                   update_sample_display(is, (int16_t *)is->audio_buf, audio_size);
               is->audio_buf_size = audio_size;
           }
           is->audio_buf_index = 0;
        }
        len1 = is->audio_buf_size - is->audio_buf_index;
        if (len1 > len)
            len1 = len;
        memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
        len -= len1;
        stream += len1;
        is->audio_buf_index += len1;
    }
2233
    bytes_per_sec = is->audio_tgt.freq * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt);
2234 2235 2236 2237
    is->audio_write_buf_size = is->audio_buf_size - is->audio_buf_index;
    /* Let's assume the audio driver that is used by SDL has two periods. */
    is->audio_current_pts = is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / bytes_per_sec;
    is->audio_current_pts_drift = is->audio_current_pts - audio_callback_time / 1000000.0;
2238 2239
    if (is->audioq.serial == is->audio_pkt_temp_serial)
        check_external_clock_sync(is, is->audio_current_pts);
Fabrice Bellard's avatar
Fabrice Bellard committed
2240 2241
}

2242
static int audio_open(void *opaque, int64_t wanted_channel_layout, int wanted_nb_channels, int wanted_sample_rate, struct AudioParams *audio_hw_params)
2243 2244 2245
{
    SDL_AudioSpec wanted_spec, spec;
    const char *env;
2246
    const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6};
2247 2248

    env = SDL_getenv("SDL_AUDIO_CHANNELS");
2249
    if (env) {
2250
        wanted_nb_channels = atoi(env);
2251 2252 2253 2254
        wanted_channel_layout = av_get_default_channel_layout(wanted_nb_channels);
    }
    if (!wanted_channel_layout || wanted_nb_channels != av_get_channel_layout_nb_channels(wanted_channel_layout)) {
        wanted_channel_layout = av_get_default_channel_layout(wanted_nb_channels);
2255 2256 2257
        wanted_channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX;
    }
    wanted_spec.channels = av_get_channel_layout_nb_channels(wanted_channel_layout);
2258
    wanted_spec.freq = wanted_sample_rate;
2259 2260 2261 2262 2263 2264 2265 2266
    if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
        fprintf(stderr, "Invalid sample rate or channel count!\n");
        return -1;
    }
    wanted_spec.format = AUDIO_S16SYS;
    wanted_spec.silence = 0;
    wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
    wanted_spec.callback = sdl_audio_callback;
2267
    wanted_spec.userdata = opaque;
2268 2269 2270 2271 2272 2273 2274 2275
    while (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
        fprintf(stderr, "SDL_OpenAudio (%d channels): %s\n", wanted_spec.channels, SDL_GetError());
        wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)];
        if (!wanted_spec.channels) {
            fprintf(stderr, "No more channel combinations to try, audio open failed\n");
            return -1;
        }
        wanted_channel_layout = av_get_default_channel_layout(wanted_spec.channels);
2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288
    }
    if (spec.format != AUDIO_S16SYS) {
        fprintf(stderr, "SDL advised audio format %d is not supported!\n", spec.format);
        return -1;
    }
    if (spec.channels != wanted_spec.channels) {
        wanted_channel_layout = av_get_default_channel_layout(spec.channels);
        if (!wanted_channel_layout) {
            fprintf(stderr, "SDL advised channel count %d is not supported!\n", spec.channels);
            return -1;
        }
    }

2289 2290 2291 2292
    audio_hw_params->fmt = AV_SAMPLE_FMT_S16;
    audio_hw_params->freq = spec.freq;
    audio_hw_params->channel_layout = wanted_channel_layout;
    audio_hw_params->channels =  spec.channels;
2293
    return spec.size;
2294 2295
}

Fabrice Bellard's avatar
Fabrice Bellard committed
2296 2297 2298 2299
/* open a given stream. Return 0 if OK */
static int stream_component_open(VideoState *is, int stream_index)
{
    AVFormatContext *ic = is->ic;
2300
    AVCodecContext *avctx;
Fabrice Bellard's avatar
Fabrice Bellard committed
2301
    AVCodec *codec;
2302 2303
    AVDictionary *opts;
    AVDictionaryEntry *t = NULL;
Fabrice Bellard's avatar
Fabrice Bellard committed
2304 2305 2306

    if (stream_index < 0 || stream_index >= ic->nb_streams)
        return -1;
2307
    avctx = ic->streams[stream_index]->codec;
2308

2309
    codec = avcodec_find_decoder(avctx->codec_id);
2310

2311
    switch(avctx->codec_type){
2312 2313 2314
        case AVMEDIA_TYPE_AUDIO   : is->last_audio_stream    = stream_index; if(audio_codec_name   ) codec= avcodec_find_decoder_by_name(   audio_codec_name); break;
        case AVMEDIA_TYPE_SUBTITLE: is->last_subtitle_stream = stream_index; if(subtitle_codec_name) codec= avcodec_find_decoder_by_name(subtitle_codec_name); break;
        case AVMEDIA_TYPE_VIDEO   : is->last_video_stream    = stream_index; if(video_codec_name   ) codec= avcodec_find_decoder_by_name(   video_codec_name); break;
2315
    }
2316 2317 2318
    if (!codec)
        return -1;

Aneesh Dogra's avatar
Aneesh Dogra committed
2319 2320
    avctx->workaround_bugs   = workaround_bugs;
    avctx->lowres            = lowres;
2321 2322 2323 2324 2325
    if(avctx->lowres > codec->max_lowres){
        av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n",
                codec->max_lowres);
        avctx->lowres= codec->max_lowres;
    }
Aneesh Dogra's avatar
Aneesh Dogra committed
2326 2327 2328 2329 2330
    avctx->idct_algo         = idct;
    avctx->skip_frame        = skip_frame;
    avctx->skip_idct         = skip_idct;
    avctx->skip_loop_filter  = skip_loop_filter;
    avctx->error_concealment = error_concealment;
2331

2332
    if(avctx->lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE;
Aneesh Dogra's avatar
Aneesh Dogra committed
2333
    if (fast)   avctx->flags2 |= CODEC_FLAG2_FAST;
2334 2335 2336
    if(codec->capabilities & CODEC_CAP_DR1)
        avctx->flags |= CODEC_FLAG_EMU_EDGE;

2337
    opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], codec);
2338 2339
    if (!av_dict_get(opts, "threads", NULL, 0))
        av_dict_set(&opts, "threads", "auto", 0);
2340
    if (avcodec_open2(avctx, codec, &opts) < 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
2341
        return -1;
2342 2343 2344 2345
    if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
        av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
        return AVERROR_OPTION_NOT_FOUND;
    }
2346 2347

    /* prepare audio output */
2348
    if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
2349 2350
        int audio_hw_buf_size = audio_open(is, avctx->channel_layout, avctx->channels, avctx->sample_rate, &is->audio_src);
        if (audio_hw_buf_size < 0)
2351
            return -1;
2352 2353
        is->audio_hw_buf_size = audio_hw_buf_size;
        is->audio_tgt = is->audio_src;
2354 2355
    }

2356
    ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
Aneesh Dogra's avatar
Aneesh Dogra committed
2357
    switch (avctx->codec_type) {
2358
    case AVMEDIA_TYPE_AUDIO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2359 2360
        is->audio_stream = stream_index;
        is->audio_st = ic->streams[stream_index];
Aneesh Dogra's avatar
Aneesh Dogra committed
2361
        is->audio_buf_size  = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2362
        is->audio_buf_index = 0;
2363 2364

        /* init averaging filter */
Aneesh Dogra's avatar
Aneesh Dogra committed
2365
        is->audio_diff_avg_coef  = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
2366 2367 2368
        is->audio_diff_avg_count = 0;
        /* since we do not have a precise anough audio fifo fullness,
           we correct audio sync only if larger than this threshold */
2369
        is->audio_diff_threshold = 2.0 * is->audio_hw_buf_size / av_samples_get_buffer_size(NULL, is->audio_tgt.channels, is->audio_tgt.freq, is->audio_tgt.fmt, 1);
2370

Fabrice Bellard's avatar
Fabrice Bellard committed
2371
        memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
2372
        memset(&is->audio_pkt_temp, 0, sizeof(is->audio_pkt_temp));
2373
        packet_queue_start(&is->audioq);
2374
        SDL_PauseAudio(0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2375
        break;
2376
    case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2377 2378 2379
        is->video_stream = stream_index;
        is->video_st = ic->streams[stream_index];

2380
        packet_queue_start(&is->videoq);
Fabrice Bellard's avatar
Fabrice Bellard committed
2381 2382
        is->video_tid = SDL_CreateThread(video_thread, is);
        break;
2383
    case AVMEDIA_TYPE_SUBTITLE:
2384 2385
        is->subtitle_stream = stream_index;
        is->subtitle_st = ic->streams[stream_index];
2386
        packet_queue_start(&is->subtitleq);
2387

2388 2389
        is->subtitle_tid = SDL_CreateThread(subtitle_thread, is);
        break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2390 2391 2392 2393 2394 2395 2396 2397 2398
    default:
        break;
    }
    return 0;
}

static void stream_component_close(VideoState *is, int stream_index)
{
    AVFormatContext *ic = is->ic;
2399
    AVCodecContext *avctx;
2400

2401 2402
    if (stream_index < 0 || stream_index >= ic->nb_streams)
        return;
2403
    avctx = ic->streams[stream_index]->codec;
Fabrice Bellard's avatar
Fabrice Bellard committed
2404

Aneesh Dogra's avatar
Aneesh Dogra committed
2405
    switch (avctx->codec_type) {
2406
    case AVMEDIA_TYPE_AUDIO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2407 2408 2409 2410
        packet_queue_abort(&is->audioq);

        SDL_CloseAudio();

2411
        packet_queue_flush(&is->audioq);
2412
        av_free_packet(&is->audio_pkt);
2413
        swr_free(&is->swr_ctx);
2414 2415
        av_freep(&is->audio_buf1);
        is->audio_buf = NULL;
2416
        avcodec_free_frame(&is->frame);
2417 2418 2419 2420

        if (is->rdft) {
            av_rdft_end(is->rdft);
            av_freep(&is->rdft_data);
2421 2422
            is->rdft = NULL;
            is->rdft_bits = 0;
2423
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
2424
        break;
2425
    case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2426 2427 2428 2429 2430 2431 2432 2433 2434 2435
        packet_queue_abort(&is->videoq);

        /* note: we also signal this mutex to make sure we deblock the
           video thread in all cases */
        SDL_LockMutex(is->pictq_mutex);
        SDL_CondSignal(is->pictq_cond);
        SDL_UnlockMutex(is->pictq_mutex);

        SDL_WaitThread(is->video_tid, NULL);

2436
        packet_queue_flush(&is->videoq);
Fabrice Bellard's avatar
Fabrice Bellard committed
2437
        break;
2438
    case AVMEDIA_TYPE_SUBTITLE:
2439
        packet_queue_abort(&is->subtitleq);
2440

2441 2442 2443 2444
        /* note: we also signal this mutex to make sure we deblock the
           video thread in all cases */
        SDL_LockMutex(is->subpq_mutex);
        is->subtitle_stream_changed = 1;
2445

2446 2447 2448 2449 2450
        SDL_CondSignal(is->subpq_cond);
        SDL_UnlockMutex(is->subpq_mutex);

        SDL_WaitThread(is->subtitle_tid, NULL);

2451
        packet_queue_flush(&is->subtitleq);
2452
        break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2453 2454 2455 2456
    default:
        break;
    }

2457
    ic->streams[stream_index]->discard = AVDISCARD_ALL;
2458
    avcodec_close(avctx);
2459
#if CONFIG_AVFILTER
2460
    free_buffer_pool(&is->buffer_pool);
2461
#endif
Aneesh Dogra's avatar
Aneesh Dogra committed
2462
    switch (avctx->codec_type) {
2463
    case AVMEDIA_TYPE_AUDIO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2464 2465 2466
        is->audio_st = NULL;
        is->audio_stream = -1;
        break;
2467
    case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2468 2469 2470
        is->video_st = NULL;
        is->video_stream = -1;
        break;
2471
    case AVMEDIA_TYPE_SUBTITLE:
2472 2473 2474
        is->subtitle_st = NULL;
        is->subtitle_stream = -1;
        break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2475 2476 2477 2478 2479
    default:
        break;
    }
}

2480
static int decode_interrupt_cb(void *ctx)
2481
{
2482 2483
    VideoState *is = ctx;
    return is->abort_request;
2484
}
Fabrice Bellard's avatar
Fabrice Bellard committed
2485

2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501
static int is_realtime(AVFormatContext *s)
{
    if(   !strcmp(s->iformat->name, "rtp")
       || !strcmp(s->iformat->name, "rtsp")
       || !strcmp(s->iformat->name, "sdp")
    )
        return 1;

    if(s->pb && (   !strncmp(s->filename, "rtp:", 4)
                 || !strncmp(s->filename, "udp:", 4)
                )
    )
        return 1;
    return 0;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
2502
/* this thread gets the stream from the disk or the network */
2503
static int read_thread(void *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
2504 2505
{
    VideoState *is = arg;
2506
    AVFormatContext *ic = NULL;
2507
    int err, i, ret;
2508
    int st_index[AVMEDIA_TYPE_NB];
Fabrice Bellard's avatar
Fabrice Bellard committed
2509
    AVPacket pkt1, *pkt = &pkt1;
Aneesh Dogra's avatar
Aneesh Dogra committed
2510
    int eof = 0;
2511
    int pkt_in_play_range = 0;
2512
    AVDictionaryEntry *t;
2513 2514
    AVDictionary **opts;
    int orig_nb_streams;
2515
    SDL_mutex *wait_mutex = SDL_CreateMutex();
2516

2517
    memset(st_index, -1, sizeof(st_index));
2518 2519 2520
    is->last_video_stream = is->video_stream = -1;
    is->last_audio_stream = is->audio_stream = -1;
    is->last_subtitle_stream = is->subtitle_stream = -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2521

2522 2523
    ic = avformat_alloc_context();
    ic->interrupt_callback.callback = decode_interrupt_cb;
2524
    ic->interrupt_callback.opaque = is;
2525
    err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts);
2526 2527 2528 2529 2530
    if (err < 0) {
        print_error(is->filename, err);
        ret = -1;
        goto fail;
    }
2531 2532 2533 2534 2535
    if ((t = av_dict_get(format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
        av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
        ret = AVERROR_OPTION_NOT_FOUND;
        goto fail;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2536
    is->ic = ic;
2537

Aneesh Dogra's avatar
Aneesh Dogra committed
2538
    if (genpts)
2539 2540
        ic->flags |= AVFMT_FLAG_GENPTS;

2541
    opts = setup_find_stream_info_opts(ic, codec_opts);
2542
    orig_nb_streams = ic->nb_streams;
2543

2544
    err = avformat_find_stream_info(ic, opts);
2545 2546 2547 2548 2549
    if (err < 0) {
        fprintf(stderr, "%s: could not find codec parameters\n", is->filename);
        ret = -1;
        goto fail;
    }
2550 2551 2552 2553
    for (i = 0; i < orig_nb_streams; i++)
        av_dict_free(&opts[i]);
    av_freep(&opts);

Aneesh Dogra's avatar
Aneesh Dogra committed
2554
    if (ic->pb)
2555
        ic->pb->eof_reached = 0; // FIXME hack, ffplay maybe should not use url_feof() to test for the end
Fabrice Bellard's avatar
Fabrice Bellard committed
2556

Aneesh Dogra's avatar
Aneesh Dogra committed
2557 2558
    if (seek_by_bytes < 0)
        seek_by_bytes = !!(ic->iformat->flags & AVFMT_TS_DISCONT);
2559

Fabrice Bellard's avatar
Fabrice Bellard committed
2560 2561 2562 2563 2564 2565 2566 2567
    /* if seeking requested, we execute it */
    if (start_time != AV_NOPTS_VALUE) {
        int64_t timestamp;

        timestamp = start_time;
        /* add the stream start time */
        if (ic->start_time != AV_NOPTS_VALUE)
            timestamp += ic->start_time;
2568
        ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2569
        if (ret < 0) {
2570
            fprintf(stderr, "%s: could not seek to position %0.3f\n",
Fabrice Bellard's avatar
Fabrice Bellard committed
2571 2572 2573 2574
                    is->filename, (double)timestamp / AV_TIME_BASE);
        }
    }

2575 2576
    is->realtime = is_realtime(ic);

2577
    for (i = 0; i < ic->nb_streams; i++)
2578
        ic->streams[i]->discard = AVDISCARD_ALL;
2579
    if (!video_disable)
2580 2581 2582
        st_index[AVMEDIA_TYPE_VIDEO] =
            av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,
                                wanted_stream[AVMEDIA_TYPE_VIDEO], -1, NULL, 0);
2583
    if (!audio_disable)
2584 2585 2586 2587 2588
        st_index[AVMEDIA_TYPE_AUDIO] =
            av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO,
                                wanted_stream[AVMEDIA_TYPE_AUDIO],
                                st_index[AVMEDIA_TYPE_VIDEO],
                                NULL, 0);
2589
    if (!video_disable)
2590 2591 2592 2593 2594 2595 2596
        st_index[AVMEDIA_TYPE_SUBTITLE] =
            av_find_best_stream(ic, AVMEDIA_TYPE_SUBTITLE,
                                wanted_stream[AVMEDIA_TYPE_SUBTITLE],
                                (st_index[AVMEDIA_TYPE_AUDIO] >= 0 ?
                                 st_index[AVMEDIA_TYPE_AUDIO] :
                                 st_index[AVMEDIA_TYPE_VIDEO]),
                                NULL, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2597
    if (show_status) {
2598
        av_dump_format(ic, 0, is->filename, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2599 2600
    }

2601 2602
    is->show_mode = show_mode;

Fabrice Bellard's avatar
Fabrice Bellard committed
2603
    /* open the streams */
2604 2605
    if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {
        stream_component_open(is, st_index[AVMEDIA_TYPE_AUDIO]);
Fabrice Bellard's avatar
Fabrice Bellard committed
2606 2607
    }

Aneesh Dogra's avatar
Aneesh Dogra committed
2608
    ret = -1;
2609
    if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
Aneesh Dogra's avatar
Aneesh Dogra committed
2610
        ret = stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO]);
Michael Niedermayer's avatar
Michael Niedermayer committed
2611
    }
2612
    is->refresh_tid = SDL_CreateThread(refresh_thread, is);
2613 2614
    if (is->show_mode == SHOW_MODE_NONE)
        is->show_mode = ret >= 0 ? SHOW_MODE_VIDEO : SHOW_MODE_RDFT;
Fabrice Bellard's avatar
Fabrice Bellard committed
2615

2616 2617
    if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) {
        stream_component_open(is, st_index[AVMEDIA_TYPE_SUBTITLE]);
2618 2619
    }

Fabrice Bellard's avatar
Fabrice Bellard committed
2620
    if (is->video_stream < 0 && is->audio_stream < 0) {
2621 2622
        fprintf(stderr, "%s: could not open codecs\n", is->filename);
        ret = -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2623 2624 2625
        goto fail;
    }

2626
    if (infinite_buffer < 0 && is->realtime)
2627 2628
        infinite_buffer = 1;

Aneesh Dogra's avatar
Aneesh Dogra committed
2629
    for (;;) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2630 2631
        if (is->abort_request)
            break;
2632 2633
        if (is->paused != is->last_paused) {
            is->last_paused = is->paused;
Fabrice Bellard's avatar
Fabrice Bellard committed
2634
            if (is->paused)
Aneesh Dogra's avatar
Aneesh Dogra committed
2635
                is->read_pause_return = av_read_pause(ic);
Fabrice Bellard's avatar
Fabrice Bellard committed
2636 2637
            else
                av_read_play(ic);
2638
        }
2639 2640 2641
#if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL
        if (is->paused &&
                (!strcmp(ic->iformat->name, "rtsp") ||
2642
                 (ic->pb && !strncmp(input_filename, "mmsh:", 5)))) {
2643 2644 2645 2646 2647
            /* wait 10 ms to avoid trying to get another packet */
            /* XXX: horrible */
            SDL_Delay(10);
            continue;
        }
2648
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
2649
        if (is->seek_req) {
Aneesh Dogra's avatar
Aneesh Dogra committed
2650 2651 2652 2653
            int64_t seek_target = is->seek_pos;
            int64_t seek_min    = is->seek_rel > 0 ? seek_target - is->seek_rel + 2: INT64_MIN;
            int64_t seek_max    = is->seek_rel < 0 ? seek_target - is->seek_rel - 2: INT64_MAX;
// FIXME the +-2 is due to rounding being not done in the correct direction in generation
2654
//      of the seek_pos/seek_rel variables
2655

2656
            ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags);
Fabrice Bellard's avatar
Fabrice Bellard committed
2657 2658
            if (ret < 0) {
                fprintf(stderr, "%s: error while seeking\n", is->ic->filename);
Aneesh Dogra's avatar
Aneesh Dogra committed
2659
            } else {
2660 2661
                if (is->audio_stream >= 0) {
                    packet_queue_flush(&is->audioq);
2662
                    packet_queue_put(&is->audioq, &flush_pkt);
2663
                }
2664 2665
                if (is->subtitle_stream >= 0) {
                    packet_queue_flush(&is->subtitleq);
2666
                    packet_queue_put(&is->subtitleq, &flush_pkt);
2667
                }
2668 2669
                if (is->video_stream >= 0) {
                    packet_queue_flush(&is->videoq);
2670
                    packet_queue_put(&is->videoq, &flush_pkt);
2671
                }
Fabrice Bellard's avatar
Fabrice Bellard committed
2672
            }
2673
            update_external_clock_pts(is, (seek_target + ic->start_time) / (double)AV_TIME_BASE);
Fabrice Bellard's avatar
Fabrice Bellard committed
2674
            is->seek_req = 0;
Aneesh Dogra's avatar
Aneesh Dogra committed
2675
            eof = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2676
        }
2677 2678 2679 2680
        if (is->que_attachments_req) {
            avformat_queue_attached_pictures(ic);
            is->que_attachments_req = 0;
        }
2681

Fabrice Bellard's avatar
Fabrice Bellard committed
2682
        /* if the queue are full, no need to read more */
2683
        if (infinite_buffer<1 &&
2684
              (is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
2685 2686
            || (   (is->audioq   .nb_packets > MIN_FRAMES || is->audio_stream < 0 || is->audioq.abort_request)
                && (is->videoq   .nb_packets > MIN_FRAMES || is->video_stream < 0 || is->videoq.abort_request)
2687
                && (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0 || is->subtitleq.abort_request)))) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2688
            /* wait 10 ms */
2689 2690 2691
            SDL_LockMutex(wait_mutex);
            SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
            SDL_UnlockMutex(wait_mutex);
Fabrice Bellard's avatar
Fabrice Bellard committed
2692 2693
            continue;
        }
Aneesh Dogra's avatar
Aneesh Dogra committed
2694 2695
        if (eof) {
            if (is->video_stream >= 0) {
Michael Niedermayer's avatar
Michael Niedermayer committed
2696
                av_init_packet(pkt);
Aneesh Dogra's avatar
Aneesh Dogra committed
2697 2698 2699
                pkt->data = NULL;
                pkt->size = 0;
                pkt->stream_index = is->video_stream;
Michael Niedermayer's avatar
Michael Niedermayer committed
2700
                packet_queue_put(&is->videoq, pkt);
2701
            }
2702 2703 2704 2705 2706 2707 2708
            if (is->audio_stream >= 0 &&
                is->audio_st->codec->codec->capabilities & CODEC_CAP_DELAY) {
                av_init_packet(pkt);
                pkt->data = NULL;
                pkt->size = 0;
                pkt->stream_index = is->audio_stream;
                packet_queue_put(&is->audioq, pkt);
2709
            }
2710
            SDL_Delay(10);
Aneesh Dogra's avatar
Aneesh Dogra committed
2711 2712
            if (is->audioq.size + is->videoq.size + is->subtitleq.size == 0) {
                if (loop != 1 && (!loop || --loop)) {
2713
                    stream_seek(is, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0);
Aneesh Dogra's avatar
Aneesh Dogra committed
2714 2715
                } else if (autoexit) {
                    ret = AVERROR_EOF;
2716 2717
                    goto fail;
                }
Michael Niedermayer's avatar
Michael Niedermayer committed
2718
            }
2719
            eof=0;
2720 2721
            continue;
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
2722
        ret = av_read_frame(ic, pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
2723
        if (ret < 0) {
2724
            if (ret == AVERROR_EOF || url_feof(ic->pb))
Aneesh Dogra's avatar
Aneesh Dogra committed
2725
                eof = 1;
2726
            if (ic->pb && ic->pb->error)
2727
                break;
2728 2729 2730
            SDL_LockMutex(wait_mutex);
            SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
            SDL_UnlockMutex(wait_mutex);
2731
            continue;
Fabrice Bellard's avatar
Fabrice Bellard committed
2732
        }
2733 2734 2735 2736
        /* check if packet is in play range specified by user, then queue, otherwise discard */
        pkt_in_play_range = duration == AV_NOPTS_VALUE ||
                (pkt->pts - ic->streams[pkt->stream_index]->start_time) *
                av_q2d(ic->streams[pkt->stream_index]->time_base) -
Aneesh Dogra's avatar
Aneesh Dogra committed
2737 2738
                (double)(start_time != AV_NOPTS_VALUE ? start_time : 0) / 1000000
                <= ((double)duration / 1000000);
2739
        if (pkt->stream_index == is->audio_stream && pkt_in_play_range) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2740
            packet_queue_put(&is->audioq, pkt);
2741
        } else if (pkt->stream_index == is->video_stream && pkt_in_play_range) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2742
            packet_queue_put(&is->videoq, pkt);
2743
        } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {
2744
            packet_queue_put(&is->subtitleq, pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
2745 2746 2747 2748 2749 2750 2751 2752 2753
        } else {
            av_free_packet(pkt);
        }
    }
    /* wait until the end */
    while (!is->abort_request) {
        SDL_Delay(100);
    }

2754
    ret = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2755 2756 2757 2758 2759 2760
 fail:
    /* close each stream */
    if (is->audio_stream >= 0)
        stream_component_close(is, is->audio_stream);
    if (is->video_stream >= 0)
        stream_component_close(is, is->video_stream);
2761 2762
    if (is->subtitle_stream >= 0)
        stream_component_close(is, is->subtitle_stream);
2763
    if (is->ic) {
2764
        avformat_close_input(&is->ic);
2765
    }
2766

2767 2768
    if (ret != 0) {
        SDL_Event event;
2769

2770 2771 2772 2773
        event.type = FF_QUIT_EVENT;
        event.user.data1 = is;
        SDL_PushEvent(&event);
    }
2774
    SDL_DestroyMutex(wait_mutex);
Fabrice Bellard's avatar
Fabrice Bellard committed
2775 2776 2777
    return 0;
}

2778
static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
Fabrice Bellard's avatar
Fabrice Bellard committed
2779 2780 2781 2782 2783 2784
{
    VideoState *is;

    is = av_mallocz(sizeof(VideoState));
    if (!is)
        return NULL;
2785
    av_strlcpy(is->filename, filename, sizeof(is->filename));
2786
    is->iformat = iformat;
Aneesh Dogra's avatar
Aneesh Dogra committed
2787 2788
    is->ytop    = 0;
    is->xleft   = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2789 2790 2791

    /* start video display */
    is->pictq_mutex = SDL_CreateMutex();
Aneesh Dogra's avatar
Aneesh Dogra committed
2792
    is->pictq_cond  = SDL_CreateCond();
2793

2794
    is->subpq_mutex = SDL_CreateMutex();
Aneesh Dogra's avatar
Aneesh Dogra committed
2795
    is->subpq_cond  = SDL_CreateCond();
2796

2797 2798 2799 2800
    packet_queue_init(&is->videoq);
    packet_queue_init(&is->audioq);
    packet_queue_init(&is->subtitleq);

2801 2802
    is->continue_read_thread = SDL_CreateCond();

2803
    update_external_clock_pts(is, 0.0);
2804
    update_external_clock_speed(is, 1.0);
2805 2806
    is->audio_current_pts_drift = -av_gettime() / 1000000.0;
    is->video_current_pts_drift = is->audio_current_pts_drift;
2807
    is->av_sync_type = av_sync_type;
2808
    is->read_tid     = SDL_CreateThread(read_thread, is);
2809
    if (!is->read_tid) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2810 2811 2812 2813 2814 2815
        av_free(is);
        return NULL;
    }
    return is;
}

2816
static void stream_cycle_channel(VideoState *is, int codec_type)
2817 2818 2819
{
    AVFormatContext *ic = is->ic;
    int start_index, stream_index;
2820
    int old_index;
2821 2822
    AVStream *st;

2823 2824 2825 2826 2827 2828 2829 2830 2831 2832
    if (codec_type == AVMEDIA_TYPE_VIDEO) {
        start_index = is->last_video_stream;
        old_index = is->video_stream;
    } else if (codec_type == AVMEDIA_TYPE_AUDIO) {
        start_index = is->last_audio_stream;
        old_index = is->audio_stream;
    } else {
        start_index = is->last_subtitle_stream;
        old_index = is->subtitle_stream;
    }
2833
    stream_index = start_index;
Aneesh Dogra's avatar
Aneesh Dogra committed
2834
    for (;;) {
2835
        if (++stream_index >= is->ic->nb_streams)
2836
        {
2837
            if (codec_type == AVMEDIA_TYPE_SUBTITLE)
2838 2839
            {
                stream_index = -1;
2840
                is->last_subtitle_stream = -1;
2841
                goto the_end;
2842 2843 2844 2845
            }
            if (start_index == -1)
                return;
            stream_index = 0;
2846
        }
2847 2848 2849
        if (stream_index == start_index)
            return;
        st = ic->streams[stream_index];
2850
        if (st->codec->codec_type == codec_type) {
2851
            /* check that parameters are OK */
Aneesh Dogra's avatar
Aneesh Dogra committed
2852
            switch (codec_type) {
2853
            case AVMEDIA_TYPE_AUDIO:
2854 2855
                if (st->codec->sample_rate != 0 &&
                    st->codec->channels != 0)
2856 2857
                    goto the_end;
                break;
2858 2859
            case AVMEDIA_TYPE_VIDEO:
            case AVMEDIA_TYPE_SUBTITLE:
2860 2861 2862 2863 2864 2865 2866
                goto the_end;
            default:
                break;
            }
        }
    }
 the_end:
2867
    stream_component_close(is, old_index);
2868
    stream_component_open(is, stream_index);
2869 2870
    if (codec_type == AVMEDIA_TYPE_VIDEO)
        is->que_attachments_req = 1;
2871 2872 2873
}


2874
static void toggle_full_screen(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
2875
{
2876
#if defined(__APPLE__) && SDL_VERSION_ATLEAST(1, 2, 14)
2877
    /* OS X needs to reallocate the SDL overlays */
2878 2879
    int i;
    for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++)
2880 2881
        is->pictq[i].reallocate = 1;
#endif
2882
    is_full_screen = !is_full_screen;
2883
    video_open(is, 1);
Fabrice Bellard's avatar
Fabrice Bellard committed
2884 2885
}

2886
static void toggle_pause(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
2887
{
2888 2889
    stream_toggle_pause(is);
    is->step = 0;
2890 2891
}

2892
static void step_to_next_frame(VideoState *is)
2893
{
2894 2895 2896 2897
    /* if the stream is paused unpause it, then step */
    if (is->paused)
        stream_toggle_pause(is);
    is->step = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2898 2899
}

2900
static void toggle_audio_display(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
2901
{
2902 2903 2904 2905
    int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
    is->show_mode = (is->show_mode + 1) % SHOW_MODE_NB;
    fill_rectangle(screen,
                is->xleft, is->ytop, is->width, is->height,
2906
                bgcolor, 1);
Fabrice Bellard's avatar
Fabrice Bellard committed
2907 2908 2909
}

/* handle an event sent by the GUI */
2910
static void event_loop(VideoState *cur_stream)
Fabrice Bellard's avatar
Fabrice Bellard committed
2911 2912
{
    SDL_Event event;
2913
    double incr, pos, frac;
Fabrice Bellard's avatar
Fabrice Bellard committed
2914

Aneesh Dogra's avatar
Aneesh Dogra committed
2915
    for (;;) {
Michael Niedermayer's avatar
Michael Niedermayer committed
2916
        double x;
Fabrice Bellard's avatar
Fabrice Bellard committed
2917
        SDL_WaitEvent(&event);
Aneesh Dogra's avatar
Aneesh Dogra committed
2918
        switch (event.type) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2919
        case SDL_KEYDOWN:
2920
            if (exit_on_keydown) {
2921
                do_exit(cur_stream);
2922 2923
                break;
            }
Aneesh Dogra's avatar
Aneesh Dogra committed
2924
            switch (event.key.keysym.sym) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2925 2926
            case SDLK_ESCAPE:
            case SDLK_q:
2927
                do_exit(cur_stream);
Fabrice Bellard's avatar
Fabrice Bellard committed
2928 2929
                break;
            case SDLK_f:
2930
                toggle_full_screen(cur_stream);
2931
                cur_stream->force_refresh = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2932 2933 2934
                break;
            case SDLK_p:
            case SDLK_SPACE:
2935
                toggle_pause(cur_stream);
Fabrice Bellard's avatar
Fabrice Bellard committed
2936
                break;
Aneesh Dogra's avatar
Aneesh Dogra committed
2937
            case SDLK_s: // S: Step to next frame
2938
                step_to_next_frame(cur_stream);
2939
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2940
            case SDLK_a:
2941
                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
2942 2943
                break;
            case SDLK_v:
2944
                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
2945
                break;
2946
            case SDLK_t:
2947
                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
2948
                break;
2949
            case SDLK_w:
2950
                toggle_audio_display(cur_stream);
2951
                cur_stream->force_refresh = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2952
                break;
2953 2954 2955 2956 2957 2958
            case SDLK_PAGEUP:
                incr = 600.0;
                goto do_seek;
            case SDLK_PAGEDOWN:
                incr = -600.0;
                goto do_seek;
Fabrice Bellard's avatar
Fabrice Bellard committed
2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970
            case SDLK_LEFT:
                incr = -10.0;
                goto do_seek;
            case SDLK_RIGHT:
                incr = 10.0;
                goto do_seek;
            case SDLK_UP:
                incr = 60.0;
                goto do_seek;
            case SDLK_DOWN:
                incr = -60.0;
            do_seek:
2971
                    if (seek_by_bytes) {
Aneesh Dogra's avatar
Aneesh Dogra committed
2972 2973 2974 2975 2976
                        if (cur_stream->video_stream >= 0 && cur_stream->video_current_pos >= 0) {
                            pos = cur_stream->video_current_pos;
                        } else if (cur_stream->audio_stream >= 0 && cur_stream->audio_pkt.pos >= 0) {
                            pos = cur_stream->audio_pkt.pos;
                        } else
2977
                            pos = avio_tell(cur_stream->ic->pb);
2978
                        if (cur_stream->ic->bit_rate)
2979
                            incr *= cur_stream->ic->bit_rate / 8.0;
2980 2981 2982
                        else
                            incr *= 180000.0;
                        pos += incr;
2983
                        stream_seek(cur_stream, pos, incr, 1);
2984 2985 2986
                    } else {
                        pos = get_master_clock(cur_stream);
                        pos += incr;
2987
                        stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0);
2988
                    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2989
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2990 2991 2992 2993
            default:
                break;
            }
            break;
2994 2995 2996
        case SDL_VIDEOEXPOSE:
            cur_stream->force_refresh = 1;
            break;
2997
        case SDL_MOUSEBUTTONDOWN:
2998
            if (exit_on_mousedown) {
2999
                do_exit(cur_stream);
3000 3001
                break;
            }
Michael Niedermayer's avatar
Michael Niedermayer committed
3002
        case SDL_MOUSEMOTION:
Aneesh Dogra's avatar
Aneesh Dogra committed
3003 3004 3005 3006
            if (event.type == SDL_MOUSEBUTTONDOWN) {
                x = event.button.x;
            } else {
                if (event.motion.state != SDL_PRESSED)
Michael Niedermayer's avatar
Michael Niedermayer committed
3007
                    break;
Aneesh Dogra's avatar
Aneesh Dogra committed
3008
                x = event.motion.x;
3009
            }
Aneesh Dogra's avatar
Aneesh Dogra committed
3010 3011
                if (seek_by_bytes || cur_stream->ic->duration <= 0) {
                    uint64_t size =  avio_size(cur_stream->ic->pb);
Michael Niedermayer's avatar
Michael Niedermayer committed
3012
                    stream_seek(cur_stream, size*x/cur_stream->width, 0, 1);
Aneesh Dogra's avatar
Aneesh Dogra committed
3013
                } else {
Michael Niedermayer's avatar
Michael Niedermayer committed
3014 3015 3016
                    int64_t ts;
                    int ns, hh, mm, ss;
                    int tns, thh, tmm, tss;
Aneesh Dogra's avatar
Aneesh Dogra committed
3017 3018 3019 3020 3021 3022 3023 3024 3025
                    tns  = cur_stream->ic->duration / 1000000LL;
                    thh  = tns / 3600;
                    tmm  = (tns % 3600) / 60;
                    tss  = (tns % 60);
                    frac = x / cur_stream->width;
                    ns   = frac * tns;
                    hh   = ns / 3600;
                    mm   = (ns % 3600) / 60;
                    ss   = (ns % 60);
Michael Niedermayer's avatar
Michael Niedermayer committed
3026 3027
                    fprintf(stderr, "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d)       \n", frac*100,
                            hh, mm, ss, thh, tmm, tss);
Aneesh Dogra's avatar
Aneesh Dogra committed
3028
                    ts = frac * cur_stream->ic->duration;
Michael Niedermayer's avatar
Michael Niedermayer committed
3029 3030 3031
                    if (cur_stream->ic->start_time != AV_NOPTS_VALUE)
                        ts += cur_stream->ic->start_time;
                    stream_seek(cur_stream, ts, 0, 0);
3032
                }
3033
            break;
Fabrice Bellard's avatar
Fabrice Bellard committed
3034
        case SDL_VIDEORESIZE:
3035
                screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 0,
Fabrice Bellard's avatar
Fabrice Bellard committed
3036
                                          SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
Aneesh Dogra's avatar
Aneesh Dogra committed
3037 3038
                screen_width  = cur_stream->width  = event.resize.w;
                screen_height = cur_stream->height = event.resize.h;
3039
                cur_stream->force_refresh = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
3040 3041
            break;
        case SDL_QUIT:
3042
        case FF_QUIT_EVENT:
3043
            do_exit(cur_stream);
Fabrice Bellard's avatar
Fabrice Bellard committed
3044 3045 3046 3047 3048
            break;
        case FF_ALLOC_EVENT:
            alloc_picture(event.user.data1);
            break;
        case FF_REFRESH_EVENT:
3049
            video_refresh(event.user.data1);
Aneesh Dogra's avatar
Aneesh Dogra committed
3050
            cur_stream->refresh = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
3051 3052 3053 3054 3055 3056 3057
            break;
        default:
            break;
        }
    }
}

3058
static int opt_frame_size(void *optctx, const char *opt, const char *arg)
3059
{
3060
    av_log(NULL, AV_LOG_WARNING, "Option -s is deprecated, use -video_size.\n");
3061
    return opt_default(NULL, "video_size", arg);
3062 3063
}

3064
static int opt_width(void *optctx, const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
3065
{
3066 3067
    screen_width = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
3068 3069
}

3070
static int opt_height(void *optctx, const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
3071
{
3072 3073
    screen_height = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
3074 3075
}

3076
static int opt_format(void *optctx, const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
3077 3078 3079 3080
{
    file_iformat = av_find_input_format(arg);
    if (!file_iformat) {
        fprintf(stderr, "Unknown input format: %s\n", arg);
3081
        return AVERROR(EINVAL);
Fabrice Bellard's avatar
Fabrice Bellard committed
3082
    }
3083
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
3084
}
3085

3086
static int opt_frame_pix_fmt(void *optctx, const char *opt, const char *arg)
3087
{
3088
    av_log(NULL, AV_LOG_WARNING, "Option -pix_fmt is deprecated, use -pixel_format.\n");
3089
    return opt_default(NULL, "pixel_format", arg);
3090 3091
}

3092
static int opt_sync(void *optctx, const char *opt, const char *arg)
3093 3094 3095 3096 3097 3098 3099
{
    if (!strcmp(arg, "audio"))
        av_sync_type = AV_SYNC_AUDIO_MASTER;
    else if (!strcmp(arg, "video"))
        av_sync_type = AV_SYNC_VIDEO_MASTER;
    else if (!strcmp(arg, "ext"))
        av_sync_type = AV_SYNC_EXTERNAL_CLOCK;
3100
    else {
3101
        fprintf(stderr, "Unknown value for %s: %s\n", opt, arg);
3102 3103
        exit(1);
    }
3104
    return 0;
3105 3106
}

3107
static int opt_seek(void *optctx, const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
3108
{
3109 3110
    start_time = parse_time_or_die(opt, arg, 1);
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
3111 3112
}

3113
static int opt_duration(void *optctx, const char *opt, const char *arg)
3114 3115 3116 3117 3118
{
    duration = parse_time_or_die(opt, arg, 1);
    return 0;
}

3119
static int opt_show_mode(void *optctx, const char *opt, const char *arg)
3120 3121 3122 3123 3124 3125 3126 3127
{
    show_mode = !strcmp(arg, "video") ? SHOW_MODE_VIDEO :
                !strcmp(arg, "waves") ? SHOW_MODE_WAVES :
                !strcmp(arg, "rdft" ) ? SHOW_MODE_RDFT  :
                parse_number_or_die(opt, arg, OPT_INT, 0, SHOW_MODE_NB-1);
    return 0;
}

3128
static void opt_input_file(void *optctx, const char *filename)
3129 3130 3131 3132
{
    if (input_filename) {
        fprintf(stderr, "Argument '%s' provided as input filename, but '%s' was already specified.\n",
                filename, input_filename);
3133
        exit(1);
3134 3135 3136 3137 3138 3139
    }
    if (!strcmp(filename, "-"))
        filename = "pipe:";
    input_filename = filename;
}

3140 3141 3142 3143 3144 3145 3146 3147 3148 3149
static int opt_codec(void *o, const char *opt, const char *arg)
{
    switch(opt[strlen(opt)-1]){
    case 'a' :    audio_codec_name = arg; break;
    case 's' : subtitle_codec_name = arg; break;
    case 'v' :    video_codec_name = arg; break;
    }
    return 0;
}

3150 3151
static int dummy;

3152
static const OptionDef options[] = {
3153
#include "cmdutils_common_opts.h"
3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187
    { "x", HAS_ARG, { .func_arg = opt_width }, "force displayed width", "width" },
    { "y", HAS_ARG, { .func_arg = opt_height }, "force displayed height", "height" },
    { "s", HAS_ARG | OPT_VIDEO, { .func_arg = opt_frame_size }, "set frame size (WxH or abbreviation)", "size" },
    { "fs", OPT_BOOL, { &is_full_screen }, "force full screen" },
    { "an", OPT_BOOL, { &audio_disable }, "disable audio" },
    { "vn", OPT_BOOL, { &video_disable }, "disable video" },
    { "ast", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_AUDIO] }, "select desired audio stream", "stream_number" },
    { "vst", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_VIDEO] }, "select desired video stream", "stream_number" },
    { "sst", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_SUBTITLE] }, "select desired subtitle stream", "stream_number" },
    { "ss", HAS_ARG, { .func_arg = opt_seek }, "seek to a given position in seconds", "pos" },
    { "t", HAS_ARG, { .func_arg = opt_duration }, "play  \"duration\" seconds of audio/video", "duration" },
    { "bytes", OPT_INT | HAS_ARG, { &seek_by_bytes }, "seek by bytes 0=off 1=on -1=auto", "val" },
    { "nodisp", OPT_BOOL, { &display_disable }, "disable graphical display" },
    { "f", HAS_ARG, { .func_arg = opt_format }, "force format", "fmt" },
    { "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_frame_pix_fmt }, "set pixel format", "format" },
    { "stats", OPT_BOOL | OPT_EXPERT, { &show_status }, "show status", "" },
    { "bug", OPT_INT | HAS_ARG | OPT_EXPERT, { &workaround_bugs }, "workaround bugs", "" },
    { "fast", OPT_BOOL | OPT_EXPERT, { &fast }, "non spec compliant optimizations", "" },
    { "genpts", OPT_BOOL | OPT_EXPERT, { &genpts }, "generate pts", "" },
    { "drp", OPT_INT | HAS_ARG | OPT_EXPERT, { &decoder_reorder_pts }, "let decoder reorder pts 0=off 1=on -1=auto", ""},
    { "lowres", OPT_INT | HAS_ARG | OPT_EXPERT, { &lowres }, "", "" },
    { "skiploop", OPT_INT | HAS_ARG | OPT_EXPERT, { &skip_loop_filter }, "", "" },
    { "skipframe", OPT_INT | HAS_ARG | OPT_EXPERT, { &skip_frame }, "", "" },
    { "skipidct", OPT_INT | HAS_ARG | OPT_EXPERT, { &skip_idct }, "", "" },
    { "idct", OPT_INT | HAS_ARG | OPT_EXPERT, { &idct }, "set idct algo",  "algo" },
    { "ec", OPT_INT | HAS_ARG | OPT_EXPERT, { &error_concealment }, "set error concealment options",  "bit_mask" },
    { "sync", HAS_ARG | OPT_EXPERT, { .func_arg = opt_sync }, "set audio-video sync. type (type=audio/video/ext)", "type" },
    { "autoexit", OPT_BOOL | OPT_EXPERT, { &autoexit }, "exit at the end", "" },
    { "exitonkeydown", OPT_BOOL | OPT_EXPERT, { &exit_on_keydown }, "exit on key down", "" },
    { "exitonmousedown", OPT_BOOL | OPT_EXPERT, { &exit_on_mousedown }, "exit on mouse down", "" },
    { "loop", OPT_INT | HAS_ARG | OPT_EXPERT, { &loop }, "set number of times the playback shall be looped", "loop count" },
    { "framedrop", OPT_BOOL | OPT_EXPERT, { &framedrop }, "drop frames when cpu is too slow", "" },
    { "infbuf", OPT_BOOL | OPT_EXPERT, { &infinite_buffer }, "don't limit the input buffer size (useful with realtime streams)", "" },
    { "window_title", OPT_STRING | HAS_ARG, { &window_title }, "set window title", "window title" },
3188
#if CONFIG_AVFILTER
3189
    { "vf", OPT_STRING | HAS_ARG, { &vfilters }, "video filters", "filter list" },
3190
#endif
3191 3192 3193 3194
    { "rdftspeed", OPT_INT | HAS_ARG| OPT_AUDIO | OPT_EXPERT, { &rdftspeed }, "rdft speed", "msecs" },
    { "showmode", HAS_ARG, { .func_arg = opt_show_mode}, "select show mode (0 = video, 1 = waves, 2 = RDFT)", "mode" },
    { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { .func_arg = opt_default }, "generic catch all option", "" },
    { "i", OPT_BOOL, { &dummy}, "read specified file", "input_file"},
3195
    { "codec", HAS_ARG, { .func_arg = opt_codec}, "force decoder", "decoder" },
Fabrice Bellard's avatar
Fabrice Bellard committed
3196 3197 3198
    { NULL, },
};

3199
static void show_usage(void)
Fabrice Bellard's avatar
Fabrice Bellard committed
3200
{
3201 3202 3203
    av_log(NULL, AV_LOG_INFO, "Simple media player\n");
    av_log(NULL, AV_LOG_INFO, "usage: %s [options] input_file\n", program_name);
    av_log(NULL, AV_LOG_INFO, "\n");
3204 3205
}

3206
void show_help_default(const char *opt, const char *arg)
3207
{
3208
    av_log_set_callback(log_callback_help);
3209
    show_usage();
3210 3211
    show_help_options(options, "Main options:", 0, OPT_EXPERT, 0);
    show_help_options(options, "Advanced options:", OPT_EXPERT, 0, 0);
3212
    printf("\n");
3213 3214
    show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM);
    show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
3215
#if !CONFIG_AVFILTER
3216
    show_help_children(sws_get_class(), AV_OPT_FLAG_ENCODING_PARAM);
3217 3218
#else
    show_help_children(avfilter_get_class(), AV_OPT_FLAG_FILTERING_PARAM);
3219
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3220 3221 3222 3223
    printf("\nWhile playing:\n"
           "q, ESC              quit\n"
           "f                   toggle full screen\n"
           "p, SPC              pause\n"
3224 3225
           "a                   cycle audio channel\n"
           "v                   cycle video channel\n"
3226
           "t                   cycle subtitle channel\n"
3227
           "w                   show audio waves\n"
3228
           "s                   activate frame-step mode\n"
Fabrice Bellard's avatar
Fabrice Bellard committed
3229 3230
           "left/right          seek backward/forward 10 seconds\n"
           "down/up             seek backward/forward 1 minute\n"
3231
           "page down/page up   seek backward/forward 10 minutes\n"
3232
           "mouse click         seek to percentage in file corresponding to fraction of width\n"
Fabrice Bellard's avatar
Fabrice Bellard committed
3233 3234 3235
           );
}

3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254
static int lockmgr(void **mtx, enum AVLockOp op)
{
   switch(op) {
      case AV_LOCK_CREATE:
          *mtx = SDL_CreateMutex();
          if(!*mtx)
              return 1;
          return 0;
      case AV_LOCK_OBTAIN:
          return !!SDL_LockMutex(*mtx);
      case AV_LOCK_RELEASE:
          return !!SDL_UnlockMutex(*mtx);
      case AV_LOCK_DESTROY:
          SDL_DestroyMutex(*mtx);
          return 0;
   }
   return 1;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
3255 3256 3257
/* Called from the main */
int main(int argc, char **argv)
{
3258
    int flags;
3259
    VideoState *is;
3260
    char dummy_videodriver[] = "SDL_VIDEODRIVER=dummy";
3261

3262
    av_log_set_flags(AV_LOG_SKIP_REPEATED);
3263
    parse_loglevel(argc, argv, options);
3264

Fabrice Bellard's avatar
Fabrice Bellard committed
3265
    /* register all codecs, demux and protocols */
Luca Abeni's avatar
Luca Abeni committed
3266
    avcodec_register_all();
3267
#if CONFIG_AVDEVICE
Luca Abeni's avatar
Luca Abeni committed
3268
    avdevice_register_all();
3269
#endif
3270 3271 3272
#if CONFIG_AVFILTER
    avfilter_register_all();
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3273
    av_register_all();
3274
    avformat_network_init();
Fabrice Bellard's avatar
Fabrice Bellard committed
3275

3276
    init_opts();
3277

3278 3279 3280
    signal(SIGINT , sigterm_handler); /* Interrupt (ANSI).    */
    signal(SIGTERM, sigterm_handler); /* Termination (ANSI).  */

3281
    show_banner(argc, argv, options);
3282

3283
    parse_options(NULL, argc, argv, options, opt_input_file);
Fabrice Bellard's avatar
Fabrice Bellard committed
3284

3285
    if (!input_filename) {
3286
        show_usage();
3287
        fprintf(stderr, "An input file must be specified\n");
Anton Khirnov's avatar
Anton Khirnov committed
3288
        fprintf(stderr, "Use -h to get full help or, even better, run 'man %s'\n", program_name);
3289 3290
        exit(1);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
3291 3292 3293 3294

    if (display_disable) {
        video_disable = 1;
    }
3295
    flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
3296 3297
    if (audio_disable)
        flags &= ~SDL_INIT_AUDIO;
3298 3299
    if (display_disable)
        SDL_putenv(dummy_videodriver); /* For the event queue, we always need a video driver. */
3300 3301
#if !defined(__MINGW32__) && !defined(__APPLE__)
    flags |= SDL_INIT_EVENTTHREAD; /* Not supported on Windows or Mac OS X */
3302
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3303
    if (SDL_Init (flags)) {
3304
        fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
3305
        fprintf(stderr, "(Did you set the DISPLAY variable?)\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
3306 3307 3308 3309
        exit(1);
    }

    if (!display_disable) {
3310
#if HAVE_SDL_VIDEO_SIZE
3311 3312 3313
        const SDL_VideoInfo *vi = SDL_GetVideoInfo();
        fs_screen_width = vi->current_w;
        fs_screen_height = vi->current_h;
3314
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3315 3316 3317 3318 3319 3320
    }

    SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
    SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
    SDL_EventState(SDL_USEREVENT, SDL_IGNORE);

3321 3322 3323 3324 3325
    if (av_lockmgr_register(lockmgr)) {
        fprintf(stderr, "Could not initialize lock manager!\n");
        do_exit(NULL);
    }

3326
    av_init_packet(&flush_pkt);
3327
    flush_pkt.data = (char *)(intptr_t)"FLUSH";
3328

3329 3330 3331 3332 3333
    is = stream_open(input_filename, file_iformat);
    if (!is) {
        fprintf(stderr, "Failed to initialize VideoState!\n");
        do_exit(NULL);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
3334

3335
    event_loop(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
3336 3337 3338 3339 3340

    /* never returns */

    return 0;
}