ffplay.c 121 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
# include "libavfilter/avfilter.h"
51
# include "libavfilter/buffersink.h"
52
# include "libavfilter/buffersrc.h"
53 54
#endif

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

58
#include "cmdutils.h"
59

60 61
#include <assert.h>

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

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

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

/* no AV sync correction is done if below the AV sync threshold */
73
#define AV_SYNC_THRESHOLD 0.01
74 75 76 77 78 79
/* 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

80 81 82 83 84
/* 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

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

88 89 90
/* polls for possible required screen refresh at least this often, should be less than 1/fps */
#define REFRESH_RATE 0.01

Fabrice Bellard's avatar
Fabrice Bellard committed
91
/* NOTE: the size must be big enough to compensate the hardware audio buffersize size */
92 93
/* 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
94

95 96
#define CURSOR_HIDE_DELAY 1000000

97
static int64_t sws_flags = SWS_BICUBIC;
98

99 100 101 102 103 104
typedef struct MyAVPacketList {
    AVPacket pkt;
    struct MyAVPacketList *next;
    int serial;
} MyAVPacketList;

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

115
#define VIDEO_PICTURE_QUEUE_SIZE 4
116
#define SUBPICTURE_QUEUE_SIZE 4
Fabrice Bellard's avatar
Fabrice Bellard committed
117 118

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

127
    AVRational sar;
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
typedef struct AudioParams {
    int freq;
    int channels;
138
    int64_t channel_layout;
139 140 141
    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
    AVInputFormat *iformat;
Fabrice Bellard's avatar
Fabrice Bellard committed
152 153
    int no_background;
    int abort_request;
154
    int force_refresh;
Fabrice Bellard's avatar
Fabrice Bellard committed
155
    int paused;
156
    int last_paused;
157
    int queue_attachments_req;
Fabrice Bellard's avatar
Fabrice Bellard committed
158
    int seek_req;
159
    int seek_flags;
Fabrice Bellard's avatar
Fabrice Bellard committed
160
    int64_t seek_pos;
161
    int64_t seek_rel;
162
    int read_pause_return;
Fabrice Bellard's avatar
Fabrice Bellard committed
163
    AVFormatContext *ic;
164
    int realtime;
Fabrice Bellard's avatar
Fabrice Bellard committed
165 166

    int audio_stream;
167

Fabrice Bellard's avatar
Fabrice Bellard committed
168
    int av_sync_type;
169 170 171
    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
172
    double external_clock_speed;             ///< speed of the external clock
173

174
    double audio_clock;
175
    int audio_clock_serial;
176 177 178 179
    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
    uint8_t silence_buf[SDL_AUDIO_BUFFER_SIZE];
184
    uint8_t *audio_buf;
185
    uint8_t *audio_buf1;
186
    unsigned int audio_buf_size; /* in bytes */
187
    unsigned int audio_buf1_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
188
    int audio_buf_index; /* in bytes */
189
    int audio_write_buf_size;
190
    int audio_buf_frames_pending;
191
    AVPacket audio_pkt_temp;
Fabrice Bellard's avatar
Fabrice Bellard committed
192
    AVPacket audio_pkt;
193
    int audio_pkt_temp_serial;
Marton Balint's avatar
Marton Balint committed
194
    int audio_last_serial;
195
    struct AudioParams audio_src;
Marton Balint's avatar
Marton Balint committed
196 197 198
#if CONFIG_AVFILTER
    struct AudioParams audio_filter_src;
#endif
199
    struct AudioParams audio_tgt;
200
    struct SwrContext *swr_ctx;
201 202
    double audio_current_pts;
    double audio_current_pts_drift;
203 204
    int frame_drops_early;
    int frame_drops_late;
205
    AVFrame *frame;
206

207
    enum ShowMode {
208
        SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB
209
    } show_mode;
Fabrice Bellard's avatar
Fabrice Bellard committed
210 211
    int16_t sample_array[SAMPLE_ARRAY_SIZE];
    int sample_array_index;
212
    int last_i_start;
213
    RDFTContext *rdft;
214
    int rdft_bits;
Måns Rullgård's avatar
Måns Rullgård committed
215
    FFTSample *rdft_data;
216
    int xpos;
217
    double last_vis_time;
218

219 220 221 222 223 224 225 226 227
    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;
228

229 230
    double frame_timer;
    double frame_last_pts;
231
    double frame_last_duration;
232
    double frame_last_dropped_pts;
233 234
    double frame_last_returned_time;
    double frame_last_filter_delay;
235
    int64_t frame_last_dropped_pos;
236
    int frame_last_dropped_serial;
Fabrice Bellard's avatar
Fabrice Bellard committed
237 238 239
    int video_stream;
    AVStream *video_st;
    PacketQueue videoq;
240
    double video_current_pts;       // current displayed pts
241 242
    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
243
    double max_frame_duration;      // maximum duration of a frame - above this, we consider the jump a timestamp discontinuity
244
    int video_clock_serial;
Fabrice Bellard's avatar
Fabrice Bellard committed
245 246 247 248
    VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE];
    int pictq_size, pictq_rindex, pictq_windex;
    SDL_mutex *pictq_mutex;
    SDL_cond *pictq_cond;
249
#if !CONFIG_AVFILTER
250
    struct SwsContext *img_convert_ctx;
251
#endif
252
    SDL_Rect last_display_rect;
253

Fabrice Bellard's avatar
Fabrice Bellard committed
254 255
    char filename[1024];
    int width, height, xleft, ytop;
256
    int step;
257

258
#if CONFIG_AVFILTER
259 260
    AVFilterContext *in_video_filter;   // the first filter in the video chain
    AVFilterContext *out_video_filter;  // the last filter in the video chain
Marton Balint's avatar
Marton Balint committed
261 262 263
    AVFilterContext *in_audio_filter;   // the first filter in the audio chain
    AVFilterContext *out_audio_filter;  // the last filter in the audio chain
    AVFilterGraph *agraph;              // audio filter graph
264
#endif
265

266
    int last_video_stream, last_audio_stream, last_subtitle_stream;
267 268

    SDL_cond *continue_read_thread;
Fabrice Bellard's avatar
Fabrice Bellard committed
269 270 271 272 273
} VideoState;

/* options specified by the user */
static AVInputFormat *file_iformat;
static const char *input_filename;
274
static const char *window_title;
Fabrice Bellard's avatar
Fabrice Bellard committed
275 276
static int fs_screen_width;
static int fs_screen_height;
277 278
static int default_width  = 640;
static int default_height = 480;
Aneesh Dogra's avatar
Aneesh Dogra committed
279
static int screen_width  = 0;
280
static int screen_height = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
281 282
static int audio_disable;
static int video_disable;
283
static int subtitle_disable;
Aneesh Dogra's avatar
Aneesh Dogra committed
284 285 286 287
static int wanted_stream[AVMEDIA_TYPE_NB] = {
    [AVMEDIA_TYPE_AUDIO]    = -1,
    [AVMEDIA_TYPE_VIDEO]    = -1,
    [AVMEDIA_TYPE_SUBTITLE] = -1,
288
};
Aneesh Dogra's avatar
Aneesh Dogra committed
289
static int seek_by_bytes = -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
290
static int display_disable;
291
static int show_status = 1;
292
static int av_sync_type = AV_SYNC_AUDIO_MASTER;
Fabrice Bellard's avatar
Fabrice Bellard committed
293
static int64_t start_time = AV_NOPTS_VALUE;
294
static int64_t duration = AV_NOPTS_VALUE;
Michael Niedermayer's avatar
Michael Niedermayer committed
295
static int workaround_bugs = 1;
296
static int fast = 0;
297
static int genpts = 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
298
static int lowres = 0;
299
static int idct = FF_IDCT_AUTO;
300
static int error_concealment = 3;
Aneesh Dogra's avatar
Aneesh Dogra committed
301
static int decoder_reorder_pts = -1;
Michael Niedermayer's avatar
Michael Niedermayer committed
302
static int autoexit;
303 304
static int exit_on_keydown;
static int exit_on_mousedown;
Aneesh Dogra's avatar
Aneesh Dogra committed
305
static int loop = 1;
306
static int framedrop = -1;
307
static int infinite_buffer = -1;
308
static enum ShowMode show_mode = SHOW_MODE_NONE;
309 310 311
static const char *audio_codec_name;
static const char *subtitle_codec_name;
static const char *video_codec_name;
312
double rdftspeed = 0.02;
313 314
static int64_t cursor_last_shown;
static int cursor_hidden = 0;
315 316
#if CONFIG_AVFILTER
static char *vfilters = NULL;
Marton Balint's avatar
Marton Balint committed
317
static char *afilters = NULL;
318
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
319 320 321

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

324
static AVPacket flush_pkt;
325

Fabrice Bellard's avatar
Fabrice Bellard committed
326
#define FF_ALLOC_EVENT   (SDL_USEREVENT)
327
#define FF_QUIT_EVENT    (SDL_USEREVENT + 2)
Fabrice Bellard's avatar
Fabrice Bellard committed
328

329
static SDL_Surface *screen;
Fabrice Bellard's avatar
Fabrice Bellard committed
330

Marton Balint's avatar
Marton Balint committed
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
static inline
int cmp_audio_fmts(enum AVSampleFormat fmt1, int64_t channel_count1,
                   enum AVSampleFormat fmt2, int64_t channel_count2)
{
    /* If channel count == 1, planar and non-planar formats are the same */
    if (channel_count1 == 1 && channel_count2 == 1)
        return av_get_packed_sample_fmt(fmt1) != av_get_packed_sample_fmt(fmt2);
    else
        return channel_count1 != channel_count2 || fmt1 != fmt2;
}

static inline
int64_t get_valid_channel_layout(int64_t channel_layout, int channels)
{
    if (channel_layout && av_get_channel_layout_nb_channels(channel_layout) == channels)
        return channel_layout;
    else
        return 0;
}

351
static int packet_queue_put(PacketQueue *q, AVPacket *pkt);
352

353
static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)
354
{
355
    MyAVPacketList *pkt1;
356

357 358
    if (q->abort_request)
       return -1;
359

360
    pkt1 = av_malloc(sizeof(MyAVPacketList));
361 362 363 364
    if (!pkt1)
        return -1;
    pkt1->pkt = *pkt;
    pkt1->next = NULL;
365 366 367
    if (pkt == &flush_pkt)
        q->serial++;
    pkt1->serial = q->serial;
368 369 370 371 372 373 374 375 376 377

    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);
378 379 380 381 382 383
    return 0;
}

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

385 386 387 388 389 390
    /* 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);
391
    SDL_UnlockMutex(q->mutex);
392 393 394 395 396

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

    return ret;
397
}
398

Fabrice Bellard's avatar
Fabrice Bellard committed
399 400 401 402 403 404
/* packet queue handling */
static void packet_queue_init(PacketQueue *q)
{
    memset(q, 0, sizeof(PacketQueue));
    q->mutex = SDL_CreateMutex();
    q->cond = SDL_CreateCond();
405
    q->abort_request = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
406 407
}

Fabrice Bellard's avatar
Fabrice Bellard committed
408
static void packet_queue_flush(PacketQueue *q)
Fabrice Bellard's avatar
Fabrice Bellard committed
409
{
410
    MyAVPacketList *pkt, *pkt1;
Fabrice Bellard's avatar
Fabrice Bellard committed
411

412
    SDL_LockMutex(q->mutex);
Aneesh Dogra's avatar
Aneesh Dogra committed
413
    for (pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {
Fabrice Bellard's avatar
Fabrice Bellard committed
414 415
        pkt1 = pkt->next;
        av_free_packet(&pkt->pkt);
416
        av_freep(&pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
417
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
418 419 420 421
    q->last_pkt = NULL;
    q->first_pkt = NULL;
    q->nb_packets = 0;
    q->size = 0;
422
    SDL_UnlockMutex(q->mutex);
Fabrice Bellard's avatar
Fabrice Bellard committed
423 424
}

425
static void packet_queue_destroy(PacketQueue *q)
Fabrice Bellard's avatar
Fabrice Bellard committed
426 427
{
    packet_queue_flush(q);
Fabrice Bellard's avatar
Fabrice Bellard committed
428 429 430 431 432 433 434 435 436
    SDL_DestroyMutex(q->mutex);
    SDL_DestroyCond(q->cond);
}

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

    q->abort_request = 1;
437

Fabrice Bellard's avatar
Fabrice Bellard committed
438 439 440 441 442
    SDL_CondSignal(q->cond);

    SDL_UnlockMutex(q->mutex);
}

443 444 445 446 447 448 449 450
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
451
/* return < 0 if aborted, 0 if no packet and > 0 if packet.  */
452
static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial)
Fabrice Bellard's avatar
Fabrice Bellard committed
453
{
454
    MyAVPacketList *pkt1;
Fabrice Bellard's avatar
Fabrice Bellard committed
455 456 457 458
    int ret;

    SDL_LockMutex(q->mutex);

Aneesh Dogra's avatar
Aneesh Dogra committed
459
    for (;;) {
Fabrice Bellard's avatar
Fabrice Bellard committed
460 461 462 463
        if (q->abort_request) {
            ret = -1;
            break;
        }
464

Fabrice Bellard's avatar
Fabrice Bellard committed
465 466 467 468 469 470
        pkt1 = q->first_pkt;
        if (pkt1) {
            q->first_pkt = pkt1->next;
            if (!q->first_pkt)
                q->last_pkt = NULL;
            q->nb_packets--;
471
            q->size -= pkt1->pkt.size + sizeof(*pkt1);
Fabrice Bellard's avatar
Fabrice Bellard committed
472
            *pkt = pkt1->pkt;
473 474
            if (serial)
                *serial = pkt1->serial;
Fabrice Bellard's avatar
Fabrice Bellard committed
475 476 477 478 479 480 481 482 483 484 485 486 487 488
            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;
}

489
static inline void fill_rectangle(SDL_Surface *screen,
490
                                  int x, int y, int w, int h, int color, int update)
Fabrice Bellard's avatar
Fabrice Bellard committed
491 492 493 494 495 496 497
{
    SDL_Rect rect;
    rect.x = x;
    rect.y = y;
    rect.w = w;
    rect.h = h;
    SDL_FillRect(screen, &rect, color);
498 499
    if (update && w > 0 && h > 0)
        SDL_UpdateRect(screen, x, y, w, h);
Fabrice Bellard's avatar
Fabrice Bellard committed
500 501
}

502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
/* 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);
}

538 539 540 541 542 543 544 545 546 547 548 549 550 551
#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)\
{\
552
    unsigned int val = ((const uint32_t *)(pal))[*(const uint8_t*)(s)];\
553 554 555 556 557 558 559 560 561 562 563 564 565 566
    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

567
static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, int imgh)
568 569 570 571 572 573
{
    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;
574 575
    int dstx, dsty, dstw, dsth;

576 577 578 579
    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);
580
    lum = dst->data[0] + dsty * dst->linesize[0];
Aneesh Dogra's avatar
Aneesh Dogra committed
581 582
    cb  = dst->data[1] + (dsty >> 1) * dst->linesize[1];
    cr  = dst->data[2] + (dsty >> 1) * dst->linesize[2];
583

584
    width2 = ((dstw + 1) >> 1) + (dstx & ~dstw & 1);
585
    skip2 = dstx >> 1;
586
    wrap = dst->linesize[0];
587 588 589
    wrap3 = rect->pict.linesize[0];
    p = rect->pict.data[0];
    pal = (const uint32_t *)rect->pict.data[1];  /* Now in YCrCb! */
590

591 592
    if (dsty & 1) {
        lum += dstx;
593 594
        cb += skip2;
        cr += skip2;
595

596
        if (dstx & 1) {
597 598 599 600 601 602 603 604 605
            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
606
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629
            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);
630 631
            p++;
            lum++;
632
        }
633 634
        p += wrap3 - dstw * BPP;
        lum += wrap - dstw - dstx;
635 636 637
        cb += dst->linesize[1] - width2 - skip2;
        cr += dst->linesize[2] - width2 - skip2;
    }
Aneesh Dogra's avatar
Aneesh Dogra committed
638
    for (h = dsth - (dsty & 1); h >= 2; h -= 2) {
639
        lum += dstx;
640 641
        cb += skip2;
        cr += skip2;
642

643
        if (dstx & 1) {
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
            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
663
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
664 665 666 667 668 669
            YUVA_IN(y, u, v, a, p, pal);
            u1 = u;
            v1 = v;
            a1 = a;
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);

670
            YUVA_IN(y, u, v, a, p + BPP, pal);
671 672 673 674 675 676 677 678 679 680 681 682 683
            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);

684
            YUVA_IN(y, u, v, a, p + BPP, pal);
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717
            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;
        }
718 719
        p += wrap3 + (wrap3 - dstw * BPP);
        lum += wrap + (wrap - dstw - dstx);
720 721 722 723 724
        cb += dst->linesize[1] - width2 - skip2;
        cr += dst->linesize[2] - width2 - skip2;
    }
    /* handle odd height */
    if (h) {
725
        lum += dstx;
726 727
        cb += skip2;
        cr += skip2;
728

729
        if (dstx & 1) {
730 731 732 733 734 735 736 737 738
            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
739
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
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
            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)
{
769
    avsubtitle_free(&sp->sub);
770 771
}

772 773 774 775 776
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;

777
    if (vp->sar.num == 0)
778 779
        aspect_ratio = 0;
    else
780
        aspect_ratio = av_q2d(vp->sar);
781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800

    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
801 802 803
static void video_image_display(VideoState *is)
{
    VideoPicture *vp;
804 805
    SubPicture *sp;
    AVPicture pict;
Fabrice Bellard's avatar
Fabrice Bellard committed
806
    SDL_Rect rect;
807
    int i;
Fabrice Bellard's avatar
Fabrice Bellard committed
808 809 810

    vp = &is->pictq[is->pictq_rindex];
    if (vp->bmp) {
811 812
        if (is->subtitle_st) {
            if (is->subpq_size > 0) {
813 814
                sp = &is->subpq[is->subpq_rindex];

815
                if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) {
816 817 818 819 820 821 822 823 824 825 826
                    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++)
827
                        blend_subrect(&pict, sp->sub.rects[i],
828
                                      vp->bmp->w, vp->bmp->h);
829 830 831 832 833 834

                    SDL_UnlockYUVOverlay (vp->bmp);
                }
            }
        }

835
        calculate_display_rect(&rect, is->xleft, is->ytop, is->width, is->height, vp);
836

Fabrice Bellard's avatar
Fabrice Bellard committed
837
        SDL_DisplayYUVOverlay(vp->bmp, &rect);
838 839 840 841 842 843

        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
844 845 846 847 848
    }
}

static inline int compute_mod(int a, int b)
{
849
    return a < 0 ? a%b + b : a%b;
Fabrice Bellard's avatar
Fabrice Bellard committed
850 851 852 853 854 855
}

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;
856
    int64_t time_diff;
857 858
    int rdft_bits, nb_freq;

Aneesh Dogra's avatar
Aneesh Dogra committed
859
    for (rdft_bits = 1; (1 << rdft_bits) < 2 * s->height; rdft_bits++)
860
        ;
Aneesh Dogra's avatar
Aneesh Dogra committed
861
    nb_freq = 1 << (rdft_bits - 1);
862

Fabrice Bellard's avatar
Fabrice Bellard committed
863
    /* compute display index : center on currently output samples */
864
    channels = s->audio_tgt.channels;
Fabrice Bellard's avatar
Fabrice Bellard committed
865
    nb_display_channels = channels;
866
    if (!s->paused) {
867
        int data_used= s->show_mode == SHOW_MODE_WAVES ? s->width : (2*nb_freq);
868
        n = 2 * channels;
869
        delay = s->audio_write_buf_size;
870
        delay /= n;
871

872 873 874 875
        /* 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;
876
            delay -= (time_diff * s->audio_tgt.freq) / 1000000;
877
        }
878

Aneesh Dogra's avatar
Aneesh Dogra committed
879
        delay += 2 * data_used;
880 881
        if (delay < data_used)
            delay = data_used;
882 883

        i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
884
        if (s->show_mode == SHOW_MODE_WAVES) {
Aneesh Dogra's avatar
Aneesh Dogra committed
885 886 887 888 889 890 891 892 893 894 895
            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;
896
                }
897 898 899
            }
        }

900 901 902
        s->last_i_start = i_start;
    } else {
        i_start = s->last_i_start;
Fabrice Bellard's avatar
Fabrice Bellard committed
903 904 905
    }

    bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
906
    if (s->show_mode == SHOW_MODE_WAVES) {
907 908
        fill_rectangle(screen,
                       s->xleft, s->ytop, s->width, s->height,
909
                       bgcolor, 0);
910 911 912 913 914 915 916

        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
917
        for (ch = 0; ch < nb_display_channels; ch++) {
918 919
            i = i_start + ch;
            y1 = s->ytop + ch * h + (h / 2); /* position of center line */
Aneesh Dogra's avatar
Aneesh Dogra committed
920
            for (x = 0; x < s->width; x++) {
921 922 923 924 925 926 927 928 929
                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,
930
                               fgcolor, 0);
931 932 933
                i += channels;
                if (i >= SAMPLE_ARRAY_SIZE)
                    i -= SAMPLE_ARRAY_SIZE;
Fabrice Bellard's avatar
Fabrice Bellard committed
934 935 936
            }
        }

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

Aneesh Dogra's avatar
Aneesh Dogra committed
939
        for (ch = 1; ch < nb_display_channels; ch++) {
940 941 942
            y = s->ytop + ch * h;
            fill_rectangle(screen,
                           s->xleft, y, s->width, 1,
943
                           fgcolor, 0);
944 945
        }
        SDL_UpdateRect(screen, s->xleft, s->ytop, s->width, s->height);
Aneesh Dogra's avatar
Aneesh Dogra committed
946
    } else {
947
        nb_display_channels= FFMIN(nb_display_channels, 2);
Aneesh Dogra's avatar
Aneesh Dogra committed
948
        if (rdft_bits != s->rdft_bits) {
949
            av_rdft_end(s->rdft);
Måns Rullgård's avatar
Måns Rullgård committed
950
            av_free(s->rdft_data);
951
            s->rdft = av_rdft_init(rdft_bits, DFT_R2C);
Aneesh Dogra's avatar
Aneesh Dogra committed
952 953
            s->rdft_bits = rdft_bits;
            s->rdft_data = av_malloc(4 * nb_freq * sizeof(*s->rdft_data));
954 955
        }
        {
Måns Rullgård's avatar
Måns Rullgård committed
956
            FFTSample *data[2];
Aneesh Dogra's avatar
Aneesh Dogra committed
957 958
            for (ch = 0; ch < nb_display_channels; ch++) {
                data[ch] = s->rdft_data + 2 * nb_freq * ch;
959
                i = i_start + ch;
Aneesh Dogra's avatar
Aneesh Dogra committed
960 961 962
                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);
963 964 965 966
                    i += channels;
                    if (i >= SAMPLE_ARRAY_SIZE)
                        i -= SAMPLE_ARRAY_SIZE;
                }
967
                av_rdft_calc(s->rdft, data[ch]);
968
            }
Aneesh Dogra's avatar
Aneesh Dogra committed
969 970 971 972 973 974 975 976 977
            // 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);
978 979 980

                fill_rectangle(screen,
                            s->xpos, s->height-y, 1, 1,
981
                            fgcolor, 0);
982 983 984
            }
        }
        SDL_UpdateRect(screen, s->xpos, s->ytop, 1, s->height);
985 986
        if (!s->paused)
            s->xpos++;
Aneesh Dogra's avatar
Aneesh Dogra committed
987
        if (s->xpos >= s->width)
988 989
            s->xpos= s->xleft;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
990 991
}

992 993 994 995 996 997 998
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);
999 1000 1001
    packet_queue_destroy(&is->videoq);
    packet_queue_destroy(&is->audioq);
    packet_queue_destroy(&is->subtitleq);
1002 1003

    /* free all pictures */
1004
    for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
        vp = &is->pictq[i];
        if (vp->bmp) {
            SDL_FreeYUVOverlay(vp->bmp);
            vp->bmp = NULL;
        }
    }
    SDL_DestroyMutex(is->pictq_mutex);
    SDL_DestroyCond(is->pictq_cond);
    SDL_DestroyMutex(is->subpq_mutex);
    SDL_DestroyCond(is->subpq_cond);
1015
    SDL_DestroyCond(is->continue_read_thread);
1016
#if !CONFIG_AVFILTER
1017
    sws_freeContext(is->img_convert_ctx);
1018 1019 1020 1021
#endif
    av_free(is);
}

1022
static void do_exit(VideoState *is)
1023
{
1024 1025
    if (is) {
        stream_close(is);
1026
    }
1027
    av_lockmgr_register(NULL);
1028 1029
    uninit_opts();
#if CONFIG_AVFILTER
1030
    av_freep(&vfilters);
1031
#endif
1032
    avformat_network_deinit();
1033 1034 1035
    if (show_status)
        printf("\n");
    SDL_Quit();
1036
    av_log(NULL, AV_LOG_QUIET, "%s", "");
1037 1038 1039
    exit(0);
}

1040 1041 1042 1043 1044
static void sigterm_handler(int sig)
{
    exit(123);
}

1045
static int video_open(VideoState *is, int force_set_video_mode, VideoPicture *vp)
Aneesh Dogra's avatar
Aneesh Dogra committed
1046 1047
{
    int flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
1048
    int w,h;
1049
    SDL_Rect rect;
1050

Aneesh Dogra's avatar
Aneesh Dogra committed
1051 1052
    if (is_full_screen) flags |= SDL_FULLSCREEN;
    else                flags |= SDL_RESIZABLE;
1053

1054 1055 1056 1057 1058 1059
    if (vp && vp->width) {
        calculate_display_rect(&rect, 0, 0, INT_MAX, vp->height, vp);
        default_width  = rect.w;
        default_height = rect.h;
    }

1060 1061 1062
    if (is_full_screen && fs_screen_width) {
        w = fs_screen_width;
        h = fs_screen_height;
Aneesh Dogra's avatar
Aneesh Dogra committed
1063
    } else if (!is_full_screen && screen_width) {
1064 1065
        w = screen_width;
        h = screen_height;
1066
    } else {
1067 1068
        w = default_width;
        h = default_height;
1069
    }
Aneesh Dogra's avatar
Aneesh Dogra committed
1070
    if (screen && is->width == screen->w && screen->w == w
1071
       && is->height== screen->h && screen->h == h && !force_set_video_mode)
1072
        return 0;
1073 1074 1075
    screen = SDL_SetVideoMode(w, h, 0, flags);
    if (!screen) {
        fprintf(stderr, "SDL: could not set video mode - exiting\n");
1076
        do_exit(is);
1077
    }
1078 1079 1080
    if (!window_title)
        window_title = input_filename;
    SDL_WM_SetCaption(window_title, window_title);
1081

Aneesh Dogra's avatar
Aneesh Dogra committed
1082
    is->width  = screen->w;
1083 1084 1085 1086
    is->height = screen->h;

    return 0;
}
1087

Fabrice Bellard's avatar
Fabrice Bellard committed
1088 1089 1090
/* display the current picture, if any */
static void video_display(VideoState *is)
{
Aneesh Dogra's avatar
Aneesh Dogra committed
1091
    if (!screen)
1092
        video_open(is, 0, NULL);
1093
    if (is->audio_st && is->show_mode != SHOW_MODE_VIDEO)
Fabrice Bellard's avatar
Fabrice Bellard committed
1094 1095 1096 1097 1098
        video_audio_display(is);
    else if (is->video_st)
        video_image_display(is);
}

1099 1100 1101
/* get the current audio clock value */
static double get_audio_clock(VideoState *is)
{
1102 1103
    if (is->audio_clock_serial != is->audioq.serial)
        return NAN;
1104 1105 1106 1107
    if (is->paused) {
        return is->audio_current_pts;
    } else {
        return is->audio_current_pts_drift + av_gettime() / 1000000.0;
1108 1109 1110 1111 1112 1113
    }
}

/* get the current video clock value */
static double get_video_clock(VideoState *is)
{
1114 1115
    if (is->video_clock_serial != is->videoq.serial)
        return NAN;
Michael Niedermayer's avatar
Michael Niedermayer committed
1116
    if (is->paused) {
1117
        return is->video_current_pts;
Fabrice Bellard's avatar
Fabrice Bellard committed
1118
    } else {
1119
        return is->video_current_pts_drift + av_gettime() / 1000000.0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1120
    }
1121 1122 1123 1124 1125
}

/* get the current external clock value */
static double get_external_clock(VideoState *is)
{
1126 1127 1128
    if (is->paused) {
        return is->external_clock;
    } else {
1129 1130
        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);
1131
    }
1132 1133
}

1134
static int get_master_sync_type(VideoState *is) {
Fabrice Bellard's avatar
Fabrice Bellard committed
1135 1136
    if (is->av_sync_type == AV_SYNC_VIDEO_MASTER) {
        if (is->video_st)
1137
            return AV_SYNC_VIDEO_MASTER;
Fabrice Bellard's avatar
Fabrice Bellard committed
1138
        else
1139
            return AV_SYNC_AUDIO_MASTER;
Fabrice Bellard's avatar
Fabrice Bellard committed
1140 1141
    } else if (is->av_sync_type == AV_SYNC_AUDIO_MASTER) {
        if (is->audio_st)
1142
            return AV_SYNC_AUDIO_MASTER;
Fabrice Bellard's avatar
Fabrice Bellard committed
1143
        else
1144
            return AV_SYNC_EXTERNAL_CLOCK;
Fabrice Bellard's avatar
Fabrice Bellard committed
1145
    } else {
1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
        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
1165
    }
1166 1167 1168
    return val;
}

1169 1170 1171 1172 1173 1174 1175 1176
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) {
1177 1178
    double ext_clock = get_external_clock(is);
    if (isnan(ext_clock) || fabs(ext_clock - pts) > AV_NOSYNC_THRESHOLD) {
1179 1180 1181 1182
        update_external_clock_pts(is, pts);
    }
}

1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
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
1202
/* seek in the stream */
1203
static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_bytes)
Fabrice Bellard's avatar
Fabrice Bellard committed
1204
{
1205 1206
    if (!is->seek_req) {
        is->seek_pos = pos;
1207
        is->seek_rel = rel;
Michael Niedermayer's avatar
Michael Niedermayer committed
1208
        is->seek_flags &= ~AVSEEK_FLAG_BYTE;
1209 1210
        if (seek_by_bytes)
            is->seek_flags |= AVSEEK_FLAG_BYTE;
1211
        is->seek_req = 1;
1212
        SDL_CondSignal(is->continue_read_thread);
1213
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
1214 1215 1216
}

/* pause or resume the video */
1217
static void stream_toggle_pause(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
1218
{
1219 1220
    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
1221
        if (is->read_pause_return != AVERROR(ENOSYS)) {
1222
            is->video_current_pts = is->video_current_pts_drift + av_gettime() / 1000000.0;
1223
        }
1224
        is->video_current_pts_drift = is->video_current_pts - av_gettime() / 1000000.0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1225
    }
1226
    update_external_clock_pts(is, get_external_clock(is));
1227
    is->paused = !is->paused;
Fabrice Bellard's avatar
Fabrice Bellard committed
1228 1229
}

1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243
static void toggle_pause(VideoState *is)
{
    stream_toggle_pause(is);
    is->step = 0;
}

static void step_to_next_frame(VideoState *is)
{
    /* if the stream is paused unpause it, then step */
    if (is->paused)
        stream_toggle_pause(is);
    is->step = 1;
}

1244
static double compute_target_delay(double delay, VideoState *is)
1245
{
1246
    double sync_threshold, diff;
1247 1248

    /* update delay to follow master synchronisation source */
1249
    if (get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER) {
1250 1251
        /* if video is slave, we try to correct big delays by
           duplicating or deleting a frame */
1252
        diff = get_video_clock(is) - get_master_clock(is);
1253 1254 1255 1256 1257

        /* 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);
1258
        if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) {
1259 1260 1261 1262 1263 1264
            if (diff <= -sync_threshold)
                delay = 0;
            else if (diff >= sync_threshold)
                delay = 2 * delay;
        }
    }
1265

1266 1267 1268 1269 1270 1271 1272 1273 1274 1275
    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;
1276

1277 1278 1279 1280
    SDL_LockMutex(is->pictq_mutex);
    is->pictq_size--;
    SDL_CondSignal(is->pictq_cond);
    SDL_UnlockMutex(is->pictq_mutex);
1281 1282
}

1283
static int pictq_prev_picture(VideoState *is) {
1284
    VideoPicture *prevvp;
1285
    int ret = 0;
1286 1287
    /* update queue size and signal for the previous picture */
    prevvp = &is->pictq[(is->pictq_rindex + VIDEO_PICTURE_QUEUE_SIZE - 1) % VIDEO_PICTURE_QUEUE_SIZE];
1288
    if (prevvp->allocated && prevvp->serial == is->videoq.serial) {
1289
        SDL_LockMutex(is->pictq_mutex);
1290
        if (is->pictq_size < VIDEO_PICTURE_QUEUE_SIZE - 1) {
1291 1292 1293
            if (--is->pictq_rindex == -1)
                is->pictq_rindex = VIDEO_PICTURE_QUEUE_SIZE - 1;
            is->pictq_size++;
1294
            ret = 1;
1295 1296 1297 1298
        }
        SDL_CondSignal(is->pictq_cond);
        SDL_UnlockMutex(is->pictq_mutex);
    }
1299
    return ret;
1300 1301
}

1302
static void update_video_pts(VideoState *is, double pts, int64_t pos, int serial) {
1303 1304 1305 1306 1307 1308
    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;
1309
    is->video_clock_serial = serial;
1310 1311
    if (is->videoq.serial == serial)
        check_external_clock_sync(is, is->video_current_pts);
1312 1313
}

Fabrice Bellard's avatar
Fabrice Bellard committed
1314
/* called to display each frame */
1315
static void video_refresh(void *opaque, double *remaining_time)
Fabrice Bellard's avatar
Fabrice Bellard committed
1316 1317 1318
{
    VideoState *is = opaque;
    VideoPicture *vp;
1319
    double time;
1320

1321
    SubPicture *sp, *sp2;
Fabrice Bellard's avatar
Fabrice Bellard committed
1322

1323 1324 1325
    if (!is->paused && get_master_sync_type(is) == AV_SYNC_EXTERNAL_CLOCK && is->realtime)
        check_external_clock_speed(is);

1326 1327 1328 1329 1330 1331 1332 1333
    if (!display_disable && is->show_mode != SHOW_MODE_VIDEO && is->audio_st) {
        time = av_gettime() / 1000000.0;
        if (is->force_refresh || is->last_vis_time + rdftspeed < time) {
            video_display(is);
            is->last_vis_time = time;
        }
        *remaining_time = FFMIN(*remaining_time, is->last_vis_time + rdftspeed - time);
    }
1334

Fabrice Bellard's avatar
Fabrice Bellard committed
1335
    if (is->video_st) {
1336
        int redisplay = 0;
1337
        if (is->force_refresh)
1338
            redisplay = pictq_prev_picture(is);
1339
retry:
Fabrice Bellard's avatar
Fabrice Bellard committed
1340
        if (is->pictq_size == 0) {
1341 1342
            SDL_LockMutex(is->pictq_mutex);
            if (is->frame_last_dropped_pts != AV_NOPTS_VALUE && is->frame_last_dropped_pts > is->frame_last_pts) {
1343
                update_video_pts(is, is->frame_last_dropped_pts, is->frame_last_dropped_pos, is->frame_last_dropped_serial);
1344 1345 1346
                is->frame_last_dropped_pts = AV_NOPTS_VALUE;
            }
            SDL_UnlockMutex(is->pictq_mutex);
1347
            // nothing to do, no picture to display in the queue
Fabrice Bellard's avatar
Fabrice Bellard committed
1348
        } else {
1349
            double last_duration, duration, delay;
1350
            /* dequeue the picture */
Fabrice Bellard's avatar
Fabrice Bellard committed
1351
            vp = &is->pictq[is->pictq_rindex];
1352

1353
            if (vp->serial != is->videoq.serial) {
1354
                pictq_next_picture(is);
1355
                redisplay = 0;
1356 1357 1358
                goto retry;
            }

1359 1360 1361
            if (is->paused)
                goto display;

1362 1363
            /* compute nominal last_duration */
            last_duration = vp->pts - is->frame_last_pts;
1364
            if (!isnan(last_duration) && last_duration > 0 && last_duration < is->max_frame_duration) {
1365 1366 1367 1368 1369
                /* 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);

1370
            time= av_gettime()/1000000.0;
1371 1372
            if (time < is->frame_timer + delay) {
                *remaining_time = FFMIN(is->frame_timer + delay - time, *remaining_time);
1373
                return;
1374
            }
1375

1376 1377
            if (delay > 0)
                is->frame_timer += delay * FFMAX(1, floor((time-is->frame_timer) / delay));
1378

1379
            SDL_LockMutex(is->pictq_mutex);
1380 1381
            if (!isnan(vp->pts))
                update_video_pts(is, vp->pts, vp->pos, vp->serial);
1382
            SDL_UnlockMutex(is->pictq_mutex);
1383

Aneesh Dogra's avatar
Aneesh Dogra committed
1384 1385
            if (is->pictq_size > 1) {
                VideoPicture *nextvp = &is->pictq[(is->pictq_rindex + 1) % VIDEO_PICTURE_QUEUE_SIZE];
1386
                duration = nextvp->pts - vp->pts;
1387 1388 1389
                if(!is->step && (redisplay || framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) && time > is->frame_timer + duration){
                    if (!redisplay)
                        is->frame_drops_late++;
1390
                    pictq_next_picture(is);
1391
                    redisplay = 0;
1392 1393 1394
                    goto retry;
                }
            }
1395

Aneesh Dogra's avatar
Aneesh Dogra committed
1396
            if (is->subtitle_st) {
1397 1398
                if (is->subtitle_stream_changed) {
                    SDL_LockMutex(is->subpq_mutex);
1399

1400 1401
                    while (is->subpq_size) {
                        free_subpicture(&is->subpq[is->subpq_rindex]);
1402

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

1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439
                        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);
                        }
                    }
                }
            }

1440
display:
Fabrice Bellard's avatar
Fabrice Bellard committed
1441
            /* display picture */
1442
            if (!display_disable && is->show_mode == SHOW_MODE_VIDEO)
1443
                video_display(is);
1444

1445
            pictq_next_picture(is);
1446 1447 1448

            if (is->step && !is->paused)
                stream_toggle_pause(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
1449 1450
        }
    }
1451
    is->force_refresh = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1452 1453 1454
    if (show_status) {
        static int64_t last_time;
        int64_t cur_time;
1455
        int aqsize, vqsize, sqsize;
1456
        double av_diff;
1457

Fabrice Bellard's avatar
Fabrice Bellard committed
1458
        cur_time = av_gettime();
1459
        if (!last_time || (cur_time - last_time) >= 30000) {
Fabrice Bellard's avatar
Fabrice Bellard committed
1460 1461
            aqsize = 0;
            vqsize = 0;
1462
            sqsize = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1463 1464 1465 1466
            if (is->audio_st)
                aqsize = is->audioq.size;
            if (is->video_st)
                vqsize = is->videoq.size;
1467 1468
            if (is->subtitle_st)
                sqsize = is->subtitleq.size;
1469 1470 1471
            av_diff = 0;
            if (is->audio_st && is->video_st)
                av_diff = get_audio_clock(is) - get_video_clock(is);
1472
            printf("%7.2f A-V:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64"   \r",
1473 1474
                   get_master_clock(is),
                   av_diff,
1475
                   is->frame_drops_early + is->frame_drops_late,
1476 1477 1478 1479 1480
                   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
1481 1482 1483 1484 1485 1486 1487 1488
            fflush(stdout);
            last_time = cur_time;
        }
    }
}

/* allocate a picture (needs to do that in main thread to avoid
   potential locking problems */
1489
static void alloc_picture(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
1490 1491 1492 1493 1494 1495 1496 1497
{
    VideoPicture *vp;

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

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

1498
    video_open(is, 0, vp);
1499

1500
    vp->bmp = SDL_CreateYUVOverlay(vp->width, vp->height,
1501
                                   SDL_YV12_OVERLAY,
1502
                                   screen);
1503 1504 1505 1506
    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
1507
                        "size of %dx%d pixels. Try using -lowres or -vf \"scale=w:h\"\n"
1508
                        "to reduce the image size.\n", vp->width, vp->height );
1509
        do_exit(is);
1510
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
1511 1512 1513 1514 1515 1516 1517

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

1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535
static void duplicate_right_border_pixels(SDL_Overlay *bmp) {
    int i, width, height;
    Uint8 *p, *maxp;
    for (i = 0; i < 3; i++) {
        width  = bmp->w;
        height = bmp->h;
        if (i > 0) {
            width  >>= 1;
            height >>= 1;
        }
        if (bmp->pitches[i] > width) {
            maxp = bmp->pixels[i] + bmp->pitches[i] * height - 1;
            for (p = bmp->pixels[i] + width - 1; p < maxp; p += bmp->pitches[i])
                *(p+1) = *p;
        }
    }
}

1536
static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t pos, int serial)
Fabrice Bellard's avatar
Fabrice Bellard committed
1537 1538
{
    VideoPicture *vp;
1539 1540

#if defined(DEBUG_SYNC) && 0
1541 1542
    printf("frame_type=%c pts=%0.3f\n",
           av_get_picture_type_char(src_frame->pict_type), pts);
1543
#endif
1544

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

1548
    /* keep the last already displayed picture in the queue */
1549
    while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE - 2 &&
Fabrice Bellard's avatar
Fabrice Bellard committed
1550 1551 1552 1553
           !is->videoq.abort_request) {
        SDL_CondWait(is->pictq_cond, is->pictq_mutex);
    }
    SDL_UnlockMutex(is->pictq_mutex);
1554

Fabrice Bellard's avatar
Fabrice Bellard committed
1555 1556 1557 1558 1559
    if (is->videoq.abort_request)
        return -1;

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

1560
    vp->sar = src_frame->sample_aspect_ratio;
1561

Fabrice Bellard's avatar
Fabrice Bellard committed
1562
    /* alloc or resize hardware picture buffer */
1563
    if (!vp->bmp || vp->reallocate || !vp->allocated ||
1564 1565
        vp->width  != src_frame->width ||
        vp->height != src_frame->height) {
Fabrice Bellard's avatar
Fabrice Bellard committed
1566 1567
        SDL_Event event;

1568
        vp->allocated  = 0;
1569
        vp->reallocate = 0;
1570 1571
        vp->width = src_frame->width;
        vp->height = src_frame->height;
Fabrice Bellard's avatar
Fabrice Bellard committed
1572 1573

        /* the allocation must be done in the main thread to avoid
1574
           locking problems. */
Fabrice Bellard's avatar
Fabrice Bellard committed
1575
        event.type = FF_ALLOC_EVENT;
1576
        event.user.data1 = is;
Fabrice Bellard's avatar
Fabrice Bellard committed
1577
        SDL_PushEvent(&event);
1578

Fabrice Bellard's avatar
Fabrice Bellard committed
1579 1580 1581 1582 1583
        /* 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);
        }
1584 1585 1586 1587 1588 1589
        /* 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
1590 1591 1592 1593 1594 1595
        SDL_UnlockMutex(is->pictq_mutex);

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

1596
    /* if the frame is not skipped, then display it */
Fabrice Bellard's avatar
Fabrice Bellard committed
1597
    if (vp->bmp) {
1598
        AVPicture pict = { { 0 } };
1599

Fabrice Bellard's avatar
Fabrice Bellard committed
1600 1601 1602 1603 1604 1605 1606 1607 1608 1609
        /* 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];
1610 1611

#if CONFIG_AVFILTER
Aneesh Dogra's avatar
Aneesh Dogra committed
1612
        // FIXME use direct rendering
1613
        av_picture_copy(&pict, (AVPicture *)src_frame,
1614
                        src_frame->format, vp->width, vp->height);
1615
#else
1616
        av_opt_get_int(sws_opts, "sws_flags", 0, &sws_flags);
1617
        is->img_convert_ctx = sws_getCachedContext(is->img_convert_ctx,
1618
            vp->width, vp->height, src_frame->format, vp->width, vp->height,
1619
            AV_PIX_FMT_YUV420P, sws_flags, NULL, NULL, NULL);
1620
        if (is->img_convert_ctx == NULL) {
1621 1622 1623
            fprintf(stderr, "Cannot initialize the conversion context\n");
            exit(1);
        }
1624
        sws_scale(is->img_convert_ctx, src_frame->data, src_frame->linesize,
1625 1626
                  0, vp->height, pict.data, pict.linesize);
#endif
1627 1628
        /* workaround SDL PITCH_WORKAROUND */
        duplicate_right_border_pixels(vp->bmp);
Fabrice Bellard's avatar
Fabrice Bellard committed
1629 1630 1631
        /* update the bitmap content */
        SDL_UnlockYUVOverlay(vp->bmp);

1632
        vp->pts = pts;
1633
        vp->pos = pos;
1634
        vp->serial = serial;
Fabrice Bellard's avatar
Fabrice Bellard committed
1635 1636 1637 1638 1639 1640 1641 1642

        /* 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);
    }
1643 1644 1645
    return 0;
}

1646
static int get_video_frame(VideoState *is, AVFrame *frame, AVPacket *pkt, int *serial)
Fabrice Bellard's avatar
Fabrice Bellard committed
1647
{
1648
    int got_picture;
Fabrice Bellard's avatar
Fabrice Bellard committed
1649

1650
    if (packet_queue_get(&is->videoq, pkt, 1, serial) < 0)
1651
        return -1;
1652

1653 1654
    if (pkt->data == flush_pkt.data) {
        avcodec_flush_buffers(is->video_st->codec);
1655

1656
        SDL_LockMutex(is->pictq_mutex);
1657
        // Make sure there are no long delay timers (ideally we should just flush the queue but that's harder)
1658 1659
        while (is->pictq_size && !is->videoq.abort_request) {
            SDL_CondWait(is->pictq_cond, is->pictq_mutex);
1660
        }
1661 1662
        is->video_current_pos = -1;
        is->frame_last_pts = AV_NOPTS_VALUE;
1663
        is->frame_last_duration = 0;
1664
        is->frame_timer = (double)av_gettime() / 1000000.0;
1665 1666
        is->frame_last_dropped_pts = AV_NOPTS_VALUE;
        SDL_UnlockMutex(is->pictq_mutex);
1667 1668
        return 0;
    }
1669

1670
    if(avcodec_decode_video2(is->video_st->codec, frame, &got_picture, pkt) < 0)
1671
        return 0;
1672 1673

    if (got_picture) {
1674
        int ret = 1;
1675
        double dpts = NAN;
1676

1677
        if (decoder_reorder_pts == -1) {
1678
            frame->pts = av_frame_get_best_effort_timestamp(frame);
1679
        } else if (decoder_reorder_pts) {
1680
            frame->pts = frame->pkt_pts;
1681
        } else {
1682
            frame->pts = frame->pkt_dts;
1683 1684
        }

1685 1686
        if (frame->pts != AV_NOPTS_VALUE)
            dpts = av_q2d(is->video_st->time_base) * frame->pts;
1687

1688 1689
        frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, frame);

1690
        if (framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) {
1691
            SDL_LockMutex(is->pictq_mutex);
1692
            if (is->frame_last_pts != AV_NOPTS_VALUE && frame->pts != AV_NOPTS_VALUE) {
1693 1694
                double clockdiff = get_video_clock(is) - get_master_clock(is);
                double ptsdiff = dpts - is->frame_last_pts;
1695
                if (!isnan(clockdiff) && fabs(clockdiff) < AV_NOSYNC_THRESHOLD &&
1696
                    !isnan(ptsdiff) && ptsdiff > 0 && ptsdiff < AV_NOSYNC_THRESHOLD &&
1697 1698
                    clockdiff + ptsdiff - is->frame_last_filter_delay < 0 &&
                    is->videoq.nb_packets) {
1699 1700
                    is->frame_last_dropped_pos = pkt->pos;
                    is->frame_last_dropped_pts = dpts;
1701
                    is->frame_last_dropped_serial = *serial;
1702
                    is->frame_drops_early++;
1703
                    av_frame_unref(frame);
1704 1705 1706 1707 1708
                    ret = 0;
                }
            }
            SDL_UnlockMutex(is->pictq_mutex);
        }
1709

1710
        return ret;
1711
    }
1712 1713 1714 1715
    return 0;
}

#if CONFIG_AVFILTER
1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746
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;
    }

1747
    ret = avfilter_graph_config(graph, NULL);
1748 1749 1750 1751 1752 1753
fail:
    avfilter_inout_free(&outputs);
    avfilter_inout_free(&inputs);
    return ret;
}

1754
static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters, AVFrame *frame)
1755
{
1756
    static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };
Stefano Sabatini's avatar
Stefano Sabatini committed
1757
    char sws_flags_str[128];
1758
    char buffersrc_args[256];
1759
    int ret;
1760
    AVFilterContext *filt_src = NULL, *filt_out = NULL, *filt_crop;
1761
    AVCodecContext *codec = is->video_st->codec;
1762
    AVRational fr = av_guess_frame_rate(is->ic, is->video_st, NULL);
1763

1764
    av_opt_get_int(sws_opts, "sws_flags", 0, &sws_flags);
1765
    snprintf(sws_flags_str, sizeof(sws_flags_str), "flags=%"PRId64, sws_flags);
Stefano Sabatini's avatar
Stefano Sabatini committed
1766
    graph->scale_sws_opts = av_strdup(sws_flags_str);
1767

1768 1769
    snprintf(buffersrc_args, sizeof(buffersrc_args),
             "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
1770
             frame->width, frame->height, frame->format,
1771
             is->video_st->time_base.num, is->video_st->time_base.den,
1772
             codec->sample_aspect_ratio.num, FFMAX(codec->sample_aspect_ratio.den, 1));
1773 1774
    if (fr.num && fr.den)
        av_strlcatf(buffersrc_args, sizeof(buffersrc_args), ":frame_rate=%d/%d", fr.num, fr.den);
1775 1776 1777

    if ((ret = avfilter_graph_create_filter(&filt_src,
                                            avfilter_get_by_name("buffer"),
1778
                                            "ffplay_buffer", buffersrc_args, NULL,
1779
                                            graph)) < 0)
1780
        goto fail;
1781

1782
    ret = avfilter_graph_create_filter(&filt_out,
1783
                                       avfilter_get_by_name("buffersink"),
1784
                                       "ffplay_buffersink", NULL, NULL, graph);
1785
    if (ret < 0)
1786
        goto fail;
1787

1788 1789 1790
    if ((ret = av_opt_set_int_list(filt_out, "pix_fmts", pix_fmts,  AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0)
        goto fail;

1791 1792 1793 1794 1795
    /* 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)
1796
        goto fail;
1797
    if ((ret = avfilter_link(filt_crop, 0, filt_out, 0)) < 0)
1798
        goto fail;
1799

1800
    if ((ret = configure_filtergraph(graph, vfilters, filt_src, filt_crop)) < 0)
1801
        goto fail;
1802

1803
    is->in_video_filter  = filt_src;
1804
    is->out_video_filter = filt_out;
1805

1806
fail:
1807 1808 1809
    return ret;
}

Marton Balint's avatar
Marton Balint committed
1810 1811
static int configure_audio_filters(VideoState *is, const char *afilters, int force_output_format)
{
1812
    static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE };
Marton Balint's avatar
Marton Balint committed
1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824
    int sample_rates[2] = { 0, -1 };
    int64_t channel_layouts[2] = { 0, -1 };
    int channels[2] = { 0, -1 };
    AVFilterContext *filt_asrc = NULL, *filt_asink = NULL;
    char asrc_args[256];
    int ret;

    avfilter_graph_free(&is->agraph);
    if (!(is->agraph = avfilter_graph_alloc()))
        return AVERROR(ENOMEM);

    ret = snprintf(asrc_args, sizeof(asrc_args),
1825
                   "sample_rate=%d:sample_fmt=%s:channels=%d:time_base=%d/%d",
Marton Balint's avatar
Marton Balint committed
1826
                   is->audio_filter_src.freq, av_get_sample_fmt_name(is->audio_filter_src.fmt),
1827 1828
                   is->audio_filter_src.channels,
                   1, is->audio_filter_src.freq);
Marton Balint's avatar
Marton Balint committed
1829 1830 1831 1832 1833 1834 1835 1836 1837 1838
    if (is->audio_filter_src.channel_layout)
        snprintf(asrc_args + ret, sizeof(asrc_args) - ret,
                 ":channel_layout=0x%"PRIx64,  is->audio_filter_src.channel_layout);

    ret = avfilter_graph_create_filter(&filt_asrc,
                                       avfilter_get_by_name("abuffer"), "ffplay_abuffer",
                                       asrc_args, NULL, is->agraph);
    if (ret < 0)
        goto end;

1839 1840 1841 1842 1843 1844 1845 1846 1847 1848

    ret = avfilter_graph_create_filter(&filt_asink,
                                       avfilter_get_by_name("abuffersink"), "ffplay_abuffersink",
                                       NULL, NULL, is->agraph);
    if (ret < 0)
        goto end;

    if ((ret = av_opt_set_int_list(filt_asink, "sample_fmts", sample_fmts,  AV_SAMPLE_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0)
        goto end;
    if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 1, AV_OPT_SEARCH_CHILDREN)) < 0)
Marton Balint's avatar
Marton Balint committed
1849 1850 1851 1852
        goto end;

    if (force_output_format) {
        channel_layouts[0] = is->audio_tgt.channel_layout;
1853 1854 1855 1856 1857 1858 1859 1860 1861 1862
        channels       [0] = is->audio_tgt.channels;
        sample_rates   [0] = is->audio_tgt.freq;
        if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 0, AV_OPT_SEARCH_CHILDREN)) < 0)
            goto end;
        if ((ret = av_opt_set_int_list(filt_asink, "channel_layouts", channel_layouts,  -1, AV_OPT_SEARCH_CHILDREN)) < 0)
            goto end;
        if ((ret = av_opt_set_int_list(filt_asink, "channel_counts" , channels       ,  -1, AV_OPT_SEARCH_CHILDREN)) < 0)
            goto end;
        if ((ret = av_opt_set_int_list(filt_asink, "sample_rates"   , sample_rates   ,  -1, AV_OPT_SEARCH_CHILDREN)) < 0)
            goto end;
Marton Balint's avatar
Marton Balint committed
1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876
    }


    if ((ret = configure_filtergraph(is->agraph, afilters, filt_asrc, filt_asink)) < 0)
        goto end;

    is->in_audio_filter  = filt_asrc;
    is->out_audio_filter = filt_asink;

end:
    if (ret < 0)
        avfilter_graph_free(&is->agraph);
    return ret;
}
1877 1878 1879 1880
#endif  /* CONFIG_AVFILTER */

static int video_thread(void *arg)
{
1881
    AVPacket pkt = { 0 };
1882
    VideoState *is = arg;
1883
    AVFrame *frame = av_frame_alloc();
1884 1885
    double pts;
    int ret;
1886
    int serial = 0;
1887 1888 1889

#if CONFIG_AVFILTER
    AVFilterGraph *graph = avfilter_graph_alloc();
1890
    AVFilterContext *filt_out = NULL, *filt_in = NULL;
1891 1892
    int last_w = 0;
    int last_h = 0;
1893
    enum AVPixelFormat last_format = -2;
1894
    int last_serial = -1;
1895 1896
#endif

Aneesh Dogra's avatar
Aneesh Dogra committed
1897
    for (;;) {
1898 1899
        while (is->paused && !is->videoq.abort_request)
            SDL_Delay(10);
1900

1901
        avcodec_get_frame_defaults(frame);
1902 1903
        av_free_packet(&pkt);

1904
        ret = get_video_frame(is, frame, &pkt, &serial);
1905 1906 1907 1908 1909
        if (ret < 0)
            goto the_end;
        if (!ret)
            continue;

1910
#if CONFIG_AVFILTER
1911 1912
        if (   last_w != frame->width
            || last_h != frame->height
1913 1914
            || last_format != frame->format
            || last_serial != serial) {
1915
            av_log(NULL, AV_LOG_DEBUG,
1916 1917 1918 1919 1920
                   "Video frame changed from size:%dx%d format:%s serial:%d to size:%dx%d format:%s serial:%d\n",
                   last_w, last_h,
                   (const char *)av_x_if_null(av_get_pix_fmt_name(last_format), "none"), last_serial,
                   frame->width, frame->height,
                   (const char *)av_x_if_null(av_get_pix_fmt_name(frame->format), "none"), serial);
1921 1922
            avfilter_graph_free(&graph);
            graph = avfilter_graph_alloc();
1923
            if ((ret = configure_video_filters(graph, is, vfilters, frame)) < 0) {
1924 1925 1926 1927
                SDL_Event event;
                event.type = FF_QUIT_EVENT;
                event.user.data1 = is;
                SDL_PushEvent(&event);
1928
                av_free_packet(&pkt);
1929
                goto the_end;
1930
            }
1931
            filt_in  = is->in_video_filter;
1932
            filt_out = is->out_video_filter;
1933 1934 1935
            last_w = frame->width;
            last_h = frame->height;
            last_format = frame->format;
1936
            last_serial = serial;
1937
        }
1938

1939 1940 1941
        ret = av_buffersrc_add_frame(filt_in, frame);
        if (ret < 0)
            goto the_end;
1942 1943
        av_frame_unref(frame);
        avcodec_get_frame_defaults(frame);
1944 1945
        av_free_packet(&pkt);

1946
        while (ret >= 0) {
1947 1948
            is->frame_last_returned_time = av_gettime() / 1000000.0;

1949
            ret = av_buffersink_get_frame_flags(filt_out, frame, 0);
1950 1951 1952 1953 1954
            if (ret < 0) {
                ret = 0;
                break;
            }

1955 1956 1957 1958
            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;

1959
            pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(filt_out->inputs[0]->time_base);
1960
            ret = queue_picture(is, frame, pts, av_frame_get_pkt_pos(frame), serial);
1961
            av_frame_unref(frame);
1962
        }
1963
#else
1964
        pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(is->video_st->time_base);
1965
        ret = queue_picture(is, frame, pts, pkt.pos, serial);
1966
        av_frame_unref(frame);
1967
#endif
1968

1969 1970
        if (ret < 0)
            goto the_end;
Fabrice Bellard's avatar
Fabrice Bellard committed
1971 1972
    }
 the_end:
1973
    avcodec_flush_buffers(is->video_st->codec);
1974
#if CONFIG_AVFILTER
1975
    avfilter_graph_free(&graph);
1976
#endif
1977
    av_free_packet(&pkt);
1978
    av_frame_free(&frame);
Fabrice Bellard's avatar
Fabrice Bellard committed
1979 1980 1981
    return 0;
}

1982 1983 1984 1985 1986
static int subtitle_thread(void *arg)
{
    VideoState *is = arg;
    SubPicture *sp;
    AVPacket pkt1, *pkt = &pkt1;
1987
    int got_subtitle;
1988 1989 1990 1991
    double pts;
    int i, j;
    int r, g, b, y, u, v, a;

Aneesh Dogra's avatar
Aneesh Dogra committed
1992
    for (;;) {
1993 1994 1995
        while (is->paused && !is->subtitleq.abort_request) {
            SDL_Delay(10);
        }
1996
        if (packet_queue_get(&is->subtitleq, pkt, 1, NULL) < 0)
1997
            break;
1998

Aneesh Dogra's avatar
Aneesh Dogra committed
1999
        if (pkt->data == flush_pkt.data) {
2000 2001 2002
            avcodec_flush_buffers(is->subtitle_st->codec);
            continue;
        }
2003 2004 2005 2006 2007 2008
        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);
2009

2010
        if (is->subtitleq.abort_request)
2011
            return 0;
2012

2013 2014 2015 2016 2017 2018
        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
2019
            pts = av_q2d(is->subtitle_st->time_base) * pkt->pts;
2020

2021 2022
        avcodec_decode_subtitle2(is->subtitle_st->codec, &sp->sub,
                                 &got_subtitle, pkt);
2023
        if (got_subtitle && sp->sub.format == 0) {
2024 2025
            if (sp->sub.pts != AV_NOPTS_VALUE)
                pts = sp->sub.pts / (double)AV_TIME_BASE;
2026
            sp->pts = pts;
2027

2028 2029
            for (i = 0; i < sp->sub.num_rects; i++)
            {
2030
                for (j = 0; j < sp->sub.rects[i]->nb_colors; j++)
2031
                {
2032
                    RGBA_IN(r, g, b, a, (uint32_t*)sp->sub.rects[i]->pict.data[1] + j);
2033 2034 2035
                    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);
2036
                    YUVA_OUT((uint32_t*)sp->sub.rects[i]->pict.data[1] + j, y, u, v, a);
2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051
                }
            }

            /* 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
2052 2053 2054
/* copy samples for viewing in editor window */
static void update_sample_display(VideoState *is, short *samples, int samples_size)
{
2055
    int size, len;
Fabrice Bellard's avatar
Fabrice Bellard committed
2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070

    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;
    }
}

2071 2072 2073
/* 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
2074
{
2075
    int wanted_nb_samples = nb_samples;
Fabrice Bellard's avatar
Fabrice Bellard committed
2076 2077

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

2082
        diff = get_audio_clock(is) - get_master_clock(is);
2083

2084
        if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) {
2085 2086 2087 2088 2089 2090 2091 2092 2093
            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) {
2094
                    wanted_nb_samples = nb_samples + (int)(diff * is->audio_src.freq);
2095 2096 2097
                    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);
2098
                }
2099
                av_dlog(NULL, "diff=%f adiff=%f sample_diff=%d apts=%0.3f %f\n",
2100
                        diff, avg_diff, wanted_nb_samples - nb_samples,
2101
                        is->audio_clock, is->audio_diff_threshold);
Fabrice Bellard's avatar
Fabrice Bellard committed
2102
            }
2103 2104 2105 2106
        } 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
2107
            is->audio_diff_cum       = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2108 2109 2110
        }
    }

2111
    return wanted_nb_samples;
Fabrice Bellard's avatar
Fabrice Bellard committed
2112 2113
}

2114 2115 2116 2117 2118 2119 2120
/**
 * Decode one audio frame and return its uncompressed size.
 *
 * The processed audio frame is decoded, converted if required, and
 * stored in is->audio_buf, with size in bytes given by the return
 * value.
 */
2121
static int audio_decode_frame(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
2122
{
2123
    AVPacket *pkt_temp = &is->audio_pkt_temp;
Fabrice Bellard's avatar
Fabrice Bellard committed
2124
    AVPacket *pkt = &is->audio_pkt;
Aneesh Dogra's avatar
Aneesh Dogra committed
2125
    AVCodecContext *dec = is->audio_st->codec;
2126
    int len1, data_size, resampled_data_size;
2127 2128
    int64_t dec_channel_layout;
    int got_frame;
2129
    av_unused double audio_clock0;
2130 2131
    int new_packet = 0;
    int flush_complete = 0;
2132
    int wanted_nb_samples;
Marton Balint's avatar
Marton Balint committed
2133
    AVRational tb;
2134 2135
    int ret;
    int reconfigure;
Fabrice Bellard's avatar
Fabrice Bellard committed
2136

Aneesh Dogra's avatar
Aneesh Dogra committed
2137
    for (;;) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2138
        /* NOTE: the audio packet can contain several frames */
2139
        while (pkt_temp->size > 0 || (!pkt_temp->data && new_packet) || is->audio_buf_frames_pending) {
2140 2141 2142
            if (!is->frame) {
                if (!(is->frame = avcodec_alloc_frame()))
                    return AVERROR(ENOMEM);
2143 2144
            } else {
                av_frame_unref(is->frame);
2145
                avcodec_get_frame_defaults(is->frame);
2146
            }
2147

2148 2149 2150
            if (is->audioq.serial != is->audio_pkt_temp_serial)
                break;

2151 2152 2153
            if (is->paused)
                return -1;

2154
            if (!is->audio_buf_frames_pending) {
Marton Balint's avatar
Marton Balint committed
2155 2156 2157 2158 2159 2160 2161 2162 2163
                if (flush_complete)
                    break;
                new_packet = 0;
                len1 = avcodec_decode_audio4(dec, is->frame, &got_frame, pkt_temp);
                if (len1 < 0) {
                    /* if error, we skip the frame */
                    pkt_temp->size = 0;
                    break;
                }
2164

Marton Balint's avatar
Marton Balint committed
2165 2166
                pkt_temp->data += len1;
                pkt_temp->size -= len1;
2167

Marton Balint's avatar
Marton Balint committed
2168 2169 2170 2171 2172 2173
                if (!got_frame) {
                    /* stop sending empty packets if the decoder is finished */
                    if (!pkt_temp->data && dec->codec->capabilities & CODEC_CAP_DELAY)
                        flush_complete = 1;
                    continue;
                }
2174

Marton Balint's avatar
Marton Balint committed
2175 2176 2177 2178 2179 2180 2181
                tb = (AVRational){1, is->frame->sample_rate};
                if (is->frame->pts != AV_NOPTS_VALUE)
                    is->frame->pts = av_rescale_q(is->frame->pts, dec->time_base, tb);
                if (is->frame->pts == AV_NOPTS_VALUE && pkt_temp->pts != AV_NOPTS_VALUE)
                    is->frame->pts = av_rescale_q(pkt_temp->pts, is->audio_st->time_base, tb);
                if (pkt_temp->pts != AV_NOPTS_VALUE)
                    pkt_temp->pts += (double) is->frame->nb_samples / is->frame->sample_rate / av_q2d(is->audio_st->time_base);
Marton Balint's avatar
Marton Balint committed
2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214

#if CONFIG_AVFILTER
                dec_channel_layout = get_valid_channel_layout(is->frame->channel_layout, av_frame_get_channels(is->frame));

                reconfigure =
                    cmp_audio_fmts(is->audio_filter_src.fmt, is->audio_filter_src.channels,
                                   is->frame->format, av_frame_get_channels(is->frame))    ||
                    is->audio_filter_src.channel_layout != dec_channel_layout ||
                    is->audio_filter_src.freq           != is->frame->sample_rate ||
                    is->audio_pkt_temp_serial           != is->audio_last_serial;

                if (reconfigure) {
                    char buf1[1024], buf2[1024];
                    av_get_channel_layout_string(buf1, sizeof(buf1), -1, is->audio_filter_src.channel_layout);
                    av_get_channel_layout_string(buf2, sizeof(buf2), -1, dec_channel_layout);
                    av_log(NULL, AV_LOG_DEBUG,
                           "Audio frame changed from rate:%d ch:%d fmt:%s layout:%s serial:%d to rate:%d ch:%d fmt:%s layout:%s serial:%d\n",
                           is->audio_filter_src.freq, is->audio_filter_src.channels, av_get_sample_fmt_name(is->audio_filter_src.fmt), buf1, is->audio_last_serial,
                           is->frame->sample_rate, av_frame_get_channels(is->frame), av_get_sample_fmt_name(is->frame->format), buf2, is->audio_pkt_temp_serial);

                    is->audio_filter_src.fmt            = is->frame->format;
                    is->audio_filter_src.channels       = av_frame_get_channels(is->frame);
                    is->audio_filter_src.channel_layout = dec_channel_layout;
                    is->audio_filter_src.freq           = is->frame->sample_rate;
                    is->audio_last_serial               = is->audio_pkt_temp_serial;

                    if ((ret = configure_audio_filters(is, afilters, 1)) < 0)
                        return ret;
                }

                if ((ret = av_buffersrc_add_frame(is->in_audio_filter, is->frame)) < 0)
                    return ret;
                av_frame_unref(is->frame);
2215 2216 2217 2218 2219 2220 2221 2222 2223
#endif
            }
#if CONFIG_AVFILTER
            if ((ret = av_buffersink_get_frame_flags(is->out_audio_filter, is->frame, 0)) < 0) {
                if (ret == AVERROR(EAGAIN)) {
                    is->audio_buf_frames_pending = 0;
                    continue;
                }
                return ret;
Marton Balint's avatar
Marton Balint committed
2224
            }
2225 2226
            is->audio_buf_frames_pending = 1;
            tb = is->out_audio_filter->inputs[0]->time_base;
Marton Balint's avatar
Marton Balint committed
2227
#endif
2228

2229
            data_size = av_samples_get_buffer_size(NULL, av_frame_get_channels(is->frame),
2230
                                                   is->frame->nb_samples,
2231
                                                   is->frame->format, 1);
2232

2233
            dec_channel_layout =
2234 2235
                (is->frame->channel_layout && av_frame_get_channels(is->frame) == av_get_channel_layout_nb_channels(is->frame->channel_layout)) ?
                is->frame->channel_layout : av_get_default_channel_layout(av_frame_get_channels(is->frame));
2236
            wanted_nb_samples = synchronize_audio(is, is->frame->nb_samples);
2237

2238 2239 2240 2241
            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)) {
2242
                swr_free(&is->swr_ctx);
2243
                is->swr_ctx = swr_alloc_set_opts(NULL,
2244
                                                 is->audio_tgt.channel_layout, is->audio_tgt.fmt, is->audio_tgt.freq,
2245
                                                 dec_channel_layout,           is->frame->format, is->frame->sample_rate,
2246
                                                 0, NULL);
2247 2248
                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",
2249
                            is->frame->sample_rate, av_get_sample_fmt_name(is->frame->format), av_frame_get_channels(is->frame),
2250
                            is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels);
2251
                    break;
2252
                }
2253
                is->audio_src.channel_layout = dec_channel_layout;
2254
                is->audio_src.channels       = av_frame_get_channels(is->frame);
2255 2256
                is->audio_src.freq = is->frame->sample_rate;
                is->audio_src.fmt = is->frame->format;
2257 2258
            }

2259
            if (is->swr_ctx) {
2260
                const uint8_t **in = (const uint8_t **)is->frame->extended_data;
2261 2262 2263
                uint8_t **out = &is->audio_buf1;
                int out_count = (int64_t)wanted_nb_samples * is->audio_tgt.freq / is->frame->sample_rate + 256;
                int out_size  = av_samples_get_buffer_size(NULL, is->audio_tgt.channels, out_count, is->audio_tgt.fmt, 0);
2264
                int len2;
2265 2266 2267 2268
                if (out_size < 0) {
                    fprintf(stderr, "av_samples_get_buffer_size() failed\n");
                    break;
                }
2269
                if (wanted_nb_samples != is->frame->nb_samples) {
2270 2271
                    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) {
2272 2273 2274 2275
                        fprintf(stderr, "swr_set_compensation() failed\n");
                        break;
                    }
                }
2276 2277 2278
                av_fast_malloc(&is->audio_buf1, &is->audio_buf1_size, out_size);
                if (!is->audio_buf1)
                    return AVERROR(ENOMEM);
2279
                len2 = swr_convert(is->swr_ctx, out, out_count, in, is->frame->nb_samples);
2280
                if (len2 < 0) {
2281
                    fprintf(stderr, "swr_convert() failed\n");
2282 2283
                    break;
                }
2284
                if (len2 == out_count) {
2285 2286 2287
                    fprintf(stderr, "warning: audio buffer is probably too small\n");
                    swr_init(is->swr_ctx);
                }
2288
                is->audio_buf = is->audio_buf1;
2289
                resampled_data_size = len2 * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt);
2290
            } else {
2291
                is->audio_buf = is->frame->data[0];
2292
                resampled_data_size = data_size;
2293 2294
            }

2295
            audio_clock0 = is->audio_clock;
2296 2297
            /* update the audio clock with the pts */
            if (is->frame->pts != AV_NOPTS_VALUE) {
Marton Balint's avatar
Marton Balint committed
2298
                is->audio_clock = is->frame->pts * av_q2d(tb) + (double) is->frame->nb_samples / is->frame->sample_rate;
2299 2300
                is->audio_clock_serial = is->audio_pkt_temp_serial;
            }
2301
#ifdef DEBUG
Fabrice Bellard's avatar
Fabrice Bellard committed
2302 2303
            {
                static double last_clock;
2304
                printf("audio: delay=%0.3f clock=%0.3f clock0=%0.3f\n",
Fabrice Bellard's avatar
Fabrice Bellard committed
2305
                       is->audio_clock - last_clock,
2306
                       is->audio_clock, audio_clock0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2307
                last_clock = is->audio_clock;
Fabrice Bellard's avatar
Fabrice Bellard committed
2308
            }
Fabrice Bellard's avatar
Fabrice Bellard committed
2309
#endif
2310
            return resampled_data_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
2311 2312
        }

Fabrice Bellard's avatar
Fabrice Bellard committed
2313 2314
        /* free the current packet */
        if (pkt->data)
Fabrice Bellard's avatar
Fabrice Bellard committed
2315
            av_free_packet(pkt);
2316
        memset(pkt_temp, 0, sizeof(*pkt_temp));
2317

2318
        if (is->audioq.abort_request) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2319 2320
            return -1;
        }
2321

2322 2323 2324
        if (is->audioq.nb_packets == 0)
            SDL_CondSignal(is->continue_read_thread);

Fabrice Bellard's avatar
Fabrice Bellard committed
2325
        /* read next packet */
2326
        if ((new_packet = packet_queue_get(&is->audioq, pkt, 1, &is->audio_pkt_temp_serial)) < 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
2327
            return -1;
2328

2329
        if (pkt->data == flush_pkt.data) {
2330
            avcodec_flush_buffers(dec);
2331
            flush_complete = 0;
2332
            is->audio_buf_frames_pending = 0;
2333
        }
2334

2335
        *pkt_temp = *pkt;
Fabrice Bellard's avatar
Fabrice Bellard committed
2336 2337 2338 2339
    }
}

/* prepare a new audio buffer */
2340
static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
Fabrice Bellard's avatar
Fabrice Bellard committed
2341 2342 2343
{
    VideoState *is = opaque;
    int audio_size, len1;
2344
    int bytes_per_sec;
2345
    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
2346 2347

    audio_callback_time = av_gettime();
2348

Fabrice Bellard's avatar
Fabrice Bellard committed
2349 2350
    while (len > 0) {
        if (is->audio_buf_index >= is->audio_buf_size) {
2351
           audio_size = audio_decode_frame(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
2352 2353
           if (audio_size < 0) {
                /* if error, just output silence */
2354
               is->audio_buf      = is->silence_buf;
2355
               is->audio_buf_size = sizeof(is->silence_buf) / frame_size * frame_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
2356
           } else {
2357
               if (is->show_mode != SHOW_MODE_VIDEO)
Fabrice Bellard's avatar
Fabrice Bellard committed
2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370
                   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;
    }
2371
    bytes_per_sec = is->audio_tgt.freq * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt);
2372 2373 2374 2375
    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;
2376
    if (is->audioq.serial == is->audio_clock_serial)
2377
        check_external_clock_sync(is, is->audio_current_pts);
Fabrice Bellard's avatar
Fabrice Bellard committed
2378 2379
}

2380
static int audio_open(void *opaque, int64_t wanted_channel_layout, int wanted_nb_channels, int wanted_sample_rate, struct AudioParams *audio_hw_params)
2381 2382 2383
{
    SDL_AudioSpec wanted_spec, spec;
    const char *env;
2384
    const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6};
2385 2386

    env = SDL_getenv("SDL_AUDIO_CHANNELS");
2387
    if (env) {
2388
        wanted_nb_channels = atoi(env);
2389 2390 2391 2392
        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);
2393 2394 2395
        wanted_channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX;
    }
    wanted_spec.channels = av_get_channel_layout_nb_channels(wanted_channel_layout);
2396
    wanted_spec.freq = wanted_sample_rate;
2397 2398 2399 2400 2401 2402 2403 2404
    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;
2405
    wanted_spec.userdata = opaque;
2406 2407 2408 2409 2410 2411 2412 2413
    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);
2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426
    }
    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;
        }
    }

2427 2428 2429 2430
    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;
2431
    return spec.size;
2432 2433
}

Fabrice Bellard's avatar
Fabrice Bellard committed
2434 2435 2436 2437
/* open a given stream. Return 0 if OK */
static int stream_component_open(VideoState *is, int stream_index)
{
    AVFormatContext *ic = is->ic;
2438
    AVCodecContext *avctx;
Fabrice Bellard's avatar
Fabrice Bellard committed
2439
    AVCodec *codec;
2440
    const char *forced_codec_name = NULL;
2441 2442
    AVDictionary *opts;
    AVDictionaryEntry *t = NULL;
Marton Balint's avatar
Marton Balint committed
2443 2444
    int sample_rate, nb_channels;
    int64_t channel_layout;
2445
    int ret;
Fabrice Bellard's avatar
Fabrice Bellard committed
2446 2447 2448

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

2451
    codec = avcodec_find_decoder(avctx->codec_id);
2452

2453
    switch(avctx->codec_type){
2454 2455 2456
        case AVMEDIA_TYPE_AUDIO   : is->last_audio_stream    = stream_index; forced_codec_name =    audio_codec_name; break;
        case AVMEDIA_TYPE_SUBTITLE: is->last_subtitle_stream = stream_index; forced_codec_name = subtitle_codec_name; break;
        case AVMEDIA_TYPE_VIDEO   : is->last_video_stream    = stream_index; forced_codec_name =    video_codec_name; break;
2457
    }
2458 2459 2460 2461 2462
    if (forced_codec_name)
        codec = avcodec_find_decoder_by_name(forced_codec_name);
    if (!codec) {
        if (forced_codec_name) fprintf(stderr, "No codec could be found with name '%s'\n", forced_codec_name);
        else                   fprintf(stderr, "No codec could be found with id %d\n", avctx->codec_id);
2463
        return -1;
2464
    }
2465

2466
    avctx->codec_id = codec->id;
Aneesh Dogra's avatar
Aneesh Dogra committed
2467 2468
    avctx->workaround_bugs   = workaround_bugs;
    avctx->lowres            = lowres;
2469 2470 2471 2472 2473
    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
2474 2475
    avctx->idct_algo         = idct;
    avctx->error_concealment = error_concealment;
2476

2477
    if(avctx->lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE;
Aneesh Dogra's avatar
Aneesh Dogra committed
2478
    if (fast)   avctx->flags2 |= CODEC_FLAG2_FAST;
2479 2480 2481
    if(codec->capabilities & CODEC_CAP_DR1)
        avctx->flags |= CODEC_FLAG_EMU_EDGE;

2482
    opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], codec);
2483 2484
    if (!av_dict_get(opts, "threads", NULL, 0))
        av_dict_set(&opts, "threads", "auto", 0);
2485
    if (avctx->codec_type == AVMEDIA_TYPE_VIDEO || avctx->codec_type == AVMEDIA_TYPE_AUDIO)
2486
        av_dict_set(&opts, "refcounted_frames", "1", 0);
2487
    if (avcodec_open2(avctx, codec, &opts) < 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
2488
        return -1;
2489 2490 2491 2492
    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;
    }
2493

2494
    ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
Aneesh Dogra's avatar
Aneesh Dogra committed
2495
    switch (avctx->codec_type) {
2496
    case AVMEDIA_TYPE_AUDIO:
Marton Balint's avatar
Marton Balint committed
2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517
#if CONFIG_AVFILTER
        {
            AVFilterLink *link;

            is->audio_filter_src.freq           = avctx->sample_rate;
            is->audio_filter_src.channels       = avctx->channels;
            is->audio_filter_src.channel_layout = get_valid_channel_layout(avctx->channel_layout, avctx->channels);
            is->audio_filter_src.fmt            = avctx->sample_fmt;
            if ((ret = configure_audio_filters(is, afilters, 0)) < 0)
                return ret;
            link = is->out_audio_filter->inputs[0];
            sample_rate    = link->sample_rate;
            nb_channels    = link->channels;
            channel_layout = link->channel_layout;
        }
#else
        sample_rate    = avctx->sample_rate;
        nb_channels    = avctx->channels;
        channel_layout = avctx->channel_layout;
#endif

2518
        /* prepare audio output */
Marton Balint's avatar
Marton Balint committed
2519
        if ((ret = audio_open(is, channel_layout, nb_channels, sample_rate, &is->audio_tgt)) < 0)
2520 2521 2522
            return ret;
        is->audio_hw_buf_size = ret;
        is->audio_src = is->audio_tgt;
Aneesh Dogra's avatar
Aneesh Dogra committed
2523
        is->audio_buf_size  = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2524
        is->audio_buf_index = 0;
2525 2526

        /* init averaging filter */
Aneesh Dogra's avatar
Aneesh Dogra committed
2527
        is->audio_diff_avg_coef  = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
2528 2529 2530
        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 */
2531
        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);
2532

Fabrice Bellard's avatar
Fabrice Bellard committed
2533
        memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
2534
        memset(&is->audio_pkt_temp, 0, sizeof(is->audio_pkt_temp));
2535 2536 2537 2538

        is->audio_stream = stream_index;
        is->audio_st = ic->streams[stream_index];

2539
        packet_queue_start(&is->audioq);
2540
        SDL_PauseAudio(0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2541
        break;
2542
    case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2543 2544 2545
        is->video_stream = stream_index;
        is->video_st = ic->streams[stream_index];

2546
        packet_queue_start(&is->videoq);
Fabrice Bellard's avatar
Fabrice Bellard committed
2547
        is->video_tid = SDL_CreateThread(video_thread, is);
2548
        is->queue_attachments_req = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2549
        break;
2550
    case AVMEDIA_TYPE_SUBTITLE:
2551 2552
        is->subtitle_stream = stream_index;
        is->subtitle_st = ic->streams[stream_index];
2553
        packet_queue_start(&is->subtitleq);
2554

2555 2556
        is->subtitle_tid = SDL_CreateThread(subtitle_thread, is);
        break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2557 2558 2559 2560 2561 2562 2563 2564 2565
    default:
        break;
    }
    return 0;
}

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

2568 2569
    if (stream_index < 0 || stream_index >= ic->nb_streams)
        return;
2570
    avctx = ic->streams[stream_index]->codec;
Fabrice Bellard's avatar
Fabrice Bellard committed
2571

Aneesh Dogra's avatar
Aneesh Dogra committed
2572
    switch (avctx->codec_type) {
2573
    case AVMEDIA_TYPE_AUDIO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2574 2575 2576 2577
        packet_queue_abort(&is->audioq);

        SDL_CloseAudio();

2578
        packet_queue_flush(&is->audioq);
2579
        av_free_packet(&is->audio_pkt);
2580
        swr_free(&is->swr_ctx);
2581
        av_freep(&is->audio_buf1);
2582
        is->audio_buf1_size = 0;
2583
        is->audio_buf = NULL;
2584
        av_frame_free(&is->frame);
2585 2586 2587 2588

        if (is->rdft) {
            av_rdft_end(is->rdft);
            av_freep(&is->rdft_data);
2589 2590
            is->rdft = NULL;
            is->rdft_bits = 0;
2591
        }
Marton Balint's avatar
Marton Balint committed
2592 2593 2594
#if CONFIG_AVFILTER
        avfilter_graph_free(&is->agraph);
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
2595
        break;
2596
    case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2597 2598 2599 2600 2601 2602 2603 2604 2605 2606
        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);

2607
        packet_queue_flush(&is->videoq);
Fabrice Bellard's avatar
Fabrice Bellard committed
2608
        break;
2609
    case AVMEDIA_TYPE_SUBTITLE:
2610
        packet_queue_abort(&is->subtitleq);
2611

2612 2613 2614 2615
        /* 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;
2616

2617 2618 2619 2620 2621
        SDL_CondSignal(is->subpq_cond);
        SDL_UnlockMutex(is->subpq_mutex);

        SDL_WaitThread(is->subtitle_tid, NULL);

2622
        packet_queue_flush(&is->subtitleq);
2623
        break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2624 2625 2626 2627
    default:
        break;
    }

2628
    ic->streams[stream_index]->discard = AVDISCARD_ALL;
2629
    avcodec_close(avctx);
Aneesh Dogra's avatar
Aneesh Dogra committed
2630
    switch (avctx->codec_type) {
2631
    case AVMEDIA_TYPE_AUDIO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2632 2633 2634
        is->audio_st = NULL;
        is->audio_stream = -1;
        break;
2635
    case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2636 2637 2638
        is->video_st = NULL;
        is->video_stream = -1;
        break;
2639
    case AVMEDIA_TYPE_SUBTITLE:
2640 2641 2642
        is->subtitle_st = NULL;
        is->subtitle_stream = -1;
        break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2643 2644 2645 2646 2647
    default:
        break;
    }
}

2648
static int decode_interrupt_cb(void *ctx)
2649
{
2650 2651
    VideoState *is = ctx;
    return is->abort_request;
2652
}
Fabrice Bellard's avatar
Fabrice Bellard committed
2653

2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669
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
2670
/* this thread gets the stream from the disk or the network */
2671
static int read_thread(void *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
2672 2673
{
    VideoState *is = arg;
2674
    AVFormatContext *ic = NULL;
2675
    int err, i, ret;
2676
    int st_index[AVMEDIA_TYPE_NB];
Fabrice Bellard's avatar
Fabrice Bellard committed
2677
    AVPacket pkt1, *pkt = &pkt1;
Aneesh Dogra's avatar
Aneesh Dogra committed
2678
    int eof = 0;
2679
    int pkt_in_play_range = 0;
2680
    AVDictionaryEntry *t;
2681 2682
    AVDictionary **opts;
    int orig_nb_streams;
2683
    SDL_mutex *wait_mutex = SDL_CreateMutex();
2684

2685
    memset(st_index, -1, sizeof(st_index));
2686 2687 2688
    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
2689

2690 2691
    ic = avformat_alloc_context();
    ic->interrupt_callback.callback = decode_interrupt_cb;
2692
    ic->interrupt_callback.opaque = is;
2693
    err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts);
2694 2695 2696 2697 2698
    if (err < 0) {
        print_error(is->filename, err);
        ret = -1;
        goto fail;
    }
2699 2700 2701 2702 2703
    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
2704
    is->ic = ic;
2705

Aneesh Dogra's avatar
Aneesh Dogra committed
2706
    if (genpts)
2707 2708
        ic->flags |= AVFMT_FLAG_GENPTS;

2709
    opts = setup_find_stream_info_opts(ic, codec_opts);
2710
    orig_nb_streams = ic->nb_streams;
2711

2712
    err = avformat_find_stream_info(ic, opts);
2713 2714 2715 2716 2717
    if (err < 0) {
        fprintf(stderr, "%s: could not find codec parameters\n", is->filename);
        ret = -1;
        goto fail;
    }
2718 2719 2720 2721
    for (i = 0; i < orig_nb_streams; i++)
        av_dict_free(&opts[i]);
    av_freep(&opts);

Aneesh Dogra's avatar
Aneesh Dogra committed
2722
    if (ic->pb)
2723
        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
2724

Aneesh Dogra's avatar
Aneesh Dogra committed
2725
    if (seek_by_bytes < 0)
2726
        seek_by_bytes = !!(ic->iformat->flags & AVFMT_TS_DISCONT) && strcmp("ogg", ic->iformat->name);
2727

2728 2729
    is->max_frame_duration = (ic->iformat->flags & AVFMT_TS_DISCONT) ? 10.0 : 3600.0;

2730 2731 2732
    if (!window_title && (t = av_dict_get(ic->metadata, "title", NULL, 0)))
        window_title = av_asprintf("%s - %s", t->value, input_filename);

Fabrice Bellard's avatar
Fabrice Bellard committed
2733 2734 2735 2736 2737 2738 2739 2740
    /* 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;
2741
        ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2742
        if (ret < 0) {
2743
            fprintf(stderr, "%s: could not seek to position %0.3f\n",
Fabrice Bellard's avatar
Fabrice Bellard committed
2744 2745 2746 2747
                    is->filename, (double)timestamp / AV_TIME_BASE);
        }
    }

2748 2749
    is->realtime = is_realtime(ic);

2750
    for (i = 0; i < ic->nb_streams; i++)
2751
        ic->streams[i]->discard = AVDISCARD_ALL;
2752
    if (!video_disable)
2753 2754 2755
        st_index[AVMEDIA_TYPE_VIDEO] =
            av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,
                                wanted_stream[AVMEDIA_TYPE_VIDEO], -1, NULL, 0);
2756
    if (!audio_disable)
2757 2758 2759 2760 2761
        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);
2762
    if (!video_disable && !subtitle_disable)
2763 2764 2765 2766 2767 2768 2769
        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
2770
    if (show_status) {
2771
        av_dump_format(ic, 0, is->filename, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2772 2773
    }

2774 2775
    is->show_mode = show_mode;

Fabrice Bellard's avatar
Fabrice Bellard committed
2776
    /* open the streams */
2777 2778
    if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {
        stream_component_open(is, st_index[AVMEDIA_TYPE_AUDIO]);
Fabrice Bellard's avatar
Fabrice Bellard committed
2779 2780
    }

Aneesh Dogra's avatar
Aneesh Dogra committed
2781
    ret = -1;
2782
    if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
Aneesh Dogra's avatar
Aneesh Dogra committed
2783
        ret = stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO]);
Michael Niedermayer's avatar
Michael Niedermayer committed
2784
    }
2785 2786
    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
2787

2788 2789
    if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) {
        stream_component_open(is, st_index[AVMEDIA_TYPE_SUBTITLE]);
2790 2791
    }

Fabrice Bellard's avatar
Fabrice Bellard committed
2792
    if (is->video_stream < 0 && is->audio_stream < 0) {
2793 2794
        fprintf(stderr, "%s: could not open codecs\n", is->filename);
        ret = -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2795 2796 2797
        goto fail;
    }

2798
    if (infinite_buffer < 0 && is->realtime)
2799 2800
        infinite_buffer = 1;

Aneesh Dogra's avatar
Aneesh Dogra committed
2801
    for (;;) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2802 2803
        if (is->abort_request)
            break;
2804 2805
        if (is->paused != is->last_paused) {
            is->last_paused = is->paused;
Fabrice Bellard's avatar
Fabrice Bellard committed
2806
            if (is->paused)
Aneesh Dogra's avatar
Aneesh Dogra committed
2807
                is->read_pause_return = av_read_pause(ic);
Fabrice Bellard's avatar
Fabrice Bellard committed
2808 2809
            else
                av_read_play(ic);
2810
        }
2811 2812 2813
#if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL
        if (is->paused &&
                (!strcmp(ic->iformat->name, "rtsp") ||
2814
                 (ic->pb && !strncmp(input_filename, "mmsh:", 5)))) {
2815 2816 2817 2818 2819
            /* wait 10 ms to avoid trying to get another packet */
            /* XXX: horrible */
            SDL_Delay(10);
            continue;
        }
2820
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
2821
        if (is->seek_req) {
Aneesh Dogra's avatar
Aneesh Dogra committed
2822 2823 2824 2825
            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
2826
//      of the seek_pos/seek_rel variables
2827

2828
            ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags);
Fabrice Bellard's avatar
Fabrice Bellard committed
2829 2830
            if (ret < 0) {
                fprintf(stderr, "%s: error while seeking\n", is->ic->filename);
Aneesh Dogra's avatar
Aneesh Dogra committed
2831
            } else {
2832 2833
                if (is->audio_stream >= 0) {
                    packet_queue_flush(&is->audioq);
2834
                    packet_queue_put(&is->audioq, &flush_pkt);
2835
                }
2836 2837
                if (is->subtitle_stream >= 0) {
                    packet_queue_flush(&is->subtitleq);
2838
                    packet_queue_put(&is->subtitleq, &flush_pkt);
2839
                }
2840 2841
                if (is->video_stream >= 0) {
                    packet_queue_flush(&is->videoq);
2842
                    packet_queue_put(&is->videoq, &flush_pkt);
2843
                }
2844
                if (is->seek_flags & AVSEEK_FLAG_BYTE) {
2845
                   update_external_clock_pts(is, NAN);
2846 2847 2848
                } else {
                   update_external_clock_pts(is, seek_target / (double)AV_TIME_BASE);
                }
Fabrice Bellard's avatar
Fabrice Bellard committed
2849 2850
            }
            is->seek_req = 0;
2851
            is->queue_attachments_req = 1;
Aneesh Dogra's avatar
Aneesh Dogra committed
2852
            eof = 0;
2853 2854
            if (is->paused)
                step_to_next_frame(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
2855
        }
2856
        if (is->queue_attachments_req) {
2857 2858 2859 2860 2861 2862
            if (is->video_st && is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC) {
                AVPacket copy;
                if ((ret = av_copy_packet(&copy, &is->video_st->attached_pic)) < 0)
                    goto fail;
                packet_queue_put(&is->videoq, &copy);
            }
2863
            is->queue_attachments_req = 0;
2864
        }
2865

Fabrice Bellard's avatar
Fabrice Bellard committed
2866
        /* if the queue are full, no need to read more */
2867
        if (infinite_buffer<1 &&
2868
              (is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
2869
            || (   (is->audioq   .nb_packets > MIN_FRAMES || is->audio_stream < 0 || is->audioq.abort_request)
2870 2871
                && (is->videoq   .nb_packets > MIN_FRAMES || is->video_stream < 0 || is->videoq.abort_request
                    || (is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC))
2872
                && (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0 || is->subtitleq.abort_request)))) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2873
            /* wait 10 ms */
2874 2875 2876
            SDL_LockMutex(wait_mutex);
            SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
            SDL_UnlockMutex(wait_mutex);
Fabrice Bellard's avatar
Fabrice Bellard committed
2877 2878
            continue;
        }
Aneesh Dogra's avatar
Aneesh Dogra committed
2879 2880
        if (eof) {
            if (is->video_stream >= 0) {
Michael Niedermayer's avatar
Michael Niedermayer committed
2881
                av_init_packet(pkt);
Aneesh Dogra's avatar
Aneesh Dogra committed
2882 2883 2884
                pkt->data = NULL;
                pkt->size = 0;
                pkt->stream_index = is->video_stream;
Michael Niedermayer's avatar
Michael Niedermayer committed
2885
                packet_queue_put(&is->videoq, pkt);
2886
            }
2887 2888 2889 2890 2891 2892 2893
            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);
2894
            }
2895
            SDL_Delay(10);
Aneesh Dogra's avatar
Aneesh Dogra committed
2896 2897
            if (is->audioq.size + is->videoq.size + is->subtitleq.size == 0) {
                if (loop != 1 && (!loop || --loop)) {
2898
                    stream_seek(is, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0);
Aneesh Dogra's avatar
Aneesh Dogra committed
2899 2900
                } else if (autoexit) {
                    ret = AVERROR_EOF;
2901 2902
                    goto fail;
                }
Michael Niedermayer's avatar
Michael Niedermayer committed
2903
            }
2904
            eof=0;
2905 2906
            continue;
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
2907
        ret = av_read_frame(ic, pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
2908
        if (ret < 0) {
2909
            if (ret == AVERROR_EOF || url_feof(ic->pb))
Aneesh Dogra's avatar
Aneesh Dogra committed
2910
                eof = 1;
2911
            if (ic->pb && ic->pb->error)
2912
                break;
2913 2914 2915
            SDL_LockMutex(wait_mutex);
            SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
            SDL_UnlockMutex(wait_mutex);
2916
            continue;
Fabrice Bellard's avatar
Fabrice Bellard committed
2917
        }
2918 2919 2920 2921
        /* 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
2922 2923
                (double)(start_time != AV_NOPTS_VALUE ? start_time : 0) / 1000000
                <= ((double)duration / 1000000);
2924
        if (pkt->stream_index == is->audio_stream && pkt_in_play_range) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2925
            packet_queue_put(&is->audioq, pkt);
2926 2927
        } else if (pkt->stream_index == is->video_stream && pkt_in_play_range
                   && !(is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC)) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2928
            packet_queue_put(&is->videoq, pkt);
2929
        } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {
2930
            packet_queue_put(&is->subtitleq, pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
2931 2932 2933 2934 2935 2936 2937 2938 2939
        } else {
            av_free_packet(pkt);
        }
    }
    /* wait until the end */
    while (!is->abort_request) {
        SDL_Delay(100);
    }

2940
    ret = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2941 2942 2943 2944 2945 2946
 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);
2947 2948
    if (is->subtitle_stream >= 0)
        stream_component_close(is, is->subtitle_stream);
2949
    if (is->ic) {
2950
        avformat_close_input(&is->ic);
2951
    }
2952

2953 2954
    if (ret != 0) {
        SDL_Event event;
2955

2956 2957 2958 2959
        event.type = FF_QUIT_EVENT;
        event.user.data1 = is;
        SDL_PushEvent(&event);
    }
2960
    SDL_DestroyMutex(wait_mutex);
Fabrice Bellard's avatar
Fabrice Bellard committed
2961 2962 2963
    return 0;
}

2964
static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
Fabrice Bellard's avatar
Fabrice Bellard committed
2965 2966 2967 2968 2969 2970
{
    VideoState *is;

    is = av_mallocz(sizeof(VideoState));
    if (!is)
        return NULL;
2971
    av_strlcpy(is->filename, filename, sizeof(is->filename));
2972
    is->iformat = iformat;
Aneesh Dogra's avatar
Aneesh Dogra committed
2973 2974
    is->ytop    = 0;
    is->xleft   = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2975 2976 2977

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

2980
    is->subpq_mutex = SDL_CreateMutex();
Aneesh Dogra's avatar
Aneesh Dogra committed
2981
    is->subpq_cond  = SDL_CreateCond();
2982

2983 2984 2985 2986
    packet_queue_init(&is->videoq);
    packet_queue_init(&is->audioq);
    packet_queue_init(&is->subtitleq);

2987 2988
    is->continue_read_thread = SDL_CreateCond();

2989
    update_external_clock_pts(is, NAN);
2990
    update_external_clock_speed(is, 1.0);
2991 2992
    is->audio_current_pts_drift = -av_gettime() / 1000000.0;
    is->video_current_pts_drift = is->audio_current_pts_drift;
2993 2994
    is->audio_clock_serial = -1;
    is->video_clock_serial = -1;
Marton Balint's avatar
Marton Balint committed
2995
    is->audio_last_serial = -1;
2996
    is->av_sync_type = av_sync_type;
2997
    is->read_tid     = SDL_CreateThread(read_thread, is);
2998
    if (!is->read_tid) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2999 3000 3001 3002 3003 3004
        av_free(is);
        return NULL;
    }
    return is;
}

3005
static void stream_cycle_channel(VideoState *is, int codec_type)
3006 3007 3008
{
    AVFormatContext *ic = is->ic;
    int start_index, stream_index;
3009
    int old_index;
3010 3011
    AVStream *st;

3012 3013 3014 3015 3016 3017 3018 3019 3020 3021
    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;
    }
3022
    stream_index = start_index;
Aneesh Dogra's avatar
Aneesh Dogra committed
3023
    for (;;) {
3024
        if (++stream_index >= is->ic->nb_streams)
3025
        {
3026
            if (codec_type == AVMEDIA_TYPE_SUBTITLE)
3027 3028
            {
                stream_index = -1;
3029
                is->last_subtitle_stream = -1;
3030
                goto the_end;
3031 3032 3033 3034
            }
            if (start_index == -1)
                return;
            stream_index = 0;
3035
        }
3036 3037 3038
        if (stream_index == start_index)
            return;
        st = ic->streams[stream_index];
3039
        if (st->codec->codec_type == codec_type) {
3040
            /* check that parameters are OK */
Aneesh Dogra's avatar
Aneesh Dogra committed
3041
            switch (codec_type) {
3042
            case AVMEDIA_TYPE_AUDIO:
3043 3044
                if (st->codec->sample_rate != 0 &&
                    st->codec->channels != 0)
3045 3046
                    goto the_end;
                break;
3047 3048
            case AVMEDIA_TYPE_VIDEO:
            case AVMEDIA_TYPE_SUBTITLE:
3049 3050 3051 3052 3053 3054 3055
                goto the_end;
            default:
                break;
            }
        }
    }
 the_end:
3056
    stream_component_close(is, old_index);
3057 3058 3059 3060
    stream_component_open(is, stream_index);
}


3061
static void toggle_full_screen(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
3062
{
3063
#if defined(__APPLE__) && SDL_VERSION_ATLEAST(1, 2, 14)
3064
    /* OS X needs to reallocate the SDL overlays */
3065 3066
    int i;
    for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++)
3067 3068
        is->pictq[i].reallocate = 1;
#endif
3069
    is_full_screen = !is_full_screen;
3070
    video_open(is, 1, NULL);
Fabrice Bellard's avatar
Fabrice Bellard committed
3071 3072
}

3073
static void toggle_audio_display(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
3074
{
3075
    int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086
    int next = is->show_mode;
    do {
        next = (next + 1) % SHOW_MODE_NB;
    } while (next != is->show_mode && (next == SHOW_MODE_VIDEO && !is->video_st || next != SHOW_MODE_VIDEO && !is->audio_st));
    if (is->show_mode != next) {
        fill_rectangle(screen,
                    is->xleft, is->ytop, is->width, is->height,
                    bgcolor, 1);
        is->force_refresh = 1;
        is->show_mode = next;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
3087 3088
}

3089
static void refresh_loop_wait_event(VideoState *is, SDL_Event *event) {
3090 3091 3092
    double remaining_time = 0.0;
    SDL_PumpEvents();
    while (!SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_ALLEVENTS)) {
3093 3094 3095 3096
        if (!cursor_hidden && av_gettime() - cursor_last_shown > CURSOR_HIDE_DELAY) {
            SDL_ShowCursor(0);
            cursor_hidden = 1;
        }
3097 3098
        if (remaining_time > 0.0)
            av_usleep((int64_t)(remaining_time * 1000000.0));
3099 3100 3101 3102
        remaining_time = REFRESH_RATE;
        if (is->show_mode != SHOW_MODE_NONE && (!is->paused || is->force_refresh))
            video_refresh(is, &remaining_time);
        SDL_PumpEvents();
3103
    }
3104 3105
}

Fabrice Bellard's avatar
Fabrice Bellard committed
3106
/* handle an event sent by the GUI */
3107
static void event_loop(VideoState *cur_stream)
Fabrice Bellard's avatar
Fabrice Bellard committed
3108 3109
{
    SDL_Event event;
3110
    double incr, pos, frac;
Fabrice Bellard's avatar
Fabrice Bellard committed
3111

Aneesh Dogra's avatar
Aneesh Dogra committed
3112
    for (;;) {
Michael Niedermayer's avatar
Michael Niedermayer committed
3113
        double x;
3114
        refresh_loop_wait_event(cur_stream, &event);
Aneesh Dogra's avatar
Aneesh Dogra committed
3115
        switch (event.type) {
Fabrice Bellard's avatar
Fabrice Bellard committed
3116
        case SDL_KEYDOWN:
3117
            if (exit_on_keydown) {
3118
                do_exit(cur_stream);
3119 3120
                break;
            }
Aneesh Dogra's avatar
Aneesh Dogra committed
3121
            switch (event.key.keysym.sym) {
Fabrice Bellard's avatar
Fabrice Bellard committed
3122 3123
            case SDLK_ESCAPE:
            case SDLK_q:
3124
                do_exit(cur_stream);
Fabrice Bellard's avatar
Fabrice Bellard committed
3125 3126
                break;
            case SDLK_f:
3127
                toggle_full_screen(cur_stream);
3128
                cur_stream->force_refresh = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
3129 3130 3131
                break;
            case SDLK_p:
            case SDLK_SPACE:
3132
                toggle_pause(cur_stream);
Fabrice Bellard's avatar
Fabrice Bellard committed
3133
                break;
Aneesh Dogra's avatar
Aneesh Dogra committed
3134
            case SDLK_s: // S: Step to next frame
3135
                step_to_next_frame(cur_stream);
3136
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
3137
            case SDLK_a:
3138
                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
3139 3140
                break;
            case SDLK_v:
3141
                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
3142
                break;
3143
            case SDLK_t:
3144
                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
3145
                break;
3146
            case SDLK_w:
3147
                toggle_audio_display(cur_stream);
Fabrice Bellard's avatar
Fabrice Bellard committed
3148
                break;
3149 3150 3151 3152 3153 3154
            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
3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166
            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:
3167
                    if (seek_by_bytes) {
Aneesh Dogra's avatar
Aneesh Dogra committed
3168 3169 3170 3171 3172
                        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
3173
                            pos = avio_tell(cur_stream->ic->pb);
3174
                        if (cur_stream->ic->bit_rate)
3175
                            incr *= cur_stream->ic->bit_rate / 8.0;
3176 3177 3178
                        else
                            incr *= 180000.0;
                        pos += incr;
3179
                        stream_seek(cur_stream, pos, incr, 1);
3180 3181
                    } else {
                        pos = get_master_clock(cur_stream);
3182 3183
                        if (isnan(pos))
                            pos = (double)cur_stream->seek_pos / AV_TIME_BASE;
3184
                        pos += incr;
3185 3186
                        if (cur_stream->ic->start_time != AV_NOPTS_VALUE && pos < cur_stream->ic->start_time / (double)AV_TIME_BASE)
                            pos = cur_stream->ic->start_time / (double)AV_TIME_BASE;
3187
                        stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0);
3188
                    }
Fabrice Bellard's avatar
Fabrice Bellard committed
3189
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
3190 3191 3192 3193
            default:
                break;
            }
            break;
3194 3195 3196
        case SDL_VIDEOEXPOSE:
            cur_stream->force_refresh = 1;
            break;
3197
        case SDL_MOUSEBUTTONDOWN:
3198
            if (exit_on_mousedown) {
3199
                do_exit(cur_stream);
3200 3201
                break;
            }
Michael Niedermayer's avatar
Michael Niedermayer committed
3202
        case SDL_MOUSEMOTION:
3203 3204 3205 3206 3207
            if (cursor_hidden) {
                SDL_ShowCursor(1);
                cursor_hidden = 0;
            }
            cursor_last_shown = av_gettime();
Aneesh Dogra's avatar
Aneesh Dogra committed
3208 3209 3210 3211
            if (event.type == SDL_MOUSEBUTTONDOWN) {
                x = event.button.x;
            } else {
                if (event.motion.state != SDL_PRESSED)
Michael Niedermayer's avatar
Michael Niedermayer committed
3212
                    break;
Aneesh Dogra's avatar
Aneesh Dogra committed
3213
                x = event.motion.x;
3214
            }
Aneesh Dogra's avatar
Aneesh Dogra committed
3215 3216
                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
3217
                    stream_seek(cur_stream, size*x/cur_stream->width, 0, 1);
Aneesh Dogra's avatar
Aneesh Dogra committed
3218
                } else {
Michael Niedermayer's avatar
Michael Niedermayer committed
3219 3220 3221
                    int64_t ts;
                    int ns, hh, mm, ss;
                    int tns, thh, tmm, tss;
Aneesh Dogra's avatar
Aneesh Dogra committed
3222 3223 3224 3225 3226 3227 3228 3229 3230
                    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
3231 3232
                    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
3233
                    ts = frac * cur_stream->ic->duration;
Michael Niedermayer's avatar
Michael Niedermayer committed
3234 3235 3236
                    if (cur_stream->ic->start_time != AV_NOPTS_VALUE)
                        ts += cur_stream->ic->start_time;
                    stream_seek(cur_stream, ts, 0, 0);
3237
                }
3238
            break;
Fabrice Bellard's avatar
Fabrice Bellard committed
3239
        case SDL_VIDEORESIZE:
3240
                screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 0,
Fabrice Bellard's avatar
Fabrice Bellard committed
3241
                                          SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
Aneesh Dogra's avatar
Aneesh Dogra committed
3242 3243
                screen_width  = cur_stream->width  = event.resize.w;
                screen_height = cur_stream->height = event.resize.h;
3244
                cur_stream->force_refresh = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
3245 3246
            break;
        case SDL_QUIT:
3247
        case FF_QUIT_EVENT:
3248
            do_exit(cur_stream);
Fabrice Bellard's avatar
Fabrice Bellard committed
3249 3250 3251 3252 3253 3254 3255 3256 3257 3258
            break;
        case FF_ALLOC_EVENT:
            alloc_picture(event.user.data1);
            break;
        default:
            break;
        }
    }
}

3259
static int opt_frame_size(void *optctx, const char *opt, const char *arg)
3260
{
3261
    av_log(NULL, AV_LOG_WARNING, "Option -s is deprecated, use -video_size.\n");
3262
    return opt_default(NULL, "video_size", arg);
3263 3264
}

3265
static int opt_width(void *optctx, const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
3266
{
3267 3268
    screen_width = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
3269 3270
}

3271
static int opt_height(void *optctx, const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
3272
{
3273 3274
    screen_height = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
3275 3276
}

3277
static int opt_format(void *optctx, const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
3278 3279 3280 3281
{
    file_iformat = av_find_input_format(arg);
    if (!file_iformat) {
        fprintf(stderr, "Unknown input format: %s\n", arg);
3282
        return AVERROR(EINVAL);
Fabrice Bellard's avatar
Fabrice Bellard committed
3283
    }
3284
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
3285
}
3286

3287
static int opt_frame_pix_fmt(void *optctx, const char *opt, const char *arg)
3288
{
3289
    av_log(NULL, AV_LOG_WARNING, "Option -pix_fmt is deprecated, use -pixel_format.\n");
3290
    return opt_default(NULL, "pixel_format", arg);
3291 3292
}

3293
static int opt_sync(void *optctx, const char *opt, const char *arg)
3294 3295 3296 3297 3298 3299 3300
{
    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;
3301
    else {
3302
        fprintf(stderr, "Unknown value for %s: %s\n", opt, arg);
3303 3304
        exit(1);
    }
3305
    return 0;
3306 3307
}

3308
static int opt_seek(void *optctx, const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
3309
{
3310 3311
    start_time = parse_time_or_die(opt, arg, 1);
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
3312 3313
}

3314
static int opt_duration(void *optctx, const char *opt, const char *arg)
3315 3316 3317 3318 3319
{
    duration = parse_time_or_die(opt, arg, 1);
    return 0;
}

3320
static int opt_show_mode(void *optctx, const char *opt, const char *arg)
3321 3322 3323 3324 3325 3326 3327 3328
{
    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;
}

3329
static void opt_input_file(void *optctx, const char *filename)
3330 3331 3332 3333
{
    if (input_filename) {
        fprintf(stderr, "Argument '%s' provided as input filename, but '%s' was already specified.\n",
                filename, input_filename);
3334
        exit(1);
3335 3336 3337 3338 3339 3340
    }
    if (!strcmp(filename, "-"))
        filename = "pipe:";
    input_filename = filename;
}

3341
static int opt_codec(void *optctx, const char *opt, const char *arg)
3342
{
3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358
   const char *spec = strchr(opt, ':');
   if (!spec) {
       fprintf(stderr, "No media specifier was specified in '%s' in option '%s'\n",
               arg, opt);
       return AVERROR(EINVAL);
   }
   spec++;
   switch (spec[0]) {
   case 'a' :    audio_codec_name = arg; break;
   case 's' : subtitle_codec_name = arg; break;
   case 'v' :    video_codec_name = arg; break;
   default:
       fprintf(stderr, "Invalid media specifier '%s' in option '%s'\n", spec, opt);
       return AVERROR(EINVAL);
   }
   return 0;
3359 3360
}

3361 3362
static int dummy;

3363
static const OptionDef options[] = {
3364
#include "cmdutils_common_opts.h"
3365 3366 3367 3368 3369 3370
    { "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" },
3371
    { "sn", OPT_BOOL, { &subtitle_disable }, "disable subtitling" },
3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396
    { "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 }, "", "" },
    { "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" },
3397
#if CONFIG_AVFILTER
3398
    { "vf", OPT_STRING | HAS_ARG, { &vfilters }, "set video filters", "filter_graph" },
Marton Balint's avatar
Marton Balint committed
3399
    { "af", OPT_STRING | HAS_ARG, { &afilters }, "set audio filters", "filter_graph" },
3400
#endif
3401 3402 3403 3404
    { "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"},
3405 3406 3407 3408
    { "codec", HAS_ARG, { .func_arg = opt_codec}, "force decoder", "decoder_name" },
    { "acodec", HAS_ARG | OPT_STRING | OPT_EXPERT, {    &audio_codec_name }, "force audio decoder",    "decoder_name" },
    { "scodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &subtitle_codec_name }, "force subtitle decoder", "decoder_name" },
    { "vcodec", HAS_ARG | OPT_STRING | OPT_EXPERT, {    &video_codec_name }, "force video decoder",    "decoder_name" },
Fabrice Bellard's avatar
Fabrice Bellard committed
3409 3410 3411
    { NULL, },
};

3412
static void show_usage(void)
Fabrice Bellard's avatar
Fabrice Bellard committed
3413
{
3414 3415 3416
    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");
3417 3418
}

3419
void show_help_default(const char *opt, const char *arg)
3420
{
3421
    av_log_set_callback(log_callback_help);
3422
    show_usage();
3423 3424
    show_help_options(options, "Main options:", 0, OPT_EXPERT, 0);
    show_help_options(options, "Advanced options:", OPT_EXPERT, 0, 0);
3425
    printf("\n");
3426 3427
    show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM);
    show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
3428
#if !CONFIG_AVFILTER
3429
    show_help_children(sws_get_class(), AV_OPT_FLAG_ENCODING_PARAM);
3430 3431
#else
    show_help_children(avfilter_get_class(), AV_OPT_FLAG_FILTERING_PARAM);
3432
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3433 3434 3435 3436
    printf("\nWhile playing:\n"
           "q, ESC              quit\n"
           "f                   toggle full screen\n"
           "p, SPC              pause\n"
3437 3438
           "a                   cycle audio channel\n"
           "v                   cycle video channel\n"
3439
           "t                   cycle subtitle channel\n"
3440
           "w                   show audio waves\n"
3441
           "s                   activate frame-step mode\n"
Fabrice Bellard's avatar
Fabrice Bellard committed
3442 3443
           "left/right          seek backward/forward 10 seconds\n"
           "down/up             seek backward/forward 1 minute\n"
3444
           "page down/page up   seek backward/forward 10 minutes\n"
3445
           "mouse click         seek to percentage in file corresponding to fraction of width\n"
Fabrice Bellard's avatar
Fabrice Bellard committed
3446 3447 3448
           );
}

3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467
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
3468 3469 3470
/* Called from the main */
int main(int argc, char **argv)
{
3471
    int flags;
3472
    VideoState *is;
3473
    char dummy_videodriver[] = "SDL_VIDEODRIVER=dummy";
3474

3475
    av_log_set_flags(AV_LOG_SKIP_REPEATED);
3476
    parse_loglevel(argc, argv, options);
3477

Fabrice Bellard's avatar
Fabrice Bellard committed
3478
    /* register all codecs, demux and protocols */
Luca Abeni's avatar
Luca Abeni committed
3479
    avcodec_register_all();
3480
#if CONFIG_AVDEVICE
Luca Abeni's avatar
Luca Abeni committed
3481
    avdevice_register_all();
3482
#endif
3483 3484 3485
#if CONFIG_AVFILTER
    avfilter_register_all();
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3486
    av_register_all();
3487
    avformat_network_init();
Fabrice Bellard's avatar
Fabrice Bellard committed
3488

3489
    init_opts();
3490

3491 3492 3493
    signal(SIGINT , sigterm_handler); /* Interrupt (ANSI).    */
    signal(SIGTERM, sigterm_handler); /* Termination (ANSI).  */

3494
    show_banner(argc, argv, options);
3495

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

3498
    if (!input_filename) {
3499
        show_usage();
3500
        fprintf(stderr, "An input file must be specified\n");
Anton Khirnov's avatar
Anton Khirnov committed
3501
        fprintf(stderr, "Use -h to get full help or, even better, run 'man %s'\n", program_name);
3502 3503
        exit(1);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
3504 3505 3506 3507

    if (display_disable) {
        video_disable = 1;
    }
3508
    flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
3509 3510
    if (audio_disable)
        flags &= ~SDL_INIT_AUDIO;
3511 3512
    if (display_disable)
        SDL_putenv(dummy_videodriver); /* For the event queue, we always need a video driver. */
3513 3514
#if !defined(__MINGW32__) && !defined(__APPLE__)
    flags |= SDL_INIT_EVENTTHREAD; /* Not supported on Windows or Mac OS X */
3515
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3516
    if (SDL_Init (flags)) {
3517
        fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
3518
        fprintf(stderr, "(Did you set the DISPLAY variable?)\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
3519 3520 3521 3522
        exit(1);
    }

    if (!display_disable) {
3523 3524 3525
        const SDL_VideoInfo *vi = SDL_GetVideoInfo();
        fs_screen_width = vi->current_w;
        fs_screen_height = vi->current_h;
Fabrice Bellard's avatar
Fabrice Bellard committed
3526 3527 3528 3529 3530 3531
    }

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

3532 3533 3534 3535 3536
    if (av_lockmgr_register(lockmgr)) {
        fprintf(stderr, "Could not initialize lock manager!\n");
        do_exit(NULL);
    }

3537
    av_init_packet(&flush_pkt);
Luca Barbato's avatar
Luca Barbato committed
3538
    flush_pkt.data = (uint8_t *)&flush_pkt;
3539

3540 3541 3542 3543 3544
    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
3545

3546
    event_loop(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
3547 3548 3549 3550 3551

    /* never returns */

    return 0;
}