ffplay.c 130 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 32
#include <stdint.h>

33
#include "libavutil/avstring.h"
34
#include "libavutil/eval.h"
35
#include "libavutil/mathematics.h"
36
#include "libavutil/pixdesc.h"
37
#include "libavutil/imgutils.h"
38
#include "libavutil/dict.h"
39 40
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
41
#include "libavutil/avassert.h"
42
#include "libavutil/time.h"
43 44 45
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
46
#include "libavutil/opt.h"
47
#include "libavcodec/avfft.h"
48
#include "libswresample/swresample.h"
Fabrice Bellard's avatar
Fabrice Bellard committed
49

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

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

59
#include "cmdutils.h"
60

61 62
#include <assert.h>

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

66
#define MAX_QUEUE_SIZE (15 * 1024 * 1024)
67
#define MIN_FRAMES 25
68 69
#define EXTERNAL_CLOCK_MIN_FRAMES 2
#define EXTERNAL_CLOCK_MAX_FRAMES 10
Fabrice Bellard's avatar
Fabrice Bellard committed
70

71
/* Minimum SDL audio buffer size, in samples. */
72 73
#define SDL_AUDIO_MIN_BUFFER_SIZE 512
/* Calculate actual buffer size keeping in mind not cause too frequent audio callbacks */
74
#define SDL_AUDIO_MAX_CALLBACKS_PER_SEC 30
75

76 77 78
/* Step size for volume control */
#define SDL_VOLUME_STEP (SDL_MIX_MAXVOLUME / 50)

79
/* no AV sync correction is done if below the minimum AV sync threshold */
80
#define AV_SYNC_THRESHOLD_MIN 0.04
81 82 83 84
/* AV sync correction is done if above the maximum AV sync threshold */
#define AV_SYNC_THRESHOLD_MAX 0.1
/* If a frame duration is longer than this, it will not be duplicated to compensate AV sync */
#define AV_SYNC_FRAMEDUP_THRESHOLD 0.1
85 86 87 88 89 90
/* 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

91 92 93 94 95
/* 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

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

99 100 101
/* 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
102
/* NOTE: the size must be big enough to compensate the hardware audio buffersize size */
103 104
/* 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
105

106 107
#define CURSOR_HIDE_DELAY 1000000

108 109
#define USE_ONEPASS_SUBTITLE_RENDER 1

110
static unsigned sws_flags = SWS_BICUBIC;
111

112 113 114 115 116 117
typedef struct MyAVPacketList {
    AVPacket pkt;
    struct MyAVPacketList *next;
    int serial;
} MyAVPacketList;

Fabrice Bellard's avatar
Fabrice Bellard committed
118
typedef struct PacketQueue {
119
    MyAVPacketList *first_pkt, *last_pkt;
Fabrice Bellard's avatar
Fabrice Bellard committed
120 121
    int nb_packets;
    int size;
122
    int64_t duration;
Fabrice Bellard's avatar
Fabrice Bellard committed
123
    int abort_request;
124
    int serial;
Fabrice Bellard's avatar
Fabrice Bellard committed
125 126 127 128
    SDL_mutex *mutex;
    SDL_cond *cond;
} PacketQueue;

129
#define VIDEO_PICTURE_QUEUE_SIZE 3
130
#define SUBPICTURE_QUEUE_SIZE 16
131 132
#define SAMPLE_QUEUE_SIZE 9
#define FRAME_QUEUE_SIZE FFMAX(SAMPLE_QUEUE_SIZE, FFMAX(VIDEO_PICTURE_QUEUE_SIZE, SUBPICTURE_QUEUE_SIZE))
133

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

143 144 145 146 147 148 149 150 151 152
typedef struct Clock {
    double pts;           /* clock base */
    double pts_drift;     /* clock base minus time at which we updated the clock */
    double last_updated;
    double speed;
    int serial;           /* clock is based on a packet with this serial */
    int paused;
    int *queue_serial;    /* pointer to the current packet queue serial, used for obsolete clock detection */
} Clock;

153 154 155 156 157 158 159 160
/* Common struct for handling all types of decoded data and allocated render buffers. */
typedef struct Frame {
    AVFrame *frame;
    AVSubtitle sub;
    int serial;
    double pts;           /* presentation timestamp for the frame */
    double duration;      /* estimated duration of the frame */
    int64_t pos;          /* byte position of the frame in the input file */
161
    SDL_Texture *bmp;
162 163 164
    int allocated;
    int width;
    int height;
165
    int format;
166
    AVRational sar;
167
    int uploaded;
168
    int flip_v;
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
} Frame;

typedef struct FrameQueue {
    Frame queue[FRAME_QUEUE_SIZE];
    int rindex;
    int windex;
    int size;
    int max_size;
    int keep_last;
    int rindex_shown;
    SDL_mutex *mutex;
    SDL_cond *cond;
    PacketQueue *pktq;
} FrameQueue;

Fabrice Bellard's avatar
Fabrice Bellard committed
184 185 186
enum {
    AV_SYNC_AUDIO_MASTER, /* default choice */
    AV_SYNC_VIDEO_MASTER,
187
    AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */
Fabrice Bellard's avatar
Fabrice Bellard committed
188 189
};

190 191 192 193 194 195 196 197 198
typedef struct Decoder {
    AVPacket pkt;
    AVPacket pkt_temp;
    PacketQueue *queue;
    AVCodecContext *avctx;
    int pkt_serial;
    int finished;
    int packet_pending;
    SDL_cond *empty_queue_cond;
199 200 201 202
    int64_t start_pts;
    AVRational start_pts_tb;
    int64_t next_pts;
    AVRational next_pts_tb;
203
    SDL_Thread *decoder_tid;
204 205
} Decoder;

Fabrice Bellard's avatar
Fabrice Bellard committed
206
typedef struct VideoState {
207
    SDL_Thread *read_tid;
208
    AVInputFormat *iformat;
Fabrice Bellard's avatar
Fabrice Bellard committed
209
    int abort_request;
210
    int force_refresh;
Fabrice Bellard's avatar
Fabrice Bellard committed
211
    int paused;
212
    int last_paused;
213
    int queue_attachments_req;
Fabrice Bellard's avatar
Fabrice Bellard committed
214
    int seek_req;
215
    int seek_flags;
Fabrice Bellard's avatar
Fabrice Bellard committed
216
    int64_t seek_pos;
217
    int64_t seek_rel;
218
    int read_pause_return;
Fabrice Bellard's avatar
Fabrice Bellard committed
219
    AVFormatContext *ic;
220
    int realtime;
Fabrice Bellard's avatar
Fabrice Bellard committed
221

222 223 224 225
    Clock audclk;
    Clock vidclk;
    Clock extclk;

226 227
    FrameQueue pictq;
    FrameQueue subpq;
228
    FrameQueue sampq;
229

230 231 232 233
    Decoder auddec;
    Decoder viddec;
    Decoder subdec;

Fabrice Bellard's avatar
Fabrice Bellard committed
234
    int audio_stream;
235

Fabrice Bellard's avatar
Fabrice Bellard committed
236
    int av_sync_type;
237

238
    double audio_clock;
239
    int audio_clock_serial;
240 241 242 243
    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
244 245 246
    AVStream *audio_st;
    PacketQueue audioq;
    int audio_hw_buf_size;
247
    uint8_t *audio_buf;
248
    uint8_t *audio_buf1;
249
    unsigned int audio_buf_size; /* in bytes */
250
    unsigned int audio_buf1_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
251
    int audio_buf_index; /* in bytes */
252
    int audio_write_buf_size;
253 254
    int audio_volume;
    int muted;
255
    struct AudioParams audio_src;
Marton Balint's avatar
Marton Balint committed
256 257 258
#if CONFIG_AVFILTER
    struct AudioParams audio_filter_src;
#endif
259
    struct AudioParams audio_tgt;
260
    struct SwrContext *swr_ctx;
261 262
    int frame_drops_early;
    int frame_drops_late;
263

264
    enum ShowMode {
265
        SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB
266
    } show_mode;
Fabrice Bellard's avatar
Fabrice Bellard committed
267 268
    int16_t sample_array[SAMPLE_ARRAY_SIZE];
    int sample_array_index;
269
    int last_i_start;
270
    RDFTContext *rdft;
271
    int rdft_bits;
Måns Rullgård's avatar
Måns Rullgård committed
272
    FFTSample *rdft_data;
273
    int xpos;
274
    double last_vis_time;
275 276
    SDL_Texture *vis_texture;
    SDL_Texture *sub_texture;
277

278 279 280
    int subtitle_stream;
    AVStream *subtitle_st;
    PacketQueue subtitleq;
281

282
    double frame_timer;
283 284
    double frame_last_returned_time;
    double frame_last_filter_delay;
Fabrice Bellard's avatar
Fabrice Bellard committed
285 286 287
    int video_stream;
    AVStream *video_st;
    PacketQueue videoq;
288
    double max_frame_duration;      // maximum duration of a frame - above this, we consider the jump a timestamp discontinuity
289
    struct SwsContext *img_convert_ctx;
290
    struct SwsContext *sub_convert_ctx;
291
    int eof;
292

293
    char *filename;
Fabrice Bellard's avatar
Fabrice Bellard committed
294
    int width, height, xleft, ytop;
295
    int step;
296

297
#if CONFIG_AVFILTER
298
    int vfilter_idx;
299 300
    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
301 302 303
    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
304
#endif
305

306
    int last_video_stream, last_audio_stream, last_subtitle_stream;
307 308

    SDL_cond *continue_read_thread;
Fabrice Bellard's avatar
Fabrice Bellard committed
309 310 311 312 313
} VideoState;

/* options specified by the user */
static AVInputFormat *file_iformat;
static const char *input_filename;
314
static const char *window_title;
315 316
static int default_width  = 640;
static int default_height = 480;
Aneesh Dogra's avatar
Aneesh Dogra committed
317
static int screen_width  = 0;
318
static int screen_height = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
319 320
static int audio_disable;
static int video_disable;
321
static int subtitle_disable;
322
static const char* wanted_stream_spec[AVMEDIA_TYPE_NB] = {0};
Aneesh Dogra's avatar
Aneesh Dogra committed
323
static int seek_by_bytes = -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
324
static int display_disable;
325
static int show_status = 1;
326
static int av_sync_type = AV_SYNC_AUDIO_MASTER;
Fabrice Bellard's avatar
Fabrice Bellard committed
327
static int64_t start_time = AV_NOPTS_VALUE;
328
static int64_t duration = AV_NOPTS_VALUE;
329
static int fast = 0;
330
static int genpts = 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
331
static int lowres = 0;
Aneesh Dogra's avatar
Aneesh Dogra committed
332
static int decoder_reorder_pts = -1;
333
static int autoexit;
334 335
static int exit_on_keydown;
static int exit_on_mousedown;
Aneesh Dogra's avatar
Aneesh Dogra committed
336
static int loop = 1;
337
static int framedrop = -1;
338
static int infinite_buffer = -1;
339
static enum ShowMode show_mode = SHOW_MODE_NONE;
340 341 342
static const char *audio_codec_name;
static const char *subtitle_codec_name;
static const char *video_codec_name;
343
double rdftspeed = 0.02;
344 345
static int64_t cursor_last_shown;
static int cursor_hidden = 0;
346
#if CONFIG_AVFILTER
347 348
static const char **vfilters_list = NULL;
static int nb_vfilters = 0;
Marton Balint's avatar
Marton Balint committed
349
static char *afilters = NULL;
350
#endif
351
static int autorotate = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
352 353 354

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

357
static AVPacket flush_pkt;
358

Fabrice Bellard's avatar
Fabrice Bellard committed
359
#define FF_ALLOC_EVENT   (SDL_USEREVENT)
360
#define FF_QUIT_EVENT    (SDL_USEREVENT + 2)
Fabrice Bellard's avatar
Fabrice Bellard committed
361

362 363
static SDL_Window *window;
static SDL_Renderer *renderer;
Fabrice Bellard's avatar
Fabrice Bellard committed
364

365 366 367 368 369 370 371 372 373
#if CONFIG_AVFILTER
static int opt_add_vfilter(void *optctx, const char *opt, const char *arg)
{
    GROW_ARRAY(vfilters_list, nb_vfilters);
    vfilters_list[nb_vfilters - 1] = arg;
    return 0;
}
#endif

Marton Balint's avatar
Marton Balint committed
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
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;
}

394 395
static void free_picture(Frame *vp);

396
static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)
397
{
398
    MyAVPacketList *pkt1;
399

400 401
    if (q->abort_request)
       return -1;
402

403
    pkt1 = av_malloc(sizeof(MyAVPacketList));
404 405 406 407
    if (!pkt1)
        return -1;
    pkt1->pkt = *pkt;
    pkt1->next = NULL;
408 409 410
    if (pkt == &flush_pkt)
        q->serial++;
    pkt1->serial = q->serial;
411 412 413 414 415 416 417 418

    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);
419
    q->duration += pkt1->pkt.duration;
420 421
    /* XXX: should duplicate packet data in DV case */
    SDL_CondSignal(q->cond);
422 423 424 425 426 427
    return 0;
}

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

429 430
    SDL_LockMutex(q->mutex);
    ret = packet_queue_put_private(q, pkt);
431
    SDL_UnlockMutex(q->mutex);
432 433

    if (pkt != &flush_pkt && ret < 0)
434
        av_packet_unref(pkt);
435 436

    return ret;
437
}
438

439 440 441 442 443 444 445 446 447 448
static int packet_queue_put_nullpacket(PacketQueue *q, int stream_index)
{
    AVPacket pkt1, *pkt = &pkt1;
    av_init_packet(pkt);
    pkt->data = NULL;
    pkt->size = 0;
    pkt->stream_index = stream_index;
    return packet_queue_put(q, pkt);
}

Fabrice Bellard's avatar
Fabrice Bellard committed
449
/* packet queue handling */
450
static int packet_queue_init(PacketQueue *q)
Fabrice Bellard's avatar
Fabrice Bellard committed
451 452 453
{
    memset(q, 0, sizeof(PacketQueue));
    q->mutex = SDL_CreateMutex();
454
    if (!q->mutex) {
455
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
456 457
        return AVERROR(ENOMEM);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
458
    q->cond = SDL_CreateCond();
459
    if (!q->cond) {
460
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
461 462
        return AVERROR(ENOMEM);
    }
463
    q->abort_request = 1;
464
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
465 466
}

Fabrice Bellard's avatar
Fabrice Bellard committed
467
static void packet_queue_flush(PacketQueue *q)
Fabrice Bellard's avatar
Fabrice Bellard committed
468
{
469
    MyAVPacketList *pkt, *pkt1;
Fabrice Bellard's avatar
Fabrice Bellard committed
470

471
    SDL_LockMutex(q->mutex);
472
    for (pkt = q->first_pkt; pkt; pkt = pkt1) {
Fabrice Bellard's avatar
Fabrice Bellard committed
473
        pkt1 = pkt->next;
474
        av_packet_unref(&pkt->pkt);
475
        av_freep(&pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
476
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
477 478 479 480
    q->last_pkt = NULL;
    q->first_pkt = NULL;
    q->nb_packets = 0;
    q->size = 0;
481
    q->duration = 0;
482
    SDL_UnlockMutex(q->mutex);
Fabrice Bellard's avatar
Fabrice Bellard committed
483 484
}

485
static void packet_queue_destroy(PacketQueue *q)
Fabrice Bellard's avatar
Fabrice Bellard committed
486 487
{
    packet_queue_flush(q);
Fabrice Bellard's avatar
Fabrice Bellard committed
488 489 490 491 492 493 494 495 496
    SDL_DestroyMutex(q->mutex);
    SDL_DestroyCond(q->cond);
}

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

    q->abort_request = 1;
497

Fabrice Bellard's avatar
Fabrice Bellard committed
498 499 500 501 502
    SDL_CondSignal(q->cond);

    SDL_UnlockMutex(q->mutex);
}

503 504 505 506 507 508 509 510
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
511
/* return < 0 if aborted, 0 if no packet and > 0 if packet.  */
512
static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial)
Fabrice Bellard's avatar
Fabrice Bellard committed
513
{
514
    MyAVPacketList *pkt1;
Fabrice Bellard's avatar
Fabrice Bellard committed
515 516 517 518
    int ret;

    SDL_LockMutex(q->mutex);

Aneesh Dogra's avatar
Aneesh Dogra committed
519
    for (;;) {
Fabrice Bellard's avatar
Fabrice Bellard committed
520 521 522 523
        if (q->abort_request) {
            ret = -1;
            break;
        }
524

Fabrice Bellard's avatar
Fabrice Bellard committed
525 526 527 528 529 530
        pkt1 = q->first_pkt;
        if (pkt1) {
            q->first_pkt = pkt1->next;
            if (!q->first_pkt)
                q->last_pkt = NULL;
            q->nb_packets--;
531
            q->size -= pkt1->pkt.size + sizeof(*pkt1);
532
            q->duration -= pkt1->pkt.duration;
Fabrice Bellard's avatar
Fabrice Bellard committed
533
            *pkt = pkt1->pkt;
534 535
            if (serial)
                *serial = pkt1->serial;
Fabrice Bellard's avatar
Fabrice Bellard committed
536 537 538 539 540 541 542 543 544 545 546 547 548 549
            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;
}

550 551 552 553 554
static void decoder_init(Decoder *d, AVCodecContext *avctx, PacketQueue *queue, SDL_cond *empty_queue_cond) {
    memset(d, 0, sizeof(Decoder));
    d->avctx = avctx;
    d->queue = queue;
    d->empty_queue_cond = empty_queue_cond;
555
    d->start_pts = AV_NOPTS_VALUE;
556 557
}

558
static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtitle *sub) {
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
    int got_frame = 0;

    do {
        int ret = -1;

        if (d->queue->abort_request)
            return -1;

        if (!d->packet_pending || d->queue->serial != d->pkt_serial) {
            AVPacket pkt;
            do {
                if (d->queue->nb_packets == 0)
                    SDL_CondSignal(d->empty_queue_cond);
                if (packet_queue_get(d->queue, &pkt, 1, &d->pkt_serial) < 0)
                    return -1;
                if (pkt.data == flush_pkt.data) {
                    avcodec_flush_buffers(d->avctx);
                    d->finished = 0;
577 578
                    d->next_pts = d->start_pts;
                    d->next_pts_tb = d->start_pts_tb;
579 580
                }
            } while (pkt.data == flush_pkt.data || d->queue->serial != d->pkt_serial);
581
            av_packet_unref(&d->pkt);
582 583 584 585 586 587
            d->pkt_temp = d->pkt = pkt;
            d->packet_pending = 1;
        }

        switch (d->avctx->codec_type) {
            case AVMEDIA_TYPE_VIDEO:
588 589 590 591
                ret = avcodec_decode_video2(d->avctx, frame, &got_frame, &d->pkt_temp);
                if (got_frame) {
                    if (decoder_reorder_pts == -1) {
                        frame->pts = av_frame_get_best_effort_timestamp(frame);
592
                    } else if (!decoder_reorder_pts) {
593 594 595
                        frame->pts = frame->pkt_dts;
                    }
                }
596 597
                break;
            case AVMEDIA_TYPE_AUDIO:
598 599 600 601
                ret = avcodec_decode_audio4(d->avctx, frame, &got_frame, &d->pkt_temp);
                if (got_frame) {
                    AVRational tb = (AVRational){1, frame->sample_rate};
                    if (frame->pts != AV_NOPTS_VALUE)
602
                        frame->pts = av_rescale_q(frame->pts, av_codec_get_pkt_timebase(d->avctx), tb);
603 604 605 606 607 608 609
                    else if (d->next_pts != AV_NOPTS_VALUE)
                        frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb);
                    if (frame->pts != AV_NOPTS_VALUE) {
                        d->next_pts = frame->pts + frame->nb_samples;
                        d->next_pts_tb = tb;
                    }
                }
610 611
                break;
            case AVMEDIA_TYPE_SUBTITLE:
612
                ret = avcodec_decode_subtitle2(d->avctx, sub, &got_frame, &d->pkt_temp);
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
                break;
        }

        if (ret < 0) {
            d->packet_pending = 0;
        } else {
            d->pkt_temp.dts =
            d->pkt_temp.pts = AV_NOPTS_VALUE;
            if (d->pkt_temp.data) {
                if (d->avctx->codec_type != AVMEDIA_TYPE_AUDIO)
                    ret = d->pkt_temp.size;
                d->pkt_temp.data += ret;
                d->pkt_temp.size -= ret;
                if (d->pkt_temp.size <= 0)
                    d->packet_pending = 0;
            } else {
                if (!got_frame) {
                    d->packet_pending = 0;
                    d->finished = d->pkt_serial;
                }
            }
        }
    } while (!got_frame && !d->finished);

    return got_frame;
}

static void decoder_destroy(Decoder *d) {
641
    av_packet_unref(&d->pkt);
642
    avcodec_free_context(&d->avctx);
643 644
}

645 646 647 648 649 650 651 652 653 654
static void frame_queue_unref_item(Frame *vp)
{
    av_frame_unref(vp->frame);
    avsubtitle_free(&vp->sub);
}

static int frame_queue_init(FrameQueue *f, PacketQueue *pktq, int max_size, int keep_last)
{
    int i;
    memset(f, 0, sizeof(FrameQueue));
655 656
    if (!(f->mutex = SDL_CreateMutex())) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
657
        return AVERROR(ENOMEM);
658 659 660
    }
    if (!(f->cond = SDL_CreateCond())) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
661
        return AVERROR(ENOMEM);
662
    }
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 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 718 719 720 721 722
    f->pktq = pktq;
    f->max_size = FFMIN(max_size, FRAME_QUEUE_SIZE);
    f->keep_last = !!keep_last;
    for (i = 0; i < f->max_size; i++)
        if (!(f->queue[i].frame = av_frame_alloc()))
            return AVERROR(ENOMEM);
    return 0;
}

static void frame_queue_destory(FrameQueue *f)
{
    int i;
    for (i = 0; i < f->max_size; i++) {
        Frame *vp = &f->queue[i];
        frame_queue_unref_item(vp);
        av_frame_free(&vp->frame);
        free_picture(vp);
    }
    SDL_DestroyMutex(f->mutex);
    SDL_DestroyCond(f->cond);
}

static void frame_queue_signal(FrameQueue *f)
{
    SDL_LockMutex(f->mutex);
    SDL_CondSignal(f->cond);
    SDL_UnlockMutex(f->mutex);
}

static Frame *frame_queue_peek(FrameQueue *f)
{
    return &f->queue[(f->rindex + f->rindex_shown) % f->max_size];
}

static Frame *frame_queue_peek_next(FrameQueue *f)
{
    return &f->queue[(f->rindex + f->rindex_shown + 1) % f->max_size];
}

static Frame *frame_queue_peek_last(FrameQueue *f)
{
    return &f->queue[f->rindex];
}

static Frame *frame_queue_peek_writable(FrameQueue *f)
{
    /* wait until we have space to put a new frame */
    SDL_LockMutex(f->mutex);
    while (f->size >= f->max_size &&
           !f->pktq->abort_request) {
        SDL_CondWait(f->cond, f->mutex);
    }
    SDL_UnlockMutex(f->mutex);

    if (f->pktq->abort_request)
        return NULL;

    return &f->queue[f->windex];
}

723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
static Frame *frame_queue_peek_readable(FrameQueue *f)
{
    /* wait until we have a readable a new frame */
    SDL_LockMutex(f->mutex);
    while (f->size - f->rindex_shown <= 0 &&
           !f->pktq->abort_request) {
        SDL_CondWait(f->cond, f->mutex);
    }
    SDL_UnlockMutex(f->mutex);

    if (f->pktq->abort_request)
        return NULL;

    return &f->queue[(f->rindex + f->rindex_shown) % f->max_size];
}

739 740 741 742 743 744
static void frame_queue_push(FrameQueue *f)
{
    if (++f->windex == f->max_size)
        f->windex = 0;
    SDL_LockMutex(f->mutex);
    f->size++;
745
    SDL_CondSignal(f->cond);
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769
    SDL_UnlockMutex(f->mutex);
}

static void frame_queue_next(FrameQueue *f)
{
    if (f->keep_last && !f->rindex_shown) {
        f->rindex_shown = 1;
        return;
    }
    frame_queue_unref_item(&f->queue[f->rindex]);
    if (++f->rindex == f->max_size)
        f->rindex = 0;
    SDL_LockMutex(f->mutex);
    f->size--;
    SDL_CondSignal(f->cond);
    SDL_UnlockMutex(f->mutex);
}

/* return the number of undisplayed frames in the queue */
static int frame_queue_nb_remaining(FrameQueue *f)
{
    return f->size - f->rindex_shown;
}

770 771 772 773 774 775 776 777 778 779
/* return last shown position */
static int64_t frame_queue_last_pos(FrameQueue *f)
{
    Frame *fp = &f->queue[f->rindex];
    if (f->rindex_shown && fp->serial == f->pktq->serial)
        return fp->pos;
    else
        return -1;
}

780 781 782 783 784 785 786 787 788
static void decoder_abort(Decoder *d, FrameQueue *fq)
{
    packet_queue_abort(d->queue);
    frame_queue_signal(fq);
    SDL_WaitThread(d->decoder_tid, NULL);
    d->decoder_tid = NULL;
    packet_queue_flush(d->queue);
}

789
static inline void fill_rectangle(int x, int y, int w, int h)
Fabrice Bellard's avatar
Fabrice Bellard committed
790 791 792 793 794 795
{
    SDL_Rect rect;
    rect.x = x;
    rect.y = y;
    rect.w = w;
    rect.h = h;
796 797
    if (w && h)
        SDL_RenderFillRect(renderer, &rect);
798 799
}

800
static void free_picture(Frame *vp)
801 802
{
     if (vp->bmp) {
803
         SDL_DestroyTexture(vp->bmp);
804 805 806 807
         vp->bmp = NULL;
     }
}

808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829
static int realloc_texture(SDL_Texture **texture, Uint32 new_format, int new_width, int new_height, SDL_BlendMode blendmode, int init_texture)
{
    Uint32 format;
    int access, w, h;
    if (SDL_QueryTexture(*texture, &format, &access, &w, &h) < 0 || new_width != w || new_height != h || new_format != format) {
        void *pixels;
        int pitch;
        SDL_DestroyTexture(*texture);
        if (!(*texture = SDL_CreateTexture(renderer, new_format, SDL_TEXTUREACCESS_STREAMING, new_width, new_height)))
            return -1;
        if (SDL_SetTextureBlendMode(*texture, blendmode) < 0)
            return -1;
        if (init_texture) {
            if (SDL_LockTexture(*texture, NULL, &pixels, &pitch) < 0)
                return -1;
            memset(pixels, 0, pitch * new_height);
            SDL_UnlockTexture(*texture);
        }
    }
    return 0;
}

830 831 832
static void calculate_display_rect(SDL_Rect *rect,
                                   int scr_xleft, int scr_ytop, int scr_width, int scr_height,
                                   int pic_width, int pic_height, AVRational pic_sar)
833 834 835 836
{
    float aspect_ratio;
    int width, height, x, y;

837
    if (pic_sar.num == 0)
838 839
        aspect_ratio = 0;
    else
840
        aspect_ratio = av_q2d(pic_sar);
841 842 843

    if (aspect_ratio <= 0.0)
        aspect_ratio = 1.0;
844
    aspect_ratio *= (float)pic_width / (float)pic_height;
845 846 847

    /* XXX: we suppose the screen has a 1.0 pixel ratio */
    height = scr_height;
848
    width = lrint(height * aspect_ratio) & ~1;
849 850
    if (width > scr_width) {
        width = scr_width;
851
        height = lrint(width / aspect_ratio) & ~1;
852 853 854 855 856 857 858 859 860
    }
    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);
}

861 862 863 864
static int upload_texture(SDL_Texture *tex, AVFrame *frame, struct SwsContext **img_convert_ctx) {
    int ret = 0;
    switch (frame->format) {
        case AV_PIX_FMT_YUV420P:
865 866 867 868
            if (frame->linesize[0] < 0 || frame->linesize[1] < 0 || frame->linesize[2] < 0) {
                av_log(NULL, AV_LOG_ERROR, "Negative linesize is not supported for YUV.\n");
                return -1;
            }
869 870 871 872 873
            ret = SDL_UpdateYUVTexture(tex, NULL, frame->data[0], frame->linesize[0],
                                                  frame->data[1], frame->linesize[1],
                                                  frame->data[2], frame->linesize[2]);
            break;
        case AV_PIX_FMT_BGRA:
874 875 876 877 878
            if (frame->linesize[0] < 0) {
                ret = SDL_UpdateTexture(tex, NULL, frame->data[0] + frame->linesize[0] * (frame->height - 1), -frame->linesize[0]);
            } else {
                ret = SDL_UpdateTexture(tex, NULL, frame->data[0], frame->linesize[0]);
            }
879 880 881 882 883 884 885
            break;
        default:
            /* This should only happen if we are not using avfilter... */
            *img_convert_ctx = sws_getCachedContext(*img_convert_ctx,
                frame->width, frame->height, frame->format, frame->width, frame->height,
                AV_PIX_FMT_BGRA, sws_flags, NULL, NULL, NULL);
            if (*img_convert_ctx != NULL) {
886 887 888
                uint8_t *pixels[4];
                int pitch[4];
                if (!SDL_LockTexture(tex, NULL, (void **)pixels, pitch)) {
889
                    sws_scale(*img_convert_ctx, (const uint8_t * const *)frame->data, frame->linesize,
890
                              0, frame->height, pixels, pitch);
891 892 893 894 895 896 897 898 899 900 901
                    SDL_UnlockTexture(tex);
                }
            } else {
                av_log(NULL, AV_LOG_FATAL, "Cannot initialize the conversion context\n");
                ret = -1;
            }
            break;
    }
    return ret;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
902 903
static void video_image_display(VideoState *is)
{
904
    Frame *vp;
905
    Frame *sp = NULL;
Fabrice Bellard's avatar
Fabrice Bellard committed
906 907
    SDL_Rect rect;

908
    vp = frame_queue_peek_last(&is->pictq);
Fabrice Bellard's avatar
Fabrice Bellard committed
909
    if (vp->bmp) {
910
        if (is->subtitle_st) {
911 912
            if (frame_queue_nb_remaining(&is->subpq) > 0) {
                sp = frame_queue_peek(&is->subpq);
913

914
                if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) {
915
                    if (!sp->uploaded) {
916 917
                        uint8_t* pixels[4];
                        int pitch[4];
918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941
                        int i;
                        if (!sp->width || !sp->height) {
                            sp->width = vp->width;
                            sp->height = vp->height;
                        }
                        if (realloc_texture(&is->sub_texture, SDL_PIXELFORMAT_ARGB8888, sp->width, sp->height, SDL_BLENDMODE_BLEND, 1) < 0)
                            return;

                        for (i = 0; i < sp->sub.num_rects; i++) {
                            AVSubtitleRect *sub_rect = sp->sub.rects[i];

                            sub_rect->x = av_clip(sub_rect->x, 0, sp->width );
                            sub_rect->y = av_clip(sub_rect->y, 0, sp->height);
                            sub_rect->w = av_clip(sub_rect->w, 0, sp->width  - sub_rect->x);
                            sub_rect->h = av_clip(sub_rect->h, 0, sp->height - sub_rect->y);

                            is->sub_convert_ctx = sws_getCachedContext(is->sub_convert_ctx,
                                sub_rect->w, sub_rect->h, AV_PIX_FMT_PAL8,
                                sub_rect->w, sub_rect->h, AV_PIX_FMT_BGRA,
                                0, NULL, NULL, NULL);
                            if (!is->sub_convert_ctx) {
                                av_log(NULL, AV_LOG_FATAL, "Cannot initialize the conversion context\n");
                                return;
                            }
942
                            if (!SDL_LockTexture(is->sub_texture, (SDL_Rect *)sub_rect, (void **)pixels, pitch)) {
943
                                sws_scale(is->sub_convert_ctx, (const uint8_t * const *)sub_rect->data, sub_rect->linesize,
944
                                          0, sub_rect->h, pixels, pitch);
945 946 947 948 949 950 951
                                SDL_UnlockTexture(is->sub_texture);
                            }
                        }
                        sp->uploaded = 1;
                    }
                } else
                    sp = NULL;
952 953 954
            }
        }

955
        calculate_display_rect(&rect, is->xleft, is->ytop, is->width, is->height, vp->width, vp->height, vp->sar);
956

957 958 959 960
        if (!vp->uploaded) {
            if (upload_texture(vp->bmp, vp->frame, &is->img_convert_ctx) < 0)
                return;
            vp->uploaded = 1;
961
            vp->flip_v = vp->frame->linesize[0] < 0;
962
        }
963

964
        SDL_RenderCopyEx(renderer, vp->bmp, NULL, &rect, 0, NULL, vp->flip_v ? SDL_FLIP_VERTICAL : 0);
965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980
        if (sp) {
#if USE_ONEPASS_SUBTITLE_RENDER
            SDL_RenderCopy(renderer, is->sub_texture, NULL, &rect);
#else
            int i;
            double xratio = (double)rect.w / (double)sp->width;
            double yratio = (double)rect.h / (double)sp->height;
            for (i = 0; i < sp->sub.num_rects; i++) {
                SDL_Rect *sub_rect = (SDL_Rect*)sp->sub.rects[i];
                SDL_Rect target = {.x = rect.x + sub_rect->x * xratio,
                                   .y = rect.y + sub_rect->y * yratio,
                                   .w = sub_rect->w * xratio,
                                   .h = sub_rect->h * yratio};
                SDL_RenderCopy(renderer, is->sub_texture, sub_rect, &target);
            }
#endif
981
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
982 983 984 985 986
    }
}

static inline int compute_mod(int a, int b)
{
987
    return a < 0 ? a%b + b : a%b;
Fabrice Bellard's avatar
Fabrice Bellard committed
988 989 990 991 992
}

static void video_audio_display(VideoState *s)
{
    int i, i_start, x, y1, y, ys, delay, n, nb_display_channels;
993
    int ch, channels, h, h2;
994
    int64_t time_diff;
995 996
    int rdft_bits, nb_freq;

Aneesh Dogra's avatar
Aneesh Dogra committed
997
    for (rdft_bits = 1; (1 << rdft_bits) < 2 * s->height; rdft_bits++)
998
        ;
Aneesh Dogra's avatar
Aneesh Dogra committed
999
    nb_freq = 1 << (rdft_bits - 1);
1000

Fabrice Bellard's avatar
Fabrice Bellard committed
1001
    /* compute display index : center on currently output samples */
1002
    channels = s->audio_tgt.channels;
Fabrice Bellard's avatar
Fabrice Bellard committed
1003
    nb_display_channels = channels;
1004
    if (!s->paused) {
1005
        int data_used= s->show_mode == SHOW_MODE_WAVES ? s->width : (2*nb_freq);
1006
        n = 2 * channels;
1007
        delay = s->audio_write_buf_size;
1008
        delay /= n;
1009

1010 1011 1012
        /* to be more precise, we take into account the time spent since
           the last buffer computation */
        if (audio_callback_time) {
1013
            time_diff = av_gettime_relative() - audio_callback_time;
1014
            delay -= (time_diff * s->audio_tgt.freq) / 1000000;
1015
        }
1016

Aneesh Dogra's avatar
Aneesh Dogra committed
1017
        delay += 2 * data_used;
1018 1019
        if (delay < data_used)
            delay = data_used;
1020 1021

        i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
1022
        if (s->show_mode == SHOW_MODE_WAVES) {
Aneesh Dogra's avatar
Aneesh Dogra committed
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033
            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;
1034
                }
1035 1036 1037
            }
        }

1038 1039 1040
        s->last_i_start = i_start;
    } else {
        i_start = s->last_i_start;
Fabrice Bellard's avatar
Fabrice Bellard committed
1041 1042
    }

1043
    if (s->show_mode == SHOW_MODE_WAVES) {
1044
        SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
1045 1046 1047 1048 1049

        /* 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
1050
        for (ch = 0; ch < nb_display_channels; ch++) {
1051 1052
            i = i_start + ch;
            y1 = s->ytop + ch * h + (h / 2); /* position of center line */
Aneesh Dogra's avatar
Aneesh Dogra committed
1053
            for (x = 0; x < s->width; x++) {
1054 1055 1056 1057 1058 1059 1060
                y = (s->sample_array[i] * h2) >> 15;
                if (y < 0) {
                    y = -y;
                    ys = y1 - y;
                } else {
                    ys = y1;
                }
1061
                fill_rectangle(s->xleft + x, ys, 1, y);
1062 1063 1064
                i += channels;
                if (i >= SAMPLE_ARRAY_SIZE)
                    i -= SAMPLE_ARRAY_SIZE;
Fabrice Bellard's avatar
Fabrice Bellard committed
1065 1066 1067
            }
        }

1068
        SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
Fabrice Bellard's avatar
Fabrice Bellard committed
1069

Aneesh Dogra's avatar
Aneesh Dogra committed
1070
        for (ch = 1; ch < nb_display_channels; ch++) {
1071
            y = s->ytop + ch * h;
1072
            fill_rectangle(s->xleft, y, s->width, 1);
1073
        }
Aneesh Dogra's avatar
Aneesh Dogra committed
1074
    } else {
1075 1076 1077
        if (realloc_texture(&s->vis_texture, SDL_PIXELFORMAT_ARGB8888, s->width, s->height, SDL_BLENDMODE_NONE, 1) < 0)
            return;

1078
        nb_display_channels= FFMIN(nb_display_channels, 2);
Aneesh Dogra's avatar
Aneesh Dogra committed
1079
        if (rdft_bits != s->rdft_bits) {
1080
            av_rdft_end(s->rdft);
Måns Rullgård's avatar
Måns Rullgård committed
1081
            av_free(s->rdft_data);
1082
            s->rdft = av_rdft_init(rdft_bits, DFT_R2C);
Aneesh Dogra's avatar
Aneesh Dogra committed
1083
            s->rdft_bits = rdft_bits;
1084
            s->rdft_data = av_malloc_array(nb_freq, 4 *sizeof(*s->rdft_data));
1085
        }
1086 1087 1088 1089
        if (!s->rdft || !s->rdft_data){
            av_log(NULL, AV_LOG_ERROR, "Failed to allocate buffers for RDFT, switching to waves display\n");
            s->show_mode = SHOW_MODE_WAVES;
        } else {
Måns Rullgård's avatar
Måns Rullgård committed
1090
            FFTSample *data[2];
1091 1092 1093
            SDL_Rect rect = {.x = s->xpos, .y = 0, .w = 1, .h = s->height};
            uint32_t *pixels;
            int pitch;
Aneesh Dogra's avatar
Aneesh Dogra committed
1094 1095
            for (ch = 0; ch < nb_display_channels; ch++) {
                data[ch] = s->rdft_data + 2 * nb_freq * ch;
1096
                i = i_start + ch;
Aneesh Dogra's avatar
Aneesh Dogra committed
1097 1098 1099
                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);
1100 1101 1102 1103
                    i += channels;
                    if (i >= SAMPLE_ARRAY_SIZE)
                        i -= SAMPLE_ARRAY_SIZE;
                }
1104
                av_rdft_calc(s->rdft, data[ch]);
1105
            }
Diego Biurrun's avatar
Diego Biurrun committed
1106 1107
            /* Least efficient way to do this, we should of course
             * directly access it but it is more than fast enough. */
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
            if (!SDL_LockTexture(s->vis_texture, &rect, (void **)&pixels, &pitch)) {
                pitch >>= 2;
                pixels += pitch * s->height;
                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 * hypot(data[1][2 * y + 0], data[1][2 * y + 1]))
                                                        : a;
                    a = FFMIN(a, 255);
                    b = FFMIN(b, 255);
                    pixels -= pitch;
                    *pixels = (a << 16) + (b << 8) + ((a+b) >> 1);
                }
                SDL_UnlockTexture(s->vis_texture);
1122
            }
1123
            SDL_RenderCopy(renderer, s->vis_texture, NULL, NULL);
1124
        }
1125 1126
        if (!s->paused)
            s->xpos++;
Aneesh Dogra's avatar
Aneesh Dogra committed
1127
        if (s->xpos >= s->width)
1128 1129
            s->xpos= s->xleft;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
1130 1131
}

1132 1133 1134
static void stream_component_close(VideoState *is, int stream_index)
{
    AVFormatContext *ic = is->ic;
1135
    AVCodecParameters *codecpar;
1136 1137 1138

    if (stream_index < 0 || stream_index >= ic->nb_streams)
        return;
1139
    codecpar = ic->streams[stream_index]->codecpar;
1140

1141
    switch (codecpar->codec_type) {
1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
    case AVMEDIA_TYPE_AUDIO:
        decoder_abort(&is->auddec, &is->sampq);
        SDL_CloseAudio();
        decoder_destroy(&is->auddec);
        swr_free(&is->swr_ctx);
        av_freep(&is->audio_buf1);
        is->audio_buf1_size = 0;
        is->audio_buf = NULL;

        if (is->rdft) {
            av_rdft_end(is->rdft);
            av_freep(&is->rdft_data);
            is->rdft = NULL;
            is->rdft_bits = 0;
        }
        break;
    case AVMEDIA_TYPE_VIDEO:
        decoder_abort(&is->viddec, &is->pictq);
        decoder_destroy(&is->viddec);
        break;
    case AVMEDIA_TYPE_SUBTITLE:
        decoder_abort(&is->subdec, &is->subpq);
        decoder_destroy(&is->subdec);
        break;
    default:
        break;
    }

    ic->streams[stream_index]->discard = AVDISCARD_ALL;
1171
    switch (codecpar->codec_type) {
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187
    case AVMEDIA_TYPE_AUDIO:
        is->audio_st = NULL;
        is->audio_stream = -1;
        break;
    case AVMEDIA_TYPE_VIDEO:
        is->video_st = NULL;
        is->video_stream = -1;
        break;
    case AVMEDIA_TYPE_SUBTITLE:
        is->subtitle_st = NULL;
        is->subtitle_stream = -1;
        break;
    default:
        break;
    }
}
1188

1189 1190 1191 1192 1193
static void stream_close(VideoState *is)
{
    /* XXX: use a special url_shutdown call to abort parse cleanly */
    is->abort_request = 1;
    SDL_WaitThread(is->read_tid, NULL);
1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204

    /* 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);
    if (is->subtitle_stream >= 0)
        stream_component_close(is, is->subtitle_stream);

    avformat_close_input(&is->ic);

1205 1206 1207
    packet_queue_destroy(&is->videoq);
    packet_queue_destroy(&is->audioq);
    packet_queue_destroy(&is->subtitleq);
1208 1209

    /* free all pictures */
1210
    frame_queue_destory(&is->pictq);
1211
    frame_queue_destory(&is->sampq);
1212
    frame_queue_destory(&is->subpq);
1213
    SDL_DestroyCond(is->continue_read_thread);
1214
    sws_freeContext(is->img_convert_ctx);
1215
    sws_freeContext(is->sub_convert_ctx);
1216
    av_free(is->filename);
1217 1218 1219 1220
    if (is->vis_texture)
        SDL_DestroyTexture(is->vis_texture);
    if (is->sub_texture)
        SDL_DestroyTexture(is->sub_texture);
1221 1222 1223
    av_free(is);
}

1224
static void do_exit(VideoState *is)
1225
{
1226 1227
    if (is) {
        stream_close(is);
1228
    }
1229 1230 1231 1232
    if (renderer)
        SDL_DestroyRenderer(renderer);
    if (window)
        SDL_DestroyWindow(window);
1233
    av_lockmgr_register(NULL);
1234 1235
    uninit_opts();
#if CONFIG_AVFILTER
1236
    av_freep(&vfilters_list);
1237
#endif
1238
    avformat_network_deinit();
1239 1240 1241
    if (show_status)
        printf("\n");
    SDL_Quit();
1242
    av_log(NULL, AV_LOG_QUIET, "%s", "");
1243 1244 1245
    exit(0);
}

1246 1247 1248 1249 1250
static void sigterm_handler(int sig)
{
    exit(123);
}

1251
static void set_default_window_size(int width, int height, AVRational sar)
1252 1253
{
    SDL_Rect rect;
1254
    calculate_display_rect(&rect, 0, 0, INT_MAX, height, width, height, sar);
1255 1256 1257 1258
    default_width  = rect.w;
    default_height = rect.h;
}

1259
static int video_open(VideoState *is, Frame *vp)
Aneesh Dogra's avatar
Aneesh Dogra committed
1260
{
1261 1262
    int w,h;

1263
    if (vp && vp->width)
1264
        set_default_window_size(vp->width, vp->height, vp->sar);
1265

1266
    if (screen_width) {
1267 1268
        w = screen_width;
        h = screen_height;
1269
    } else {
1270 1271
        w = default_width;
        h = default_height;
1272
    }
1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284

    if (!window) {
        int flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE;
        if (!window_title)
            window_title = input_filename;
        if (is_full_screen)
            flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
        window = SDL_CreateWindow(window_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, flags);
        SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
        if (window) {
            SDL_RendererInfo info;
            renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
1285 1286 1287 1288
            if (!renderer) {
                av_log(NULL, AV_LOG_WARNING, "Failed to initialize a hardware accelerated renderer: %s\n", SDL_GetError());
                renderer = SDL_CreateRenderer(window, -1, 0);
            }
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298
            if (renderer) {
                if (!SDL_GetRendererInfo(renderer, &info))
                    av_log(NULL, AV_LOG_VERBOSE, "Initialized %s renderer.\n", info.name);
            }
        }
    } else {
        SDL_SetWindowSize(window, w, h);
    }

    if (!window || !renderer) {
1299
        av_log(NULL, AV_LOG_FATAL, "SDL: could not set video mode - exiting\n");
1300
        do_exit(is);
1301 1302
    }

1303 1304
    is->width  = w;
    is->height = h;
1305 1306 1307

    return 0;
}
1308

Fabrice Bellard's avatar
Fabrice Bellard committed
1309 1310 1311
/* display the current picture, if any */
static void video_display(VideoState *is)
{
1312 1313 1314 1315 1316
    if (!window)
        video_open(is, NULL);

    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);
1317
    if (is->audio_st && is->show_mode != SHOW_MODE_VIDEO)
Fabrice Bellard's avatar
Fabrice Bellard committed
1318 1319 1320
        video_audio_display(is);
    else if (is->video_st)
        video_image_display(is);
1321
    SDL_RenderPresent(renderer);
Fabrice Bellard's avatar
Fabrice Bellard committed
1322 1323
}

1324
static double get_clock(Clock *c)
1325
{
1326
    if (*c->queue_serial != c->serial)
1327
        return NAN;
1328 1329
    if (c->paused) {
        return c->pts;
1330
    } else {
1331
        double time = av_gettime_relative() / 1000000.0;
1332
        return c->pts_drift + time - (time - c->last_updated) * (1.0 - c->speed);
1333 1334 1335
    }
}

1336
static void set_clock_at(Clock *c, double pts, int serial, double time)
1337
{
1338 1339 1340 1341
    c->pts = pts;
    c->last_updated = time;
    c->pts_drift = c->pts - time;
    c->serial = serial;
1342 1343
}

1344
static void set_clock(Clock *c, double pts, int serial)
1345
{
1346
    double time = av_gettime_relative() / 1000000.0;
1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369
    set_clock_at(c, pts, serial, time);
}

static void set_clock_speed(Clock *c, double speed)
{
    set_clock(c, get_clock(c), c->serial);
    c->speed = speed;
}

static void init_clock(Clock *c, int *queue_serial)
{
    c->speed = 1.0;
    c->paused = 0;
    c->queue_serial = queue_serial;
    set_clock(c, NAN, -1);
}

static void sync_clock_to_slave(Clock *c, Clock *slave)
{
    double clock = get_clock(c);
    double slave_clock = get_clock(slave);
    if (!isnan(slave_clock) && (isnan(clock) || fabs(clock - slave_clock) > AV_NOSYNC_THRESHOLD))
        set_clock(c, slave_clock, slave->serial);
1370 1371
}

1372
static int get_master_sync_type(VideoState *is) {
Fabrice Bellard's avatar
Fabrice Bellard committed
1373 1374
    if (is->av_sync_type == AV_SYNC_VIDEO_MASTER) {
        if (is->video_st)
1375
            return AV_SYNC_VIDEO_MASTER;
Fabrice Bellard's avatar
Fabrice Bellard committed
1376
        else
1377
            return AV_SYNC_AUDIO_MASTER;
Fabrice Bellard's avatar
Fabrice Bellard committed
1378 1379
    } else if (is->av_sync_type == AV_SYNC_AUDIO_MASTER) {
        if (is->audio_st)
1380
            return AV_SYNC_AUDIO_MASTER;
Fabrice Bellard's avatar
Fabrice Bellard committed
1381
        else
1382
            return AV_SYNC_EXTERNAL_CLOCK;
Fabrice Bellard's avatar
Fabrice Bellard committed
1383
    } else {
1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394
        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:
1395
            val = get_clock(&is->vidclk);
1396 1397
            break;
        case AV_SYNC_AUDIO_MASTER:
1398
            val = get_clock(&is->audclk);
1399 1400
            break;
        default:
1401
            val = get_clock(&is->extclk);
1402
            break;
Fabrice Bellard's avatar
Fabrice Bellard committed
1403
    }
1404 1405 1406
    return val;
}

1407
static void check_external_clock_speed(VideoState *is) {
1408 1409
   if (is->video_stream >= 0 && is->videoq.nb_packets <= EXTERNAL_CLOCK_MIN_FRAMES ||
       is->audio_stream >= 0 && is->audioq.nb_packets <= EXTERNAL_CLOCK_MIN_FRAMES) {
1410
       set_clock_speed(&is->extclk, FFMAX(EXTERNAL_CLOCK_SPEED_MIN, is->extclk.speed - EXTERNAL_CLOCK_SPEED_STEP));
1411 1412
   } else if ((is->video_stream < 0 || is->videoq.nb_packets > EXTERNAL_CLOCK_MAX_FRAMES) &&
              (is->audio_stream < 0 || is->audioq.nb_packets > EXTERNAL_CLOCK_MAX_FRAMES)) {
1413
       set_clock_speed(&is->extclk, FFMIN(EXTERNAL_CLOCK_SPEED_MAX, is->extclk.speed + EXTERNAL_CLOCK_SPEED_STEP));
1414
   } else {
1415
       double speed = is->extclk.speed;
1416
       if (speed != 1.0)
1417
           set_clock_speed(&is->extclk, speed + EXTERNAL_CLOCK_SPEED_STEP * (1.0 - speed) / fabs(1.0 - speed));
1418 1419 1420
   }
}

Fabrice Bellard's avatar
Fabrice Bellard committed
1421
/* seek in the stream */
1422
static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_bytes)
Fabrice Bellard's avatar
Fabrice Bellard committed
1423
{
1424 1425
    if (!is->seek_req) {
        is->seek_pos = pos;
1426
        is->seek_rel = rel;
Michael Niedermayer's avatar
Michael Niedermayer committed
1427
        is->seek_flags &= ~AVSEEK_FLAG_BYTE;
1428 1429
        if (seek_by_bytes)
            is->seek_flags |= AVSEEK_FLAG_BYTE;
1430
        is->seek_req = 1;
1431
        SDL_CondSignal(is->continue_read_thread);
1432
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
1433 1434 1435
}

/* pause or resume the video */
1436
static void stream_toggle_pause(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
1437
{
1438
    if (is->paused) {
1439
        is->frame_timer += av_gettime_relative() / 1000000.0 - is->vidclk.last_updated;
Aneesh Dogra's avatar
Aneesh Dogra committed
1440
        if (is->read_pause_return != AVERROR(ENOSYS)) {
1441
            is->vidclk.paused = 0;
1442
        }
1443
        set_clock(&is->vidclk, get_clock(&is->vidclk), is->vidclk.serial);
Fabrice Bellard's avatar
Fabrice Bellard committed
1444
    }
1445 1446
    set_clock(&is->extclk, get_clock(&is->extclk), is->extclk.serial);
    is->paused = is->audclk.paused = is->vidclk.paused = is->extclk.paused = !is->paused;
Fabrice Bellard's avatar
Fabrice Bellard committed
1447 1448
}

1449 1450 1451 1452 1453 1454
static void toggle_pause(VideoState *is)
{
    stream_toggle_pause(is);
    is->step = 0;
}

1455 1456 1457 1458 1459 1460 1461 1462 1463 1464
static void toggle_mute(VideoState *is)
{
    is->muted = !is->muted;
}

static void update_volume(VideoState *is, int sign, int step)
{
    is->audio_volume = av_clip(is->audio_volume + sign * step, 0, SDL_MIX_MAXVOLUME);
}

1465 1466 1467 1468 1469 1470 1471 1472
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;
}

1473
static double compute_target_delay(double delay, VideoState *is)
1474
{
1475
    double sync_threshold, diff = 0;
1476 1477

    /* update delay to follow master synchronisation source */
1478
    if (get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER) {
1479 1480
        /* if video is slave, we try to correct big delays by
           duplicating or deleting a frame */
1481
        diff = get_clock(&is->vidclk) - get_master_clock(is);
1482 1483 1484 1485

        /* 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 */
1486 1487
        sync_threshold = FFMAX(AV_SYNC_THRESHOLD_MIN, FFMIN(AV_SYNC_THRESHOLD_MAX, delay));
        if (!isnan(diff) && fabs(diff) < is->max_frame_duration) {
1488
            if (diff <= -sync_threshold)
1489 1490 1491
                delay = FFMAX(0, delay + diff);
            else if (diff >= sync_threshold && delay > AV_SYNC_FRAMEDUP_THRESHOLD)
                delay = delay + diff;
1492 1493 1494 1495
            else if (diff >= sync_threshold)
                delay = 2 * delay;
        }
    }
1496

1497
    av_log(NULL, AV_LOG_TRACE, "video: delay=%0.3f A-V=%f\n",
1498 1499 1500 1501 1502
            delay, -diff);

    return delay;
}

1503
static double vp_duration(VideoState *is, Frame *vp, Frame *nextvp) {
1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514
    if (vp->serial == nextvp->serial) {
        double duration = nextvp->pts - vp->pts;
        if (isnan(duration) || duration <= 0 || duration > is->max_frame_duration)
            return vp->duration;
        else
            return duration;
    } else {
        return 0.0;
    }
}

1515
static void update_video_pts(VideoState *is, double pts, int64_t pos, int serial) {
1516
    /* update current video pts */
1517 1518
    set_clock(&is->vidclk, pts, serial);
    sync_clock_to_slave(&is->extclk, &is->vidclk);
1519 1520
}

Fabrice Bellard's avatar
Fabrice Bellard committed
1521
/* called to display each frame */
1522
static void video_refresh(void *opaque, double *remaining_time)
Fabrice Bellard's avatar
Fabrice Bellard committed
1523 1524
{
    VideoState *is = opaque;
1525
    double time;
1526

1527
    Frame *sp, *sp2;
Fabrice Bellard's avatar
Fabrice Bellard committed
1528

1529 1530 1531
    if (!is->paused && get_master_sync_type(is) == AV_SYNC_EXTERNAL_CLOCK && is->realtime)
        check_external_clock_speed(is);

1532
    if (!display_disable && is->show_mode != SHOW_MODE_VIDEO && is->audio_st) {
1533
        time = av_gettime_relative() / 1000000.0;
1534 1535 1536 1537 1538 1539
        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);
    }
1540

Fabrice Bellard's avatar
Fabrice Bellard committed
1541
    if (is->video_st) {
1542
retry:
1543
        if (frame_queue_nb_remaining(&is->pictq) == 0) {
1544
            // nothing to do, no picture to display in the queue
Fabrice Bellard's avatar
Fabrice Bellard committed
1545
        } else {
1546
            double last_duration, duration, delay;
1547
            Frame *vp, *lastvp;
1548

1549
            /* dequeue the picture */
1550 1551
            lastvp = frame_queue_peek_last(&is->pictq);
            vp = frame_queue_peek(&is->pictq);
1552

1553
            if (vp->serial != is->videoq.serial) {
1554
                frame_queue_next(&is->pictq);
1555 1556 1557
                goto retry;
            }

1558
            if (lastvp->serial != vp->serial)
1559
                is->frame_timer = av_gettime_relative() / 1000000.0;
1560

1561 1562 1563
            if (is->paused)
                goto display;

1564
            /* compute nominal last_duration */
1565
            last_duration = vp_duration(is, lastvp, vp);
1566
            delay = compute_target_delay(last_duration, is);
1567

1568
            time= av_gettime_relative()/1000000.0;
1569
            if (time < is->frame_timer + delay) {
1570
                *remaining_time = FFMIN(is->frame_timer + delay - time, *remaining_time);
1571
                goto display;
1572
            }
1573

1574 1575 1576
            is->frame_timer += delay;
            if (delay > 0 && time - is->frame_timer > AV_SYNC_THRESHOLD_MAX)
                is->frame_timer = time;
1577

1578
            SDL_LockMutex(is->pictq.mutex);
1579
            if (!isnan(vp->pts))
1580
                update_video_pts(is, vp->pts, vp->pos, vp->serial);
1581
            SDL_UnlockMutex(is->pictq.mutex);
1582

1583 1584
            if (frame_queue_nb_remaining(&is->pictq) > 1) {
                Frame *nextvp = frame_queue_peek_next(&is->pictq);
1585
                duration = vp_duration(is, vp, nextvp);
1586 1587
                if(!is->step && (framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) && time > is->frame_timer + duration){
                    is->frame_drops_late++;
1588
                    frame_queue_next(&is->pictq);
1589 1590 1591
                    goto retry;
                }
            }
1592

Aneesh Dogra's avatar
Aneesh Dogra committed
1593
            if (is->subtitle_st) {
1594 1595
                    while (frame_queue_nb_remaining(&is->subpq) > 0) {
                        sp = frame_queue_peek(&is->subpq);
1596

1597 1598
                        if (frame_queue_nb_remaining(&is->subpq) > 1)
                            sp2 = frame_queue_peek_next(&is->subpq);
1599 1600 1601
                        else
                            sp2 = NULL;

1602 1603
                        if (sp->serial != is->subtitleq.serial
                                || (is->vidclk.pts > (sp->pts + ((float) sp->sub.end_display_time / 1000)))
1604
                                || (sp2 && is->vidclk.pts > (sp2->pts + ((float) sp2->sub.start_display_time / 1000))))
1605
                        {
1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619
                            if (sp->uploaded) {
                                int i;
                                for (i = 0; i < sp->sub.num_rects; i++) {
                                    AVSubtitleRect *sub_rect = sp->sub.rects[i];
                                    uint8_t *pixels;
                                    int pitch, j;

                                    if (!SDL_LockTexture(is->sub_texture, (SDL_Rect *)sub_rect, (void **)&pixels, &pitch)) {
                                        for (j = 0; j < sub_rect->h; j++, pixels += pitch)
                                            memset(pixels, 0, sub_rect->w << 2);
                                        SDL_UnlockTexture(is->sub_texture);
                                    }
                                }
                            }
1620
                            frame_queue_next(&is->subpq);
1621 1622
                        } else {
                            break;
1623 1624 1625 1626
                        }
                    }
            }

1627
            frame_queue_next(&is->pictq);
1628
            is->force_refresh = 1;
1629 1630 1631

            if (is->step && !is->paused)
                stream_toggle_pause(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
1632
        }
1633 1634 1635 1636
display:
        /* display picture */
        if (!display_disable && is->force_refresh && is->show_mode == SHOW_MODE_VIDEO && is->pictq.rindex_shown)
            video_display(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
1637
    }
1638
    is->force_refresh = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1639 1640 1641
    if (show_status) {
        static int64_t last_time;
        int64_t cur_time;
1642
        int aqsize, vqsize, sqsize;
1643
        double av_diff;
1644

1645
        cur_time = av_gettime_relative();
1646
        if (!last_time || (cur_time - last_time) >= 30000) {
Fabrice Bellard's avatar
Fabrice Bellard committed
1647 1648
            aqsize = 0;
            vqsize = 0;
1649
            sqsize = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1650 1651 1652 1653
            if (is->audio_st)
                aqsize = is->audioq.size;
            if (is->video_st)
                vqsize = is->videoq.size;
1654 1655
            if (is->subtitle_st)
                sqsize = is->subtitleq.size;
1656 1657
            av_diff = 0;
            if (is->audio_st && is->video_st)
1658
                av_diff = get_clock(&is->audclk) - get_clock(&is->vidclk);
1659 1660 1661 1662
            else if (is->video_st)
                av_diff = get_master_clock(is) - get_clock(&is->vidclk);
            else if (is->audio_st)
                av_diff = get_master_clock(is) - get_clock(&is->audclk);
1663 1664
            av_log(NULL, AV_LOG_INFO,
                   "%7.2f %s:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64"   \r",
1665
                   get_master_clock(is),
1666
                   (is->audio_st && is->video_st) ? "A-V" : (is->video_st ? "M-V" : (is->audio_st ? "M-A" : "   ")),
1667
                   av_diff,
1668
                   is->frame_drops_early + is->frame_drops_late,
1669 1670 1671
                   aqsize / 1024,
                   vqsize / 1024,
                   sqsize,
1672 1673
                   is->video_st ? is->viddec.avctx->pts_correction_num_faulty_dts : 0,
                   is->video_st ? is->viddec.avctx->pts_correction_num_faulty_pts : 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
1674 1675 1676 1677 1678 1679 1680 1681
            fflush(stdout);
            last_time = cur_time;
        }
    }
}

/* allocate a picture (needs to do that in main thread to avoid
   potential locking problems */
1682
static void alloc_picture(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
1683
{
1684
    Frame *vp;
1685
    int sdl_format;
Fabrice Bellard's avatar
Fabrice Bellard committed
1686

1687
    vp = &is->pictq.queue[is->pictq.windex];
Fabrice Bellard's avatar
Fabrice Bellard committed
1688

1689
    video_open(is, vp);
Fabrice Bellard's avatar
Fabrice Bellard committed
1690

1691 1692 1693 1694
    if (vp->format == AV_PIX_FMT_YUV420P)
        sdl_format = SDL_PIXELFORMAT_YV12;
    else
        sdl_format = SDL_PIXELFORMAT_ARGB8888;
1695

1696
    if (realloc_texture(&vp->bmp, sdl_format, vp->width, vp->height, SDL_BLENDMODE_NONE, 0) < 0) {
1697 1698
        /* SDL allocates a buffer smaller than requested if the video
         * overlay hardware is unable to support the requested size. */
1699 1700
        av_log(NULL, AV_LOG_FATAL,
               "Error: the video system does not support an image\n"
Michael Niedermayer's avatar
Michael Niedermayer committed
1701
                        "size of %dx%d pixels. Try using -lowres or -vf \"scale=w:h\"\n"
1702
                        "to reduce the image size.\n", vp->width, vp->height );
1703
        do_exit(is);
1704
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
1705

1706
    SDL_LockMutex(is->pictq.mutex);
Fabrice Bellard's avatar
Fabrice Bellard committed
1707
    vp->allocated = 1;
1708 1709
    SDL_CondSignal(is->pictq.cond);
    SDL_UnlockMutex(is->pictq.mutex);
Fabrice Bellard's avatar
Fabrice Bellard committed
1710 1711
}

1712
static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, double duration, int64_t pos, int serial)
Fabrice Bellard's avatar
Fabrice Bellard committed
1713
{
1714
    Frame *vp;
1715

1716
#if defined(DEBUG_SYNC)
1717 1718
    printf("frame_type=%c pts=%0.3f\n",
           av_get_picture_type_char(src_frame->pict_type), pts);
1719
#endif
1720

1721
    if (!(vp = frame_queue_peek_writable(&is->pictq)))
Fabrice Bellard's avatar
Fabrice Bellard committed
1722 1723
        return -1;

1724
    vp->sar = src_frame->sample_aspect_ratio;
1725
    vp->uploaded = 0;
1726

Fabrice Bellard's avatar
Fabrice Bellard committed
1727
    /* alloc or resize hardware picture buffer */
1728
    if (!vp->bmp || !vp->allocated ||
1729
        vp->width  != src_frame->width ||
1730 1731
        vp->height != src_frame->height ||
        vp->format != src_frame->format) {
Fabrice Bellard's avatar
Fabrice Bellard committed
1732 1733
        SDL_Event event;

1734
        vp->allocated = 0;
1735 1736
        vp->width = src_frame->width;
        vp->height = src_frame->height;
1737
        vp->format = src_frame->format;
Fabrice Bellard's avatar
Fabrice Bellard committed
1738 1739

        /* the allocation must be done in the main thread to avoid
1740
           locking problems. */
Fabrice Bellard's avatar
Fabrice Bellard committed
1741
        event.type = FF_ALLOC_EVENT;
1742
        event.user.data1 = is;
Fabrice Bellard's avatar
Fabrice Bellard committed
1743
        SDL_PushEvent(&event);
1744

Fabrice Bellard's avatar
Fabrice Bellard committed
1745
        /* wait until the picture is allocated */
1746
        SDL_LockMutex(is->pictq.mutex);
Fabrice Bellard's avatar
Fabrice Bellard committed
1747
        while (!vp->allocated && !is->videoq.abort_request) {
1748
            SDL_CondWait(is->pictq.cond, is->pictq.mutex);
Fabrice Bellard's avatar
Fabrice Bellard committed
1749
        }
1750
        /* if the queue is aborted, we have to pop the pending ALLOC event or wait for the allocation to complete */
1751
        if (is->videoq.abort_request && SDL_PeepEvents(&event, 1, SDL_GETEVENT, FF_ALLOC_EVENT, FF_ALLOC_EVENT) != 1) {
1752
            while (!vp->allocated && !is->abort_request) {
1753
                SDL_CondWait(is->pictq.cond, is->pictq.mutex);
1754 1755
            }
        }
1756
        SDL_UnlockMutex(is->pictq.mutex);
Fabrice Bellard's avatar
Fabrice Bellard committed
1757 1758 1759 1760 1761

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

1762
    /* if the frame is not skipped, then display it */
Fabrice Bellard's avatar
Fabrice Bellard committed
1763
    if (vp->bmp) {
1764
        vp->pts = pts;
1765
        vp->duration = duration;
1766
        vp->pos = pos;
1767
        vp->serial = serial;
Fabrice Bellard's avatar
Fabrice Bellard committed
1768

1769
        av_frame_move_ref(vp->frame, src_frame);
1770
        frame_queue_push(&is->pictq);
Fabrice Bellard's avatar
Fabrice Bellard committed
1771
    }
1772 1773 1774
    return 0;
}

1775
static int get_video_frame(VideoState *is, AVFrame *frame)
Fabrice Bellard's avatar
Fabrice Bellard committed
1776
{
1777
    int got_picture;
Fabrice Bellard's avatar
Fabrice Bellard committed
1778

1779
    if ((got_picture = decoder_decode_frame(&is->viddec, frame, NULL)) < 0)
1780
        return -1;
1781

1782
    if (got_picture) {
1783
        double dpts = NAN;
1784

1785 1786
        if (frame->pts != AV_NOPTS_VALUE)
            dpts = av_q2d(is->video_st->time_base) * frame->pts;
1787

1788 1789
        frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, frame);

1790
        if (framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) {
1791 1792 1793 1794
            if (frame->pts != AV_NOPTS_VALUE) {
                double diff = dpts - get_master_clock(is);
                if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD &&
                    diff - is->frame_last_filter_delay < 0 &&
1795
                    is->viddec.pkt_serial == is->vidclk.serial &&
1796
                    is->videoq.nb_packets) {
1797
                    is->frame_drops_early++;
1798
                    av_frame_unref(frame);
1799
                    got_picture = 0;
1800 1801 1802
                }
            }
        }
1803
    }
1804 1805

    return got_picture;
1806 1807 1808
}

#if CONFIG_AVFILTER
1809 1810 1811
static int configure_filtergraph(AVFilterGraph *graph, const char *filtergraph,
                                 AVFilterContext *source_ctx, AVFilterContext *sink_ctx)
{
1812 1813
    int ret, i;
    int nb_filters = graph->nb_filters;
1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833
    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;

1834
        if ((ret = avfilter_graph_parse_ptr(graph, filtergraph, &inputs, &outputs, NULL)) < 0)
1835 1836 1837 1838 1839 1840
            goto fail;
    } else {
        if ((ret = avfilter_link(source_ctx, 0, sink_ctx, 0)) < 0)
            goto fail;
    }

1841 1842 1843 1844
    /* Reorder the filters to ensure that inputs of the custom filters are merged first */
    for (i = 0; i < graph->nb_filters - nb_filters; i++)
        FFSWAP(AVFilterContext*, graph->filters[i], graph->filters[i + nb_filters]);

1845
    ret = avfilter_graph_config(graph, NULL);
1846 1847 1848 1849 1850 1851
fail:
    avfilter_inout_free(&outputs);
    avfilter_inout_free(&inputs);
    return ret;
}

1852
static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters, AVFrame *frame)
1853
{
1854
    static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_BGRA, AV_PIX_FMT_NONE };
1855
    char sws_flags_str[512] = "";
1856
    char buffersrc_args[256];
1857
    int ret;
1858
    AVFilterContext *filt_src = NULL, *filt_out = NULL, *last_filter = NULL;
1859
    AVCodecParameters *codecpar = is->video_st->codecpar;
1860
    AVRational fr = av_guess_frame_rate(is->ic, is->video_st, NULL);
1861 1862 1863 1864 1865 1866 1867 1868 1869 1870
    AVDictionaryEntry *e = NULL;

    while ((e = av_dict_get(sws_dict, "", e, AV_DICT_IGNORE_SUFFIX))) {
        if (!strcmp(e->key, "sws_flags")) {
            av_strlcatf(sws_flags_str, sizeof(sws_flags_str), "%s=%s:", "flags", e->value);
        } else
            av_strlcatf(sws_flags_str, sizeof(sws_flags_str), "%s=%s:", e->key, e->value);
    }
    if (strlen(sws_flags_str))
        sws_flags_str[strlen(sws_flags_str)-1] = '\0';
1871

Stefano Sabatini's avatar
Stefano Sabatini committed
1872
    graph->scale_sws_opts = av_strdup(sws_flags_str);
1873

1874 1875
    snprintf(buffersrc_args, sizeof(buffersrc_args),
             "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
1876
             frame->width, frame->height, frame->format,
1877
             is->video_st->time_base.num, is->video_st->time_base.den,
1878
             codecpar->sample_aspect_ratio.num, FFMAX(codecpar->sample_aspect_ratio.den, 1));
1879 1880
    if (fr.num && fr.den)
        av_strlcatf(buffersrc_args, sizeof(buffersrc_args), ":frame_rate=%d/%d", fr.num, fr.den);
1881 1882 1883

    if ((ret = avfilter_graph_create_filter(&filt_src,
                                            avfilter_get_by_name("buffer"),
1884
                                            "ffplay_buffer", buffersrc_args, NULL,
1885
                                            graph)) < 0)
1886
        goto fail;
1887

1888
    ret = avfilter_graph_create_filter(&filt_out,
1889
                                       avfilter_get_by_name("buffersink"),
1890
                                       "ffplay_buffersink", NULL, NULL, graph);
1891
    if (ret < 0)
1892
        goto fail;
1893

1894 1895 1896
    if ((ret = av_opt_set_int_list(filt_out, "pix_fmts", pix_fmts,  AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0)
        goto fail;

1897 1898 1899 1900
    last_filter = filt_out;

/* Note: this macro adds a filter before the lastly added filter, so the
 * processing order of the filters is in reverse */
1901 1902 1903 1904 1905 1906 1907 1908 1909
#define INSERT_FILT(name, arg) do {                                          \
    AVFilterContext *filt_ctx;                                               \
                                                                             \
    ret = avfilter_graph_create_filter(&filt_ctx,                            \
                                       avfilter_get_by_name(name),           \
                                       "ffplay_" name, arg, NULL, graph);    \
    if (ret < 0)                                                             \
        goto fail;                                                           \
                                                                             \
1910
    ret = avfilter_link(filt_ctx, 0, last_filter, 0);                        \
1911 1912 1913
    if (ret < 0)                                                             \
        goto fail;                                                           \
                                                                             \
1914
    last_filter = filt_ctx;                                                  \
1915 1916 1917
} while (0)

    if (autorotate) {
1918
        double theta  = get_rotation(is->video_st);
1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930

        if (fabs(theta - 90) < 1.0) {
            INSERT_FILT("transpose", "clock");
        } else if (fabs(theta - 180) < 1.0) {
            INSERT_FILT("hflip", NULL);
            INSERT_FILT("vflip", NULL);
        } else if (fabs(theta - 270) < 1.0) {
            INSERT_FILT("transpose", "cclock");
        } else if (fabs(theta) > 1.0) {
            char rotate_buf[64];
            snprintf(rotate_buf, sizeof(rotate_buf), "%f*PI/180", theta);
            INSERT_FILT("rotate", rotate_buf);
1931 1932
        }
    }
1933

1934
    if ((ret = configure_filtergraph(graph, vfilters, filt_src, last_filter)) < 0)
1935
        goto fail;
1936

1937
    is->in_video_filter  = filt_src;
1938
    is->out_video_filter = filt_out;
1939

1940
fail:
1941 1942 1943
    return ret;
}

Marton Balint's avatar
Marton Balint committed
1944 1945
static int configure_audio_filters(VideoState *is, const char *afilters, int force_output_format)
{
1946
    static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE };
Marton Balint's avatar
Marton Balint committed
1947 1948 1949 1950
    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;
1951 1952
    char aresample_swr_opts[512] = "";
    AVDictionaryEntry *e = NULL;
Marton Balint's avatar
Marton Balint committed
1953 1954 1955 1956 1957 1958 1959
    char asrc_args[256];
    int ret;

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

1960 1961 1962 1963 1964 1965
    while ((e = av_dict_get(swr_opts, "", e, AV_DICT_IGNORE_SUFFIX)))
        av_strlcatf(aresample_swr_opts, sizeof(aresample_swr_opts), "%s=%s:", e->key, e->value);
    if (strlen(aresample_swr_opts))
        aresample_swr_opts[strlen(aresample_swr_opts)-1] = '\0';
    av_opt_set(is->agraph, "aresample_swr_opts", aresample_swr_opts, 0);

Marton Balint's avatar
Marton Balint committed
1966
    ret = snprintf(asrc_args, sizeof(asrc_args),
1967
                   "sample_rate=%d:sample_fmt=%s:channels=%d:time_base=%d/%d",
Marton Balint's avatar
Marton Balint committed
1968
                   is->audio_filter_src.freq, av_get_sample_fmt_name(is->audio_filter_src.fmt),
1969 1970
                   is->audio_filter_src.channels,
                   1, is->audio_filter_src.freq);
Marton Balint's avatar
Marton Balint committed
1971 1972 1973 1974 1975 1976 1977 1978 1979 1980
    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;

1981 1982 1983 1984 1985 1986 1987 1988 1989 1990

    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
1991 1992 1993 1994
        goto end;

    if (force_output_format) {
        channel_layouts[0] = is->audio_tgt.channel_layout;
1995 1996 1997 1998 1999 2000 2001 2002 2003 2004
        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
2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018
    }


    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;
}
2019 2020
#endif  /* CONFIG_AVFILTER */

2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107
static int audio_thread(void *arg)
{
    VideoState *is = arg;
    AVFrame *frame = av_frame_alloc();
    Frame *af;
#if CONFIG_AVFILTER
    int last_serial = -1;
    int64_t dec_channel_layout;
    int reconfigure;
#endif
    int got_frame = 0;
    AVRational tb;
    int ret = 0;

    if (!frame)
        return AVERROR(ENOMEM);

    do {
        if ((got_frame = decoder_decode_frame(&is->auddec, frame, NULL)) < 0)
            goto the_end;

        if (got_frame) {
                tb = (AVRational){1, frame->sample_rate};

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

                reconfigure =
                    cmp_audio_fmts(is->audio_filter_src.fmt, is->audio_filter_src.channels,
                                   frame->format, av_frame_get_channels(frame))    ||
                    is->audio_filter_src.channel_layout != dec_channel_layout ||
                    is->audio_filter_src.freq           != frame->sample_rate ||
                    is->auddec.pkt_serial               != 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, last_serial,
                           frame->sample_rate, av_frame_get_channels(frame), av_get_sample_fmt_name(frame->format), buf2, is->auddec.pkt_serial);

                    is->audio_filter_src.fmt            = frame->format;
                    is->audio_filter_src.channels       = av_frame_get_channels(frame);
                    is->audio_filter_src.channel_layout = dec_channel_layout;
                    is->audio_filter_src.freq           = frame->sample_rate;
                    last_serial                         = is->auddec.pkt_serial;

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

            if ((ret = av_buffersrc_add_frame(is->in_audio_filter, frame)) < 0)
                goto the_end;

            while ((ret = av_buffersink_get_frame_flags(is->out_audio_filter, frame, 0)) >= 0) {
                tb = is->out_audio_filter->inputs[0]->time_base;
#endif
                if (!(af = frame_queue_peek_writable(&is->sampq)))
                    goto the_end;

                af->pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);
                af->pos = av_frame_get_pkt_pos(frame);
                af->serial = is->auddec.pkt_serial;
                af->duration = av_q2d((AVRational){frame->nb_samples, frame->sample_rate});

                av_frame_move_ref(af->frame, frame);
                frame_queue_push(&is->sampq);

#if CONFIG_AVFILTER
                if (is->audioq.serial != is->auddec.pkt_serial)
                    break;
            }
            if (ret == AVERROR_EOF)
                is->auddec.finished = is->auddec.pkt_serial;
#endif
        }
    } while (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF);
 the_end:
#if CONFIG_AVFILTER
    avfilter_graph_free(&is->agraph);
#endif
    av_frame_free(&frame);
    return ret;
}

2108
static int decoder_start(Decoder *d, int (*fn)(void *), void *arg)
2109 2110
{
    packet_queue_start(d->queue);
2111
    d->decoder_tid = SDL_CreateThread(fn, "decoder", arg);
2112
    if (!d->decoder_tid) {
2113
        av_log(NULL, AV_LOG_ERROR, "SDL_CreateThread(): %s\n", SDL_GetError());
2114 2115 2116
        return AVERROR(ENOMEM);
    }
    return 0;
2117 2118
}

2119 2120 2121
static int video_thread(void *arg)
{
    VideoState *is = arg;
2122
    AVFrame *frame = av_frame_alloc();
2123
    double pts;
2124
    double duration;
2125
    int ret;
2126
    AVRational tb = is->video_st->time_base;
2127
    AVRational frame_rate = av_guess_frame_rate(is->ic, is->video_st, NULL);
2128 2129 2130

#if CONFIG_AVFILTER
    AVFilterGraph *graph = avfilter_graph_alloc();
2131
    AVFilterContext *filt_out = NULL, *filt_in = NULL;
2132 2133
    int last_w = 0;
    int last_h = 0;
2134
    enum AVPixelFormat last_format = -2;
2135
    int last_serial = -1;
2136
    int last_vfilter_idx = 0;
2137 2138
    if (!graph) {
        av_frame_free(&frame);
2139
        return AVERROR(ENOMEM);
2140
    }
2141

2142 2143
#endif

2144 2145 2146 2147
    if (!frame) {
#if CONFIG_AVFILTER
        avfilter_graph_free(&graph);
#endif
2148
        return AVERROR(ENOMEM);
2149
    }
2150

Aneesh Dogra's avatar
Aneesh Dogra committed
2151
    for (;;) {
2152
        ret = get_video_frame(is, frame);
2153 2154 2155 2156 2157
        if (ret < 0)
            goto the_end;
        if (!ret)
            continue;

2158
#if CONFIG_AVFILTER
2159 2160
        if (   last_w != frame->width
            || last_h != frame->height
2161
            || last_format != frame->format
2162
            || last_serial != is->viddec.pkt_serial
2163
            || last_vfilter_idx != is->vfilter_idx) {
2164
            av_log(NULL, AV_LOG_DEBUG,
2165 2166 2167 2168
                   "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,
2169
                   (const char *)av_x_if_null(av_get_pix_fmt_name(frame->format), "none"), is->viddec.pkt_serial);
2170 2171
            avfilter_graph_free(&graph);
            graph = avfilter_graph_alloc();
2172
            if ((ret = configure_video_filters(graph, is, vfilters_list ? vfilters_list[is->vfilter_idx] : NULL, frame)) < 0) {
2173 2174 2175 2176
                SDL_Event event;
                event.type = FF_QUIT_EVENT;
                event.user.data1 = is;
                SDL_PushEvent(&event);
2177
                goto the_end;
2178
            }
2179
            filt_in  = is->in_video_filter;
2180
            filt_out = is->out_video_filter;
2181 2182 2183
            last_w = frame->width;
            last_h = frame->height;
            last_format = frame->format;
2184
            last_serial = is->viddec.pkt_serial;
2185
            last_vfilter_idx = is->vfilter_idx;
2186
            frame_rate = filt_out->inputs[0]->frame_rate;
2187
        }
2188

2189 2190 2191
        ret = av_buffersrc_add_frame(filt_in, frame);
        if (ret < 0)
            goto the_end;
2192

2193
        while (ret >= 0) {
2194
            is->frame_last_returned_time = av_gettime_relative() / 1000000.0;
2195

2196
            ret = av_buffersink_get_frame_flags(filt_out, frame, 0);
2197
            if (ret < 0) {
2198
                if (ret == AVERROR_EOF)
2199
                    is->viddec.finished = is->viddec.pkt_serial;
2200 2201 2202 2203
                ret = 0;
                break;
            }

2204
            is->frame_last_filter_delay = av_gettime_relative() / 1000000.0 - is->frame_last_returned_time;
2205 2206
            if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0)
                is->frame_last_filter_delay = 0;
2207 2208
            tb = filt_out->inputs[0]->time_base;
#endif
2209
            duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0);
2210
            pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);
2211
            ret = queue_picture(is, frame, pts, duration, av_frame_get_pkt_pos(frame), is->viddec.pkt_serial);
2212
            av_frame_unref(frame);
2213
#if CONFIG_AVFILTER
2214
        }
2215
#endif
2216

2217 2218
        if (ret < 0)
            goto the_end;
Fabrice Bellard's avatar
Fabrice Bellard committed
2219 2220
    }
 the_end:
2221
#if CONFIG_AVFILTER
2222
    avfilter_graph_free(&graph);
2223
#endif
2224
    av_frame_free(&frame);
Fabrice Bellard's avatar
Fabrice Bellard committed
2225 2226 2227
    return 0;
}

2228 2229 2230
static int subtitle_thread(void *arg)
{
    VideoState *is = arg;
2231
    Frame *sp;
2232
    int got_subtitle;
2233 2234
    double pts;

Aneesh Dogra's avatar
Aneesh Dogra committed
2235
    for (;;) {
2236
        if (!(sp = frame_queue_peek_writable(&is->subpq)))
2237
            return 0;
2238

2239
        if ((got_subtitle = decoder_decode_frame(&is->subdec, NULL, &sp->sub)) < 0)
2240 2241
            break;

2242 2243 2244
        pts = 0;

        if (got_subtitle && sp->sub.format == 0) {
2245 2246
            if (sp->sub.pts != AV_NOPTS_VALUE)
                pts = sp->sub.pts / (double)AV_TIME_BASE;
2247
            sp->pts = pts;
2248
            sp->serial = is->subdec.pkt_serial;
2249 2250
            sp->width = is->subdec.avctx->width;
            sp->height = is->subdec.avctx->height;
2251
            sp->uploaded = 0;
2252 2253

            /* now we can update the picture count */
2254
            frame_queue_push(&is->subpq);
2255 2256
        } else if (got_subtitle) {
            avsubtitle_free(&sp->sub);
2257 2258 2259 2260 2261
        }
    }
    return 0;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
2262 2263 2264
/* copy samples for viewing in editor window */
static void update_sample_display(VideoState *is, short *samples, int samples_size)
{
2265
    int size, len;
Fabrice Bellard's avatar
Fabrice Bellard committed
2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280

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

2281 2282 2283
/* 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
2284
{
2285
    int wanted_nb_samples = nb_samples;
Fabrice Bellard's avatar
Fabrice Bellard committed
2286 2287

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

2292
        diff = get_clock(&is->audclk) - get_master_clock(is);
2293

2294
        if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) {
2295 2296 2297 2298 2299 2300 2301 2302 2303
            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) {
2304
                    wanted_nb_samples = nb_samples + (int)(diff * is->audio_src.freq);
2305 2306
                    min_nb_samples = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100));
                    max_nb_samples = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100));
2307
                    wanted_nb_samples = av_clip(wanted_nb_samples, min_nb_samples, max_nb_samples);
2308
                }
2309
                av_log(NULL, AV_LOG_TRACE, "diff=%f adiff=%f sample_diff=%d apts=%0.3f %f\n",
2310
                        diff, avg_diff, wanted_nb_samples - nb_samples,
2311
                        is->audio_clock, is->audio_diff_threshold);
Fabrice Bellard's avatar
Fabrice Bellard committed
2312
            }
2313 2314 2315 2316
        } 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
2317
            is->audio_diff_cum       = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2318 2319 2320
        }
    }

2321
    return wanted_nb_samples;
Fabrice Bellard's avatar
Fabrice Bellard committed
2322 2323
}

2324 2325 2326 2327 2328 2329 2330
/**
 * 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.
 */
2331
static int audio_decode_frame(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
2332
{
2333
    int data_size, resampled_data_size;
2334
    int64_t dec_channel_layout;
2335
    av_unused double audio_clock0;
2336
    int wanted_nb_samples;
2337
    Frame *af;
2338

2339 2340 2341 2342
    if (is->paused)
        return -1;

    do {
2343 2344 2345 2346 2347 2348 2349
#if defined(_WIN32)
        while (frame_queue_nb_remaining(&is->sampq) == 0) {
            if ((av_gettime_relative() - audio_callback_time) > 1000000LL * is->audio_hw_buf_size / is->audio_tgt.bytes_per_sec / 2)
                return -1;
            av_usleep (1000);
        }
#endif
2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378
        if (!(af = frame_queue_peek_readable(&is->sampq)))
            return -1;
        frame_queue_next(&is->sampq);
    } while (af->serial != is->audioq.serial);

    data_size = av_samples_get_buffer_size(NULL, av_frame_get_channels(af->frame),
                                           af->frame->nb_samples,
                                           af->frame->format, 1);

    dec_channel_layout =
        (af->frame->channel_layout && av_frame_get_channels(af->frame) == av_get_channel_layout_nb_channels(af->frame->channel_layout)) ?
        af->frame->channel_layout : av_get_default_channel_layout(av_frame_get_channels(af->frame));
    wanted_nb_samples = synchronize_audio(is, af->frame->nb_samples);

    if (af->frame->format        != is->audio_src.fmt            ||
        dec_channel_layout       != is->audio_src.channel_layout ||
        af->frame->sample_rate   != is->audio_src.freq           ||
        (wanted_nb_samples       != af->frame->nb_samples && !is->swr_ctx)) {
        swr_free(&is->swr_ctx);
        is->swr_ctx = swr_alloc_set_opts(NULL,
                                         is->audio_tgt.channel_layout, is->audio_tgt.fmt, is->audio_tgt.freq,
                                         dec_channel_layout,           af->frame->format, af->frame->sample_rate,
                                         0, NULL);
        if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) {
            av_log(NULL, AV_LOG_ERROR,
                   "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",
                    af->frame->sample_rate, av_get_sample_fmt_name(af->frame->format), av_frame_get_channels(af->frame),
                    is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels);
            swr_free(&is->swr_ctx);
2379
            return -1;
2380 2381 2382 2383 2384 2385
        }
        is->audio_src.channel_layout = dec_channel_layout;
        is->audio_src.channels       = av_frame_get_channels(af->frame);
        is->audio_src.freq = af->frame->sample_rate;
        is->audio_src.fmt = af->frame->format;
    }
2386

2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400
    if (is->swr_ctx) {
        const uint8_t **in = (const uint8_t **)af->frame->extended_data;
        uint8_t **out = &is->audio_buf1;
        int out_count = (int64_t)wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate + 256;
        int out_size  = av_samples_get_buffer_size(NULL, is->audio_tgt.channels, out_count, is->audio_tgt.fmt, 0);
        int len2;
        if (out_size < 0) {
            av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size() failed\n");
            return -1;
        }
        if (wanted_nb_samples != af->frame->nb_samples) {
            if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - af->frame->nb_samples) * is->audio_tgt.freq / af->frame->sample_rate,
                                        wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate) < 0) {
                av_log(NULL, AV_LOG_ERROR, "swr_set_compensation() failed\n");
2401
                return -1;
2402
            }
2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422
        }
        av_fast_malloc(&is->audio_buf1, &is->audio_buf1_size, out_size);
        if (!is->audio_buf1)
            return AVERROR(ENOMEM);
        len2 = swr_convert(is->swr_ctx, out, out_count, in, af->frame->nb_samples);
        if (len2 < 0) {
            av_log(NULL, AV_LOG_ERROR, "swr_convert() failed\n");
            return -1;
        }
        if (len2 == out_count) {
            av_log(NULL, AV_LOG_WARNING, "audio buffer is probably too small\n");
            if (swr_init(is->swr_ctx) < 0)
                swr_free(&is->swr_ctx);
        }
        is->audio_buf = is->audio_buf1;
        resampled_data_size = len2 * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt);
    } else {
        is->audio_buf = af->frame->data[0];
        resampled_data_size = data_size;
    }
2423

2424 2425 2426 2427 2428 2429 2430
    audio_clock0 = is->audio_clock;
    /* update the audio clock with the pts */
    if (!isnan(af->pts))
        is->audio_clock = af->pts + (double) af->frame->nb_samples / af->frame->sample_rate;
    else
        is->audio_clock = NAN;
    is->audio_clock_serial = af->serial;
2431
#ifdef DEBUG
2432 2433 2434 2435 2436 2437
    {
        static double last_clock;
        printf("audio: delay=%0.3f clock=%0.3f clock0=%0.3f\n",
               is->audio_clock - last_clock,
               is->audio_clock, audio_clock0);
        last_clock = is->audio_clock;
Fabrice Bellard's avatar
Fabrice Bellard committed
2438
    }
2439 2440
#endif
    return resampled_data_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
2441 2442 2443
}

/* prepare a new audio buffer */
2444
static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
Fabrice Bellard's avatar
Fabrice Bellard committed
2445 2446
{
    VideoState *is = opaque;
2447
    int audio_size, len1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2448

2449
    audio_callback_time = av_gettime_relative();
2450

Fabrice Bellard's avatar
Fabrice Bellard committed
2451 2452
    while (len > 0) {
        if (is->audio_buf_index >= is->audio_buf_size) {
2453
           audio_size = audio_decode_frame(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
2454 2455
           if (audio_size < 0) {
                /* if error, just output silence */
2456
               is->audio_buf = NULL;
2457
               is->audio_buf_size = SDL_AUDIO_MIN_BUFFER_SIZE / is->audio_tgt.frame_size * is->audio_tgt.frame_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
2458
           } else {
2459
               if (is->show_mode != SHOW_MODE_VIDEO)
Fabrice Bellard's avatar
Fabrice Bellard committed
2460 2461 2462 2463 2464 2465 2466 2467
                   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;
2468
        if (!is->muted && is->audio_buf && is->audio_volume == SDL_MIX_MAXVOLUME)
2469 2470
            memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
        else {
2471
            memset(stream, 0, len1);
2472
            if (!is->muted && is->audio_buf)
2473 2474
                SDL_MixAudio(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1, is->audio_volume);
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
2475 2476 2477 2478
        len -= len1;
        stream += len1;
        is->audio_buf_index += len1;
    }
2479 2480
    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. */
2481
    if (!isnan(is->audio_clock)) {
2482
        set_clock_at(&is->audclk, is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / is->audio_tgt.bytes_per_sec, is->audio_clock_serial, audio_callback_time / 1000000.0);
2483 2484
        sync_clock_to_slave(&is->extclk, &is->audclk);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2485 2486
}

2487
static int audio_open(void *opaque, int64_t wanted_channel_layout, int wanted_nb_channels, int wanted_sample_rate, struct AudioParams *audio_hw_params)
2488 2489 2490
{
    SDL_AudioSpec wanted_spec, spec;
    const char *env;
2491
    static const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6};
2492 2493
    static const int next_sample_rates[] = {0, 44100, 48000, 96000, 192000};
    int next_sample_rate_idx = FF_ARRAY_ELEMS(next_sample_rates) - 1;
2494 2495

    env = SDL_getenv("SDL_AUDIO_CHANNELS");
2496
    if (env) {
2497
        wanted_nb_channels = atoi(env);
2498 2499 2500 2501
        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);
2502 2503
        wanted_channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX;
    }
2504 2505
    wanted_nb_channels = av_get_channel_layout_nb_channels(wanted_channel_layout);
    wanted_spec.channels = wanted_nb_channels;
2506
    wanted_spec.freq = wanted_sample_rate;
2507
    if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
2508
        av_log(NULL, AV_LOG_ERROR, "Invalid sample rate or channel count!\n");
2509 2510
        return -1;
    }
2511 2512
    while (next_sample_rate_idx && next_sample_rates[next_sample_rate_idx] >= wanted_spec.freq)
        next_sample_rate_idx--;
2513 2514
    wanted_spec.format = AUDIO_S16SYS;
    wanted_spec.silence = 0;
2515
    wanted_spec.samples = FFMAX(SDL_AUDIO_MIN_BUFFER_SIZE, 2 << av_log2(wanted_spec.freq / SDL_AUDIO_MAX_CALLBACKS_PER_SEC));
2516
    wanted_spec.callback = sdl_audio_callback;
2517
    wanted_spec.userdata = opaque;
2518
    while (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
2519 2520
        av_log(NULL, AV_LOG_WARNING, "SDL_OpenAudio (%d channels, %d Hz): %s\n",
               wanted_spec.channels, wanted_spec.freq, SDL_GetError());
2521 2522
        wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)];
        if (!wanted_spec.channels) {
2523 2524 2525 2526 2527 2528 2529
            wanted_spec.freq = next_sample_rates[next_sample_rate_idx--];
            wanted_spec.channels = wanted_nb_channels;
            if (!wanted_spec.freq) {
                av_log(NULL, AV_LOG_ERROR,
                       "No more combinations to try, audio open failed\n");
                return -1;
            }
2530 2531
        }
        wanted_channel_layout = av_get_default_channel_layout(wanted_spec.channels);
2532 2533
    }
    if (spec.format != AUDIO_S16SYS) {
2534 2535
        av_log(NULL, AV_LOG_ERROR,
               "SDL advised audio format %d is not supported!\n", spec.format);
2536 2537 2538 2539 2540
        return -1;
    }
    if (spec.channels != wanted_spec.channels) {
        wanted_channel_layout = av_get_default_channel_layout(spec.channels);
        if (!wanted_channel_layout) {
2541 2542
            av_log(NULL, AV_LOG_ERROR,
                   "SDL advised channel count %d is not supported!\n", spec.channels);
2543 2544 2545 2546
            return -1;
        }
    }

2547 2548 2549 2550
    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;
2551 2552 2553 2554 2555 2556
    audio_hw_params->frame_size = av_samples_get_buffer_size(NULL, audio_hw_params->channels, 1, audio_hw_params->fmt, 1);
    audio_hw_params->bytes_per_sec = av_samples_get_buffer_size(NULL, audio_hw_params->channels, audio_hw_params->freq, audio_hw_params->fmt, 1);
    if (audio_hw_params->bytes_per_sec <= 0 || audio_hw_params->frame_size <= 0) {
        av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size failed\n");
        return -1;
    }
2557
    return spec.size;
2558 2559
}

Fabrice Bellard's avatar
Fabrice Bellard committed
2560 2561 2562 2563
/* open a given stream. Return 0 if OK */
static int stream_component_open(VideoState *is, int stream_index)
{
    AVFormatContext *ic = is->ic;
2564
    AVCodecContext *avctx;
Fabrice Bellard's avatar
Fabrice Bellard committed
2565
    AVCodec *codec;
2566
    const char *forced_codec_name = NULL;
2567
    AVDictionary *opts = NULL;
2568
    AVDictionaryEntry *t = NULL;
Marton Balint's avatar
Marton Balint committed
2569 2570
    int sample_rate, nb_channels;
    int64_t channel_layout;
2571
    int ret = 0;
2572
    int stream_lowres = lowres;
Fabrice Bellard's avatar
Fabrice Bellard committed
2573 2574 2575

    if (stream_index < 0 || stream_index >= ic->nb_streams)
        return -1;
2576 2577 2578 2579 2580 2581 2582 2583 2584

    avctx = avcodec_alloc_context3(NULL);
    if (!avctx)
        return AVERROR(ENOMEM);

    ret = avcodec_parameters_to_context(avctx, ic->streams[stream_index]->codecpar);
    if (ret < 0)
        goto fail;
    av_codec_set_pkt_timebase(avctx, ic->streams[stream_index]->time_base);
2585

2586
    codec = avcodec_find_decoder(avctx->codec_id);
2587

2588
    switch(avctx->codec_type){
2589 2590 2591
        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;
2592
    }
2593 2594 2595
    if (forced_codec_name)
        codec = avcodec_find_decoder_by_name(forced_codec_name);
    if (!codec) {
2596 2597 2598 2599
        if (forced_codec_name) av_log(NULL, AV_LOG_WARNING,
                                      "No codec could be found with name '%s'\n", forced_codec_name);
        else                   av_log(NULL, AV_LOG_WARNING,
                                      "No codec could be found with id %d\n", avctx->codec_id);
2600 2601
        ret = AVERROR(EINVAL);
        goto fail;
2602
    }
2603

2604
    avctx->codec_id = codec->id;
2605
    if(stream_lowres > av_codec_get_max_lowres(codec)){
2606
        av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n",
2607
                av_codec_get_max_lowres(codec));
2608
        stream_lowres = av_codec_get_max_lowres(codec);
2609
    }
2610
    av_codec_set_lowres(avctx, stream_lowres);
2611

2612
#if FF_API_EMU_EDGE
2613
    if(stream_lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE;
2614
#endif
2615 2616
    if (fast)
        avctx->flags2 |= AV_CODEC_FLAG2_FAST;
2617
#if FF_API_EMU_EDGE
2618
    if(codec->capabilities & AV_CODEC_CAP_DR1)
2619
        avctx->flags |= CODEC_FLAG_EMU_EDGE;
2620
#endif
2621

2622
    opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], codec);
2623 2624
    if (!av_dict_get(opts, "threads", NULL, 0))
        av_dict_set(&opts, "threads", "auto", 0);
2625
    if (stream_lowres)
2626
        av_dict_set_int(&opts, "lowres", stream_lowres, 0);
2627
    if (avctx->codec_type == AVMEDIA_TYPE_VIDEO || avctx->codec_type == AVMEDIA_TYPE_AUDIO)
2628
        av_dict_set(&opts, "refcounted_frames", "1", 0);
2629 2630 2631
    if ((ret = avcodec_open2(avctx, codec, &opts)) < 0) {
        goto fail;
    }
2632 2633
    if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
        av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
2634 2635
        ret =  AVERROR_OPTION_NOT_FOUND;
        goto fail;
2636
    }
2637

2638
    is->eof = 0;
2639
    ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
Aneesh Dogra's avatar
Aneesh Dogra committed
2640
    switch (avctx->codec_type) {
2641
    case AVMEDIA_TYPE_AUDIO:
Marton Balint's avatar
Marton Balint committed
2642 2643 2644 2645 2646 2647 2648 2649 2650
#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)
2651
                goto fail;
Marton Balint's avatar
Marton Balint committed
2652 2653
            link = is->out_audio_filter->inputs[0];
            sample_rate    = link->sample_rate;
2654
            nb_channels    = avfilter_link_get_channels(link);
Marton Balint's avatar
Marton Balint committed
2655 2656 2657 2658 2659 2660 2661 2662
            channel_layout = link->channel_layout;
        }
#else
        sample_rate    = avctx->sample_rate;
        nb_channels    = avctx->channels;
        channel_layout = avctx->channel_layout;
#endif

2663
        /* prepare audio output */
Marton Balint's avatar
Marton Balint committed
2664
        if ((ret = audio_open(is, channel_layout, nb_channels, sample_rate, &is->audio_tgt)) < 0)
2665
            goto fail;
2666 2667
        is->audio_hw_buf_size = ret;
        is->audio_src = is->audio_tgt;
Aneesh Dogra's avatar
Aneesh Dogra committed
2668
        is->audio_buf_size  = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2669
        is->audio_buf_index = 0;
2670 2671

        /* init averaging filter */
Aneesh Dogra's avatar
Aneesh Dogra committed
2672
        is->audio_diff_avg_coef  = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
2673
        is->audio_diff_avg_count = 0;
2674
        /* since we do not have a precise anough audio FIFO fullness,
2675
           we correct audio sync only if larger than this threshold */
2676
        is->audio_diff_threshold = (double)(is->audio_hw_buf_size) / is->audio_tgt.bytes_per_sec;
2677

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

2681
        decoder_init(&is->auddec, avctx, &is->audioq, is->continue_read_thread);
2682 2683 2684 2685
        if ((is->ic->iformat->flags & (AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK)) && !is->ic->iformat->read_seek) {
            is->auddec.start_pts = is->audio_st->start_time;
            is->auddec.start_pts_tb = is->audio_st->time_base;
        }
2686
        if ((ret = decoder_start(&is->auddec, audio_thread, is)) < 0)
2687
            goto out;
2688
        SDL_PauseAudio(0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2689
        break;
2690
    case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2691 2692 2693
        is->video_stream = stream_index;
        is->video_st = ic->streams[stream_index];

2694
        decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread);
2695
        if ((ret = decoder_start(&is->viddec, video_thread, is)) < 0)
2696
            goto out;
2697
        is->queue_attachments_req = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2698
        break;
2699
    case AVMEDIA_TYPE_SUBTITLE:
2700 2701
        is->subtitle_stream = stream_index;
        is->subtitle_st = ic->streams[stream_index];
2702

2703
        decoder_init(&is->subdec, avctx, &is->subtitleq, is->continue_read_thread);
2704
        if ((ret = decoder_start(&is->subdec, subtitle_thread, is)) < 0)
2705
            goto out;
2706
        break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2707 2708 2709
    default:
        break;
    }
2710
    goto out;
2711 2712

fail:
2713 2714
    avcodec_free_context(&avctx);
out:
2715 2716 2717
    av_dict_free(&opts);

    return ret;
Fabrice Bellard's avatar
Fabrice Bellard committed
2718 2719
}

2720
static int decode_interrupt_cb(void *ctx)
2721
{
2722 2723
    VideoState *is = ctx;
    return is->abort_request;
2724
}
Fabrice Bellard's avatar
Fabrice Bellard committed
2725

2726 2727 2728 2729
static int stream_has_enough_packets(AVStream *st, int stream_id, PacketQueue *queue) {
    return stream_id < 0 ||
           queue->abort_request ||
           (st->disposition & AV_DISPOSITION_ATTACHED_PIC) ||
2730
           queue->nb_packets > MIN_FRAMES && (!queue->duration || av_q2d(st->time_base) * queue->duration > 1.0);
2731 2732
}

2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748
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
2749
/* this thread gets the stream from the disk or the network */
2750
static int read_thread(void *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
2751 2752
{
    VideoState *is = arg;
2753
    AVFormatContext *ic = NULL;
2754
    int err, i, ret;
2755
    int st_index[AVMEDIA_TYPE_NB];
Fabrice Bellard's avatar
Fabrice Bellard committed
2756
    AVPacket pkt1, *pkt = &pkt1;
2757
    int64_t stream_start_time;
2758
    int pkt_in_play_range = 0;
2759
    AVDictionaryEntry *t;
2760 2761
    AVDictionary **opts;
    int orig_nb_streams;
2762
    SDL_mutex *wait_mutex = SDL_CreateMutex();
2763
    int scan_all_pmts_set = 0;
2764
    int64_t pkt_ts;
2765

2766 2767 2768 2769 2770 2771
    if (!wait_mutex) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
        ret = AVERROR(ENOMEM);
        goto fail;
    }

2772
    memset(st_index, -1, sizeof(st_index));
2773 2774 2775
    is->last_video_stream = is->video_stream = -1;
    is->last_audio_stream = is->audio_stream = -1;
    is->last_subtitle_stream = is->subtitle_stream = -1;
2776
    is->eof = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2777

2778
    ic = avformat_alloc_context();
2779 2780 2781 2782 2783
    if (!ic) {
        av_log(NULL, AV_LOG_FATAL, "Could not allocate context.\n");
        ret = AVERROR(ENOMEM);
        goto fail;
    }
2784
    ic->interrupt_callback.callback = decode_interrupt_cb;
2785
    ic->interrupt_callback.opaque = is;
2786 2787 2788 2789
    if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
        av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
        scan_all_pmts_set = 1;
    }
2790
    err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts);
2791 2792 2793 2794 2795
    if (err < 0) {
        print_error(is->filename, err);
        ret = -1;
        goto fail;
    }
2796 2797 2798
    if (scan_all_pmts_set)
        av_dict_set(&format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE);

2799 2800 2801 2802 2803
    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
2804
    is->ic = ic;
2805

Aneesh Dogra's avatar
Aneesh Dogra committed
2806
    if (genpts)
2807 2808
        ic->flags |= AVFMT_FLAG_GENPTS;

2809 2810
    av_format_inject_global_side_data(ic);

2811
    opts = setup_find_stream_info_opts(ic, codec_opts);
2812
    orig_nb_streams = ic->nb_streams;
2813

2814
    err = avformat_find_stream_info(ic, opts);
2815 2816 2817 2818 2819

    for (i = 0; i < orig_nb_streams; i++)
        av_dict_free(&opts[i]);
    av_freep(&opts);

2820
    if (err < 0) {
2821 2822
        av_log(NULL, AV_LOG_WARNING,
               "%s: could not find codec parameters\n", is->filename);
2823 2824 2825
        ret = -1;
        goto fail;
    }
2826

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

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

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

2835 2836 2837
    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
2838 2839 2840 2841 2842 2843 2844 2845
    /* 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;
2846
        ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2847
        if (ret < 0) {
2848
            av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n",
Fabrice Bellard's avatar
Fabrice Bellard committed
2849 2850 2851 2852
                    is->filename, (double)timestamp / AV_TIME_BASE);
        }
    }

2853 2854
    is->realtime = is_realtime(ic);

2855 2856 2857
    if (show_status)
        av_dump_format(ic, 0, is->filename, 0);

2858 2859
    for (i = 0; i < ic->nb_streams; i++) {
        AVStream *st = ic->streams[i];
2860
        enum AVMediaType type = st->codecpar->codec_type;
2861
        st->discard = AVDISCARD_ALL;
2862
        if (type >= 0 && wanted_stream_spec[type] && st_index[type] == -1)
2863 2864 2865 2866 2867 2868 2869 2870 2871 2872
            if (avformat_match_stream_specifier(ic, st, wanted_stream_spec[type]) > 0)
                st_index[type] = i;
    }
    for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
        if (wanted_stream_spec[i] && st_index[i] == -1) {
            av_log(NULL, AV_LOG_ERROR, "Stream specifier %s does not match any %s stream\n", wanted_stream_spec[i], av_get_media_type_string(i));
            st_index[i] = INT_MAX;
        }
    }

2873
    if (!video_disable)
2874 2875
        st_index[AVMEDIA_TYPE_VIDEO] =
            av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,
2876
                                st_index[AVMEDIA_TYPE_VIDEO], -1, NULL, 0);
2877
    if (!audio_disable)
2878 2879
        st_index[AVMEDIA_TYPE_AUDIO] =
            av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO,
2880
                                st_index[AVMEDIA_TYPE_AUDIO],
2881 2882
                                st_index[AVMEDIA_TYPE_VIDEO],
                                NULL, 0);
2883
    if (!video_disable && !subtitle_disable)
2884 2885
        st_index[AVMEDIA_TYPE_SUBTITLE] =
            av_find_best_stream(ic, AVMEDIA_TYPE_SUBTITLE,
2886
                                st_index[AVMEDIA_TYPE_SUBTITLE],
2887 2888 2889 2890
                                (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
2891

2892
    is->show_mode = show_mode;
2893 2894
    if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
        AVStream *st = ic->streams[st_index[AVMEDIA_TYPE_VIDEO]];
2895
        AVCodecParameters *codecpar = st->codecpar;
2896
        AVRational sar = av_guess_sample_aspect_ratio(ic, st, NULL);
2897 2898
        if (codecpar->width)
            set_default_window_size(codecpar->width, codecpar->height, sar);
2899
    }
2900

Fabrice Bellard's avatar
Fabrice Bellard committed
2901
    /* open the streams */
2902 2903
    if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {
        stream_component_open(is, st_index[AVMEDIA_TYPE_AUDIO]);
Fabrice Bellard's avatar
Fabrice Bellard committed
2904 2905
    }

Aneesh Dogra's avatar
Aneesh Dogra committed
2906
    ret = -1;
2907
    if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
Aneesh Dogra's avatar
Aneesh Dogra committed
2908
        ret = stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO]);
Michael Niedermayer's avatar
Michael Niedermayer committed
2909
    }
2910 2911
    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
2912

2913 2914
    if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) {
        stream_component_open(is, st_index[AVMEDIA_TYPE_SUBTITLE]);
2915 2916
    }

Fabrice Bellard's avatar
Fabrice Bellard committed
2917
    if (is->video_stream < 0 && is->audio_stream < 0) {
2918 2919
        av_log(NULL, AV_LOG_FATAL, "Failed to open file '%s' or configure filtergraph\n",
               is->filename);
2920
        ret = -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2921 2922 2923
        goto fail;
    }

2924
    if (infinite_buffer < 0 && is->realtime)
2925 2926
        infinite_buffer = 1;

Aneesh Dogra's avatar
Aneesh Dogra committed
2927
    for (;;) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2928 2929
        if (is->abort_request)
            break;
2930 2931
        if (is->paused != is->last_paused) {
            is->last_paused = is->paused;
Fabrice Bellard's avatar
Fabrice Bellard committed
2932
            if (is->paused)
Aneesh Dogra's avatar
Aneesh Dogra committed
2933
                is->read_pause_return = av_read_pause(ic);
Fabrice Bellard's avatar
Fabrice Bellard committed
2934 2935
            else
                av_read_play(ic);
2936
        }
2937 2938 2939
#if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL
        if (is->paused &&
                (!strcmp(ic->iformat->name, "rtsp") ||
2940
                 (ic->pb && !strncmp(input_filename, "mmsh:", 5)))) {
2941 2942 2943 2944 2945
            /* wait 10 ms to avoid trying to get another packet */
            /* XXX: horrible */
            SDL_Delay(10);
            continue;
        }
2946
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
2947
        if (is->seek_req) {
Aneesh Dogra's avatar
Aneesh Dogra committed
2948 2949 2950 2951
            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
2952
//      of the seek_pos/seek_rel variables
2953

2954
            ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags);
Fabrice Bellard's avatar
Fabrice Bellard committed
2955
            if (ret < 0) {
2956 2957
                av_log(NULL, AV_LOG_ERROR,
                       "%s: error while seeking\n", is->ic->filename);
Aneesh Dogra's avatar
Aneesh Dogra committed
2958
            } else {
2959 2960
                if (is->audio_stream >= 0) {
                    packet_queue_flush(&is->audioq);
2961
                    packet_queue_put(&is->audioq, &flush_pkt);
2962
                }
2963 2964
                if (is->subtitle_stream >= 0) {
                    packet_queue_flush(&is->subtitleq);
2965
                    packet_queue_put(&is->subtitleq, &flush_pkt);
2966
                }
2967 2968
                if (is->video_stream >= 0) {
                    packet_queue_flush(&is->videoq);
2969
                    packet_queue_put(&is->videoq, &flush_pkt);
2970
                }
2971
                if (is->seek_flags & AVSEEK_FLAG_BYTE) {
2972
                   set_clock(&is->extclk, NAN, 0);
2973
                } else {
2974
                   set_clock(&is->extclk, seek_target / (double)AV_TIME_BASE, 0);
2975
                }
Fabrice Bellard's avatar
Fabrice Bellard committed
2976 2977
            }
            is->seek_req = 0;
2978
            is->queue_attachments_req = 1;
2979
            is->eof = 0;
2980 2981
            if (is->paused)
                step_to_next_frame(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
2982
        }
2983
        if (is->queue_attachments_req) {
2984 2985 2986 2987 2988
            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);
2989
                packet_queue_put_nullpacket(&is->videoq, is->video_stream);
2990
            }
2991
            is->queue_attachments_req = 0;
2992
        }
2993

Fabrice Bellard's avatar
Fabrice Bellard committed
2994
        /* if the queue are full, no need to read more */
2995
        if (infinite_buffer<1 &&
2996
              (is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
2997 2998 2999
            || (stream_has_enough_packets(is->audio_st, is->audio_stream, &is->audioq) &&
                stream_has_enough_packets(is->video_st, is->video_stream, &is->videoq) &&
                stream_has_enough_packets(is->subtitle_st, is->subtitle_stream, &is->subtitleq)))) {
Fabrice Bellard's avatar
Fabrice Bellard committed
3000
            /* wait 10 ms */
3001 3002 3003
            SDL_LockMutex(wait_mutex);
            SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
            SDL_UnlockMutex(wait_mutex);
Fabrice Bellard's avatar
Fabrice Bellard committed
3004 3005
            continue;
        }
3006
        if (!is->paused &&
3007
            (!is->audio_st || (is->auddec.finished == is->audioq.serial && frame_queue_nb_remaining(&is->sampq) == 0)) &&
3008
            (!is->video_st || (is->viddec.finished == is->videoq.serial && frame_queue_nb_remaining(&is->pictq) == 0))) {
3009 3010 3011 3012 3013 3014 3015
            if (loop != 1 && (!loop || --loop)) {
                stream_seek(is, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0);
            } else if (autoexit) {
                ret = AVERROR_EOF;
                goto fail;
            }
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
3016
        ret = av_read_frame(ic, pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
3017
        if (ret < 0) {
3018
            if ((ret == AVERROR_EOF || avio_feof(ic->pb)) && !is->eof) {
3019 3020 3021 3022 3023 3024
                if (is->video_stream >= 0)
                    packet_queue_put_nullpacket(&is->videoq, is->video_stream);
                if (is->audio_stream >= 0)
                    packet_queue_put_nullpacket(&is->audioq, is->audio_stream);
                if (is->subtitle_stream >= 0)
                    packet_queue_put_nullpacket(&is->subtitleq, is->subtitle_stream);
3025
                is->eof = 1;
3026
            }
3027
            if (ic->pb && ic->pb->error)
3028
                break;
3029 3030 3031
            SDL_LockMutex(wait_mutex);
            SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
            SDL_UnlockMutex(wait_mutex);
3032
            continue;
3033
        } else {
3034
            is->eof = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
3035
        }
3036
        /* check if packet is in play range specified by user, then queue, otherwise discard */
3037
        stream_start_time = ic->streams[pkt->stream_index]->start_time;
3038
        pkt_ts = pkt->pts == AV_NOPTS_VALUE ? pkt->dts : pkt->pts;
3039
        pkt_in_play_range = duration == AV_NOPTS_VALUE ||
3040
                (pkt_ts - (stream_start_time != AV_NOPTS_VALUE ? stream_start_time : 0)) *
3041
                av_q2d(ic->streams[pkt->stream_index]->time_base) -
Aneesh Dogra's avatar
Aneesh Dogra committed
3042 3043
                (double)(start_time != AV_NOPTS_VALUE ? start_time : 0) / 1000000
                <= ((double)duration / 1000000);
3044
        if (pkt->stream_index == is->audio_stream && pkt_in_play_range) {
Fabrice Bellard's avatar
Fabrice Bellard committed
3045
            packet_queue_put(&is->audioq, pkt);
3046 3047
        } 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
3048
            packet_queue_put(&is->videoq, pkt);
3049
        } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {
3050
            packet_queue_put(&is->subtitleq, pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
3051
        } else {
3052
            av_packet_unref(pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
3053 3054 3055
        }
    }

3056
    ret = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
3057
 fail:
3058
    if (ic && !is->ic)
3059
        avformat_close_input(&ic);
3060

3061 3062
    if (ret != 0) {
        SDL_Event event;
3063

3064 3065 3066 3067
        event.type = FF_QUIT_EVENT;
        event.user.data1 = is;
        SDL_PushEvent(&event);
    }
3068
    SDL_DestroyMutex(wait_mutex);
Fabrice Bellard's avatar
Fabrice Bellard committed
3069 3070 3071
    return 0;
}

3072
static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
Fabrice Bellard's avatar
Fabrice Bellard committed
3073 3074 3075 3076 3077 3078
{
    VideoState *is;

    is = av_mallocz(sizeof(VideoState));
    if (!is)
        return NULL;
3079 3080 3081
    is->filename = av_strdup(filename);
    if (!is->filename)
        goto fail;
3082
    is->iformat = iformat;
Aneesh Dogra's avatar
Aneesh Dogra committed
3083 3084
    is->ytop    = 0;
    is->xleft   = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
3085 3086

    /* start video display */
3087 3088 3089 3090
    if (frame_queue_init(&is->pictq, &is->videoq, VIDEO_PICTURE_QUEUE_SIZE, 1) < 0)
        goto fail;
    if (frame_queue_init(&is->subpq, &is->subtitleq, SUBPICTURE_QUEUE_SIZE, 0) < 0)
        goto fail;
3091 3092
    if (frame_queue_init(&is->sampq, &is->audioq, SAMPLE_QUEUE_SIZE, 1) < 0)
        goto fail;
3093

3094 3095 3096 3097
    if (packet_queue_init(&is->videoq) < 0 ||
        packet_queue_init(&is->audioq) < 0 ||
        packet_queue_init(&is->subtitleq) < 0)
        goto fail;
3098

3099 3100 3101 3102
    if (!(is->continue_read_thread = SDL_CreateCond())) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
        goto fail;
    }
3103

3104 3105 3106
    init_clock(&is->vidclk, &is->videoq.serial);
    init_clock(&is->audclk, &is->audioq.serial);
    init_clock(&is->extclk, &is->extclk.serial);
3107
    is->audio_clock_serial = -1;
3108 3109
    is->audio_volume = SDL_MIX_MAXVOLUME;
    is->muted = 0;
3110
    is->av_sync_type = av_sync_type;
3111
    is->read_tid     = SDL_CreateThread(read_thread, "read_thread", is);
3112
    if (!is->read_tid) {
3113
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateThread(): %s\n", SDL_GetError());
3114 3115
fail:
        stream_close(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
3116 3117 3118 3119 3120
        return NULL;
    }
    return is;
}

3121
static void stream_cycle_channel(VideoState *is, int codec_type)
3122 3123 3124
{
    AVFormatContext *ic = is->ic;
    int start_index, stream_index;
3125
    int old_index;
3126
    AVStream *st;
3127 3128
    AVProgram *p = NULL;
    int nb_streams = is->ic->nb_streams;
3129

3130 3131 3132 3133 3134 3135 3136 3137 3138 3139
    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;
    }
3140
    stream_index = start_index;
3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154

    if (codec_type != AVMEDIA_TYPE_VIDEO && is->video_stream != -1) {
        p = av_find_program_from_stream(ic, NULL, is->video_stream);
        if (p) {
            nb_streams = p->nb_stream_indexes;
            for (start_index = 0; start_index < nb_streams; start_index++)
                if (p->stream_index[start_index] == stream_index)
                    break;
            if (start_index == nb_streams)
                start_index = -1;
            stream_index = start_index;
        }
    }

Aneesh Dogra's avatar
Aneesh Dogra committed
3155
    for (;;) {
3156
        if (++stream_index >= nb_streams)
3157
        {
3158
            if (codec_type == AVMEDIA_TYPE_SUBTITLE)
3159 3160
            {
                stream_index = -1;
3161
                is->last_subtitle_stream = -1;
3162
                goto the_end;
3163 3164 3165 3166
            }
            if (start_index == -1)
                return;
            stream_index = 0;
3167
        }
3168 3169
        if (stream_index == start_index)
            return;
3170
        st = is->ic->streams[p ? p->stream_index[stream_index] : stream_index];
3171
        if (st->codecpar->codec_type == codec_type) {
3172
            /* check that parameters are OK */
Aneesh Dogra's avatar
Aneesh Dogra committed
3173
            switch (codec_type) {
3174
            case AVMEDIA_TYPE_AUDIO:
3175 3176
                if (st->codecpar->sample_rate != 0 &&
                    st->codecpar->channels != 0)
3177 3178
                    goto the_end;
                break;
3179 3180
            case AVMEDIA_TYPE_VIDEO:
            case AVMEDIA_TYPE_SUBTITLE:
3181 3182 3183 3184 3185 3186 3187
                goto the_end;
            default:
                break;
            }
        }
    }
 the_end:
3188 3189
    if (p && stream_index != -1)
        stream_index = p->stream_index[stream_index];
3190 3191 3192 3193 3194
    av_log(NULL, AV_LOG_INFO, "Switch %s stream from #%d to #%d\n",
           av_get_media_type_string(codec_type),
           old_index,
           stream_index);

3195
    stream_component_close(is, old_index);
3196 3197 3198 3199
    stream_component_open(is, stream_index);
}


3200
static void toggle_full_screen(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
3201
{
3202
    is_full_screen = !is_full_screen;
3203
    SDL_SetWindowFullscreen(window, is_full_screen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
3204 3205
}

3206
static void toggle_audio_display(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
3207
{
3208 3209 3210 3211 3212 3213 3214 3215
    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) {
        is->force_refresh = 1;
        is->show_mode = next;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
3216 3217
}

3218
static void refresh_loop_wait_event(VideoState *is, SDL_Event *event) {
3219 3220
    double remaining_time = 0.0;
    SDL_PumpEvents();
3221
    while (!SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
3222
        if (!cursor_hidden && av_gettime_relative() - cursor_last_shown > CURSOR_HIDE_DELAY) {
3223 3224 3225
            SDL_ShowCursor(0);
            cursor_hidden = 1;
        }
3226 3227
        if (remaining_time > 0.0)
            av_usleep((int64_t)(remaining_time * 1000000.0));
3228 3229 3230 3231
        remaining_time = REFRESH_RATE;
        if (is->show_mode != SHOW_MODE_NONE && (!is->paused || is->force_refresh))
            video_refresh(is, &remaining_time);
        SDL_PumpEvents();
3232
    }
3233 3234
}

3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261
static void seek_chapter(VideoState *is, int incr)
{
    int64_t pos = get_master_clock(is) * AV_TIME_BASE;
    int i;

    if (!is->ic->nb_chapters)
        return;

    /* find the current chapter */
    for (i = 0; i < is->ic->nb_chapters; i++) {
        AVChapter *ch = is->ic->chapters[i];
        if (av_compare_ts(pos, AV_TIME_BASE_Q, ch->start, ch->time_base) < 0) {
            i--;
            break;
        }
    }

    i += incr;
    i = FFMAX(i, 0);
    if (i >= is->ic->nb_chapters)
        return;

    av_log(NULL, AV_LOG_VERBOSE, "Seeking to chapter %d.\n", i);
    stream_seek(is, av_rescale_q(is->ic->chapters[i]->start, is->ic->chapters[i]->time_base,
                                 AV_TIME_BASE_Q), 0, 0);
}

Fabrice Bellard's avatar
Fabrice Bellard committed
3262
/* handle an event sent by the GUI */
3263
static void event_loop(VideoState *cur_stream)
Fabrice Bellard's avatar
Fabrice Bellard committed
3264 3265
{
    SDL_Event event;
3266
    double incr, pos, frac;
Fabrice Bellard's avatar
Fabrice Bellard committed
3267

Aneesh Dogra's avatar
Aneesh Dogra committed
3268
    for (;;) {
Michael Niedermayer's avatar
Michael Niedermayer committed
3269
        double x;
3270
        refresh_loop_wait_event(cur_stream, &event);
Aneesh Dogra's avatar
Aneesh Dogra committed
3271
        switch (event.type) {
Fabrice Bellard's avatar
Fabrice Bellard committed
3272
        case SDL_KEYDOWN:
3273
            if (exit_on_keydown) {
3274
                do_exit(cur_stream);
3275 3276
                break;
            }
Aneesh Dogra's avatar
Aneesh Dogra committed
3277
            switch (event.key.keysym.sym) {
Fabrice Bellard's avatar
Fabrice Bellard committed
3278 3279
            case SDLK_ESCAPE:
            case SDLK_q:
3280
                do_exit(cur_stream);
Fabrice Bellard's avatar
Fabrice Bellard committed
3281 3282
                break;
            case SDLK_f:
3283
                toggle_full_screen(cur_stream);
3284
                cur_stream->force_refresh = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
3285 3286 3287
                break;
            case SDLK_p:
            case SDLK_SPACE:
3288
                toggle_pause(cur_stream);
Fabrice Bellard's avatar
Fabrice Bellard committed
3289
                break;
3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300
            case SDLK_m:
                toggle_mute(cur_stream);
                break;
            case SDLK_KP_MULTIPLY:
            case SDLK_0:
                update_volume(cur_stream, 1, SDL_VOLUME_STEP);
                break;
            case SDLK_KP_DIVIDE:
            case SDLK_9:
                update_volume(cur_stream, -1, SDL_VOLUME_STEP);
                break;
Aneesh Dogra's avatar
Aneesh Dogra committed
3301
            case SDLK_s: // S: Step to next frame
3302
                step_to_next_frame(cur_stream);
3303
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
3304
            case SDLK_a:
3305
                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
3306 3307
                break;
            case SDLK_v:
3308
                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
3309
                break;
3310 3311 3312 3313 3314
            case SDLK_c:
                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
                break;
3315
            case SDLK_t:
3316
                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
3317
                break;
3318
            case SDLK_w:
3319 3320 3321 3322 3323 3324 3325 3326 3327
#if CONFIG_AVFILTER
                if (cur_stream->show_mode == SHOW_MODE_VIDEO && cur_stream->vfilter_idx < nb_vfilters - 1) {
                    if (++cur_stream->vfilter_idx >= nb_vfilters)
                        cur_stream->vfilter_idx = 0;
                } else {
                    cur_stream->vfilter_idx = 0;
                    toggle_audio_display(cur_stream);
                }
#else
3328
                toggle_audio_display(cur_stream);
3329
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3330
                break;
3331
            case SDLK_PAGEUP:
3332 3333 3334 3335 3336 3337
                if (cur_stream->ic->nb_chapters <= 1) {
                    incr = 600.0;
                    goto do_seek;
                }
                seek_chapter(cur_stream, 1);
                break;
3338
            case SDLK_PAGEDOWN:
3339 3340 3341 3342 3343 3344
                if (cur_stream->ic->nb_chapters <= 1) {
                    incr = -600.0;
                    goto do_seek;
                }
                seek_chapter(cur_stream, -1);
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356
            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:
3357
                    if (seek_by_bytes) {
3358 3359 3360
                        pos = -1;
                        if (pos < 0 && cur_stream->video_stream >= 0)
                            pos = frame_queue_last_pos(&cur_stream->pictq);
3361 3362
                        if (pos < 0 && cur_stream->audio_stream >= 0)
                            pos = frame_queue_last_pos(&cur_stream->sampq);
3363
                        if (pos < 0)
3364
                            pos = avio_tell(cur_stream->ic->pb);
3365
                        if (cur_stream->ic->bit_rate)
3366
                            incr *= cur_stream->ic->bit_rate / 8.0;
3367 3368 3369
                        else
                            incr *= 180000.0;
                        pos += incr;
3370
                        stream_seek(cur_stream, pos, incr, 1);
3371 3372
                    } else {
                        pos = get_master_clock(cur_stream);
3373 3374
                        if (isnan(pos))
                            pos = (double)cur_stream->seek_pos / AV_TIME_BASE;
3375
                        pos += incr;
3376 3377
                        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;
3378
                        stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0);
3379
                    }
Fabrice Bellard's avatar
Fabrice Bellard committed
3380
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
3381 3382 3383 3384
            default:
                break;
            }
            break;
3385
        case SDL_MOUSEBUTTONDOWN:
3386
            if (exit_on_mousedown) {
3387
                do_exit(cur_stream);
3388 3389
                break;
            }
3390 3391 3392 3393 3394 3395 3396 3397 3398 3399
            if (event.button.button == SDL_BUTTON_LEFT) {
                static int64_t last_mouse_left_click = 0;
                if (av_gettime_relative() - last_mouse_left_click <= 500000) {
                    toggle_full_screen(cur_stream);
                    cur_stream->force_refresh = 1;
                    last_mouse_left_click = 0;
                } else {
                    last_mouse_left_click = av_gettime_relative();
                }
            }
Michael Niedermayer's avatar
Michael Niedermayer committed
3400
        case SDL_MOUSEMOTION:
3401 3402 3403 3404
            if (cursor_hidden) {
                SDL_ShowCursor(1);
                cursor_hidden = 0;
            }
3405
            cursor_last_shown = av_gettime_relative();
Aneesh Dogra's avatar
Aneesh Dogra committed
3406
            if (event.type == SDL_MOUSEBUTTONDOWN) {
3407 3408
                if (event.button.button != SDL_BUTTON_RIGHT)
                    break;
Aneesh Dogra's avatar
Aneesh Dogra committed
3409 3410
                x = event.button.x;
            } else {
3411
                if (!(event.motion.state & SDL_BUTTON_RMASK))
Michael Niedermayer's avatar
Michael Niedermayer committed
3412
                    break;
Aneesh Dogra's avatar
Aneesh Dogra committed
3413
                x = event.motion.x;
3414
            }
Aneesh Dogra's avatar
Aneesh Dogra committed
3415 3416
                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
3417
                    stream_seek(cur_stream, size*x/cur_stream->width, 0, 1);
Aneesh Dogra's avatar
Aneesh Dogra committed
3418
                } else {
Michael Niedermayer's avatar
Michael Niedermayer committed
3419 3420 3421
                    int64_t ts;
                    int ns, hh, mm, ss;
                    int tns, thh, tmm, tss;
Aneesh Dogra's avatar
Aneesh Dogra committed
3422 3423 3424 3425 3426 3427 3428 3429 3430
                    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);
3431 3432
                    av_log(NULL, AV_LOG_INFO,
                           "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d)       \n", frac*100,
Michael Niedermayer's avatar
Michael Niedermayer committed
3433
                            hh, mm, ss, thh, tmm, tss);
Aneesh Dogra's avatar
Aneesh Dogra committed
3434
                    ts = frac * cur_stream->ic->duration;
Michael Niedermayer's avatar
Michael Niedermayer committed
3435 3436 3437
                    if (cur_stream->ic->start_time != AV_NOPTS_VALUE)
                        ts += cur_stream->ic->start_time;
                    stream_seek(cur_stream, ts, 0, 0);
3438
                }
3439
            break;
3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451
        case SDL_WINDOWEVENT:
            switch (event.window.event) {
                case SDL_WINDOWEVENT_RESIZED:
                    screen_width  = cur_stream->width  = event.window.data1;
                    screen_height = cur_stream->height = event.window.data2;
                    if (cur_stream->vis_texture) {
                        SDL_DestroyTexture(cur_stream->vis_texture);
                        cur_stream->vis_texture = NULL;
                    }
                case SDL_WINDOWEVENT_EXPOSED:
                    cur_stream->force_refresh = 1;
            }
Fabrice Bellard's avatar
Fabrice Bellard committed
3452 3453
            break;
        case SDL_QUIT:
3454
        case FF_QUIT_EVENT:
3455
            do_exit(cur_stream);
Fabrice Bellard's avatar
Fabrice Bellard committed
3456 3457 3458 3459 3460 3461 3462 3463 3464 3465
            break;
        case FF_ALLOC_EVENT:
            alloc_picture(event.user.data1);
            break;
        default:
            break;
        }
    }
}

3466
static int opt_frame_size(void *optctx, const char *opt, const char *arg)
3467
{
3468
    av_log(NULL, AV_LOG_WARNING, "Option -s is deprecated, use -video_size.\n");
3469
    return opt_default(NULL, "video_size", arg);
3470 3471
}

3472
static int opt_width(void *optctx, const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
3473
{
3474 3475
    screen_width = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
3476 3477
}

3478
static int opt_height(void *optctx, const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
3479
{
3480 3481
    screen_height = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
3482 3483
}

3484
static int opt_format(void *optctx, const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
3485 3486 3487
{
    file_iformat = av_find_input_format(arg);
    if (!file_iformat) {
3488
        av_log(NULL, AV_LOG_FATAL, "Unknown input format: %s\n", arg);
3489
        return AVERROR(EINVAL);
Fabrice Bellard's avatar
Fabrice Bellard committed
3490
    }
3491
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
3492
}
3493

3494
static int opt_frame_pix_fmt(void *optctx, const char *opt, const char *arg)
3495
{
3496
    av_log(NULL, AV_LOG_WARNING, "Option -pix_fmt is deprecated, use -pixel_format.\n");
3497
    return opt_default(NULL, "pixel_format", arg);
3498 3499
}

3500
static int opt_sync(void *optctx, const char *opt, const char *arg)
3501 3502 3503 3504 3505 3506 3507
{
    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;
3508
    else {
3509
        av_log(NULL, AV_LOG_ERROR, "Unknown value for %s: %s\n", opt, arg);
3510 3511
        exit(1);
    }
3512
    return 0;
3513 3514
}

3515
static int opt_seek(void *optctx, const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
3516
{
3517 3518
    start_time = parse_time_or_die(opt, arg, 1);
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
3519 3520
}

3521
static int opt_duration(void *optctx, const char *opt, const char *arg)
3522 3523 3524 3525 3526
{
    duration = parse_time_or_die(opt, arg, 1);
    return 0;
}

3527
static int opt_show_mode(void *optctx, const char *opt, const char *arg)
3528 3529 3530 3531 3532 3533 3534 3535
{
    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;
}

3536
static void opt_input_file(void *optctx, const char *filename)
3537 3538
{
    if (input_filename) {
3539 3540
        av_log(NULL, AV_LOG_FATAL,
               "Argument '%s' provided as input filename, but '%s' was already specified.\n",
3541
                filename, input_filename);
3542
        exit(1);
3543 3544 3545 3546 3547 3548
    }
    if (!strcmp(filename, "-"))
        filename = "pipe:";
    input_filename = filename;
}

3549
static int opt_codec(void *optctx, const char *opt, const char *arg)
3550
{
3551 3552
   const char *spec = strchr(opt, ':');
   if (!spec) {
3553 3554
       av_log(NULL, AV_LOG_ERROR,
              "No media specifier was specified in '%s' in option '%s'\n",
3555 3556 3557 3558 3559 3560 3561 3562 3563
               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:
3564 3565
       av_log(NULL, AV_LOG_ERROR,
              "Invalid media specifier '%s' in option '%s'\n", spec, opt);
3566 3567 3568
       return AVERROR(EINVAL);
   }
   return 0;
3569 3570
}

3571 3572
static int dummy;

3573
static const OptionDef options[] = {
3574
#include "cmdutils_common_opts.h"
3575 3576 3577 3578 3579 3580
    { "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" },
3581
    { "sn", OPT_BOOL, { &subtitle_disable }, "disable subtitling" },
3582 3583 3584
    { "ast", OPT_STRING | HAS_ARG | OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_AUDIO] }, "select desired audio stream", "stream_specifier" },
    { "vst", OPT_STRING | HAS_ARG | OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_VIDEO] }, "select desired video stream", "stream_specifier" },
    { "sst", OPT_STRING | HAS_ARG | OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_SUBTITLE] }, "select desired subtitle stream", "stream_specifier" },
3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603
    { "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", "" },
    { "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 }, "", "" },
    { "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" },
3604
#if CONFIG_AVFILTER
3605
    { "vf", OPT_EXPERT | HAS_ARG, { .func_arg = opt_add_vfilter }, "set video filters", "filter_graph" },
Marton Balint's avatar
Marton Balint committed
3606
    { "af", OPT_STRING | HAS_ARG, { &afilters }, "set audio filters", "filter_graph" },
3607
#endif
3608 3609 3610 3611
    { "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"},
3612 3613 3614 3615
    { "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" },
3616
    { "autorotate", OPT_BOOL, { &autorotate }, "automatically rotate video", "" },
Fabrice Bellard's avatar
Fabrice Bellard committed
3617 3618 3619
    { NULL, },
};

3620
static void show_usage(void)
Fabrice Bellard's avatar
Fabrice Bellard committed
3621
{
3622 3623 3624
    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");
3625 3626
}

3627
void show_help_default(const char *opt, const char *arg)
3628
{
3629
    av_log_set_callback(log_callback_help);
3630
    show_usage();
3631 3632
    show_help_options(options, "Main options:", 0, OPT_EXPERT, 0);
    show_help_options(options, "Advanced options:", OPT_EXPERT, 0, 0);
3633
    printf("\n");
3634 3635
    show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM);
    show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
3636
#if !CONFIG_AVFILTER
3637
    show_help_children(sws_get_class(), AV_OPT_FLAG_ENCODING_PARAM);
3638 3639
#else
    show_help_children(avfilter_get_class(), AV_OPT_FLAG_FILTERING_PARAM);
3640
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3641 3642 3643 3644
    printf("\nWhile playing:\n"
           "q, ESC              quit\n"
           "f                   toggle full screen\n"
           "p, SPC              pause\n"
3645 3646 3647
           "m                   toggle mute\n"
           "9, 0                decrease and increase volume respectively\n"
           "/, *                decrease and increase volume respectively\n"
3648
           "a                   cycle audio channel in the current program\n"
3649
           "v                   cycle video channel\n"
3650
           "t                   cycle subtitle channel in the current program\n"
3651
           "c                   cycle program\n"
3652
           "w                   cycle video filters or show modes\n"
3653
           "s                   activate frame-step mode\n"
Fabrice Bellard's avatar
Fabrice Bellard committed
3654 3655
           "left/right          seek backward/forward 10 seconds\n"
           "down/up             seek backward/forward 1 minute\n"
3656
           "page down/page up   seek backward/forward 10 minutes\n"
3657 3658
           "right mouse click   seek to percentage in file corresponding to fraction of width\n"
           "left double-click   toggle full screen\n"
Fabrice Bellard's avatar
Fabrice Bellard committed
3659 3660 3661
           );
}

3662 3663 3664 3665 3666
static int lockmgr(void **mtx, enum AVLockOp op)
{
   switch(op) {
      case AV_LOCK_CREATE:
          *mtx = SDL_CreateMutex();
3667 3668
          if(!*mtx) {
              av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
3669
              return 1;
3670
          }
3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682
          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
3683 3684 3685
/* Called from the main */
int main(int argc, char **argv)
{
3686
    int flags;
3687
    VideoState *is;
3688

3689 3690
    init_dynload();

3691
    av_log_set_flags(AV_LOG_SKIP_REPEATED);
3692
    parse_loglevel(argc, argv, options);
3693

Fabrice Bellard's avatar
Fabrice Bellard committed
3694
    /* register all codecs, demux and protocols */
3695
#if CONFIG_AVDEVICE
Luca Abeni's avatar
Luca Abeni committed
3696
    avdevice_register_all();
3697
#endif
3698 3699 3700
#if CONFIG_AVFILTER
    avfilter_register_all();
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3701
    av_register_all();
3702
    avformat_network_init();
Fabrice Bellard's avatar
Fabrice Bellard committed
3703

3704
    init_opts();
3705

3706 3707 3708
    signal(SIGINT , sigterm_handler); /* Interrupt (ANSI).    */
    signal(SIGTERM, sigterm_handler); /* Termination (ANSI).  */

3709
    show_banner(argc, argv, options);
3710

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

3713
    if (!input_filename) {
3714
        show_usage();
3715 3716 3717
        av_log(NULL, AV_LOG_FATAL, "An input file must be specified\n");
        av_log(NULL, AV_LOG_FATAL,
               "Use -h to get full help or, even better, run 'man %s'\n", program_name);
3718 3719
        exit(1);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
3720 3721 3722 3723

    if (display_disable) {
        video_disable = 1;
    }
3724
    flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
3725 3726
    if (audio_disable)
        flags &= ~SDL_INIT_AUDIO;
3727 3728 3729 3730
    else {
        /* Try to work around an occasional ALSA buffer underflow issue when the
         * period size is NPOT due to ALSA resampling by forcing the buffer size. */
        if (!SDL_getenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE"))
3731
            SDL_setenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE","1", 1);
3732
    }
3733
    if (display_disable)
3734
        flags &= ~SDL_INIT_VIDEO;
Fabrice Bellard's avatar
Fabrice Bellard committed
3735
    if (SDL_Init (flags)) {
3736 3737
        av_log(NULL, AV_LOG_FATAL, "Could not initialize SDL - %s\n", SDL_GetError());
        av_log(NULL, AV_LOG_FATAL, "(Did you set the DISPLAY variable?)\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
3738 3739 3740 3741 3742 3743
        exit(1);
    }

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

3744
    if (av_lockmgr_register(lockmgr)) {
3745
        av_log(NULL, AV_LOG_FATAL, "Could not initialize lock manager!\n");
3746 3747 3748
        do_exit(NULL);
    }

3749
    av_init_packet(&flush_pkt);
Luca Barbato's avatar
Luca Barbato committed
3750
    flush_pkt.data = (uint8_t *)&flush_pkt;
3751

3752 3753
    is = stream_open(input_filename, file_iformat);
    if (!is) {
3754
        av_log(NULL, AV_LOG_FATAL, "Failed to initialize VideoState!\n");
3755 3756
        do_exit(NULL);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
3757

3758
    event_loop(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
3759 3760 3761 3762 3763

    /* never returns */

    return 0;
}