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

22
#include "config.h"
23
#include <inttypes.h>
24 25
#include <math.h>
#include <limits.h>
26 27
#include <stdint.h>

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

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

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

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

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

60 61
#include <assert.h>

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

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

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

/* no AV sync correction is done if below the AV sync threshold */
74
#define AV_SYNC_THRESHOLD 0.01
75 76 77
/* no AV correction is done if too big error */
#define AV_NOSYNC_THRESHOLD 10.0

78 79
#define FRAME_SKIP_FACTOR 0.05

80 81 82 83 84 85
/* maximum audio speed change to get correct sync */
#define SAMPLE_CORRECTION_PERCENT_MAX 10

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

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

89
static int64_t sws_flags = SWS_BICUBIC;
90

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

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

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

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

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

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

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

    int audio_stream;
144

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

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

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

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

193 194 195
    double frame_timer;
    double frame_last_pts;
    double frame_last_delay;
196
    double video_clock;             // pts of last decoded frame / predicted pts of next decoded frame
Fabrice Bellard's avatar
Fabrice Bellard committed
197 198 199
    int video_stream;
    AVStream *video_st;
    PacketQueue videoq;
200
    double video_current_pts;       // current displayed pts (different from video_clock if frame fifos are used)
201
    double video_current_pts_drift; // video_current_pts - time (av_gettime_relative) at which we updated video_current_pts - used to have running video pts
202
    int64_t video_current_pos;      // current displayed file pos
Fabrice Bellard's avatar
Fabrice Bellard committed
203 204 205 206
    VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE];
    int pictq_size, pictq_rindex, pictq_windex;
    SDL_mutex *pictq_mutex;
    SDL_cond *pictq_cond;
207
#if !CONFIG_AVFILTER
208
    struct SwsContext *img_convert_ctx;
209
#endif
210

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

215
    PtsCorrectionContext pts_ctx;
216

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

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

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

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

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

276
static AVPacket flush_pkt;
277

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

282
static SDL_Surface *screen;
Fabrice Bellard's avatar
Fabrice Bellard committed
283

284 285
static int packet_queue_put(PacketQueue *q, AVPacket *pkt);

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

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

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

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

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

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

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

Fabrice Bellard's avatar
Fabrice Bellard committed
333

Fabrice Bellard's avatar
Fabrice Bellard committed
334 335 336 337 338 339 340 341 342
    SDL_LockMutex(q->mutex);

    if (!q->last_pkt)

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

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

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

    q->abort_request = 1;
356

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

    SDL_UnlockMutex(q->mutex);
}

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

    SDL_LockMutex(q->mutex);

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

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

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

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

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

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

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


#define BPP 1

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

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

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

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

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

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

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

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

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

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

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

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

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

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

static void free_subpicture(SubPicture *sp)
{
640
    avsubtitle_free(&sp->sub);
641 642
}

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

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

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

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

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

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

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

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

                    SDL_UnlockYUVOverlay (vp->bmp);
                }
            }
        }


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                fill_rectangle(screen,
                            s->xpos, s->height-y, 1, 1,
                            fgcolor);
            }
        }
        SDL_UpdateRect(screen, s->xpos, s->ytop, 1, s->height);
        s->xpos++;
Aneesh Dogra's avatar
Aneesh Dogra committed
871
        if (s->xpos >= s->width)
872 873
            s->xpos= s->xleft;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
874 875
}

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

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

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

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

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

    return 0;
}
926

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

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

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

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

/* get the current external clock value */
static double get_external_clock(VideoState *is)
{
    int64_t ti;
985
    ti = av_gettime_relative();
986 987 988 989 990 991 992 993
    return is->external_clock + ((ti - is->external_clock_time) * 1e-6);
}

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

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

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

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

1036
static double compute_target_time(double frame_current_pts, VideoState *is)
1037
{
1038
    double delay, sync_threshold, diff = 0;
1039 1040 1041 1042 1043 1044

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

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

        /* skip or repeat frame. We take into account the
           delay to compute the threshold. I still don't know
           if it is the best guess */
        sync_threshold = FFMAX(AV_SYNC_THRESHOLD, delay);
        if (fabs(diff) < AV_NOSYNC_THRESHOLD) {
            if (diff <= -sync_threshold)
                delay = 0;
            else if (diff >= sync_threshold)
                delay = 2 * delay;
        }
    }
    is->frame_timer += delay;
1069

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

1073
    return is->frame_timer;
1074 1075
}

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

1082
    SubPicture *sp, *sp2;
Fabrice Bellard's avatar
Fabrice Bellard committed
1083 1084

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

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

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

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

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

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

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

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

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

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

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

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

Fabrice Bellard's avatar
Fabrice Bellard committed
1166
            /* display picture */
1167
            if (!display_disable)
1168
                video_display(is);
1169

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

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

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

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

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

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

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

static void do_exit(void)
{
    if (cur_stream) {
        stream_close(cur_stream);
        cur_stream = NULL;
    }
1252
    uninit_opts();
1253
    avformat_network_deinit();
1254 1255 1256
    if (show_status)
        printf("\n");
    SDL_Quit();
1257
    av_log(NULL, AV_LOG_QUIET, "");
1258 1259 1260
    exit(0);
}

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

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

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

1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283
#if CONFIG_AVFILTER
    vp->width   = is->out_video_filter->inputs[0]->w;
    vp->height  = is->out_video_filter->inputs[0]->h;
    vp->pix_fmt = is->out_video_filter->inputs[0]->format;
#else
    vp->width   = is->video_st->codec->width;
    vp->height  = is->video_st->codec->height;
    vp->pix_fmt = is->video_st->codec->pix_fmt;
#endif

    vp->bmp = SDL_CreateYUVOverlay(vp->width, vp->height,
1284
                                   SDL_YV12_OVERLAY,
1285
                                   screen);
1286 1287 1288 1289
    if (!vp->bmp || vp->bmp->pitches[0] < vp->width) {
        /* SDL allocates a buffer smaller than requested if the video
         * overlay hardware is unable to support the requested size. */
        fprintf(stderr, "Error: the video system does not support an image\n"
1290
                        "size of %dx%d pixels. Try using -vf \"scale=w:h\"\n"
1291 1292 1293
                        "to reduce the image size.\n", vp->width, vp->height );
        do_exit();
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
1294 1295 1296 1297 1298 1299 1300

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

1301 1302
/* The 'pts' parameter is the dts of the packet / pts of the frame and
 * guessed if not known. */
1303
static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t pos)
Fabrice Bellard's avatar
Fabrice Bellard committed
1304 1305
{
    VideoPicture *vp;
1306 1307
#if CONFIG_AVFILTER
    AVPicture pict_src;
1308
#else
1309
    int dst_pix_fmt = AV_PIX_FMT_YUV420P;
1310
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
1311 1312
    /* wait until we have space to put a new picture */
    SDL_LockMutex(is->pictq_mutex);
1313

Aneesh Dogra's avatar
Aneesh Dogra committed
1314 1315
    if (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && !is->refresh)
        is->skip_frames = FFMAX(1.0 - FRAME_SKIP_FACTOR, is->skip_frames * (1.0 - FRAME_SKIP_FACTOR));
1316

Fabrice Bellard's avatar
Fabrice Bellard committed
1317 1318 1319 1320 1321
    while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE &&
           !is->videoq.abort_request) {
        SDL_CondWait(is->pictq_cond, is->pictq_mutex);
    }
    SDL_UnlockMutex(is->pictq_mutex);
1322

Fabrice Bellard's avatar
Fabrice Bellard committed
1323 1324 1325 1326 1327
    if (is->videoq.abort_request)
        return -1;

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

1328 1329
    vp->sar = src_frame->sample_aspect_ratio;

Fabrice Bellard's avatar
Fabrice Bellard committed
1330
    /* alloc or resize hardware picture buffer */
1331
    if (!vp->bmp || vp->reallocate ||
1332 1333 1334 1335
#if CONFIG_AVFILTER
        vp->width  != is->out_video_filter->inputs[0]->w ||
        vp->height != is->out_video_filter->inputs[0]->h) {
#else
1336 1337
        vp->width != is->video_st->codec->width ||
        vp->height != is->video_st->codec->height) {
1338
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
1339 1340
        SDL_Event event;

1341 1342
        vp->allocated  = 0;
        vp->reallocate = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1343 1344 1345 1346 1347 1348

        /* the allocation must be done in the main thread to avoid
           locking problems */
        event.type = FF_ALLOC_EVENT;
        event.user.data1 = is;
        SDL_PushEvent(&event);
1349

Fabrice Bellard's avatar
Fabrice Bellard committed
1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360
        /* wait until the picture is allocated */
        SDL_LockMutex(is->pictq_mutex);
        while (!vp->allocated && !is->videoq.abort_request) {
            SDL_CondWait(is->pictq_cond, is->pictq_mutex);
        }
        SDL_UnlockMutex(is->pictq_mutex);

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

1361
    /* if the frame is not skipped, then display it */
Fabrice Bellard's avatar
Fabrice Bellard committed
1362
    if (vp->bmp) {
1363
        AVPicture pict = { { 0 } };
1364

Fabrice Bellard's avatar
Fabrice Bellard committed
1365 1366 1367 1368 1369 1370 1371 1372 1373 1374
        /* get a pointer on the bitmap */
        SDL_LockYUVOverlay (vp->bmp);

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

        pict.linesize[0] = vp->bmp->pitches[0];
        pict.linesize[1] = vp->bmp->pitches[2];
        pict.linesize[2] = vp->bmp->pitches[1];
1375 1376 1377 1378 1379 1380 1381 1382 1383 1384

#if CONFIG_AVFILTER
        pict_src.data[0] = src_frame->data[0];
        pict_src.data[1] = src_frame->data[1];
        pict_src.data[2] = src_frame->data[2];

        pict_src.linesize[0] = src_frame->linesize[0];
        pict_src.linesize[1] = src_frame->linesize[1];
        pict_src.linesize[2] = src_frame->linesize[2];

Aneesh Dogra's avatar
Aneesh Dogra committed
1385
        // FIXME use direct rendering
1386 1387 1388
        av_picture_copy(&pict, &pict_src,
                        vp->pix_fmt, vp->width, vp->height);
#else
1389
        av_opt_get_int(sws_opts, "sws_flags", 0, &sws_flags);
1390
        is->img_convert_ctx = sws_getCachedContext(is->img_convert_ctx,
1391
            vp->width, vp->height, vp->pix_fmt, vp->width, vp->height,
1392
            dst_pix_fmt, sws_flags, NULL, NULL, NULL);
1393
        if (!is->img_convert_ctx) {
1394 1395 1396
            fprintf(stderr, "Cannot initialize the conversion context\n");
            exit(1);
        }
1397
        sws_scale(is->img_convert_ctx, src_frame->data, src_frame->linesize,
1398 1399
                  0, vp->height, pict.data, pict.linesize);
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
1400 1401 1402
        /* update the bitmap content */
        SDL_UnlockYUVOverlay(vp->bmp);

1403
        vp->pts = pts;
1404
        vp->pos = pos;
Fabrice Bellard's avatar
Fabrice Bellard committed
1405 1406 1407 1408 1409

        /* now we can update the picture count */
        if (++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE)
            is->pictq_windex = 0;
        SDL_LockMutex(is->pictq_mutex);
Aneesh Dogra's avatar
Aneesh Dogra committed
1410
        vp->target_clock = compute_target_time(vp->pts, is);
1411

Fabrice Bellard's avatar
Fabrice Bellard committed
1412 1413 1414
        is->pictq_size++;
        SDL_UnlockMutex(is->pictq_mutex);
    }
1415 1416 1417
    return 0;
}

1418 1419
/* Compute the exact PTS for the picture if it is omitted in the stream.
 * The 'pts1' parameter is the dts of the packet / pts of the frame. */
1420
static int output_picture2(VideoState *is, AVFrame *src_frame, double pts1, int64_t pos)
1421 1422
{
    double frame_delay, pts;
1423
    int ret;
1424

1425 1426
    pts = pts1;

Fabrice Bellard's avatar
Fabrice Bellard committed
1427
    if (pts != 0) {
1428
        /* update video clock with pts, if present */
Fabrice Bellard's avatar
Fabrice Bellard committed
1429 1430
        is->video_clock = pts;
    } else {
Fabrice Bellard's avatar
Fabrice Bellard committed
1431 1432 1433
        pts = is->video_clock;
    }
    /* update video clock for next frame */
1434
    frame_delay = av_q2d(is->video_st->codec->time_base);
Fabrice Bellard's avatar
Fabrice Bellard committed
1435 1436
    /* for MPEG2, the frame can be repeated, so we update the
       clock accordingly */
1437
    frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);
Fabrice Bellard's avatar
Fabrice Bellard committed
1438
    is->video_clock += frame_delay;
1439

1440 1441 1442
    ret = queue_picture(is, src_frame, pts, pos);
    av_frame_unref(src_frame);
    return ret;
Fabrice Bellard's avatar
Fabrice Bellard committed
1443 1444
}

1445
static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacket *pkt)
Fabrice Bellard's avatar
Fabrice Bellard committed
1446
{
1447
    int got_picture, i;
Fabrice Bellard's avatar
Fabrice Bellard committed
1448

1449 1450
    if (packet_queue_get(&is->videoq, pkt, 1) < 0)
        return -1;
1451

1452 1453
    if (pkt->data == flush_pkt.data) {
        avcodec_flush_buffers(is->video_st->codec);
1454

1455
        SDL_LockMutex(is->pictq_mutex);
Aneesh Dogra's avatar
Aneesh Dogra committed
1456
        // Make sure there are no long delay timers (ideally we should just flush the que but thats harder)
1457 1458 1459 1460 1461
        for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
            is->pictq[i].target_clock= 0;
        }
        while (is->pictq_size && !is->videoq.abort_request) {
            SDL_CondWait(is->pictq_cond, is->pictq_mutex);
1462
        }
1463 1464
        is->video_current_pos = -1;
        SDL_UnlockMutex(is->pictq_mutex);
1465

1466 1467 1468
        init_pts_correction(&is->pts_ctx);
        is->frame_last_pts = AV_NOPTS_VALUE;
        is->frame_last_delay = 0;
1469
        is->frame_timer = (double)av_gettime_relative() / 1000000.0;
1470 1471 1472 1473
        is->skip_frames = 1;
        is->skip_frames_index = 0;
        return 0;
    }
1474

1475
    avcodec_decode_video2(is->video_st->codec, frame, &got_picture, pkt);
1476 1477 1478

    if (got_picture) {
        if (decoder_reorder_pts == -1) {
1479
            *pts = guess_correct_pts(&is->pts_ctx, frame->pkt_pts, frame->pkt_dts);
1480
        } else if (decoder_reorder_pts) {
1481
            *pts = frame->pkt_pts;
1482
        } else {
1483
            *pts = frame->pkt_dts;
1484 1485 1486 1487
        }

        if (*pts == AV_NOPTS_VALUE) {
            *pts = 0;
1488
        }
1489 1490 1491
        if (is->video_st->sample_aspect_ratio.num) {
            frame->sample_aspect_ratio = is->video_st->sample_aspect_ratio;
        }
1492

1493
        is->skip_frames_index += 1;
Aneesh Dogra's avatar
Aneesh Dogra committed
1494
        if (is->skip_frames_index >= is->skip_frames) {
1495 1496 1497
            is->skip_frames_index -= FFMAX(is->skip_frames, 1.0);
            return 1;
        }
1498
        av_frame_unref(frame);
1499
    }
1500 1501 1502 1503
    return 0;
}

#if CONFIG_AVFILTER
1504
static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters)
1505
{
Stefano Sabatini's avatar
Stefano Sabatini committed
1506
    char sws_flags_str[128];
1507
    char buffersrc_args[256];
1508
    int ret;
1509
    AVFilterContext *filt_src = NULL, *filt_out = NULL, *last_filter;
1510 1511
    AVCodecContext *codec = is->video_st->codec;

1512
    snprintf(sws_flags_str, sizeof(sws_flags_str), "flags=%"PRId64, sws_flags);
Stefano Sabatini's avatar
Stefano Sabatini committed
1513
    graph->scale_sws_opts = av_strdup(sws_flags_str);
1514

1515 1516 1517 1518 1519 1520 1521 1522 1523 1524
    snprintf(buffersrc_args, sizeof(buffersrc_args), "%d:%d:%d:%d:%d:%d:%d",
             codec->width, codec->height, codec->pix_fmt,
             is->video_st->time_base.num, is->video_st->time_base.den,
             codec->sample_aspect_ratio.num, codec->sample_aspect_ratio.den);


    if ((ret = avfilter_graph_create_filter(&filt_src,
                                            avfilter_get_by_name("buffer"),
                                            "src", buffersrc_args, NULL,
                                            graph)) < 0)
1525
        return ret;
1526 1527 1528
    if ((ret = avfilter_graph_create_filter(&filt_out,
                                            avfilter_get_by_name("buffersink"),
                                            "out", NULL, NULL, graph)) < 0)
1529
        return ret;
1530

1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551
    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 */
#define INSERT_FILT(name, arg) do {                                          \
    AVFilterContext *filt_ctx;                                               \
                                                                             \
    ret = avfilter_graph_create_filter(&filt_ctx,                            \
                                       avfilter_get_by_name(name),           \
                                       "avplay_" name, arg, NULL, graph);    \
    if (ret < 0)                                                             \
        return ret;                                                          \
                                                                             \
    ret = avfilter_link(filt_ctx, 0, last_filter, 0);                        \
    if (ret < 0)                                                             \
        return ret;                                                          \
                                                                             \
    last_filter = filt_ctx;                                                  \
} while (0)

    INSERT_FILT("format", "yuv420p");
1552

1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568
    if (autorotate) {
        uint8_t* displaymatrix = av_stream_get_side_data(is->video_st,
                                                         AV_PKT_DATA_DISPLAYMATRIX, NULL);
        if (displaymatrix) {
            double rot = av_display_rotation_get((int32_t*) displaymatrix);
            if (rot < -135 || rot > 135) {
                INSERT_FILT("vflip", NULL);
                INSERT_FILT("hflip", NULL);
            } else if (rot < -45) {
                INSERT_FILT("transpose", "dir=clock");
            } else if (rot > 45) {
                INSERT_FILT("transpose", "dir=cclock");
            }
        }
    }

Aneesh Dogra's avatar
Aneesh Dogra committed
1569
    if (vfilters) {
1570 1571
        AVFilterInOut *outputs = avfilter_inout_alloc();
        AVFilterInOut *inputs  = avfilter_inout_alloc();
1572 1573

        outputs->name    = av_strdup("in");
1574
        outputs->filter_ctx = filt_src;
1575 1576 1577 1578
        outputs->pad_idx = 0;
        outputs->next    = NULL;

        inputs->name    = av_strdup("out");
1579
        inputs->filter_ctx = last_filter;
1580 1581 1582
        inputs->pad_idx = 0;
        inputs->next    = NULL;

1583
        if ((ret = avfilter_graph_parse(graph, vfilters, inputs, outputs, NULL)) < 0)
1584
            return ret;
1585
    } else {
1586
        if ((ret = avfilter_link(filt_src, 0, last_filter, 0)) < 0)
1587
            return ret;
1588 1589
    }

1590
    if ((ret = avfilter_graph_config(graph, NULL)) < 0)
1591
        return ret;
1592

1593
    is->in_video_filter  = filt_src;
1594
    is->out_video_filter = filt_out;
1595

1596 1597 1598 1599 1600 1601 1602
    return ret;
}

#endif  /* CONFIG_AVFILTER */

static int video_thread(void *arg)
{
1603
    AVPacket pkt = { 0 };
1604
    VideoState *is = arg;
1605
    AVFrame *frame = av_frame_alloc();
1606 1607 1608 1609 1610 1611
    int64_t pts_int;
    double pts;
    int ret;

#if CONFIG_AVFILTER
    AVFilterGraph *graph = avfilter_graph_alloc();
1612
    AVFilterContext *filt_out = NULL, *filt_in = NULL;
1613 1614
    int last_w = is->video_st->codec->width;
    int last_h = is->video_st->codec->height;
1615 1616
    if (!graph) {
        av_frame_free(&frame);
1617
        return AVERROR(ENOMEM);
1618
    }
1619 1620 1621

    if ((ret = configure_video_filters(graph, is, vfilters)) < 0)
        goto the_end;
1622
    filt_in  = is->in_video_filter;
1623
    filt_out = is->out_video_filter;
1624 1625
#endif

1626 1627 1628 1629
    if (!frame) {
#if CONFIG_AVFILTER
        avfilter_graph_free(&graph);
#endif
1630
        return AVERROR(ENOMEM);
1631
    }
1632

Aneesh Dogra's avatar
Aneesh Dogra committed
1633
    for (;;) {
1634
#if CONFIG_AVFILTER
1635
        AVRational tb;
1636 1637 1638
#endif
        while (is->paused && !is->videoq.abort_request)
            SDL_Delay(10);
1639

1640 1641
        av_free_packet(&pkt);

1642 1643 1644 1645 1646 1647 1648
        ret = get_video_frame(is, frame, &pts_int, &pkt);
        if (ret < 0)
            goto the_end;

        if (!ret)
            continue;

1649
#if CONFIG_AVFILTER
1650 1651
        if (   last_w != is->video_st->codec->width
            || last_h != is->video_st->codec->height) {
1652
            av_log(NULL, AV_LOG_TRACE, "Changing size %dx%d -> %dx%d\n", last_w, last_h,
1653 1654 1655 1656 1657
                    is->video_st->codec->width, is->video_st->codec->height);
            avfilter_graph_free(&graph);
            graph = avfilter_graph_alloc();
            if ((ret = configure_video_filters(graph, is, vfilters)) < 0)
                goto the_end;
1658
            filt_in  = is->in_video_filter;
1659 1660 1661 1662
            filt_out = is->out_video_filter;
            last_w = is->video_st->codec->width;
            last_h = is->video_st->codec->height;
        }
1663 1664

        frame->pts = pts_int;
1665 1666 1667
        ret = av_buffersrc_add_frame(filt_in, frame);
        if (ret < 0)
            goto the_end;
1668 1669

        while (ret >= 0) {
1670
            ret = av_buffersink_get_frame(filt_out, frame);
1671 1672 1673 1674 1675
            if (ret < 0) {
                ret = 0;
                break;
            }

1676
            pts_int = frame->pts;
1677
            tb      = filt_out->inputs[0]->time_base;
1678 1679 1680
            if (av_cmp_q(tb, is->video_st->time_base)) {
                av_unused int64_t pts1 = pts_int;
                pts_int = av_rescale_q(pts_int, tb, is->video_st->time_base);
1681
                av_log(NULL, AV_LOG_TRACE, "video_thread(): "
1682 1683 1684 1685 1686
                        "tb:%d/%d pts:%"PRId64" -> tb:%d/%d pts:%"PRId64"\n",
                        tb.num, tb.den, pts1,
                        is->video_st->time_base.num, is->video_st->time_base.den, pts_int);
            }
            pts = pts_int * av_q2d(is->video_st->time_base);
1687
            ret = output_picture2(is, frame, pts, 0);
1688
        }
1689
#else
Aneesh Dogra's avatar
Aneesh Dogra committed
1690
        pts = pts_int * av_q2d(is->video_st->time_base);
1691
        ret = output_picture2(is, frame, pts,  pkt.pos);
1692
#endif
1693

1694 1695 1696
        if (ret < 0)
            goto the_end;

1697

1698
        if (step)
1699 1700
            if (cur_stream)
                stream_pause(cur_stream);
Fabrice Bellard's avatar
Fabrice Bellard committed
1701 1702
    }
 the_end:
1703
#if CONFIG_AVFILTER
1704
    av_freep(&vfilters);
1705
    avfilter_graph_free(&graph);
1706
#endif
1707
    av_free_packet(&pkt);
1708
    av_frame_free(&frame);
Fabrice Bellard's avatar
Fabrice Bellard committed
1709 1710 1711
    return 0;
}

1712 1713 1714 1715 1716
static int subtitle_thread(void *arg)
{
    VideoState *is = arg;
    SubPicture *sp;
    AVPacket pkt1, *pkt = &pkt1;
1717
    int got_subtitle;
1718 1719 1720 1721
    double pts;
    int i, j;
    int r, g, b, y, u, v, a;

Aneesh Dogra's avatar
Aneesh Dogra committed
1722
    for (;;) {
1723 1724 1725 1726 1727
        while (is->paused && !is->subtitleq.abort_request) {
            SDL_Delay(10);
        }
        if (packet_queue_get(&is->subtitleq, pkt, 1) < 0)
            break;
1728

Aneesh Dogra's avatar
Aneesh Dogra committed
1729
        if (pkt->data == flush_pkt.data) {
1730 1731 1732
            avcodec_flush_buffers(is->subtitle_st->codec);
            continue;
        }
1733 1734 1735 1736 1737 1738
        SDL_LockMutex(is->subpq_mutex);
        while (is->subpq_size >= SUBPICTURE_QUEUE_SIZE &&
               !is->subtitleq.abort_request) {
            SDL_CondWait(is->subpq_cond, is->subpq_mutex);
        }
        SDL_UnlockMutex(is->subpq_mutex);
1739

1740
        if (is->subtitleq.abort_request)
1741
            return 0;
1742

1743 1744 1745 1746 1747 1748
        sp = &is->subpq[is->subpq_windex];

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

1751 1752 1753
        avcodec_decode_subtitle2(is->subtitle_st->codec, &sp->sub,
                                 &got_subtitle, pkt);

1754 1755
        if (got_subtitle && sp->sub.format == 0) {
            sp->pts = pts;
1756

1757 1758
            for (i = 0; i < sp->sub.num_rects; i++)
            {
1759
                for (j = 0; j < sp->sub.rects[i]->nb_colors; j++)
1760
                {
1761
                    RGBA_IN(r, g, b, a, (uint32_t*)sp->sub.rects[i]->pict.data[1] + j);
1762 1763 1764
                    y = RGB_TO_Y_CCIR(r, g, b);
                    u = RGB_TO_U_CCIR(r, g, b, 0);
                    v = RGB_TO_V_CCIR(r, g, b, 0);
1765
                    YUVA_OUT((uint32_t*)sp->sub.rects[i]->pict.data[1] + j, y, u, v, a);
1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780
                }
            }

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

Fabrice Bellard's avatar
Fabrice Bellard committed
1781 1782 1783
/* copy samples for viewing in editor window */
static void update_sample_display(VideoState *is, short *samples, int samples_size)
{
1784
    int size, len;
Fabrice Bellard's avatar
Fabrice Bellard committed
1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801

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

/* return the new audio buffer size (samples can be added or deleted
   to get better sync if video or external master clock) */
1802
static int synchronize_audio(VideoState *is, short *samples,
1803
                             int samples_size1, double pts)
Fabrice Bellard's avatar
Fabrice Bellard committed
1804
{
1805
    int n, samples_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
1806
    double ref_clock;
1807

1808
    n = is->sdl_channels * av_get_bytes_per_sample(is->sdl_sample_fmt);
1809
    samples_size = samples_size1;
Fabrice Bellard's avatar
Fabrice Bellard committed
1810 1811 1812

    /* if not master, then we try to remove or add samples to correct the clock */
    if (((is->av_sync_type == AV_SYNC_VIDEO_MASTER && is->video_st) ||
1813 1814
         is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {
        double diff, avg_diff;
Fabrice Bellard's avatar
Fabrice Bellard committed
1815
        int wanted_size, min_size, max_size, nb_samples;
1816

1817 1818
        ref_clock = get_master_clock(is);
        diff = get_audio_clock(is) - ref_clock;
1819

1820 1821 1822 1823 1824 1825 1826 1827 1828 1829
        if (diff < AV_NOSYNC_THRESHOLD) {
            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) {
1830
                    wanted_size = samples_size + ((int)(diff * is->sdl_sample_rate) * n);
1831
                    nb_samples = samples_size / n;
1832

1833 1834 1835 1836 1837 1838
                    min_size = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n;
                    max_size = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n;
                    if (wanted_size < min_size)
                        wanted_size = min_size;
                    else if (wanted_size > max_size)
                        wanted_size = max_size;
1839

1840 1841 1842 1843 1844 1845 1846
                    /* add or remove samples to correction the synchro */
                    if (wanted_size < samples_size) {
                        /* remove samples */
                        samples_size = wanted_size;
                    } else if (wanted_size > samples_size) {
                        uint8_t *samples_end, *q;
                        int nb;
1847

1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859
                        /* add samples */
                        nb = (samples_size - wanted_size);
                        samples_end = (uint8_t *)samples + samples_size - n;
                        q = samples_end + n;
                        while (nb > 0) {
                            memcpy(q, samples_end, n);
                            q += n;
                            nb -= n;
                        }
                        samples_size = wanted_size;
                    }
                }
1860
                av_log(NULL, AV_LOG_TRACE, "diff=%f adiff=%f sample_diff=%d apts=%0.3f vpts=%0.3f %f\n",
1861 1862
                        diff, avg_diff, samples_size - samples_size1,
                        is->audio_clock, is->video_clock, is->audio_diff_threshold);
Fabrice Bellard's avatar
Fabrice Bellard committed
1863
            }
1864 1865 1866 1867
        } 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
1868
            is->audio_diff_cum       = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1869 1870 1871 1872 1873 1874 1875
        }
    }

    return samples_size;
}

/* decode one audio frame and returns its uncompressed size */
1876
static int audio_decode_frame(VideoState *is, double *pts_ptr)
Fabrice Bellard's avatar
Fabrice Bellard committed
1877
{
1878
    AVPacket *pkt_temp = &is->audio_pkt_temp;
Fabrice Bellard's avatar
Fabrice Bellard committed
1879
    AVPacket *pkt = &is->audio_pkt;
Aneesh Dogra's avatar
Aneesh Dogra committed
1880
    AVCodecContext *dec = is->audio_st->codec;
1881
    int n, len1, data_size, got_frame;
Fabrice Bellard's avatar
Fabrice Bellard committed
1882
    double pts;
1883 1884
    int new_packet = 0;
    int flush_complete = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1885

Aneesh Dogra's avatar
Aneesh Dogra committed
1886
    for (;;) {
Fabrice Bellard's avatar
Fabrice Bellard committed
1887
        /* NOTE: the audio packet can contain several frames */
1888
        while (pkt_temp->size > 0 || (!pkt_temp->data && new_packet)) {
1889 1890
            int resample_changed, audio_resample;

1891
            if (!is->frame) {
1892
                if (!(is->frame = av_frame_alloc()))
1893
                    return AVERROR(ENOMEM);
1894
            }
1895

1896 1897 1898
            if (flush_complete)
                break;
            new_packet = 0;
1899
            len1 = avcodec_decode_audio4(dec, is->frame, &got_frame, pkt_temp);
Fabrice Bellard's avatar
Fabrice Bellard committed
1900 1901
            if (len1 < 0) {
                /* if error, we skip the frame */
1902
                pkt_temp->size = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1903
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
1904
            }
1905

1906 1907
            pkt_temp->data += len1;
            pkt_temp->size -= len1;
1908

1909
            if (!got_frame) {
1910
                /* stop sending empty packets if the decoder is finished */
1911
                if (!pkt_temp->data && (dec->codec->capabilities & AV_CODEC_CAP_DELAY))
1912
                    flush_complete = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
1913
                continue;
1914
            }
1915 1916
            data_size = av_samples_get_buffer_size(NULL, dec->channels,
                                                   is->frame->nb_samples,
1917
                                                   is->frame->format, 1);
1918

1919 1920 1921
            audio_resample = is->frame->format         != is->sdl_sample_fmt     ||
                             is->frame->channel_layout != is->sdl_channel_layout ||
                             is->frame->sample_rate    != is->sdl_sample_rate;
1922

1923 1924 1925
            resample_changed = is->frame->format         != is->resample_sample_fmt     ||
                               is->frame->channel_layout != is->resample_channel_layout ||
                               is->frame->sample_rate    != is->resample_sample_rate;
1926 1927

            if ((!is->avr && audio_resample) || resample_changed) {
1928
                int ret;
1929 1930 1931 1932 1933 1934
                if (is->avr)
                    avresample_close(is->avr);
                else if (audio_resample) {
                    is->avr = avresample_alloc_context();
                    if (!is->avr) {
                        fprintf(stderr, "error allocating AVAudioResampleContext\n");
1935
                        break;
1936
                    }
1937 1938
                }
                if (audio_resample) {
1939 1940 1941
                    av_opt_set_int(is->avr, "in_channel_layout",  is->frame->channel_layout, 0);
                    av_opt_set_int(is->avr, "in_sample_fmt",      is->frame->format,         0);
                    av_opt_set_int(is->avr, "in_sample_rate",     is->frame->sample_rate,    0);
1942 1943 1944
                    av_opt_set_int(is->avr, "out_channel_layout", is->sdl_channel_layout,    0);
                    av_opt_set_int(is->avr, "out_sample_fmt",     is->sdl_sample_fmt,        0);
                    av_opt_set_int(is->avr, "out_sample_rate",    is->sdl_sample_rate,       0);
1945 1946 1947 1948 1949

                    if ((ret = avresample_open(is->avr)) < 0) {
                        fprintf(stderr, "error initializing libavresample\n");
                        break;
                    }
1950
                }
1951 1952
                is->resample_sample_fmt     = is->frame->format;
                is->resample_channel_layout = is->frame->channel_layout;
1953
                is->resample_sample_rate    = is->frame->sample_rate;
1954 1955
            }

1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967
            if (audio_resample) {
                void *tmp_out;
                int out_samples, out_size, out_linesize;
                int osize      = av_get_bytes_per_sample(is->sdl_sample_fmt);
                int nb_samples = is->frame->nb_samples;

                out_size = av_samples_get_buffer_size(&out_linesize,
                                                      is->sdl_channels,
                                                      nb_samples,
                                                      is->sdl_sample_fmt, 0);
                tmp_out = av_realloc(is->audio_buf1, out_size);
                if (!tmp_out)
1968
                    return AVERROR(ENOMEM);
1969 1970 1971
                is->audio_buf1 = tmp_out;

                out_samples = avresample_convert(is->avr,
1972
                                                 &is->audio_buf1,
1973
                                                 out_linesize, nb_samples,
1974
                                                 is->frame->data,
1975 1976 1977 1978
                                                 is->frame->linesize[0],
                                                 is->frame->nb_samples);
                if (out_samples < 0) {
                    fprintf(stderr, "avresample_convert() failed\n");
1979 1980
                    break;
                }
1981
                is->audio_buf = is->audio_buf1;
1982
                data_size = out_samples * osize * is->sdl_channels;
Aneesh Dogra's avatar
Aneesh Dogra committed
1983
            } else {
1984
                is->audio_buf = is->frame->data[0];
1985 1986
            }

Fabrice Bellard's avatar
Fabrice Bellard committed
1987 1988 1989
            /* if no pts, then compute it */
            pts = is->audio_clock;
            *pts_ptr = pts;
1990
            n = is->sdl_channels * av_get_bytes_per_sample(is->sdl_sample_fmt);
1991
            is->audio_clock += (double)data_size /
1992
                (double)(n * is->sdl_sample_rate);
1993
#ifdef DEBUG
Fabrice Bellard's avatar
Fabrice Bellard committed
1994 1995 1996 1997 1998 1999
            {
                static double last_clock;
                printf("audio: delay=%0.3f clock=%0.3f pts=%0.3f\n",
                       is->audio_clock - last_clock,
                       is->audio_clock, pts);
                last_clock = is->audio_clock;
Fabrice Bellard's avatar
Fabrice Bellard committed
2000
            }
Fabrice Bellard's avatar
Fabrice Bellard committed
2001 2002
#endif
            return data_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
2003 2004
        }

Fabrice Bellard's avatar
Fabrice Bellard committed
2005 2006
        /* free the current packet */
        if (pkt->data)
Fabrice Bellard's avatar
Fabrice Bellard committed
2007
            av_free_packet(pkt);
2008
        memset(pkt_temp, 0, sizeof(*pkt_temp));
2009

Fabrice Bellard's avatar
Fabrice Bellard committed
2010 2011 2012
        if (is->paused || is->audioq.abort_request) {
            return -1;
        }
2013

Fabrice Bellard's avatar
Fabrice Bellard committed
2014
        /* read next packet */
2015
        if ((new_packet = packet_queue_get(&is->audioq, pkt, 1)) < 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
2016
            return -1;
2017

2018
        if (pkt->data == flush_pkt.data) {
2019
            avcodec_flush_buffers(dec);
2020 2021
            flush_complete = 0;
        }
2022

2023
        *pkt_temp = *pkt;
2024

Fabrice Bellard's avatar
Fabrice Bellard committed
2025 2026
        /* if update the audio clock with the pts */
        if (pkt->pts != AV_NOPTS_VALUE) {
2027
            is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts;
Fabrice Bellard's avatar
Fabrice Bellard committed
2028
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
2029 2030 2031 2032
    }
}

/* prepare a new audio buffer */
2033
static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
Fabrice Bellard's avatar
Fabrice Bellard committed
2034 2035 2036 2037 2038
{
    VideoState *is = opaque;
    int audio_size, len1;
    double pts;

2039
    audio_callback_time = av_gettime_relative();
2040

Fabrice Bellard's avatar
Fabrice Bellard committed
2041 2042
    while (len > 0) {
        if (is->audio_buf_index >= is->audio_buf_size) {
2043
           audio_size = audio_decode_frame(is, &pts);
Fabrice Bellard's avatar
Fabrice Bellard committed
2044 2045
           if (audio_size < 0) {
                /* if error, just output silence */
2046 2047
               is->audio_buf      = is->silence_buf;
               is->audio_buf_size = sizeof(is->silence_buf);
Fabrice Bellard's avatar
Fabrice Bellard committed
2048 2049 2050
           } else {
               if (is->show_audio)
                   update_sample_display(is, (int16_t *)is->audio_buf, audio_size);
2051
               audio_size = synchronize_audio(is, (int16_t *)is->audio_buf, audio_size,
Fabrice Bellard's avatar
Fabrice Bellard committed
2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070
                                              pts);
               is->audio_buf_size = audio_size;
           }
           is->audio_buf_index = 0;
        }
        len1 = is->audio_buf_size - is->audio_buf_index;
        if (len1 > len)
            len1 = len;
        memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
        len -= len1;
        stream += len1;
        is->audio_buf_index += len1;
    }
}

/* open a given stream. Return 0 if OK */
static int stream_component_open(VideoState *is, int stream_index)
{
    AVFormatContext *ic = is->ic;
2071
    AVCodecContext *avctx;
Fabrice Bellard's avatar
Fabrice Bellard committed
2072 2073
    AVCodec *codec;
    SDL_AudioSpec wanted_spec, spec;
2074 2075
    AVDictionary *opts;
    AVDictionaryEntry *t = NULL;
Luca Barbato's avatar
Luca Barbato committed
2076
    int ret = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2077 2078 2079

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

2082
    opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], NULL);
2083

2084
    codec = avcodec_find_decoder(avctx->codec_id);
Aneesh Dogra's avatar
Aneesh Dogra committed
2085 2086 2087 2088 2089 2090 2091
    avctx->workaround_bugs   = workaround_bugs;
    avctx->idct_algo         = idct;
    avctx->skip_frame        = skip_frame;
    avctx->skip_idct         = skip_idct;
    avctx->skip_loop_filter  = skip_loop_filter;
    avctx->error_concealment = error_concealment;

2092 2093
    if (fast)
        avctx->flags2 |= AV_CODEC_FLAG2_FAST;
2094

2095 2096
    if (!av_dict_get(opts, "threads", NULL, 0))
        av_dict_set(&opts, "threads", "auto", 0);
2097 2098
    if (avctx->codec_type == AVMEDIA_TYPE_VIDEO)
        av_dict_set(&opts, "refcounted_frames", "1", 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2099
    if (!codec ||
Luca Barbato's avatar
Luca Barbato committed
2100 2101 2102
        (ret = avcodec_open2(avctx, codec, &opts)) < 0) {
        goto fail;
    }
2103 2104
    if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
        av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
Luca Barbato's avatar
Luca Barbato committed
2105 2106
        ret =  AVERROR_OPTION_NOT_FOUND;
        goto fail;
2107
    }
2108 2109

    /* prepare audio output */
2110
    if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
2111
        is->sdl_sample_rate = avctx->sample_rate;
2112 2113 2114 2115 2116

        if (!avctx->channel_layout)
            avctx->channel_layout = av_get_default_channel_layout(avctx->channels);
        if (!avctx->channel_layout) {
            fprintf(stderr, "unable to guess channel layout\n");
Luca Barbato's avatar
Luca Barbato committed
2117 2118
            ret = AVERROR_INVALIDDATA;
            goto fail;
2119 2120 2121 2122 2123 2124 2125
        }
        if (avctx->channels == 1)
            is->sdl_channel_layout = AV_CH_LAYOUT_MONO;
        else
            is->sdl_channel_layout = AV_CH_LAYOUT_STEREO;
        is->sdl_channels = av_get_channel_layout_nb_channels(is->sdl_channel_layout);

2126 2127
        wanted_spec.format = AUDIO_S16SYS;
        wanted_spec.freq = is->sdl_sample_rate;
2128
        wanted_spec.channels = is->sdl_channels;
2129 2130 2131 2132 2133 2134
        wanted_spec.silence = 0;
        wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
        wanted_spec.callback = sdl_audio_callback;
        wanted_spec.userdata = is;
        if (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
            fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
Luca Barbato's avatar
Luca Barbato committed
2135 2136
            ret = AVERROR_UNKNOWN;
            goto fail;
2137 2138
        }
        is->audio_hw_buf_size = spec.size;
2139 2140
        is->sdl_sample_fmt          = AV_SAMPLE_FMT_S16;
        is->resample_sample_fmt     = is->sdl_sample_fmt;
2141 2142
        is->resample_channel_layout = avctx->channel_layout;
        is->resample_sample_rate    = avctx->sample_rate;
2143 2144
    }

2145
    ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
Aneesh Dogra's avatar
Aneesh Dogra committed
2146
    switch (avctx->codec_type) {
2147
    case AVMEDIA_TYPE_AUDIO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2148 2149
        is->audio_stream = stream_index;
        is->audio_st = ic->streams[stream_index];
Aneesh Dogra's avatar
Aneesh Dogra committed
2150
        is->audio_buf_size  = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2151
        is->audio_buf_index = 0;
2152 2153

        /* init averaging filter */
Aneesh Dogra's avatar
Aneesh Dogra committed
2154
        is->audio_diff_avg_coef  = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
2155 2156 2157
        is->audio_diff_avg_count = 0;
        /* since we do not have a precise anough audio fifo fullness,
           we correct audio sync only if larger than this threshold */
2158
        is->audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / avctx->sample_rate;
2159

Fabrice Bellard's avatar
Fabrice Bellard committed
2160 2161
        memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
        packet_queue_init(&is->audioq);
2162
        SDL_PauseAudio(0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2163
        break;
2164
    case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2165 2166 2167 2168 2169 2170
        is->video_stream = stream_index;
        is->video_st = ic->streams[stream_index];

        packet_queue_init(&is->videoq);
        is->video_tid = SDL_CreateThread(video_thread, is);
        break;
2171
    case AVMEDIA_TYPE_SUBTITLE:
2172 2173 2174
        is->subtitle_stream = stream_index;
        is->subtitle_st = ic->streams[stream_index];
        packet_queue_init(&is->subtitleq);
2175

2176 2177
        is->subtitle_tid = SDL_CreateThread(subtitle_thread, is);
        break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2178 2179 2180
    default:
        break;
    }
Luca Barbato's avatar
Luca Barbato committed
2181 2182 2183 2184 2185

fail:
    av_dict_free(&opts);

    return ret;
Fabrice Bellard's avatar
Fabrice Bellard committed
2186 2187 2188 2189 2190
}

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

2193 2194
    if (stream_index < 0 || stream_index >= ic->nb_streams)
        return;
2195
    avctx = ic->streams[stream_index]->codec;
Fabrice Bellard's avatar
Fabrice Bellard committed
2196

Aneesh Dogra's avatar
Aneesh Dogra committed
2197
    switch (avctx->codec_type) {
2198
    case AVMEDIA_TYPE_AUDIO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2199 2200 2201 2202 2203
        packet_queue_abort(&is->audioq);

        SDL_CloseAudio();

        packet_queue_end(&is->audioq);
2204
        av_free_packet(&is->audio_pkt);
2205 2206
        if (is->avr)
            avresample_free(&is->avr);
2207 2208
        av_freep(&is->audio_buf1);
        is->audio_buf = NULL;
2209
        av_frame_free(&is->frame);
2210 2211 2212 2213

        if (is->rdft) {
            av_rdft_end(is->rdft);
            av_freep(&is->rdft_data);
2214 2215
            is->rdft = NULL;
            is->rdft_bits = 0;
2216
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
2217
        break;
2218
    case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230
        packet_queue_abort(&is->videoq);

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

        SDL_WaitThread(is->video_tid, NULL);

        packet_queue_end(&is->videoq);
        break;
2231
    case AVMEDIA_TYPE_SUBTITLE:
2232
        packet_queue_abort(&is->subtitleq);
2233

2234 2235 2236 2237
        /* note: we also signal this mutex to make sure we deblock the
           video thread in all cases */
        SDL_LockMutex(is->subpq_mutex);
        is->subtitle_stream_changed = 1;
2238

2239 2240 2241 2242 2243 2244 2245
        SDL_CondSignal(is->subpq_cond);
        SDL_UnlockMutex(is->subpq_mutex);

        SDL_WaitThread(is->subtitle_tid, NULL);

        packet_queue_end(&is->subtitleq);
        break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2246 2247 2248 2249
    default:
        break;
    }

2250
    ic->streams[stream_index]->discard = AVDISCARD_ALL;
2251
    avcodec_close(avctx);
Aneesh Dogra's avatar
Aneesh Dogra committed
2252
    switch (avctx->codec_type) {
2253
    case AVMEDIA_TYPE_AUDIO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2254 2255 2256
        is->audio_st = NULL;
        is->audio_stream = -1;
        break;
2257
    case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2258 2259 2260
        is->video_st = NULL;
        is->video_stream = -1;
        break;
2261
    case AVMEDIA_TYPE_SUBTITLE:
2262 2263 2264
        is->subtitle_st = NULL;
        is->subtitle_stream = -1;
        break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2265 2266 2267 2268 2269
    default:
        break;
    }
}

2270 2271 2272 2273
/* since we have only one decoding thread, we can use a global
   variable instead of a thread local variable */
static VideoState *global_video_state;

2274
static int decode_interrupt_cb(void *ctx)
2275
{
2276
    return global_video_state && global_video_state->abort_request;
2277
}
Fabrice Bellard's avatar
Fabrice Bellard committed
2278 2279 2280 2281 2282

/* this thread gets the stream from the disk or the network */
static int decode_thread(void *arg)
{
    VideoState *is = arg;
2283
    AVFormatContext *ic = NULL;
2284
    int err, i, ret;
2285
    int st_index[AVMEDIA_TYPE_NB];
Fabrice Bellard's avatar
Fabrice Bellard committed
2286
    AVPacket pkt1, *pkt = &pkt1;
Aneesh Dogra's avatar
Aneesh Dogra committed
2287
    int eof = 0;
2288
    int pkt_in_play_range = 0;
2289
    AVDictionaryEntry *t;
2290 2291
    AVDictionary **opts;
    int orig_nb_streams;
2292

2293
    memset(st_index, -1, sizeof(st_index));
Fabrice Bellard's avatar
Fabrice Bellard committed
2294 2295
    is->video_stream = -1;
    is->audio_stream = -1;
2296
    is->subtitle_stream = -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2297

2298 2299
    global_video_state = is;

2300
    ic = avformat_alloc_context();
2301 2302 2303 2304 2305
    if (!ic) {
        av_log(NULL, AV_LOG_FATAL, "Could not allocate context.\n");
        ret = AVERROR(ENOMEM);
        goto fail;
    }
2306
    ic->interrupt_callback.callback = decode_interrupt_cb;
2307
    err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts);
2308 2309 2310 2311 2312
    if (err < 0) {
        print_error(is->filename, err);
        ret = -1;
        goto fail;
    }
2313 2314 2315 2316 2317
    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
2318
    is->ic = ic;
2319

Aneesh Dogra's avatar
Aneesh Dogra committed
2320
    if (genpts)
2321 2322
        ic->flags |= AVFMT_FLAG_GENPTS;

2323
    opts = setup_find_stream_info_opts(ic, codec_opts);
2324
    orig_nb_streams = ic->nb_streams;
2325

2326
    err = avformat_find_stream_info(ic, opts);
2327 2328 2329 2330 2331

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

2332 2333 2334 2335 2336
    if (err < 0) {
        fprintf(stderr, "%s: could not find codec parameters\n", is->filename);
        ret = -1;
        goto fail;
    }
2337

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

Aneesh Dogra's avatar
Aneesh Dogra committed
2341 2342
    if (seek_by_bytes < 0)
        seek_by_bytes = !!(ic->iformat->flags & AVFMT_TS_DISCONT);
2343

Fabrice Bellard's avatar
Fabrice Bellard committed
2344 2345 2346 2347 2348 2349 2350 2351
    /* 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;
2352
        ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2353
        if (ret < 0) {
2354
            fprintf(stderr, "%s: could not seek to position %0.3f\n",
Fabrice Bellard's avatar
Fabrice Bellard committed
2355 2356 2357 2358
                    is->filename, (double)timestamp / AV_TIME_BASE);
        }
    }

2359
    for (i = 0; i < ic->nb_streams; i++)
2360
        ic->streams[i]->discard = AVDISCARD_ALL;
2361
    if (!video_disable)
2362 2363 2364
        st_index[AVMEDIA_TYPE_VIDEO] =
            av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,
                                wanted_stream[AVMEDIA_TYPE_VIDEO], -1, NULL, 0);
2365
    if (!audio_disable)
2366 2367 2368 2369 2370
        st_index[AVMEDIA_TYPE_AUDIO] =
            av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO,
                                wanted_stream[AVMEDIA_TYPE_AUDIO],
                                st_index[AVMEDIA_TYPE_VIDEO],
                                NULL, 0);
2371
    if (!video_disable)
2372 2373 2374 2375 2376 2377 2378
        st_index[AVMEDIA_TYPE_SUBTITLE] =
            av_find_best_stream(ic, AVMEDIA_TYPE_SUBTITLE,
                                wanted_stream[AVMEDIA_TYPE_SUBTITLE],
                                (st_index[AVMEDIA_TYPE_AUDIO] >= 0 ?
                                 st_index[AVMEDIA_TYPE_AUDIO] :
                                 st_index[AVMEDIA_TYPE_VIDEO]),
                                NULL, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2379
    if (show_status) {
2380
        av_dump_format(ic, 0, is->filename, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2381 2382 2383
    }

    /* open the streams */
2384 2385
    if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {
        stream_component_open(is, st_index[AVMEDIA_TYPE_AUDIO]);
Fabrice Bellard's avatar
Fabrice Bellard committed
2386 2387
    }

Aneesh Dogra's avatar
Aneesh Dogra committed
2388
    ret = -1;
2389
    if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
Aneesh Dogra's avatar
Aneesh Dogra committed
2390
        ret = stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO]);
Michael Niedermayer's avatar
Michael Niedermayer committed
2391
    }
2392
    is->refresh_tid = SDL_CreateThread(refresh_thread, is);
Aneesh Dogra's avatar
Aneesh Dogra committed
2393
    if (ret < 0) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2394
        if (!display_disable)
2395
            is->show_audio = 2;
Fabrice Bellard's avatar
Fabrice Bellard committed
2396 2397
    }

2398 2399
    if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) {
        stream_component_open(is, st_index[AVMEDIA_TYPE_SUBTITLE]);
2400 2401
    }

Fabrice Bellard's avatar
Fabrice Bellard committed
2402
    if (is->video_stream < 0 && is->audio_stream < 0) {
2403 2404
        fprintf(stderr, "%s: could not open codecs\n", is->filename);
        ret = -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2405 2406 2407
        goto fail;
    }

Aneesh Dogra's avatar
Aneesh Dogra committed
2408
    for (;;) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2409 2410
        if (is->abort_request)
            break;
2411 2412
        if (is->paused != is->last_paused) {
            is->last_paused = is->paused;
Fabrice Bellard's avatar
Fabrice Bellard committed
2413
            if (is->paused)
Aneesh Dogra's avatar
Aneesh Dogra committed
2414
                is->read_pause_return = av_read_pause(ic);
Fabrice Bellard's avatar
Fabrice Bellard committed
2415 2416
            else
                av_read_play(ic);
2417
        }
2418 2419
#if CONFIG_RTSP_DEMUXER
        if (is->paused && !strcmp(ic->iformat->name, "rtsp")) {
2420 2421 2422 2423 2424
            /* wait 10 ms to avoid trying to get another packet */
            /* XXX: horrible */
            SDL_Delay(10);
            continue;
        }
2425
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
2426
        if (is->seek_req) {
Aneesh Dogra's avatar
Aneesh Dogra committed
2427 2428 2429 2430
            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
2431
//      of the seek_pos/seek_rel variables
2432

2433
            ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags);
Fabrice Bellard's avatar
Fabrice Bellard committed
2434 2435
            if (ret < 0) {
                fprintf(stderr, "%s: error while seeking\n", is->ic->filename);
Aneesh Dogra's avatar
Aneesh Dogra committed
2436
            } else {
2437 2438
                if (is->audio_stream >= 0) {
                    packet_queue_flush(&is->audioq);
2439
                    packet_queue_put(&is->audioq, &flush_pkt);
2440
                }
2441 2442
                if (is->subtitle_stream >= 0) {
                    packet_queue_flush(&is->subtitleq);
2443
                    packet_queue_put(&is->subtitleq, &flush_pkt);
2444
                }
2445 2446
                if (is->video_stream >= 0) {
                    packet_queue_flush(&is->videoq);
2447
                    packet_queue_put(&is->videoq, &flush_pkt);
2448
                }
Fabrice Bellard's avatar
Fabrice Bellard committed
2449 2450
            }
            is->seek_req = 0;
Aneesh Dogra's avatar
Aneesh Dogra committed
2451
            eof = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2452
        }
2453

Fabrice Bellard's avatar
Fabrice Bellard committed
2454
        /* if the queue are full, no need to read more */
2455 2456
        if (!infinite_buffer &&
              (is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
Aneesh Dogra's avatar
Aneesh Dogra committed
2457 2458
            || (   (is->audioq   .size  > MIN_AUDIOQ_SIZE || is->audio_stream < 0)
                && (is->videoq   .nb_packets > MIN_FRAMES || is->video_stream < 0)
2459
                && (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0)))) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2460 2461 2462 2463
            /* wait 10 ms */
            SDL_Delay(10);
            continue;
        }
Aneesh Dogra's avatar
Aneesh Dogra committed
2464 2465
        if (eof) {
            if (is->video_stream >= 0) {
Michael Niedermayer's avatar
Michael Niedermayer committed
2466
                av_init_packet(pkt);
Aneesh Dogra's avatar
Aneesh Dogra committed
2467 2468 2469
                pkt->data = NULL;
                pkt->size = 0;
                pkt->stream_index = is->video_stream;
Michael Niedermayer's avatar
Michael Niedermayer committed
2470
                packet_queue_put(&is->videoq, pkt);
2471
            }
2472
            if (is->audio_stream >= 0 &&
2473
                (is->audio_st->codec->codec->capabilities & AV_CODEC_CAP_DELAY)) {
2474 2475 2476 2477 2478 2479
                av_init_packet(pkt);
                pkt->data = NULL;
                pkt->size = 0;
                pkt->stream_index = is->audio_stream;
                packet_queue_put(&is->audioq, pkt);
            }
2480
            SDL_Delay(10);
Aneesh Dogra's avatar
Aneesh Dogra committed
2481 2482
            if (is->audioq.size + is->videoq.size + is->subtitleq.size == 0) {
                if (loop != 1 && (!loop || --loop)) {
2483
                    stream_seek(cur_stream, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0);
2484
                } else if (!noautoexit) {
Aneesh Dogra's avatar
Aneesh Dogra committed
2485
                    ret = AVERROR_EOF;
2486 2487
                    goto fail;
                }
Michael Niedermayer's avatar
Michael Niedermayer committed
2488
            }
2489 2490
            continue;
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
2491
        ret = av_read_frame(ic, pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
2492
        if (ret < 0) {
2493
            if (ret == AVERROR_EOF || (ic->pb && ic->pb->eof_reached))
Aneesh Dogra's avatar
Aneesh Dogra committed
2494
                eof = 1;
2495
            if (ic->pb && ic->pb->error)
2496
                break;
2497 2498
            SDL_Delay(100); /* wait for user event */
            continue;
Fabrice Bellard's avatar
Fabrice Bellard committed
2499
        }
2500 2501 2502 2503
        /* check if packet is in play range specified by user, then queue, otherwise discard */
        pkt_in_play_range = duration == AV_NOPTS_VALUE ||
                (pkt->pts - ic->streams[pkt->stream_index]->start_time) *
                av_q2d(ic->streams[pkt->stream_index]->time_base) -
Aneesh Dogra's avatar
Aneesh Dogra committed
2504 2505
                (double)(start_time != AV_NOPTS_VALUE ? start_time : 0) / 1000000
                <= ((double)duration / 1000000);
2506
        if (pkt->stream_index == is->audio_stream && pkt_in_play_range) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2507
            packet_queue_put(&is->audioq, pkt);
2508
        } else if (pkt->stream_index == is->video_stream && pkt_in_play_range) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2509
            packet_queue_put(&is->videoq, pkt);
2510
        } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {
2511
            packet_queue_put(&is->subtitleq, pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
2512 2513 2514 2515 2516 2517 2518 2519 2520
        } else {
            av_free_packet(pkt);
        }
    }
    /* wait until the end */
    while (!is->abort_request) {
        SDL_Delay(100);
    }

2521
    ret = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2522
 fail:
2523 2524 2525
    /* disable interrupting */
    global_video_state = NULL;

Fabrice Bellard's avatar
Fabrice Bellard committed
2526 2527 2528 2529 2530
    /* 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);
2531 2532
    if (is->subtitle_stream >= 0)
        stream_component_close(is, is->subtitle_stream);
2533
    if (is->ic) {
2534
        avformat_close_input(&is->ic);
2535
    }
2536

2537 2538
    if (ret != 0) {
        SDL_Event event;
2539

2540 2541 2542 2543
        event.type = FF_QUIT_EVENT;
        event.user.data1 = is;
        SDL_PushEvent(&event);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2544 2545 2546
    return 0;
}

2547
static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
Fabrice Bellard's avatar
Fabrice Bellard committed
2548 2549 2550 2551 2552 2553
{
    VideoState *is;

    is = av_mallocz(sizeof(VideoState));
    if (!is)
        return NULL;
2554
    av_strlcpy(is->filename, filename, sizeof(is->filename));
2555
    is->iformat = iformat;
Aneesh Dogra's avatar
Aneesh Dogra committed
2556 2557
    is->ytop    = 0;
    is->xleft   = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2558 2559 2560

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

2563
    is->subpq_mutex = SDL_CreateMutex();
Aneesh Dogra's avatar
Aneesh Dogra committed
2564
    is->subpq_cond  = SDL_CreateCond();
2565

2566
    is->av_sync_type = av_sync_type;
Aneesh Dogra's avatar
Aneesh Dogra committed
2567
    is->parse_tid    = SDL_CreateThread(decode_thread, is);
Fabrice Bellard's avatar
Fabrice Bellard committed
2568 2569 2570 2571 2572 2573 2574
    if (!is->parse_tid) {
        av_free(is);
        return NULL;
    }
    return is;
}

2575
static void stream_cycle_channel(VideoState *is, int codec_type)
2576 2577 2578 2579 2580
{
    AVFormatContext *ic = is->ic;
    int start_index, stream_index;
    AVStream *st;

2581
    if (codec_type == AVMEDIA_TYPE_VIDEO)
2582
        start_index = is->video_stream;
2583
    else if (codec_type == AVMEDIA_TYPE_AUDIO)
2584
        start_index = is->audio_stream;
2585 2586
    else
        start_index = is->subtitle_stream;
2587
    if (start_index < (codec_type == AVMEDIA_TYPE_SUBTITLE ? -1 : 0))
2588 2589
        return;
    stream_index = start_index;
Aneesh Dogra's avatar
Aneesh Dogra committed
2590
    for (;;) {
2591
        if (++stream_index >= is->ic->nb_streams)
2592
        {
2593
            if (codec_type == AVMEDIA_TYPE_SUBTITLE)
2594 2595 2596 2597 2598 2599
            {
                stream_index = -1;
                goto the_end;
            } else
                stream_index = 0;
        }
2600 2601 2602
        if (stream_index == start_index)
            return;
        st = ic->streams[stream_index];
2603
        if (st->codec->codec_type == codec_type) {
2604
            /* check that parameters are OK */
Aneesh Dogra's avatar
Aneesh Dogra committed
2605
            switch (codec_type) {
2606
            case AVMEDIA_TYPE_AUDIO:
2607 2608
                if (st->codec->sample_rate != 0 &&
                    st->codec->channels != 0)
2609 2610
                    goto the_end;
                break;
2611 2612
            case AVMEDIA_TYPE_VIDEO:
            case AVMEDIA_TYPE_SUBTITLE:
2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624
                goto the_end;
            default:
                break;
            }
        }
    }
 the_end:
    stream_component_close(is, start_index);
    stream_component_open(is, stream_index);
}


2625
static void toggle_full_screen(void)
Fabrice Bellard's avatar
Fabrice Bellard committed
2626
{
2627
#if defined(__APPLE__) && SDL_VERSION_ATLEAST(1, 2, 14)
2628
    /* OS X needs to empty the picture_queue */
2629 2630
    int i;
    for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++)
2631 2632
        cur_stream->pictq[i].reallocate = 1;
#endif
2633
    is_full_screen = !is_full_screen;
2634
    video_open(cur_stream);
Fabrice Bellard's avatar
Fabrice Bellard committed
2635 2636
}

2637
static void toggle_pause(void)
Fabrice Bellard's avatar
Fabrice Bellard committed
2638 2639 2640
{
    if (cur_stream)
        stream_pause(cur_stream);
2641 2642 2643
    step = 0;
}

2644
static void step_to_next_frame(void)
2645 2646
{
    if (cur_stream) {
2647
        /* if the stream is paused unpause it, then step */
2648
        if (cur_stream->paused)
2649
            stream_pause(cur_stream);
2650 2651
    }
    step = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2652 2653
}

2654
static void toggle_audio_display(void)
Fabrice Bellard's avatar
Fabrice Bellard committed
2655 2656
{
    if (cur_stream) {
2657
        int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
2658
        cur_stream->show_audio = (cur_stream->show_audio + 1) % 3;
2659
        fill_rectangle(screen,
Aneesh Dogra's avatar
Aneesh Dogra committed
2660 2661
                       cur_stream->xleft, cur_stream->ytop, cur_stream->width, cur_stream->height,
                       bgcolor);
2662
        SDL_UpdateRect(screen, cur_stream->xleft, cur_stream->ytop, cur_stream->width, cur_stream->height);
Fabrice Bellard's avatar
Fabrice Bellard committed
2663 2664 2665
    }
}

2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692
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
2693
/* handle an event sent by the GUI */
2694
static void event_loop(void)
Fabrice Bellard's avatar
Fabrice Bellard committed
2695 2696
{
    SDL_Event event;
2697
    double incr, pos, frac;
Fabrice Bellard's avatar
Fabrice Bellard committed
2698

Aneesh Dogra's avatar
Aneesh Dogra committed
2699
    for (;;) {
Michael Niedermayer's avatar
Michael Niedermayer committed
2700
        double x;
Fabrice Bellard's avatar
Fabrice Bellard committed
2701
        SDL_WaitEvent(&event);
Aneesh Dogra's avatar
Aneesh Dogra committed
2702
        switch (event.type) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2703
        case SDL_KEYDOWN:
2704 2705 2706 2707
            if (exit_on_keydown) {
                do_exit();
                break;
            }
Aneesh Dogra's avatar
Aneesh Dogra committed
2708
            switch (event.key.keysym.sym) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719
            case SDLK_ESCAPE:
            case SDLK_q:
                do_exit();
                break;
            case SDLK_f:
                toggle_full_screen();
                break;
            case SDLK_p:
            case SDLK_SPACE:
                toggle_pause();
                break;
Aneesh Dogra's avatar
Aneesh Dogra committed
2720
            case SDLK_s: // S: Step to next frame
2721 2722
                step_to_next_frame();
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2723
            case SDLK_a:
2724
                if (cur_stream)
2725
                    stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
2726 2727
                break;
            case SDLK_v:
2728
                if (cur_stream)
2729
                    stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
2730
                break;
2731
            case SDLK_t:
2732
                if (cur_stream)
2733
                    stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
2734
                break;
2735
            case SDLK_w:
Fabrice Bellard's avatar
Fabrice Bellard committed
2736 2737
                toggle_audio_display();
                break;
2738 2739 2740 2741 2742 2743
            case SDLK_PAGEUP:
                seek_chapter(cur_stream, 1);
                break;
            case SDLK_PAGEDOWN:
                seek_chapter(cur_stream, -1);
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756
            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:
                if (cur_stream) {
2757
                    if (seek_by_bytes) {
Aneesh Dogra's avatar
Aneesh Dogra committed
2758 2759 2760 2761 2762
                        if (cur_stream->video_stream >= 0 && cur_stream->video_current_pos >= 0) {
                            pos = cur_stream->video_current_pos;
                        } else if (cur_stream->audio_stream >= 0 && cur_stream->audio_pkt.pos >= 0) {
                            pos = cur_stream->audio_pkt.pos;
                        } else
2763
                            pos = avio_tell(cur_stream->ic->pb);
2764
                        if (cur_stream->ic->bit_rate)
2765
                            incr *= cur_stream->ic->bit_rate / 8.0;
2766 2767 2768
                        else
                            incr *= 180000.0;
                        pos += incr;
2769
                        stream_seek(cur_stream, pos, incr, 1);
2770 2771 2772
                    } else {
                        pos = get_master_clock(cur_stream);
                        pos += incr;
2773
                        stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0);
2774
                    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2775 2776
                }
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2777 2778 2779 2780
            default:
                break;
            }
            break;
2781
        case SDL_MOUSEBUTTONDOWN:
2782 2783 2784 2785
            if (exit_on_mousedown) {
                do_exit();
                break;
            }
Michael Niedermayer's avatar
Michael Niedermayer committed
2786
        case SDL_MOUSEMOTION:
Aneesh Dogra's avatar
Aneesh Dogra committed
2787 2788 2789 2790
            if (event.type == SDL_MOUSEBUTTONDOWN) {
                x = event.button.x;
            } else {
                if (event.motion.state != SDL_PRESSED)
Michael Niedermayer's avatar
Michael Niedermayer committed
2791
                    break;
Aneesh Dogra's avatar
Aneesh Dogra committed
2792
                x = event.motion.x;
Michael Niedermayer's avatar
Michael Niedermayer committed
2793
            }
2794
            if (cur_stream) {
Aneesh Dogra's avatar
Aneesh Dogra committed
2795 2796
                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
2797
                    stream_seek(cur_stream, size*x/cur_stream->width, 0, 1);
Aneesh Dogra's avatar
Aneesh Dogra committed
2798
                } else {
Michael Niedermayer's avatar
Michael Niedermayer committed
2799 2800 2801
                    int64_t ts;
                    int ns, hh, mm, ss;
                    int tns, thh, tmm, tss;
Aneesh Dogra's avatar
Aneesh Dogra committed
2802 2803 2804 2805 2806 2807 2808 2809 2810
                    tns  = cur_stream->ic->duration / 1000000LL;
                    thh  = tns / 3600;
                    tmm  = (tns % 3600) / 60;
                    tss  = (tns % 60);
                    frac = x / cur_stream->width;
                    ns   = frac * tns;
                    hh   = ns / 3600;
                    mm   = (ns % 3600) / 60;
                    ss   = (ns % 60);
Michael Niedermayer's avatar
Michael Niedermayer committed
2811 2812
                    fprintf(stderr, "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d)       \n", frac*100,
                            hh, mm, ss, thh, tmm, tss);
Aneesh Dogra's avatar
Aneesh Dogra committed
2813
                    ts = frac * cur_stream->ic->duration;
Michael Niedermayer's avatar
Michael Niedermayer committed
2814 2815 2816
                    if (cur_stream->ic->start_time != AV_NOPTS_VALUE)
                        ts += cur_stream->ic->start_time;
                    stream_seek(cur_stream, ts, 0, 0);
2817
                }
2818 2819
            }
            break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2820 2821
        case SDL_VIDEORESIZE:
            if (cur_stream) {
2822
                screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 0,
Fabrice Bellard's avatar
Fabrice Bellard committed
2823
                                          SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
Aneesh Dogra's avatar
Aneesh Dogra committed
2824 2825
                screen_width  = cur_stream->width  = event.resize.w;
                screen_height = cur_stream->height = event.resize.h;
Fabrice Bellard's avatar
Fabrice Bellard committed
2826 2827 2828
            }
            break;
        case SDL_QUIT:
2829
        case FF_QUIT_EVENT:
Fabrice Bellard's avatar
Fabrice Bellard committed
2830 2831 2832
            do_exit();
            break;
        case FF_ALLOC_EVENT:
2833
            video_open(event.user.data1);
Fabrice Bellard's avatar
Fabrice Bellard committed
2834 2835 2836 2837
            alloc_picture(event.user.data1);
            break;
        case FF_REFRESH_EVENT:
            video_refresh_timer(event.user.data1);
Aneesh Dogra's avatar
Aneesh Dogra committed
2838
            cur_stream->refresh = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2839 2840 2841 2842 2843 2844 2845
            break;
        default:
            break;
        }
    }
}

2846
static int opt_frame_size(void *optctx, const char *opt, const char *arg)
2847
{
2848 2849 2850
    av_log(NULL, AV_LOG_ERROR,
           "Option '%s' has been removed, use private format options instead\n", opt);
    return AVERROR(EINVAL);
2851 2852
}

2853
static int opt_width(void *optctx, const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
2854
{
2855 2856
    screen_width = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2857 2858
}

2859
static int opt_height(void *optctx, const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
2860
{
2861 2862
    screen_height = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2863 2864
}

2865
static int opt_format(void *optctx, const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
2866 2867 2868 2869
{
    file_iformat = av_find_input_format(arg);
    if (!file_iformat) {
        fprintf(stderr, "Unknown input format: %s\n", arg);
2870
        return AVERROR(EINVAL);
Fabrice Bellard's avatar
Fabrice Bellard committed
2871
    }
2872
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2873
}
2874

2875
static int opt_frame_pix_fmt(void *optctx, const char *opt, const char *arg)
2876
{
2877 2878 2879
    av_log(NULL, AV_LOG_ERROR,
           "Option '%s' has been removed, use private format options instead\n", opt);
    return AVERROR(EINVAL);
2880 2881
}

2882
static int opt_sync(void *optctx, const char *opt, const char *arg)
2883 2884 2885 2886 2887 2888 2889
{
    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;
2890
    else {
2891
        fprintf(stderr, "Unknown value for %s: %s\n", opt, arg);
2892 2893
        exit(1);
    }
2894
    return 0;
2895 2896
}

2897
static int opt_seek(void *optctx, const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
2898
{
2899 2900
    start_time = parse_time_or_die(opt, arg, 1);
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2901 2902
}

2903
static int opt_duration(void *optctx, const char *opt, const char *arg)
2904 2905 2906 2907 2908
{
    duration = parse_time_or_die(opt, arg, 1);
    return 0;
}

2909
static const OptionDef options[] = {
2910
#include "cmdutils_common_opts.h"
2911 2912 2913
    { "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" },
2914 2915 2916 2917 2918 2919
    { "fs", OPT_BOOL, { &is_full_screen }, "force full screen" },
    { "an", OPT_BOOL, { &audio_disable }, "disable audio" },
    { "vn", OPT_BOOL, { &video_disable }, "disable video" },
    { "ast", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_AUDIO] }, "select desired audio stream", "stream_number" },
    { "vst", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_VIDEO] }, "select desired video stream", "stream_number" },
    { "sst", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_SUBTITLE] }, "select desired subtitle stream", "stream_number" },
2920 2921
    { "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" },
2922 2923
    { "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" },
2924 2925
    { "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" },
2926 2927 2928 2929 2930 2931 2932 2933 2934 2935
    { "stats", OPT_BOOL | OPT_EXPERT, { &show_status }, "show status", "" },
    { "bug", OPT_INT | HAS_ARG | OPT_EXPERT, { &workaround_bugs }, "workaround bugs", "" },
    { "fast", OPT_BOOL | OPT_EXPERT, { &fast }, "non spec compliant optimizations", "" },
    { "genpts", OPT_BOOL | OPT_EXPERT, { &genpts }, "generate pts", "" },
    { "drp", OPT_INT | HAS_ARG | OPT_EXPERT, { &decoder_reorder_pts }, "let decoder reorder pts 0=off 1=on -1=auto", ""},
    { "skiploop", OPT_INT | HAS_ARG | OPT_EXPERT, { &skip_loop_filter }, "", "" },
    { "skipframe", OPT_INT | HAS_ARG | OPT_EXPERT, { &skip_frame }, "", "" },
    { "skipidct", OPT_INT | HAS_ARG | OPT_EXPERT, { &skip_idct }, "", "" },
    { "idct", OPT_INT | HAS_ARG | OPT_EXPERT, { &idct }, "set idct algo",  "algo" },
    { "ec", OPT_INT | HAS_ARG | OPT_EXPERT, { &error_concealment }, "set error concealment options",  "bit_mask" },
2936
    { "sync", HAS_ARG | OPT_EXPERT, { .func_arg = opt_sync }, "set audio-video sync. type (type=audio/video/ext)", "type" },
2937
    { "noautoexit", OPT_BOOL | OPT_EXPERT, { &noautoexit }, "Do not exit at the end of playback", "" },
2938 2939 2940 2941 2942 2943
    { "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" },
2944
#if CONFIG_AVFILTER
2945
    { "vf", OPT_STRING | HAS_ARG, { &vfilters }, "video filters", "filter list" },
2946
#endif
2947 2948
    { "rdftspeed", OPT_INT | HAS_ARG| OPT_AUDIO | OPT_EXPERT, { &rdftspeed }, "rdft speed", "msecs" },
    { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { opt_default }, "generic catch all option", "" },
Aneesh Dogra's avatar
Aneesh Dogra committed
2949
    { "i", 0, { NULL }, "avconv compatibility dummy option", ""},
2950
    { "autorotate", OPT_BOOL, { &autorotate }, "automatically rotate video", "" },
Fabrice Bellard's avatar
Fabrice Bellard committed
2951 2952 2953
    { NULL, },
};

2954
static void show_usage(void)
Fabrice Bellard's avatar
Fabrice Bellard committed
2955
{
2956
    printf("Simple media player\n");
Anton Khirnov's avatar
Anton Khirnov committed
2957
    printf("usage: %s [options] input_file\n", program_name);
Fabrice Bellard's avatar
Fabrice Bellard committed
2958
    printf("\n");
2959 2960
}

2961
void show_help_default(const char *opt, const char *arg)
2962
{
2963
    av_log_set_callback(log_callback_help);
2964
    show_usage();
2965 2966
    show_help_options(options, "Main options:", 0, OPT_EXPERT, 0);
    show_help_options(options, "Advanced options:", OPT_EXPERT, 0, 0);
2967
    printf("\n");
2968 2969
    show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM);
    show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
2970
#if !CONFIG_AVFILTER
2971
    show_help_children(sws_get_class(), AV_OPT_FLAG_ENCODING_PARAM);
2972
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
2973 2974 2975 2976
    printf("\nWhile playing:\n"
           "q, ESC              quit\n"
           "f                   toggle full screen\n"
           "p, SPC              pause\n"
2977 2978
           "a                   cycle audio channel\n"
           "v                   cycle video channel\n"
2979
           "t                   cycle subtitle channel\n"
2980
           "w                   show audio waves\n"
2981
           "s                   activate frame-step mode\n"
Fabrice Bellard's avatar
Fabrice Bellard committed
2982 2983
           "left/right          seek backward/forward 10 seconds\n"
           "down/up             seek backward/forward 1 minute\n"
2984
           "mouse click         seek to percentage in file corresponding to fraction of width\n"
Fabrice Bellard's avatar
Fabrice Bellard committed
2985 2986 2987
           );
}

2988
static void opt_input_file(void *optctx, const char *filename)
Fabrice Bellard's avatar
Fabrice Bellard committed
2989
{
2990 2991 2992 2993 2994
    if (input_filename) {
        fprintf(stderr, "Argument '%s' provided as input filename, but '%s' was already specified.\n",
                filename, input_filename);
        exit(1);
    }
2995
    if (!strcmp(filename, "-"))
2996
        filename = "pipe:";
Fabrice Bellard's avatar
Fabrice Bellard committed
2997 2998 2999 3000 3001 3002
    input_filename = filename;
}

/* Called from the main */
int main(int argc, char **argv)
{
3003
    int flags;
3004

3005
    av_log_set_flags(AV_LOG_SKIP_REPEATED);
3006
    parse_loglevel(argc, argv, options);
3007

Fabrice Bellard's avatar
Fabrice Bellard committed
3008
    /* register all codecs, demux and protocols */
Luca Abeni's avatar
Luca Abeni committed
3009
    avcodec_register_all();
3010
#if CONFIG_AVDEVICE
Luca Abeni's avatar
Luca Abeni committed
3011
    avdevice_register_all();
3012
#endif
3013 3014 3015
#if CONFIG_AVFILTER
    avfilter_register_all();
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3016
    av_register_all();
3017
    avformat_network_init();
Fabrice Bellard's avatar
Fabrice Bellard committed
3018

3019
    init_opts();
3020

3021
    show_banner();
3022

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

3025
    if (!input_filename) {
3026
        show_usage();
3027
        fprintf(stderr, "An input file must be specified\n");
Anton Khirnov's avatar
Anton Khirnov committed
3028
        fprintf(stderr, "Use -h to get full help or, even better, run 'man %s'\n", program_name);
3029 3030
        exit(1);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
3031 3032 3033 3034

    if (display_disable) {
        video_disable = 1;
    }
3035
    flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
3036 3037
#if !defined(__MINGW32__) && !defined(__APPLE__)
    flags |= SDL_INIT_EVENTTHREAD; /* Not supported on Windows or Mac OS X */
3038
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3039
    if (SDL_Init (flags)) {
3040
        fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
Fabrice Bellard's avatar
Fabrice Bellard committed
3041 3042 3043 3044
        exit(1);
    }

    if (!display_disable) {
3045 3046 3047
        const SDL_VideoInfo *vi = SDL_GetVideoInfo();
        fs_screen_width = vi->current_w;
        fs_screen_height = vi->current_h;
Fabrice Bellard's avatar
Fabrice Bellard committed
3048 3049 3050 3051 3052 3053
    }

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

3054
    av_init_packet(&flush_pkt);
Luca Barbato's avatar
Luca Barbato committed
3055
    flush_pkt.data = (uint8_t *)&flush_pkt;
3056

3057
    cur_stream = stream_open(input_filename, file_iformat);
Fabrice Bellard's avatar
Fabrice Bellard committed
3058 3059 3060 3061 3062 3063 3064

    event_loop();

    /* never returns */

    return 0;
}