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

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

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

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

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

58
#include "cmdutils.h"
59

60 61 62
#include <unistd.h>
#include <assert.h>

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

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

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

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

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

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

87 88
static int sws_flags = SWS_BICUBIC;

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

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

typedef struct VideoPicture {
Aneesh Dogra's avatar
Aneesh Dogra committed
102
    double pts;                                  ///< presentation time stamp for this picture
103
    double duration;                             ///< expected duration of the frame
Aneesh Dogra's avatar
Aneesh Dogra committed
104
    int64_t pos;                                 ///< byte position in file
105
    int skip;
Fabrice Bellard's avatar
Fabrice Bellard committed
106 107 108
    SDL_Overlay *bmp;
    int width, height; /* source height & width */
    int allocated;
109
    int reallocate;
110 111 112
    enum PixelFormat pix_fmt;

#if CONFIG_AVFILTER
113
    AVFilterBufferRef *picref;
114
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
115 116
} VideoPicture;

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

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

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

    int audio_stream;
146

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

151 152 153 154 155
    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
156 157 158
    AVStream *audio_st;
    PacketQueue audioq;
    int audio_hw_buf_size;
159
    DECLARE_ALIGNED(16,uint8_t,audio_buf2)[AVCODEC_MAX_AUDIO_FRAME_SIZE * 4];
160
    uint8_t silence_buf[SDL_AUDIO_BUFFER_SIZE];
161
    uint8_t *audio_buf;
162
    uint8_t *audio_buf1;
163
    unsigned int audio_buf_size; /* in bytes */
Fabrice Bellard's avatar
Fabrice Bellard committed
164
    int audio_buf_index; /* in bytes */
165
    int audio_write_buf_size;
166
    AVPacket audio_pkt_temp;
Fabrice Bellard's avatar
Fabrice Bellard committed
167
    AVPacket audio_pkt;
168
    enum AVSampleFormat audio_src_fmt;
169 170 171 172 173 174 175 176
    enum AVSampleFormat audio_tgt_fmt;
    int audio_src_channels;
    int audio_tgt_channels;
    int64_t audio_src_channel_layout;
    int64_t audio_tgt_channel_layout;
    int audio_src_freq;
    int audio_tgt_freq;
    struct SwrContext *swr_ctx;
177 178
    double audio_current_pts;
    double audio_current_pts_drift;
179 180
    int frame_drops_early;
    int frame_drops_late;
181
    AVFrame *frame;
182

183
    enum ShowMode {
184
        SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB
185
    } show_mode;
Fabrice Bellard's avatar
Fabrice Bellard committed
186 187
    int16_t sample_array[SAMPLE_ARRAY_SIZE];
    int sample_array_index;
188
    int last_i_start;
189
    RDFTContext *rdft;
190
    int rdft_bits;
Måns Rullgård's avatar
Måns Rullgård committed
191
    FFTSample *rdft_data;
192
    int xpos;
193

194 195 196 197 198 199 200 201 202
    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;
203

204 205
    double frame_timer;
    double frame_last_pts;
206
    double frame_last_duration;
207
    double frame_last_dropped_pts;
208 209
    double frame_last_returned_time;
    double frame_last_filter_delay;
210
    int64_t frame_last_dropped_pos;
Aneesh Dogra's avatar
Aneesh Dogra committed
211
    double video_clock;                          ///< pts of last decoded frame / predicted pts of next decoded frame
Fabrice Bellard's avatar
Fabrice Bellard committed
212 213 214
    int video_stream;
    AVStream *video_st;
    PacketQueue videoq;
Aneesh Dogra's avatar
Aneesh Dogra committed
215 216 217
    double video_current_pts;                    ///< current displayed pts (different from video_clock if frame fifos are used)
    double video_current_pts_drift;              ///< video_current_pts - time (av_gettime) at which we updated video_current_pts - used to have running video pts
    int64_t video_current_pos;                   ///< current displayed file pos
Fabrice Bellard's avatar
Fabrice Bellard committed
218 219 220 221
    VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE];
    int pictq_size, pictq_rindex, pictq_windex;
    SDL_mutex *pictq_mutex;
    SDL_cond *pictq_cond;
222
#if !CONFIG_AVFILTER
223
    struct SwsContext *img_convert_ctx;
224
#endif
225

Fabrice Bellard's avatar
Fabrice Bellard committed
226 227
    char filename[1024];
    int width, height, xleft, ytop;
228
    int step;
229

230
#if CONFIG_AVFILTER
Aneesh Dogra's avatar
Aneesh Dogra committed
231
    AVFilterContext *out_video_filter;          ///< the last filter in the video chain
232
#endif
233 234

    int refresh;
Fabrice Bellard's avatar
Fabrice Bellard committed
235 236
} VideoState;

237
static int opt_help(const char *opt, const char *arg);
Fabrice Bellard's avatar
Fabrice Bellard committed
238 239 240 241

/* options specified by the user */
static AVInputFormat *file_iformat;
static const char *input_filename;
242
static const char *window_title;
Fabrice Bellard's avatar
Fabrice Bellard committed
243 244
static int fs_screen_width;
static int fs_screen_height;
Aneesh Dogra's avatar
Aneesh Dogra committed
245
static int screen_width  = 0;
246
static int screen_height = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
247 248
static int audio_disable;
static int video_disable;
Aneesh Dogra's avatar
Aneesh Dogra committed
249 250 251 252
static int wanted_stream[AVMEDIA_TYPE_NB] = {
    [AVMEDIA_TYPE_AUDIO]    = -1,
    [AVMEDIA_TYPE_VIDEO]    = -1,
    [AVMEDIA_TYPE_SUBTITLE] = -1,
253
};
Aneesh Dogra's avatar
Aneesh Dogra committed
254
static int seek_by_bytes = -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
255
static int display_disable;
256
static int show_status = 1;
257
static int av_sync_type = AV_SYNC_AUDIO_MASTER;
Fabrice Bellard's avatar
Fabrice Bellard committed
258
static int64_t start_time = AV_NOPTS_VALUE;
259
static int64_t duration = AV_NOPTS_VALUE;
Michael Niedermayer's avatar
Michael Niedermayer committed
260
static int workaround_bugs = 1;
261
static int fast = 0;
262
static int genpts = 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
263
static int lowres = 0;
264
static int idct = FF_IDCT_AUTO;
Aneesh Dogra's avatar
Aneesh Dogra committed
265 266 267
static enum AVDiscard skip_frame       = AVDISCARD_DEFAULT;
static enum AVDiscard skip_idct        = AVDISCARD_DEFAULT;
static enum AVDiscard skip_loop_filter = AVDISCARD_DEFAULT;
268
static int error_concealment = 3;
Aneesh Dogra's avatar
Aneesh Dogra committed
269
static int decoder_reorder_pts = -1;
Michael Niedermayer's avatar
Michael Niedermayer committed
270
static int autoexit;
271 272
static int exit_on_keydown;
static int exit_on_mousedown;
Aneesh Dogra's avatar
Aneesh Dogra committed
273
static int loop = 1;
274
static int framedrop = -1;
275
static enum ShowMode show_mode = SHOW_MODE_NONE;
276 277 278
static const char *audio_codec_name;
static const char *subtitle_codec_name;
static const char *video_codec_name;
Aneesh Dogra's avatar
Aneesh Dogra committed
279
static int rdftspeed = 20;
280 281 282
#if CONFIG_AVFILTER
static char *vfilters = NULL;
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
283 284 285

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

288
static AVPacket flush_pkt;
289

Fabrice Bellard's avatar
Fabrice Bellard committed
290 291
#define FF_ALLOC_EVENT   (SDL_USEREVENT)
#define FF_REFRESH_EVENT (SDL_USEREVENT + 1)
292
#define FF_QUIT_EVENT    (SDL_USEREVENT + 2)
Fabrice Bellard's avatar
Fabrice Bellard committed
293

294
static SDL_Surface *screen;
Fabrice Bellard's avatar
Fabrice Bellard committed
295

296
void av_noreturn exit_program(int ret)
297 298 299 300
{
    exit(ret);
}

301 302 303 304 305
static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
{
    AVPacketList *pkt1;

    /* duplicate the packet */
306
    if (pkt != &flush_pkt && av_dup_packet(pkt) < 0)
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
        return -1;

    pkt1 = av_malloc(sizeof(AVPacketList));
    if (!pkt1)
        return -1;
    pkt1->pkt = *pkt;
    pkt1->next = NULL;


    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++;
    q->size += pkt1->pkt.size + sizeof(*pkt1);
    /* XXX: should duplicate packet data in DV case */
    SDL_CondSignal(q->cond);

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

Fabrice Bellard's avatar
Fabrice Bellard committed
333 334 335 336 337 338
/* packet queue handling */
static void packet_queue_init(PacketQueue *q)
{
    memset(q, 0, sizeof(PacketQueue));
    q->mutex = SDL_CreateMutex();
    q->cond = SDL_CreateCond();
339
    packet_queue_put(q, &flush_pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
340 341
}

Fabrice Bellard's avatar
Fabrice Bellard committed
342
static void packet_queue_flush(PacketQueue *q)
Fabrice Bellard's avatar
Fabrice Bellard committed
343 344 345
{
    AVPacketList *pkt, *pkt1;

346
    SDL_LockMutex(q->mutex);
Aneesh Dogra's avatar
Aneesh Dogra committed
347
    for (pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {
Fabrice Bellard's avatar
Fabrice Bellard committed
348 349
        pkt1 = pkt->next;
        av_free_packet(&pkt->pkt);
350
        av_freep(&pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
351
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
352 353 354 355
    q->last_pkt = NULL;
    q->first_pkt = NULL;
    q->nb_packets = 0;
    q->size = 0;
356
    SDL_UnlockMutex(q->mutex);
Fabrice Bellard's avatar
Fabrice Bellard committed
357 358 359 360 361
}

static void packet_queue_end(PacketQueue *q)
{
    packet_queue_flush(q);
Fabrice Bellard's avatar
Fabrice Bellard committed
362 363 364 365 366 367 368 369 370
    SDL_DestroyMutex(q->mutex);
    SDL_DestroyCond(q->cond);
}

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

    q->abort_request = 1;
371

Fabrice Bellard's avatar
Fabrice Bellard committed
372 373 374 375 376 377 378 379 380 381 382 383 384
    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
385
    for (;;) {
Fabrice Bellard's avatar
Fabrice Bellard committed
386 387 388 389
        if (q->abort_request) {
            ret = -1;
            break;
        }
390

Fabrice Bellard's avatar
Fabrice Bellard committed
391 392 393 394 395 396
        pkt1 = q->first_pkt;
        if (pkt1) {
            q->first_pkt = pkt1->next;
            if (!q->first_pkt)
                q->last_pkt = NULL;
            q->nb_packets--;
397
            q->size -= pkt1->pkt.size + sizeof(*pkt1);
Fabrice Bellard's avatar
Fabrice Bellard committed
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
            *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;
}

413
static inline void fill_rectangle(SDL_Surface *screen,
Fabrice Bellard's avatar
Fabrice Bellard committed
414 415 416 417 418 419 420 421 422 423
                                  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);
}

424 425 426 427 428 429 430 431 432 433 434 435 436 437
#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)\
{\
438
    unsigned int val = ((const uint32_t *)(pal))[*(const uint8_t*)(s)];\
439 440 441 442 443 444 445 446 447 448 449 450 451 452
    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

453
static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, int imgh)
454 455 456 457 458 459
{
    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;
460 461
    int dstx, dsty, dstw, dsth;

462 463 464 465
    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);
466
    lum = dst->data[0] + dsty * dst->linesize[0];
Aneesh Dogra's avatar
Aneesh Dogra committed
467 468
    cb  = dst->data[1] + (dsty >> 1) * dst->linesize[1];
    cr  = dst->data[2] + (dsty >> 1) * dst->linesize[2];
469

470
    width2 = ((dstw + 1) >> 1) + (dstx & ~dstw & 1);
471
    skip2 = dstx >> 1;
472
    wrap = dst->linesize[0];
473 474 475
    wrap3 = rect->pict.linesize[0];
    p = rect->pict.data[0];
    pal = (const uint32_t *)rect->pict.data[1];  /* Now in YCrCb! */
476

477 478
    if (dsty & 1) {
        lum += dstx;
479 480
        cb += skip2;
        cr += skip2;
481

482
        if (dstx & 1) {
483 484 485 486 487 488 489 490 491
            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
492
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
            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);
516 517
            p++;
            lum++;
518
        }
519 520
        p += wrap3 - dstw * BPP;
        lum += wrap - dstw - dstx;
521 522 523
        cb += dst->linesize[1] - width2 - skip2;
        cr += dst->linesize[2] - width2 - skip2;
    }
Aneesh Dogra's avatar
Aneesh Dogra committed
524
    for (h = dsth - (dsty & 1); h >= 2; h -= 2) {
525
        lum += dstx;
526 527
        cb += skip2;
        cr += skip2;
528

529
        if (dstx & 1) {
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
            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
549
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
550 551 552 553 554 555
            YUVA_IN(y, u, v, a, p, pal);
            u1 = u;
            v1 = v;
            a1 = a;
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);

556
            YUVA_IN(y, u, v, a, p + BPP, pal);
557 558 559 560 561 562 563 564 565 566 567 568 569
            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);

570
            YUVA_IN(y, u, v, a, p + BPP, pal);
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
            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;
        }
604 605
        p += wrap3 + (wrap3 - dstw * BPP);
        lum += wrap + (wrap - dstw - dstx);
606 607 608 609 610
        cb += dst->linesize[1] - width2 - skip2;
        cr += dst->linesize[2] - width2 - skip2;
    }
    /* handle odd height */
    if (h) {
611
        lum += dstx;
612 613
        cb += skip2;
        cr += skip2;
614

615
        if (dstx & 1) {
616 617 618 619 620 621 622 623 624
            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
625
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
            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)
{
655
    avsubtitle_free(&sp->sub);
656 657
}

Fabrice Bellard's avatar
Fabrice Bellard committed
658 659 660
static void video_image_display(VideoState *is)
{
    VideoPicture *vp;
661 662
    SubPicture *sp;
    AVPicture pict;
Fabrice Bellard's avatar
Fabrice Bellard committed
663 664 665
    float aspect_ratio;
    int width, height, x, y;
    SDL_Rect rect;
666
    int i;
Fabrice Bellard's avatar
Fabrice Bellard committed
667 668 669

    vp = &is->pictq[is->pictq_rindex];
    if (vp->bmp) {
670
#if CONFIG_AVFILTER
671
         if (vp->picref->video->sample_aspect_ratio.num == 0)
672 673
             aspect_ratio = 0;
         else
674
             aspect_ratio = av_q2d(vp->picref->video->sample_aspect_ratio);
675 676
#else

Fabrice Bellard's avatar
Fabrice Bellard committed
677
        /* XXX: use variable in the frame */
678 679 680 681
        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
682
        else
683
            aspect_ratio = 0;
684
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
685
        if (aspect_ratio <= 0.0)
686
            aspect_ratio = 1.0;
687
        aspect_ratio *= (float)vp->width / (float)vp->height;
Fabrice Bellard's avatar
Fabrice Bellard committed
688

689 690
        if (is->subtitle_st) {
            if (is->subpq_size > 0) {
691 692
                sp = &is->subpq[is->subpq_rindex];

693
                if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) {
694 695 696 697 698 699 700 701 702 703 704
                    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++)
705
                        blend_subrect(&pict, sp->sub.rects[i],
706
                                      vp->bmp->w, vp->bmp->h);
707 708 709 710 711 712 713

                    SDL_UnlockYUVOverlay (vp->bmp);
                }
            }
        }


Fabrice Bellard's avatar
Fabrice Bellard committed
714 715
        /* XXX: we suppose the screen has a 1.0 pixel ratio */
        height = is->height;
716
        width = ((int)rint(height * aspect_ratio)) & ~1;
Fabrice Bellard's avatar
Fabrice Bellard committed
717 718
        if (width > is->width) {
            width = is->width;
719
            height = ((int)rint(width / aspect_ratio)) & ~1;
Fabrice Bellard's avatar
Fabrice Bellard committed
720 721 722
        }
        x = (is->width - width) / 2;
        y = (is->height - height) / 2;
723
        is->no_background = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
724
        rect.x = is->xleft + x;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
725
        rect.y = is->ytop  + y;
726 727
        rect.w = FFMAX(width,  1);
        rect.h = FFMAX(height, 1);
Fabrice Bellard's avatar
Fabrice Bellard committed
728 729 730 731 732 733
        SDL_DisplayYUVOverlay(vp->bmp, &rect);
    }
}

static inline int compute_mod(int a, int b)
{
734
    return a < 0 ? a%b + b : a%b;
Fabrice Bellard's avatar
Fabrice Bellard committed
735 736 737 738 739 740 741
}

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;
742 743
    int rdft_bits, nb_freq;

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

Fabrice Bellard's avatar
Fabrice Bellard committed
748
    /* compute display index : center on currently output samples */
749
    channels = s->audio_tgt_channels;
Fabrice Bellard's avatar
Fabrice Bellard committed
750
    nb_display_channels = channels;
751
    if (!s->paused) {
752
        int data_used= s->show_mode == SHOW_MODE_WAVES ? s->width : (2*nb_freq);
753
        n = 2 * channels;
754
        delay = s->audio_write_buf_size;
755
        delay /= n;
756

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

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

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

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

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

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

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

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

877 878 879 880 881 882 883 884 885 886
static void stream_close(VideoState *is)
{
    VideoPicture *vp;
    int i;
    /* XXX: use a special url_shutdown call to abort parse cleanly */
    is->abort_request = 1;
    SDL_WaitThread(is->read_tid, NULL);
    SDL_WaitThread(is->refresh_tid, NULL);

    /* free all pictures */
887
    for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910
        vp = &is->pictq[i];
#if CONFIG_AVFILTER
        if (vp->picref) {
            avfilter_unref_buffer(vp->picref);
            vp->picref = NULL;
        }
#endif
        if (vp->bmp) {
            SDL_FreeYUVOverlay(vp->bmp);
            vp->bmp = NULL;
        }
    }
    SDL_DestroyMutex(is->pictq_mutex);
    SDL_DestroyCond(is->pictq_cond);
    SDL_DestroyMutex(is->subpq_mutex);
    SDL_DestroyCond(is->subpq_cond);
#if !CONFIG_AVFILTER
    if (is->img_convert_ctx)
        sws_freeContext(is->img_convert_ctx);
#endif
    av_free(is);
}

911
static void do_exit(VideoState *is)
912
{
913 914
    if (is) {
        stream_close(is);
915
    }
916
    av_lockmgr_register(NULL);
917 918 919 920
    uninit_opts();
#if CONFIG_AVFILTER
    avfilter_uninit();
#endif
921
    avformat_network_deinit();
922 923 924
    if (show_status)
        printf("\n");
    SDL_Quit();
925
    av_log(NULL, AV_LOG_QUIET, "%s", "");
926 927 928
    exit(0);
}

929 930 931 932 933
static void sigterm_handler(int sig)
{
    exit(123);
}

934
static int video_open(VideoState *is, int force_set_video_mode)
Aneesh Dogra's avatar
Aneesh Dogra committed
935 936
{
    int flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
937 938
    int w,h;

Aneesh Dogra's avatar
Aneesh Dogra committed
939 940
    if (is_full_screen) flags |= SDL_FULLSCREEN;
    else                flags |= SDL_RESIZABLE;
941

942 943 944
    if (is_full_screen && fs_screen_width) {
        w = fs_screen_width;
        h = fs_screen_height;
Aneesh Dogra's avatar
Aneesh Dogra committed
945
    } else if (!is_full_screen && screen_width) {
946 947
        w = screen_width;
        h = screen_height;
948
#if CONFIG_AVFILTER
Aneesh Dogra's avatar
Aneesh Dogra committed
949
    } else if (is->out_video_filter && is->out_video_filter->inputs[0]) {
950 951 952
        w = is->out_video_filter->inputs[0]->w;
        h = is->out_video_filter->inputs[0]->h;
#else
Aneesh Dogra's avatar
Aneesh Dogra committed
953
    } else if (is->video_st && is->video_st->codec->width) {
954 955
        w = is->video_st->codec->width;
        h = is->video_st->codec->height;
956
#endif
957
    } else {
958 959
        w = 640;
        h = 480;
960
    }
Aneesh Dogra's avatar
Aneesh Dogra committed
961
    if (screen && is->width == screen->w && screen->w == w
962
       && is->height== screen->h && screen->h == h && !force_set_video_mode)
963
        return 0;
964 965 966
    screen = SDL_SetVideoMode(w, h, 0, flags);
    if (!screen) {
        fprintf(stderr, "SDL: could not set video mode - exiting\n");
967
        do_exit(is);
968
    }
969 970 971
    if (!window_title)
        window_title = input_filename;
    SDL_WM_SetCaption(window_title, window_title);
972

Aneesh Dogra's avatar
Aneesh Dogra committed
973
    is->width  = screen->w;
974 975 976 977
    is->height = screen->h;

    return 0;
}
978

Fabrice Bellard's avatar
Fabrice Bellard committed
979 980 981
/* display the current picture, if any */
static void video_display(VideoState *is)
{
Aneesh Dogra's avatar
Aneesh Dogra committed
982
    if (!screen)
983
        video_open(is, 0);
984
    if (is->audio_st && is->show_mode != SHOW_MODE_VIDEO)
Fabrice Bellard's avatar
Fabrice Bellard committed
985 986 987 988 989
        video_audio_display(is);
    else if (is->video_st)
        video_image_display(is);
}

990
static int refresh_thread(void *opaque)
Fabrice Bellard's avatar
Fabrice Bellard committed
991
{
992
    VideoState *is= opaque;
Aneesh Dogra's avatar
Aneesh Dogra committed
993
    while (!is->abort_request) {
994 995 996
        SDL_Event event;
        event.type = FF_REFRESH_EVENT;
        event.user.data1 = opaque;
997
        if (!is->refresh && (!is->paused || is->force_refresh)) {
Aneesh Dogra's avatar
Aneesh Dogra committed
998
            is->refresh = 1;
999
            SDL_PushEvent(&event);
1000
        }
1001 1002
        //FIXME ideally we should wait the correct time but SDLs event passing is so slow it would be silly
        usleep(is->audio_st && is->show_mode != SHOW_MODE_VIDEO ? rdftspeed*1000 : 5000);
1003 1004
    }
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1005 1006
}

1007 1008 1009
/* get the current audio clock value */
static double get_audio_clock(VideoState *is)
{
1010 1011 1012 1013
    if (is->paused) {
        return is->audio_current_pts;
    } else {
        return is->audio_current_pts_drift + av_gettime() / 1000000.0;
1014 1015 1016 1017 1018 1019
    }
}

/* get the current video clock value */
static double get_video_clock(VideoState *is)
{
Michael Niedermayer's avatar
Michael Niedermayer committed
1020
    if (is->paused) {
1021
        return is->video_current_pts;
Fabrice Bellard's avatar
Fabrice Bellard committed
1022
    } else {
1023
        return is->video_current_pts_drift + av_gettime() / 1000000.0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1024
    }
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
}

/* get the current external clock value */
static double get_external_clock(VideoState *is)
{
    int64_t ti;
    ti = av_gettime();
    return is->external_clock + ((ti - is->external_clock_time) * 1e-6);
}

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

Fabrice Bellard's avatar
Fabrice Bellard committed
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050
    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 {
1051
        val = get_external_clock(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
1052
    }
1053 1054 1055
    return val;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
1056
/* seek in the stream */
1057
static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_bytes)
Fabrice Bellard's avatar
Fabrice Bellard committed
1058
{
1059 1060
    if (!is->seek_req) {
        is->seek_pos = pos;
1061
        is->seek_rel = rel;
Michael Niedermayer's avatar
Michael Niedermayer committed
1062
        is->seek_flags &= ~AVSEEK_FLAG_BYTE;
1063 1064
        if (seek_by_bytes)
            is->seek_flags |= AVSEEK_FLAG_BYTE;
1065 1066
        is->seek_req = 1;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
1067 1068 1069
}

/* pause or resume the video */
1070
static void stream_toggle_pause(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
1071
{
1072 1073
    if (is->paused) {
        is->frame_timer += av_gettime() / 1000000.0 + is->video_current_pts_drift - is->video_current_pts;
Aneesh Dogra's avatar
Aneesh Dogra committed
1074
        if (is->read_pause_return != AVERROR(ENOSYS)) {
1075
            is->video_current_pts = is->video_current_pts_drift + av_gettime() / 1000000.0;
1076
        }
1077
        is->video_current_pts_drift = is->video_current_pts - av_gettime() / 1000000.0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1078
    }
1079
    is->paused = !is->paused;
Fabrice Bellard's avatar
Fabrice Bellard committed
1080 1081
}

1082
static double compute_target_delay(double delay, VideoState *is)
1083
{
1084
    double sync_threshold, diff;
1085 1086 1087 1088 1089 1090

    /* 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 */
1091
        diff = get_video_clock(is) - get_master_clock(is);
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103

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

1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
    av_dlog(NULL, "video: delay=%0.3f A-V=%f\n",
            delay, -diff);

    return delay;
}

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

1116 1117 1118 1119
    SDL_LockMutex(is->pictq_mutex);
    is->pictq_size--;
    SDL_CondSignal(is->pictq_cond);
    SDL_UnlockMutex(is->pictq_mutex);
1120 1121
}

1122 1123 1124 1125 1126 1127 1128 1129 1130
static void update_video_pts(VideoState *is, double pts, int64_t pos) {
    double time = av_gettime() / 1000000.0;
    /* update current video pts */
    is->video_current_pts = pts;
    is->video_current_pts_drift = is->video_current_pts - time;
    is->video_current_pos = pos;
    is->frame_last_pts = pts;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
1131
/* called to display each frame */
1132
static void video_refresh(void *opaque)
Fabrice Bellard's avatar
Fabrice Bellard committed
1133 1134 1135
{
    VideoState *is = opaque;
    VideoPicture *vp;
1136
    double time;
1137

1138
    SubPicture *sp, *sp2;
Fabrice Bellard's avatar
Fabrice Bellard committed
1139 1140

    if (is->video_st) {
1141
retry:
Fabrice Bellard's avatar
Fabrice Bellard committed
1142
        if (is->pictq_size == 0) {
1143 1144 1145 1146 1147 1148
            SDL_LockMutex(is->pictq_mutex);
            if (is->frame_last_dropped_pts != AV_NOPTS_VALUE && is->frame_last_dropped_pts > is->frame_last_pts) {
                update_video_pts(is, is->frame_last_dropped_pts, is->frame_last_dropped_pos);
                is->frame_last_dropped_pts = AV_NOPTS_VALUE;
            }
            SDL_UnlockMutex(is->pictq_mutex);
Aneesh Dogra's avatar
Aneesh Dogra committed
1149
            // nothing to do, no picture to display in the que
Fabrice Bellard's avatar
Fabrice Bellard committed
1150
        } else {
1151
            double last_duration, duration, delay;
1152
            /* dequeue the picture */
Fabrice Bellard's avatar
Fabrice Bellard committed
1153
            vp = &is->pictq[is->pictq_rindex];
1154

1155 1156 1157 1158 1159
            if (vp->skip) {
                pictq_next_picture(is);
                goto retry;
            }

1160 1161 1162
            if (is->paused)
                goto display;

1163 1164 1165 1166 1167 1168 1169 1170
            /* compute nominal last_duration */
            last_duration = vp->pts - is->frame_last_pts;
            if (last_duration > 0 && last_duration < 10.0) {
                /* if duration of the last frame was sane, update last_duration in video state */
                is->frame_last_duration = last_duration;
            }
            delay = compute_target_delay(is->frame_last_duration, is);

1171
            time= av_gettime()/1000000.0;
1172
            if (time < is->frame_timer + delay)
1173
                return;
1174

1175 1176
            if (delay > 0)
                is->frame_timer += delay * FFMAX(1, floor((time-is->frame_timer) / delay));
1177

1178 1179 1180
            SDL_LockMutex(is->pictq_mutex);
            update_video_pts(is, vp->pts, vp->pos);
            SDL_UnlockMutex(is->pictq_mutex);
1181

Aneesh Dogra's avatar
Aneesh Dogra committed
1182 1183
            if (is->pictq_size > 1) {
                VideoPicture *nextvp = &is->pictq[(is->pictq_rindex + 1) % VIDEO_PICTURE_QUEUE_SIZE];
1184
                duration = nextvp->pts - vp->pts; // More accurate this way, 1/time_base is often not reflecting FPS
1185
            } else {
1186
                duration = vp->duration;
1187
            }
1188 1189

            if((framedrop>0 || (framedrop && is->audio_st)) && time > is->frame_timer + duration){
1190
                if(is->pictq_size > 1){
1191
                    is->frame_drops_late++;
1192
                    pictq_next_picture(is);
1193 1194 1195
                    goto retry;
                }
            }
1196

Aneesh Dogra's avatar
Aneesh Dogra committed
1197
            if (is->subtitle_st) {
1198 1199
                if (is->subtitle_stream_changed) {
                    SDL_LockMutex(is->subpq_mutex);
1200

1201 1202
                    while (is->subpq_size) {
                        free_subpicture(&is->subpq[is->subpq_rindex]);
1203

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

1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240
                        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);
                        }
                    }
                }
            }

1241
display:
Fabrice Bellard's avatar
Fabrice Bellard committed
1242
            /* display picture */
1243
            if (!display_disable)
1244
                video_display(is);
1245

1246 1247
            if (!is->paused)
                pictq_next_picture(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
1248 1249 1250 1251 1252 1253
        }
    } 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 */
1254

Fabrice Bellard's avatar
Fabrice Bellard committed
1255
        /* display picture */
1256
        if (!display_disable)
1257
            video_display(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
1258
    }
1259
    is->force_refresh = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1260 1261 1262
    if (show_status) {
        static int64_t last_time;
        int64_t cur_time;
1263
        int aqsize, vqsize, sqsize;
1264
        double av_diff;
1265

Fabrice Bellard's avatar
Fabrice Bellard committed
1266
        cur_time = av_gettime();
1267
        if (!last_time || (cur_time - last_time) >= 30000) {
Fabrice Bellard's avatar
Fabrice Bellard committed
1268 1269
            aqsize = 0;
            vqsize = 0;
1270
            sqsize = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1271 1272 1273 1274
            if (is->audio_st)
                aqsize = is->audioq.size;
            if (is->video_st)
                vqsize = is->videoq.size;
1275 1276
            if (is->subtitle_st)
                sqsize = is->subtitleq.size;
1277 1278 1279
            av_diff = 0;
            if (is->audio_st && is->video_st)
                av_diff = get_audio_clock(is) - get_video_clock(is);
1280
            printf("%7.2f A-V:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64"   \r",
1281 1282
                   get_master_clock(is),
                   av_diff,
1283
                   is->frame_drops_early + is->frame_drops_late,
1284 1285 1286 1287 1288
                   aqsize / 1024,
                   vqsize / 1024,
                   sqsize,
                   is->video_st ? is->video_st->codec->pts_correction_num_faulty_dts : 0,
                   is->video_st ? is->video_st->codec->pts_correction_num_faulty_pts : 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306
            fflush(stdout);
            last_time = cur_time;
        }
    }
}

/* 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);

1307 1308
#if CONFIG_AVFILTER
    if (vp->picref)
1309
        avfilter_unref_buffer(vp->picref);
1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321
    vp->picref = NULL;

    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,
1322
                                   SDL_YV12_OVERLAY,
1323
                                   screen);
1324 1325 1326 1327
    if (!vp->bmp || vp->bmp->pitches[0] < vp->width) {
        /* SDL allocates a buffer smaller than requested if the video
         * overlay hardware is unable to support the requested size. */
        fprintf(stderr, "Error: the video system does not support an image\n"
Michael Niedermayer's avatar
Michael Niedermayer committed
1328
                        "size of %dx%d pixels. Try using -lowres or -vf \"scale=w:h\"\n"
1329
                        "to reduce the image size.\n", vp->width, vp->height );
1330
        do_exit(is);
1331
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
1332 1333 1334 1335 1336 1337 1338

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

1339
static int queue_picture(VideoState *is, AVFrame *src_frame, double pts1, int64_t pos)
Fabrice Bellard's avatar
Fabrice Bellard committed
1340 1341
{
    VideoPicture *vp;
1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360
    double frame_delay, pts = pts1;

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

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

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

Fabrice Bellard's avatar
Fabrice Bellard committed
1367 1368 1369 1370 1371
    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);
1372

Fabrice Bellard's avatar
Fabrice Bellard committed
1373 1374 1375 1376 1377
    if (is->videoq.abort_request)
        return -1;

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

1378 1379
    vp->duration = frame_delay;

Fabrice Bellard's avatar
Fabrice Bellard committed
1380
    /* alloc or resize hardware picture buffer */
1381
    if (!vp->bmp || vp->reallocate ||
1382 1383 1384 1385
#if CONFIG_AVFILTER
        vp->width  != is->out_video_filter->inputs[0]->w ||
        vp->height != is->out_video_filter->inputs[0]->h) {
#else
1386 1387
        vp->width != is->video_st->codec->width ||
        vp->height != is->video_st->codec->height) {
1388
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
1389 1390
        SDL_Event event;

1391
        vp->allocated  = 0;
1392
        vp->reallocate = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1393 1394 1395 1396 1397 1398

        /* 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);
1399

Fabrice Bellard's avatar
Fabrice Bellard committed
1400 1401 1402 1403 1404
        /* 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);
        }
1405 1406 1407 1408 1409 1410
        /* if the queue is aborted, we have to pop the pending ALLOC event or wait for the allocation to complete */
        if (is->videoq.abort_request && SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_EVENTMASK(FF_ALLOC_EVENT)) != 1) {
            while (!vp->allocated) {
                SDL_CondWait(is->pictq_cond, is->pictq_mutex);
            }
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
1411 1412 1413 1414 1415 1416
        SDL_UnlockMutex(is->pictq_mutex);

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

1417
    /* if the frame is not skipped, then display it */
Fabrice Bellard's avatar
Fabrice Bellard committed
1418
    if (vp->bmp) {
1419
        AVPicture pict = { { 0 } };
1420
#if CONFIG_AVFILTER
Aneesh Dogra's avatar
Aneesh Dogra committed
1421
        if (vp->picref)
1422
            avfilter_unref_buffer(vp->picref);
1423 1424
        vp->picref = src_frame->opaque;
#endif
1425

Fabrice Bellard's avatar
Fabrice Bellard committed
1426 1427 1428 1429 1430 1431 1432 1433 1434 1435
        /* 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];
1436 1437

#if CONFIG_AVFILTER
Aneesh Dogra's avatar
Aneesh Dogra committed
1438
        // FIXME use direct rendering
1439
        av_picture_copy(&pict, (AVPicture *)src_frame,
1440 1441
                        vp->pix_fmt, vp->width, vp->height);
#else
1442
        sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
1443
        is->img_convert_ctx = sws_getCachedContext(is->img_convert_ctx,
1444
            vp->width, vp->height, vp->pix_fmt, vp->width, vp->height,
1445
            PIX_FMT_YUV420P, sws_flags, NULL, NULL, NULL);
1446
        if (is->img_convert_ctx == NULL) {
1447 1448 1449
            fprintf(stderr, "Cannot initialize the conversion context\n");
            exit(1);
        }
1450
        sws_scale(is->img_convert_ctx, src_frame->data, src_frame->linesize,
1451 1452
                  0, vp->height, pict.data, pict.linesize);
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
1453 1454 1455
        /* update the bitmap content */
        SDL_UnlockYUVOverlay(vp->bmp);

1456
        vp->pts = pts;
1457
        vp->pos = pos;
1458
        vp->skip = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1459 1460 1461 1462 1463 1464 1465 1466

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

1470
static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacket *pkt)
Fabrice Bellard's avatar
Fabrice Bellard committed
1471
{
1472
    int got_picture, i;
Fabrice Bellard's avatar
Fabrice Bellard committed
1473

1474 1475
    if (packet_queue_get(&is->videoq, pkt, 1) < 0)
        return -1;
1476

1477 1478
    if (pkt->data == flush_pkt.data) {
        avcodec_flush_buffers(is->video_st->codec);
1479

1480
        SDL_LockMutex(is->pictq_mutex);
Aneesh Dogra's avatar
Aneesh Dogra committed
1481
        // Make sure there are no long delay timers (ideally we should just flush the que but thats harder)
1482
        for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
1483
            is->pictq[i].skip = 1;
1484 1485 1486
        }
        while (is->pictq_size && !is->videoq.abort_request) {
            SDL_CondWait(is->pictq_cond, is->pictq_mutex);
1487
        }
1488 1489
        is->video_current_pos = -1;
        is->frame_last_pts = AV_NOPTS_VALUE;
1490
        is->frame_last_duration = 0;
1491
        is->frame_timer = (double)av_gettime() / 1000000.0;
1492 1493 1494
        is->frame_last_dropped_pts = AV_NOPTS_VALUE;
        SDL_UnlockMutex(is->pictq_mutex);

1495 1496
        return 0;
    }
1497

1498
    avcodec_decode_video2(is->video_st->codec, frame, &got_picture, pkt);
1499 1500

    if (got_picture) {
1501 1502
        int ret = 1;

1503
        if (decoder_reorder_pts == -1) {
1504
            *pts = *(int64_t*)av_opt_ptr(avcodec_get_frame_class(), frame, "best_effort_timestamp");
1505
        } else if (decoder_reorder_pts) {
1506
            *pts = frame->pkt_pts;
1507
        } else {
1508
            *pts = frame->pkt_dts;
1509 1510 1511 1512
        }

        if (*pts == AV_NOPTS_VALUE) {
            *pts = 0;
1513
        }
1514

1515 1516 1517 1518 1519 1520 1521 1522 1523
        if (((is->av_sync_type == AV_SYNC_AUDIO_MASTER && is->audio_st) || is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK) &&
             (framedrop>0 || (framedrop && is->audio_st))) {
            SDL_LockMutex(is->pictq_mutex);
            if (is->frame_last_pts != AV_NOPTS_VALUE && *pts) {
                double clockdiff = get_video_clock(is) - get_master_clock(is);
                double dpts = av_q2d(is->video_st->time_base) * *pts;
                double ptsdiff = dpts - is->frame_last_pts;
                if (fabs(clockdiff) < AV_NOSYNC_THRESHOLD &&
                     ptsdiff > 0 && ptsdiff < AV_NOSYNC_THRESHOLD &&
1524
                     clockdiff + ptsdiff - is->frame_last_filter_delay < 0) {
1525 1526
                    is->frame_last_dropped_pos = pkt->pos;
                    is->frame_last_dropped_pts = dpts;
1527
                    is->frame_drops_early++;
1528 1529 1530 1531 1532
                    ret = 0;
                }
            }
            SDL_UnlockMutex(is->pictq_mutex);
        }
1533

1534 1535 1536
        if (ret)
            is->frame_last_returned_time = av_gettime() / 1000000.0;

1537
        return ret;
1538
    }
1539 1540 1541 1542 1543 1544 1545
    return 0;
}

#if CONFIG_AVFILTER
typedef struct {
    VideoState *is;
    AVFrame *frame;
1546
    int use_dr1;
1547 1548
} FilterPriv;

1549 1550 1551
static int input_get_buffer(AVCodecContext *codec, AVFrame *pic)
{
    AVFilterContext *ctx = codec->opaque;
1552
    AVFilterBufferRef  *ref;
1553
    int perms = AV_PERM_WRITE;
1554
    int i, w, h, stride[AV_NUM_DATA_POINTERS];
1555
    unsigned edge;
1556
    int pixel_size;
1557

1558 1559
    av_assert0(codec->flags & CODEC_FLAG_EMU_EDGE);

1560 1561 1562
    if (codec->codec->capabilities & CODEC_CAP_NEG_LINESIZES)
        perms |= AV_PERM_NEG_LINESIZES;

Aneesh Dogra's avatar
Aneesh Dogra committed
1563 1564 1565 1566
    if (pic->buffer_hints & FF_BUFFER_HINTS_VALID) {
        if (pic->buffer_hints & FF_BUFFER_HINTS_READABLE) perms |= AV_PERM_READ;
        if (pic->buffer_hints & FF_BUFFER_HINTS_PRESERVE) perms |= AV_PERM_PRESERVE;
        if (pic->buffer_hints & FF_BUFFER_HINTS_REUSABLE) perms |= AV_PERM_REUSE2;
1567
    }
Aneesh Dogra's avatar
Aneesh Dogra committed
1568
    if (pic->reference) perms |= AV_PERM_READ | AV_PERM_PRESERVE;
1569 1570 1571

    w = codec->width;
    h = codec->height;
1572

1573
    if(av_image_check_size(w, h, 0, codec) || codec->pix_fmt<0)
1574 1575
        return -1;

1576 1577 1578 1579
    avcodec_align_dimensions2(codec, &w, &h, stride);
    edge = codec->flags & CODEC_FLAG_EMU_EDGE ? 0 : avcodec_get_edge_width();
    w += edge << 1;
    h += edge << 1;
1580 1581 1582 1583
    if (codec->pix_fmt != ctx->outputs[0]->format) {
        av_log(codec, AV_LOG_ERROR, "Pixel format mismatches %d %d\n", codec->pix_fmt, ctx->outputs[0]->format);
        return -1;
    }
Aneesh Dogra's avatar
Aneesh Dogra committed
1584
    if (!(ref = avfilter_get_video_buffer(ctx->outputs[0], perms, w, h)))
1585 1586
        return -1;

Aneesh Dogra's avatar
Aneesh Dogra committed
1587
    pixel_size = av_pix_fmt_descriptors[ref->format].comp[0].step_minus1 + 1;
1588 1589
    ref->video->w = codec->width;
    ref->video->h = codec->height;
Aneesh Dogra's avatar
Aneesh Dogra committed
1590
    for (i = 0; i < 4; i ++) {
1591 1592
        unsigned hshift = (i == 1 || i == 2) ? av_pix_fmt_descriptors[ref->format].log2_chroma_w : 0;
        unsigned vshift = (i == 1 || i == 2) ? av_pix_fmt_descriptors[ref->format].log2_chroma_h : 0;
1593

1594
        if (ref->data[i]) {
1595
            ref->data[i]    += ((edge * pixel_size) >> hshift) + ((edge * ref->linesize[i]) >> vshift);
1596
        }
1597 1598 1599 1600 1601
        pic->data[i]     = ref->data[i];
        pic->linesize[i] = ref->linesize[i];
    }
    pic->opaque = ref;
    pic->type   = FF_BUFFER_TYPE_USER;
1602
    pic->reordered_opaque = codec->reordered_opaque;
1603 1604 1605 1606
    pic->width               = codec->width;
    pic->height              = codec->height;
    pic->format              = codec->pix_fmt;
    pic->sample_aspect_ratio = codec->sample_aspect_ratio;
Aneesh Dogra's avatar
Aneesh Dogra committed
1607 1608
    if (codec->pkt) pic->pkt_pts = codec->pkt->pts;
    else            pic->pkt_pts = AV_NOPTS_VALUE;
1609 1610 1611 1612 1613 1614
    return 0;
}

static void input_release_buffer(AVCodecContext *codec, AVFrame *pic)
{
    memset(pic->data, 0, sizeof(pic->data));
1615
    avfilter_unref_buffer(pic->opaque);
1616 1617
}

1618 1619
static int input_reget_buffer(AVCodecContext *codec, AVFrame *pic)
{
1620
    AVFilterBufferRef *ref = pic->opaque;
1621 1622 1623 1624 1625 1626

    if (pic->data[0] == NULL) {
        pic->buffer_hints |= FF_BUFFER_HINTS_READABLE;
        return codec->get_buffer(codec, pic);
    }

1627
    if ((codec->width != ref->video->w) || (codec->height != ref->video->h) ||
1628
        (codec->pix_fmt != ref->format)) {
1629 1630 1631 1632 1633
        av_log(codec, AV_LOG_ERROR, "Picture properties changed.\n");
        return -1;
    }

    pic->reordered_opaque = codec->reordered_opaque;
Aneesh Dogra's avatar
Aneesh Dogra committed
1634 1635
    if (codec->pkt) pic->pkt_pts = codec->pkt->pts;
    else            pic->pkt_pts = AV_NOPTS_VALUE;
1636 1637 1638
    return 0;
}

1639 1640 1641
static int input_init(AVFilterContext *ctx, const char *args, void *opaque)
{
    FilterPriv *priv = ctx->priv;
1642
    AVCodecContext *codec;
Aneesh Dogra's avatar
Aneesh Dogra committed
1643
    if (!opaque) return -1;
1644 1645

    priv->is = opaque;
1646 1647
    codec    = priv->is->video_st->codec;
    codec->opaque = ctx;
Aneesh Dogra's avatar
Aneesh Dogra committed
1648
    if (codec->codec->capabilities & CODEC_CAP_DR1) {
1649
        av_assert0(codec->flags & CODEC_FLAG_EMU_EDGE);
1650 1651 1652
        priv->use_dr1 = 1;
        codec->get_buffer     = input_get_buffer;
        codec->release_buffer = input_release_buffer;
1653
        codec->reget_buffer   = input_reget_buffer;
1654
        codec->thread_safe_callbacks = 1;
1655 1656
    }

1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670
    priv->frame = avcodec_alloc_frame();

    return 0;
}

static void input_uninit(AVFilterContext *ctx)
{
    FilterPriv *priv = ctx->priv;
    av_free(priv->frame);
}

static int input_request_frame(AVFilterLink *link)
{
    FilterPriv *priv = link->src->priv;
1671
    AVFilterBufferRef *picref;
1672
    int64_t pts = 0;
1673 1674 1675 1676 1677 1678 1679 1680
    AVPacket pkt;
    int ret;

    while (!(ret = get_video_frame(priv->is, priv->frame, &pts, &pkt)))
        av_free_packet(&pkt);
    if (ret < 0)
        return -1;

1681
    if (priv->use_dr1 && priv->frame->opaque) {
1682
        picref = avfilter_ref_buffer(priv->frame->opaque, ~0);
1683
    } else {
Bobby Bingham's avatar
Bobby Bingham committed
1684
        picref = avfilter_get_video_buffer(link, AV_PERM_WRITE, link->w, link->h);
1685
        av_image_copy(picref->data, picref->linesize,
1686
                      (const uint8_t **)(void **)priv->frame->data, priv->frame->linesize,
Stefano Sabatini's avatar
Stefano Sabatini committed
1687
                      picref->format, link->w, link->h);
1688
    }
1689 1690
    av_free_packet(&pkt);

1691
    avfilter_copy_frame_props(picref, priv->frame);
1692
    picref->pts = pts;
1693

1694
    avfilter_start_frame(link, picref);
1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707
    avfilter_draw_slice(link, 0, link->h, 1);
    avfilter_end_frame(link);

    return 0;
}

static int input_query_formats(AVFilterContext *ctx)
{
    FilterPriv *priv = ctx->priv;
    enum PixelFormat pix_fmts[] = {
        priv->is->video_st->codec->pix_fmt, PIX_FMT_NONE
    };

1708
    avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
1709 1710 1711 1712 1713 1714
    return 0;
}

static int input_config_props(AVFilterLink *link)
{
    FilterPriv *priv  = link->src->priv;
1715
    AVStream *s = priv->is->video_st;
1716

1717 1718
    link->w = s->codec->width;
    link->h = s->codec->height;
1719
    link->sample_aspect_ratio = s->sample_aspect_ratio.num ?
1720 1721
        s->sample_aspect_ratio : s->codec->sample_aspect_ratio;
    link->time_base = s->time_base;
1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738

    return 0;
}

static AVFilter input_filter =
{
    .name      = "ffplay_input",

    .priv_size = sizeof(FilterPriv),

    .init      = input_init,
    .uninit    = input_uninit,

    .query_formats = input_query_formats,

    .inputs    = (AVFilterPad[]) {{ .name = NULL }},
    .outputs   = (AVFilterPad[]) {{ .name = "default",
1739
                                    .type = AVMEDIA_TYPE_VIDEO,
1740 1741 1742 1743 1744
                                    .request_frame = input_request_frame,
                                    .config_props  = input_config_props, },
                                  { .name = NULL }},
};

1745
static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters)
1746
{
1747
    static const enum PixelFormat pix_fmts[] = { PIX_FMT_YUV420P, PIX_FMT_NONE };
Stefano Sabatini's avatar
Stefano Sabatini committed
1748
    char sws_flags_str[128];
1749
    int ret;
1750
    AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc();
1751
    AVFilterContext *filt_src = NULL, *filt_out = NULL;
Stefano Sabatini's avatar
Stefano Sabatini committed
1752 1753
    snprintf(sws_flags_str, sizeof(sws_flags_str), "flags=%d", sws_flags);
    graph->scale_sws_opts = av_strdup(sws_flags_str);
1754

1755 1756
    if ((ret = avfilter_graph_create_filter(&filt_src, &input_filter, "src",
                                            NULL, is, graph)) < 0)
1757
        return ret;
1758

1759 1760 1761 1762 1763 1764 1765 1766 1767 1768
#if FF_API_OLD_VSINK_API
    ret = avfilter_graph_create_filter(&filt_out, avfilter_get_by_name("buffersink"), "out",
                                       NULL, pix_fmts, graph);
#else
    buffersink_params->pixel_fmts = pix_fmts;
    ret = avfilter_graph_create_filter(&filt_out, avfilter_get_by_name("buffersink"), "out",
                                       NULL, buffersink_params, graph);
#endif
    av_freep(&buffersink_params);
    if (ret < 0)
1769
        return ret;
1770

Aneesh Dogra's avatar
Aneesh Dogra committed
1771
    if (vfilters) {
1772 1773
        AVFilterInOut *outputs = avfilter_inout_alloc();
        AVFilterInOut *inputs  = avfilter_inout_alloc();
1774 1775

        outputs->name    = av_strdup("in");
1776
        outputs->filter_ctx = filt_src;
1777 1778 1779 1780
        outputs->pad_idx = 0;
        outputs->next    = NULL;

        inputs->name    = av_strdup("out");
1781
        inputs->filter_ctx = filt_out;
1782 1783 1784
        inputs->pad_idx = 0;
        inputs->next    = NULL;

1785
        if ((ret = avfilter_graph_parse(graph, vfilters, &inputs, &outputs, NULL)) < 0)
1786
            return ret;
1787
    } else {
1788
        if ((ret = avfilter_link(filt_src, 0, filt_out, 0)) < 0)
1789
            return ret;
1790 1791
    }

1792
    if ((ret = avfilter_graph_config(graph, NULL)) < 0)
1793
        return ret;
1794 1795

    is->out_video_filter = filt_out;
1796

1797 1798 1799 1800 1801 1802 1803 1804
    return ret;
}

#endif  /* CONFIG_AVFILTER */

static int video_thread(void *arg)
{
    VideoState *is = arg;
Aneesh Dogra's avatar
Aneesh Dogra committed
1805
    AVFrame *frame = avcodec_alloc_frame();
1806
    int64_t pts_int = AV_NOPTS_VALUE, pos = -1;
1807 1808 1809 1810 1811 1812
    double pts;
    int ret;

#if CONFIG_AVFILTER
    AVFilterGraph *graph = avfilter_graph_alloc();
    AVFilterContext *filt_out = NULL;
1813 1814
    int last_w = is->video_st->codec->width;
    int last_h = is->video_st->codec->height;
1815 1816 1817 1818

    if ((ret = configure_video_filters(graph, is, vfilters)) < 0)
        goto the_end;
    filt_out = is->out_video_filter;
1819 1820
#endif

Aneesh Dogra's avatar
Aneesh Dogra committed
1821
    for (;;) {
1822 1823
#if !CONFIG_AVFILTER
        AVPacket pkt;
1824
#else
1825
        AVFilterBufferRef *picref;
1826
        AVRational tb = filt_out->inputs[0]->time_base;
1827 1828 1829 1830
#endif
        while (is->paused && !is->videoq.abort_request)
            SDL_Delay(10);
#if CONFIG_AVFILTER
1831 1832
        if (   last_w != is->video_st->codec->width
            || last_h != is->video_st->codec->height) {
1833 1834
            av_log(NULL, AV_LOG_INFO, "Frame changed from size:%dx%d to size:%dx%d\n",
                   last_w, last_h, is->video_st->codec->width, is->video_st->codec->height);
1835 1836 1837 1838 1839 1840 1841 1842
            avfilter_graph_free(&graph);
            graph = avfilter_graph_alloc();
            if ((ret = configure_video_filters(graph, is, vfilters)) < 0)
                goto the_end;
            filt_out = is->out_video_filter;
            last_w = is->video_st->codec->width;
            last_h = is->video_st->codec->height;
        }
1843
        ret = av_buffersink_get_buffer_ref(filt_out, &picref, 0);
1844
        if (picref) {
1845
            avfilter_fill_frame_from_video_buffer_ref(frame, picref);
1846 1847 1848 1849
            pts_int = picref->pts;
            pos     = picref->pos;
            frame->opaque = picref;
        }
1850

1851
        if (ret >= 0 && av_cmp_q(tb, is->video_st->time_base)) {
1852
            av_unused int64_t pts1 = pts_int;
1853
            pts_int = av_rescale_q(pts_int, tb, is->video_st->time_base);
1854 1855 1856 1857
            av_dlog(NULL, "video_thread(): "
                    "tb:%d/%d pts:%"PRId64" -> tb:%d/%d pts:%"PRId64"\n",
                    tb.num, tb.den, pts1,
                    is->video_st->time_base.num, is->video_st->time_base.den, pts_int);
1858
        }
1859 1860
#else
        ret = get_video_frame(is, frame, &pts_int, &pkt);
1861
        pos = pkt.pos;
1862
        av_free_packet(&pkt);
1863 1864
#endif

Aneesh Dogra's avatar
Aneesh Dogra committed
1865 1866
        if (ret < 0)
            goto the_end;
1867

1868 1869 1870 1871
        is->frame_last_filter_delay = av_gettime() / 1000000.0 - is->frame_last_returned_time;
        if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0)
            is->frame_last_filter_delay = 0;

1872
#if CONFIG_AVFILTER
1873
        if (!picref)
1874
            continue;
1875
#endif
1876

Aneesh Dogra's avatar
Aneesh Dogra committed
1877
        pts = pts_int * av_q2d(is->video_st->time_base);
1878

1879
        ret = queue_picture(is, frame, pts, pos);
1880

1881 1882 1883
        if (ret < 0)
            goto the_end;

1884 1885
        if (is->step)
            stream_toggle_pause(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
1886 1887
    }
 the_end:
1888
#if CONFIG_AVFILTER
1889
    av_freep(&vfilters);
1890
    avfilter_graph_free(&graph);
1891
#endif
1892
    av_free(frame);
Fabrice Bellard's avatar
Fabrice Bellard committed
1893 1894 1895
    return 0;
}

1896 1897 1898 1899 1900
static int subtitle_thread(void *arg)
{
    VideoState *is = arg;
    SubPicture *sp;
    AVPacket pkt1, *pkt = &pkt1;
1901
    int got_subtitle;
1902 1903 1904 1905
    double pts;
    int i, j;
    int r, g, b, y, u, v, a;

Aneesh Dogra's avatar
Aneesh Dogra committed
1906
    for (;;) {
1907 1908 1909 1910 1911
        while (is->paused && !is->subtitleq.abort_request) {
            SDL_Delay(10);
        }
        if (packet_queue_get(&is->subtitleq, pkt, 1) < 0)
            break;
1912

Aneesh Dogra's avatar
Aneesh Dogra committed
1913
        if (pkt->data == flush_pkt.data) {
1914 1915 1916
            avcodec_flush_buffers(is->subtitle_st->codec);
            continue;
        }
1917 1918 1919 1920 1921 1922
        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);
1923

1924
        if (is->subtitleq.abort_request)
1925
            return 0;
1926

1927 1928 1929 1930 1931 1932
        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
1933
            pts = av_q2d(is->subtitle_st->time_base) * pkt->pts;
1934

1935 1936 1937
        avcodec_decode_subtitle2(is->subtitle_st->codec, &sp->sub,
                                 &got_subtitle, pkt);

1938 1939
        if (got_subtitle && sp->sub.format == 0) {
            sp->pts = pts;
1940

1941 1942
            for (i = 0; i < sp->sub.num_rects; i++)
            {
1943
                for (j = 0; j < sp->sub.rects[i]->nb_colors; j++)
1944
                {
1945
                    RGBA_IN(r, g, b, a, (uint32_t*)sp->sub.rects[i]->pict.data[1] + j);
1946 1947 1948
                    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);
1949
                    YUVA_OUT((uint32_t*)sp->sub.rects[i]->pict.data[1] + j, y, u, v, a);
1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964
                }
            }

            /* 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
1965 1966 1967
/* copy samples for viewing in editor window */
static void update_sample_display(VideoState *is, short *samples, int samples_size)
{
1968
    int size, len;
Fabrice Bellard's avatar
Fabrice Bellard committed
1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983

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

1984 1985 1986
/* return the wanted number of samples to get better sync if sync_type is video
 * or external master clock */
static int synchronize_audio(VideoState *is, int nb_samples)
Fabrice Bellard's avatar
Fabrice Bellard committed
1987
{
1988
    int wanted_nb_samples = nb_samples;
Fabrice Bellard's avatar
Fabrice Bellard committed
1989 1990 1991

    /* 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) ||
1992 1993
         is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {
        double diff, avg_diff;
1994
        int min_nb_samples, max_nb_samples;
1995

1996
        diff = get_audio_clock(is) - get_master_clock(is);
1997

1998 1999 2000 2001 2002 2003 2004 2005 2006 2007
        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) {
2008 2009 2010 2011
                    wanted_nb_samples = nb_samples + (int)(diff * is->audio_src_freq);
                    min_nb_samples = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100));
                    max_nb_samples = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100));
                    wanted_nb_samples = FFMIN(FFMAX(wanted_nb_samples, min_nb_samples), max_nb_samples);
2012
                }
2013
                av_dlog(NULL, "diff=%f adiff=%f sample_diff=%d apts=%0.3f vpts=%0.3f %f\n",
2014
                        diff, avg_diff, wanted_nb_samples - nb_samples,
2015
                        is->audio_clock, is->video_clock, is->audio_diff_threshold);
Fabrice Bellard's avatar
Fabrice Bellard committed
2016
            }
2017 2018 2019 2020
        } 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
2021
            is->audio_diff_cum       = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2022 2023 2024
        }
    }

2025
    return wanted_nb_samples;
Fabrice Bellard's avatar
Fabrice Bellard committed
2026 2027 2028
}

/* decode one audio frame and returns its uncompressed size */
2029
static int audio_decode_frame(VideoState *is, double *pts_ptr)
Fabrice Bellard's avatar
Fabrice Bellard committed
2030
{
2031
    AVPacket *pkt_temp = &is->audio_pkt_temp;
Fabrice Bellard's avatar
Fabrice Bellard committed
2032
    AVPacket *pkt = &is->audio_pkt;
Aneesh Dogra's avatar
Aneesh Dogra committed
2033
    AVCodecContext *dec = is->audio_st->codec;
2034
    int len1, len2, data_size, resampled_data_size;
2035 2036
    int64_t dec_channel_layout;
    int got_frame;
Fabrice Bellard's avatar
Fabrice Bellard committed
2037
    double pts;
2038 2039
    int new_packet = 0;
    int flush_complete = 0;
2040
    int wanted_nb_samples;
Fabrice Bellard's avatar
Fabrice Bellard committed
2041

Aneesh Dogra's avatar
Aneesh Dogra committed
2042
    for (;;) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2043
        /* NOTE: the audio packet can contain several frames */
2044
        while (pkt_temp->size > 0 || (!pkt_temp->data && new_packet)) {
2045 2046 2047 2048 2049 2050
            if (!is->frame) {
                if (!(is->frame = avcodec_alloc_frame()))
                    return AVERROR(ENOMEM);
            } else
                avcodec_get_frame_defaults(is->frame);

2051 2052 2053
            if (flush_complete)
                break;
            new_packet = 0;
2054
            len1 = avcodec_decode_audio4(dec, is->frame, &got_frame, pkt_temp);
Fabrice Bellard's avatar
Fabrice Bellard committed
2055 2056
            if (len1 < 0) {
                /* if error, we skip the frame */
2057
                pkt_temp->size = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2058
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2059
            }
2060

2061 2062
            pkt_temp->data += len1;
            pkt_temp->size -= len1;
2063

2064
            if (!got_frame) {
2065 2066 2067
                /* stop sending empty packets if the decoder is finished */
                if (!pkt_temp->data && dec->codec->capabilities & CODEC_CAP_DELAY)
                    flush_complete = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2068
                continue;
2069
            }
2070 2071 2072
            data_size = av_samples_get_buffer_size(NULL, dec->channels,
                                                   is->frame->nb_samples,
                                                   dec->sample_fmt, 1);
2073

2074
            dec_channel_layout = (dec->channel_layout && dec->channels == av_get_channel_layout_nb_channels(dec->channel_layout)) ? dec->channel_layout : av_get_default_channel_layout(dec->channels);
2075
            wanted_nb_samples = synchronize_audio(is, is->frame->nb_samples);
2076

2077 2078 2079 2080
            if (dec->sample_fmt != is->audio_src_fmt ||
                dec_channel_layout != is->audio_src_channel_layout ||
                dec->sample_rate != is->audio_src_freq ||
                (wanted_nb_samples != is->frame->nb_samples && !is->swr_ctx)) {
2081 2082
                if (is->swr_ctx)
                    swr_free(&is->swr_ctx);
2083 2084 2085
                is->swr_ctx = swr_alloc_set_opts(NULL,
                                                 is->audio_tgt_channel_layout, is->audio_tgt_fmt, is->audio_tgt_freq,
                                                 dec_channel_layout,           dec->sample_fmt,   dec->sample_rate,
2086
                                                 0, NULL);
2087 2088 2089
                if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) {
                    fprintf(stderr, "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",
                        dec->sample_rate,
2090
                        av_get_sample_fmt_name(dec->sample_fmt),
2091 2092 2093 2094 2095
                        dec->channels,
                        is->audio_tgt_freq,
                        av_get_sample_fmt_name(is->audio_tgt_fmt),
                        is->audio_tgt_channels);
                    break;
2096
                }
2097 2098 2099 2100
                is->audio_src_channel_layout = dec_channel_layout;
                is->audio_src_channels = dec->channels;
                is->audio_src_freq = dec->sample_rate;
                is->audio_src_fmt = dec->sample_fmt;
2101 2102
            }

2103 2104
            resampled_data_size = data_size;
            if (is->swr_ctx) {
2105
                const uint8_t *in[] = { is->frame->data[0] };
2106
                uint8_t *out[] = {is->audio_buf2};
2107 2108 2109 2110 2111 2112 2113
                if (wanted_nb_samples != is->frame->nb_samples) {
                    if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - is->frame->nb_samples) * is->audio_tgt_freq / dec->sample_rate,
                                                wanted_nb_samples * is->audio_tgt_freq / dec->sample_rate) < 0) {
                        fprintf(stderr, "swr_set_compensation() failed\n");
                        break;
                    }
                }
2114
                len2 = swr_convert(is->swr_ctx, out, sizeof(is->audio_buf2) / is->audio_tgt_channels / av_get_bytes_per_sample(is->audio_tgt_fmt),
2115
                                                in, is->frame->nb_samples);
2116 2117
                if (len2 < 0) {
                    fprintf(stderr, "audio_resample() failed\n");
2118 2119
                    break;
                }
2120 2121 2122 2123 2124 2125 2126
                if (len2 == sizeof(is->audio_buf2) / is->audio_tgt_channels / av_get_bytes_per_sample(is->audio_tgt_fmt)) {
                    fprintf(stderr, "warning: audio buffer is probably too small\n");
                    swr_init(is->swr_ctx);
                }
                is->audio_buf = is->audio_buf2;
                resampled_data_size = len2 * is->audio_tgt_channels * av_get_bytes_per_sample(is->audio_tgt_fmt);
            } else {
2127
                is->audio_buf = is->frame->data[0];
2128 2129
            }

Fabrice Bellard's avatar
Fabrice Bellard committed
2130 2131 2132
            /* if no pts, then compute it */
            pts = is->audio_clock;
            *pts_ptr = pts;
2133
            is->audio_clock += (double)data_size / (dec->channels * dec->sample_rate * av_get_bytes_per_sample(dec->sample_fmt));
2134
#ifdef DEBUG
Fabrice Bellard's avatar
Fabrice Bellard committed
2135 2136 2137 2138 2139 2140
            {
                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
2141
            }
Fabrice Bellard's avatar
Fabrice Bellard committed
2142
#endif
2143
            return resampled_data_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
2144 2145
        }

Fabrice Bellard's avatar
Fabrice Bellard committed
2146 2147
        /* free the current packet */
        if (pkt->data)
Fabrice Bellard's avatar
Fabrice Bellard committed
2148
            av_free_packet(pkt);
2149
        memset(pkt_temp, 0, sizeof(*pkt_temp));
2150

Fabrice Bellard's avatar
Fabrice Bellard committed
2151 2152 2153
        if (is->paused || is->audioq.abort_request) {
            return -1;
        }
2154

Fabrice Bellard's avatar
Fabrice Bellard committed
2155
        /* read next packet */
2156
        if ((new_packet = packet_queue_get(&is->audioq, pkt, 1)) < 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
2157
            return -1;
2158

2159
        if (pkt->data == flush_pkt.data) {
2160
            avcodec_flush_buffers(dec);
2161 2162
            flush_complete = 0;
        }
2163

2164
        *pkt_temp = *pkt;
2165

Fabrice Bellard's avatar
Fabrice Bellard committed
2166 2167
        /* if update the audio clock with the pts */
        if (pkt->pts != AV_NOPTS_VALUE) {
2168
            is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts;
Fabrice Bellard's avatar
Fabrice Bellard committed
2169
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
2170 2171 2172 2173
    }
}

/* prepare a new audio buffer */
2174
static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
Fabrice Bellard's avatar
Fabrice Bellard committed
2175 2176 2177
{
    VideoState *is = opaque;
    int audio_size, len1;
2178
    int bytes_per_sec;
2179
    int frame_size = av_samples_get_buffer_size(NULL, is->audio_tgt_channels, 1, is->audio_tgt_fmt, 1);
Fabrice Bellard's avatar
Fabrice Bellard committed
2180 2181 2182
    double pts;

    audio_callback_time = av_gettime();
2183

Fabrice Bellard's avatar
Fabrice Bellard committed
2184 2185
    while (len > 0) {
        if (is->audio_buf_index >= is->audio_buf_size) {
2186
           audio_size = audio_decode_frame(is, &pts);
Fabrice Bellard's avatar
Fabrice Bellard committed
2187 2188
           if (audio_size < 0) {
                /* if error, just output silence */
2189
               is->audio_buf      = is->silence_buf;
2190
               is->audio_buf_size = sizeof(is->silence_buf) / frame_size * frame_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
2191
           } else {
2192
               if (is->show_mode != SHOW_MODE_VIDEO)
Fabrice Bellard's avatar
Fabrice Bellard committed
2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205
                   update_sample_display(is, (int16_t *)is->audio_buf, audio_size);
               is->audio_buf_size = audio_size;
           }
           is->audio_buf_index = 0;
        }
        len1 = is->audio_buf_size - is->audio_buf_index;
        if (len1 > len)
            len1 = len;
        memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
        len -= len1;
        stream += len1;
        is->audio_buf_index += len1;
    }
2206
    bytes_per_sec = is->audio_tgt_freq * is->audio_tgt_channels * av_get_bytes_per_sample(is->audio_tgt_fmt);
2207 2208 2209 2210
    is->audio_write_buf_size = is->audio_buf_size - is->audio_buf_index;
    /* Let's assume the audio driver that is used by SDL has two periods. */
    is->audio_current_pts = is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / bytes_per_sec;
    is->audio_current_pts_drift = is->audio_current_pts - audio_callback_time / 1000000.0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2211 2212 2213 2214 2215 2216
}

/* open a given stream. Return 0 if OK */
static int stream_component_open(VideoState *is, int stream_index)
{
    AVFormatContext *ic = is->ic;
2217
    AVCodecContext *avctx;
Fabrice Bellard's avatar
Fabrice Bellard committed
2218 2219
    AVCodec *codec;
    SDL_AudioSpec wanted_spec, spec;
2220 2221
    AVDictionary *opts;
    AVDictionaryEntry *t = NULL;
2222
    int64_t wanted_channel_layout = 0;
2223 2224
    int wanted_nb_channels;
    const char *env;
Fabrice Bellard's avatar
Fabrice Bellard committed
2225 2226 2227

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

2230
    codec = avcodec_find_decoder(avctx->codec_id);
2231 2232
    opts = filter_codec_opts(codec_opts, codec, ic, ic->streams[stream_index]);

2233
    switch(avctx->codec_type){
2234 2235 2236
        case AVMEDIA_TYPE_AUDIO   : if(audio_codec_name   ) codec= avcodec_find_decoder_by_name(   audio_codec_name); break;
        case AVMEDIA_TYPE_SUBTITLE: if(subtitle_codec_name) codec= avcodec_find_decoder_by_name(subtitle_codec_name); break;
        case AVMEDIA_TYPE_VIDEO   : if(video_codec_name   ) codec= avcodec_find_decoder_by_name(   video_codec_name); break;
2237
    }
2238 2239 2240
    if (!codec)
        return -1;

Aneesh Dogra's avatar
Aneesh Dogra committed
2241 2242
    avctx->workaround_bugs   = workaround_bugs;
    avctx->lowres            = lowres;
2243 2244 2245 2246 2247
    if(avctx->lowres > codec->max_lowres){
        av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n",
                codec->max_lowres);
        avctx->lowres= codec->max_lowres;
    }
Aneesh Dogra's avatar
Aneesh Dogra committed
2248 2249 2250 2251 2252
    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;
2253

2254
    if(avctx->lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE;
Aneesh Dogra's avatar
Aneesh Dogra committed
2255
    if (fast)   avctx->flags2 |= CODEC_FLAG2_FAST;
2256 2257 2258
    if(codec->capabilities & CODEC_CAP_DR1)
        avctx->flags |= CODEC_FLAG_EMU_EDGE;

2259
    if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
2260
        memset(&is->audio_pkt_temp, 0, sizeof(is->audio_pkt_temp));
2261 2262 2263 2264
        env = SDL_getenv("SDL_AUDIO_CHANNELS");
        if (env)
            wanted_channel_layout = av_get_default_channel_layout(SDL_atoi(env));
        if (!wanted_channel_layout) {
2265
            wanted_channel_layout = (avctx->channel_layout && avctx->channels == av_get_channel_layout_nb_channels(avctx->channel_layout)) ? avctx->channel_layout : av_get_default_channel_layout(avctx->channels);
2266 2267 2268 2269 2270 2271 2272 2273
            wanted_channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX;
            wanted_nb_channels = av_get_channel_layout_nb_channels(wanted_channel_layout);
            /* SDL only supports 1, 2, 4 or 6 channels at the moment, so we have to make sure not to request anything else. */
            while (wanted_nb_channels > 0 && (wanted_nb_channels == 3 || wanted_nb_channels == 5 || wanted_nb_channels > 6)) {
                wanted_nb_channels--;
                wanted_channel_layout = av_get_default_channel_layout(wanted_nb_channels);
            }
        }
2274 2275 2276 2277
        wanted_spec.channels = av_get_channel_layout_nb_channels(wanted_channel_layout);
        wanted_spec.freq = avctx->sample_rate;
        if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
            fprintf(stderr, "Invalid sample rate or channel count!\n");
2278 2279 2280 2281
            return -1;
        }
    }

2282 2283
    if (!av_dict_get(opts, "threads", NULL, 0))
        av_dict_set(&opts, "threads", "auto", 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2284
    if (!codec ||
2285
        avcodec_open2(avctx, codec, &opts) < 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
2286
        return -1;
2287 2288 2289 2290
    if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
        av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
        return AVERROR_OPTION_NOT_FOUND;
    }
2291 2292

    /* prepare audio output */
2293
    if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
2294 2295 2296 2297 2298 2299 2300 2301 2302 2303
        wanted_spec.format = AUDIO_S16SYS;
        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());
            return -1;
        }
        is->audio_hw_buf_size = spec.size;
2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318
        if (spec.format != AUDIO_S16SYS) {
            fprintf(stderr, "SDL advised audio format %d is not supported!\n", spec.format);
            return -1;
        }
        if (spec.channels != wanted_spec.channels) {
            wanted_channel_layout = av_get_default_channel_layout(spec.channels);
            if (!wanted_channel_layout) {
                fprintf(stderr, "SDL advised channel count %d is not supported!\n", spec.channels);
                return -1;
            }
        }
        is->audio_src_fmt = is->audio_tgt_fmt = AV_SAMPLE_FMT_S16;
        is->audio_src_freq = is->audio_tgt_freq = spec.freq;
        is->audio_src_channel_layout = is->audio_tgt_channel_layout = wanted_channel_layout;
        is->audio_src_channels = is->audio_tgt_channels = spec.channels;
2319 2320
    }

2321
    ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
Aneesh Dogra's avatar
Aneesh Dogra committed
2322
    switch (avctx->codec_type) {
2323
    case AVMEDIA_TYPE_AUDIO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2324 2325
        is->audio_stream = stream_index;
        is->audio_st = ic->streams[stream_index];
Aneesh Dogra's avatar
Aneesh Dogra committed
2326
        is->audio_buf_size  = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2327
        is->audio_buf_index = 0;
2328 2329

        /* init averaging filter */
Aneesh Dogra's avatar
Aneesh Dogra committed
2330
        is->audio_diff_avg_coef  = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
2331 2332 2333
        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 */
2334
        is->audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / wanted_spec.freq;
2335

Fabrice Bellard's avatar
Fabrice Bellard committed
2336 2337
        memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
        packet_queue_init(&is->audioq);
2338
        SDL_PauseAudio(0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2339
        break;
2340
    case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2341 2342 2343 2344 2345 2346
        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;
2347
    case AVMEDIA_TYPE_SUBTITLE:
2348 2349 2350
        is->subtitle_stream = stream_index;
        is->subtitle_st = ic->streams[stream_index];
        packet_queue_init(&is->subtitleq);
2351

2352 2353
        is->subtitle_tid = SDL_CreateThread(subtitle_thread, is);
        break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2354 2355 2356 2357 2358 2359 2360 2361 2362
    default:
        break;
    }
    return 0;
}

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

2365 2366
    if (stream_index < 0 || stream_index >= ic->nb_streams)
        return;
2367
    avctx = ic->streams[stream_index]->codec;
Fabrice Bellard's avatar
Fabrice Bellard committed
2368

Aneesh Dogra's avatar
Aneesh Dogra committed
2369
    switch (avctx->codec_type) {
2370
    case AVMEDIA_TYPE_AUDIO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2371 2372 2373 2374 2375
        packet_queue_abort(&is->audioq);

        SDL_CloseAudio();

        packet_queue_end(&is->audioq);
2376 2377
        if (is->swr_ctx)
            swr_free(&is->swr_ctx);
2378
        av_free_packet(&is->audio_pkt);
2379 2380 2381
        av_freep(&is->audio_buf1);
        is->audio_buf = NULL;
        av_freep(&is->frame);
2382 2383 2384 2385

        if (is->rdft) {
            av_rdft_end(is->rdft);
            av_freep(&is->rdft_data);
2386 2387
            is->rdft = NULL;
            is->rdft_bits = 0;
2388
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
2389
        break;
2390
    case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402
        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;
2403
    case AVMEDIA_TYPE_SUBTITLE:
2404
        packet_queue_abort(&is->subtitleq);
2405

2406 2407 2408 2409
        /* 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;
2410

2411 2412 2413 2414 2415 2416 2417
        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
2418 2419 2420 2421
    default:
        break;
    }

2422
    ic->streams[stream_index]->discard = AVDISCARD_ALL;
2423
    avcodec_close(avctx);
Aneesh Dogra's avatar
Aneesh Dogra committed
2424
    switch (avctx->codec_type) {
2425
    case AVMEDIA_TYPE_AUDIO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2426 2427 2428
        is->audio_st = NULL;
        is->audio_stream = -1;
        break;
2429
    case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2430 2431 2432
        is->video_st = NULL;
        is->video_stream = -1;
        break;
2433
    case AVMEDIA_TYPE_SUBTITLE:
2434 2435 2436
        is->subtitle_st = NULL;
        is->subtitle_stream = -1;
        break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2437 2438 2439 2440 2441
    default:
        break;
    }
}

2442
static int decode_interrupt_cb(void *ctx)
2443
{
2444 2445
    VideoState *is = ctx;
    return is->abort_request;
2446
}
Fabrice Bellard's avatar
Fabrice Bellard committed
2447 2448

/* this thread gets the stream from the disk or the network */
2449
static int read_thread(void *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
2450 2451
{
    VideoState *is = arg;
2452
    AVFormatContext *ic = NULL;
2453
    int err, i, ret;
2454
    int st_index[AVMEDIA_TYPE_NB];
Fabrice Bellard's avatar
Fabrice Bellard committed
2455
    AVPacket pkt1, *pkt = &pkt1;
Aneesh Dogra's avatar
Aneesh Dogra committed
2456
    int eof = 0;
2457
    int pkt_in_play_range = 0;
2458
    AVDictionaryEntry *t;
2459 2460
    AVDictionary **opts;
    int orig_nb_streams;
2461

2462
    memset(st_index, -1, sizeof(st_index));
Fabrice Bellard's avatar
Fabrice Bellard committed
2463 2464
    is->video_stream = -1;
    is->audio_stream = -1;
2465
    is->subtitle_stream = -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2466

2467 2468
    ic = avformat_alloc_context();
    ic->interrupt_callback.callback = decode_interrupt_cb;
2469
    ic->interrupt_callback.opaque = is;
2470
    err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts);
2471 2472 2473 2474 2475
    if (err < 0) {
        print_error(is->filename, err);
        ret = -1;
        goto fail;
    }
2476 2477 2478 2479 2480
    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
2481
    is->ic = ic;
2482

Aneesh Dogra's avatar
Aneesh Dogra committed
2483
    if (genpts)
2484 2485
        ic->flags |= AVFMT_FLAG_GENPTS;

2486
    opts = setup_find_stream_info_opts(ic, codec_opts);
2487
    orig_nb_streams = ic->nb_streams;
2488

2489
    err = avformat_find_stream_info(ic, opts);
2490 2491 2492 2493 2494
    if (err < 0) {
        fprintf(stderr, "%s: could not find codec parameters\n", is->filename);
        ret = -1;
        goto fail;
    }
2495 2496 2497 2498
    for (i = 0; i < orig_nb_streams; i++)
        av_dict_free(&opts[i]);
    av_freep(&opts);

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

Aneesh Dogra's avatar
Aneesh Dogra committed
2502 2503
    if (seek_by_bytes < 0)
        seek_by_bytes = !!(ic->iformat->flags & AVFMT_TS_DISCONT);
2504

Fabrice Bellard's avatar
Fabrice Bellard committed
2505 2506 2507 2508 2509 2510 2511 2512
    /* 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;
2513
        ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2514
        if (ret < 0) {
2515
            fprintf(stderr, "%s: could not seek to position %0.3f\n",
Fabrice Bellard's avatar
Fabrice Bellard committed
2516 2517 2518 2519
                    is->filename, (double)timestamp / AV_TIME_BASE);
        }
    }

2520
    for (i = 0; i < ic->nb_streams; i++)
2521
        ic->streams[i]->discard = AVDISCARD_ALL;
2522
    if (!video_disable)
2523 2524 2525
        st_index[AVMEDIA_TYPE_VIDEO] =
            av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,
                                wanted_stream[AVMEDIA_TYPE_VIDEO], -1, NULL, 0);
2526
    if (!audio_disable)
2527 2528 2529 2530 2531
        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);
2532
    if (!video_disable)
2533 2534 2535 2536 2537 2538 2539
        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
2540
    if (show_status) {
2541
        av_dump_format(ic, 0, is->filename, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2542 2543
    }

2544 2545
    is->show_mode = show_mode;

Fabrice Bellard's avatar
Fabrice Bellard committed
2546
    /* open the streams */
2547 2548
    if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {
        stream_component_open(is, st_index[AVMEDIA_TYPE_AUDIO]);
Fabrice Bellard's avatar
Fabrice Bellard committed
2549 2550
    }

Aneesh Dogra's avatar
Aneesh Dogra committed
2551
    ret = -1;
2552
    if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
Aneesh Dogra's avatar
Aneesh Dogra committed
2553
        ret = stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO]);
Michael Niedermayer's avatar
Michael Niedermayer committed
2554
    }
2555
    is->refresh_tid = SDL_CreateThread(refresh_thread, is);
2556 2557
    if (is->show_mode == SHOW_MODE_NONE)
        is->show_mode = ret >= 0 ? SHOW_MODE_VIDEO : SHOW_MODE_RDFT;
Fabrice Bellard's avatar
Fabrice Bellard committed
2558

2559 2560
    if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) {
        stream_component_open(is, st_index[AVMEDIA_TYPE_SUBTITLE]);
2561 2562
    }

Fabrice Bellard's avatar
Fabrice Bellard committed
2563
    if (is->video_stream < 0 && is->audio_stream < 0) {
2564 2565
        fprintf(stderr, "%s: could not open codecs\n", is->filename);
        ret = -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2566 2567 2568
        goto fail;
    }

Aneesh Dogra's avatar
Aneesh Dogra committed
2569
    for (;;) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2570 2571
        if (is->abort_request)
            break;
2572 2573
        if (is->paused != is->last_paused) {
            is->last_paused = is->paused;
Fabrice Bellard's avatar
Fabrice Bellard committed
2574
            if (is->paused)
Aneesh Dogra's avatar
Aneesh Dogra committed
2575
                is->read_pause_return = av_read_pause(ic);
Fabrice Bellard's avatar
Fabrice Bellard committed
2576 2577
            else
                av_read_play(ic);
2578
        }
2579 2580 2581
#if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL
        if (is->paused &&
                (!strcmp(ic->iformat->name, "rtsp") ||
2582
                 (ic->pb && !strncmp(input_filename, "mmsh:", 5)))) {
2583 2584 2585 2586 2587
            /* wait 10 ms to avoid trying to get another packet */
            /* XXX: horrible */
            SDL_Delay(10);
            continue;
        }
2588
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
2589
        if (is->seek_req) {
Aneesh Dogra's avatar
Aneesh Dogra committed
2590 2591 2592 2593
            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
2594
//      of the seek_pos/seek_rel variables
2595

2596
            ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags);
Fabrice Bellard's avatar
Fabrice Bellard committed
2597 2598
            if (ret < 0) {
                fprintf(stderr, "%s: error while seeking\n", is->ic->filename);
Aneesh Dogra's avatar
Aneesh Dogra committed
2599
            } else {
2600 2601
                if (is->audio_stream >= 0) {
                    packet_queue_flush(&is->audioq);
2602
                    packet_queue_put(&is->audioq, &flush_pkt);
2603
                }
2604 2605
                if (is->subtitle_stream >= 0) {
                    packet_queue_flush(&is->subtitleq);
2606
                    packet_queue_put(&is->subtitleq, &flush_pkt);
2607
                }
2608 2609
                if (is->video_stream >= 0) {
                    packet_queue_flush(&is->videoq);
2610
                    packet_queue_put(&is->videoq, &flush_pkt);
2611
                }
Fabrice Bellard's avatar
Fabrice Bellard committed
2612 2613
            }
            is->seek_req = 0;
Aneesh Dogra's avatar
Aneesh Dogra committed
2614
            eof = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2615
        }
2616

Fabrice Bellard's avatar
Fabrice Bellard committed
2617
        /* if the queue are full, no need to read more */
2618
        if (   is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
2619
            || (   (is->audioq   .nb_packets > MIN_FRAMES || is->audio_stream < 0)
Aneesh Dogra's avatar
Aneesh Dogra committed
2620 2621
                && (is->videoq   .nb_packets > MIN_FRAMES || is->video_stream < 0)
                && (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0))) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2622 2623 2624 2625
            /* wait 10 ms */
            SDL_Delay(10);
            continue;
        }
Aneesh Dogra's avatar
Aneesh Dogra committed
2626 2627
        if (eof) {
            if (is->video_stream >= 0) {
Michael Niedermayer's avatar
Michael Niedermayer committed
2628
                av_init_packet(pkt);
Aneesh Dogra's avatar
Aneesh Dogra committed
2629 2630 2631
                pkt->data = NULL;
                pkt->size = 0;
                pkt->stream_index = is->video_stream;
Michael Niedermayer's avatar
Michael Niedermayer committed
2632
                packet_queue_put(&is->videoq, pkt);
2633
            }
2634 2635 2636 2637 2638 2639 2640
            if (is->audio_stream >= 0 &&
                is->audio_st->codec->codec->capabilities & CODEC_CAP_DELAY) {
                av_init_packet(pkt);
                pkt->data = NULL;
                pkt->size = 0;
                pkt->stream_index = is->audio_stream;
                packet_queue_put(&is->audioq, pkt);
2641
            }
2642
            SDL_Delay(10);
Aneesh Dogra's avatar
Aneesh Dogra committed
2643 2644
            if (is->audioq.size + is->videoq.size + is->subtitleq.size == 0) {
                if (loop != 1 && (!loop || --loop)) {
2645
                    stream_seek(is, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0);
Aneesh Dogra's avatar
Aneesh Dogra committed
2646 2647
                } else if (autoexit) {
                    ret = AVERROR_EOF;
2648 2649
                    goto fail;
                }
Michael Niedermayer's avatar
Michael Niedermayer committed
2650
            }
2651
            eof=0;
2652 2653
            continue;
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
2654
        ret = av_read_frame(ic, pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
2655
        if (ret < 0) {
2656
            if (ret == AVERROR_EOF || url_feof(ic->pb))
Aneesh Dogra's avatar
Aneesh Dogra committed
2657
                eof = 1;
2658
            if (ic->pb && ic->pb->error)
2659
                break;
2660 2661
            SDL_Delay(100); /* wait for user event */
            continue;
Fabrice Bellard's avatar
Fabrice Bellard committed
2662
        }
2663 2664 2665 2666
        /* 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
2667 2668
                (double)(start_time != AV_NOPTS_VALUE ? start_time : 0) / 1000000
                <= ((double)duration / 1000000);
2669
        if (pkt->stream_index == is->audio_stream && pkt_in_play_range) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2670
            packet_queue_put(&is->audioq, pkt);
2671
        } else if (pkt->stream_index == is->video_stream && pkt_in_play_range) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2672
            packet_queue_put(&is->videoq, pkt);
2673
        } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {
2674
            packet_queue_put(&is->subtitleq, pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
2675 2676 2677 2678 2679 2680 2681 2682 2683
        } else {
            av_free_packet(pkt);
        }
    }
    /* wait until the end */
    while (!is->abort_request) {
        SDL_Delay(100);
    }

2684
    ret = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2685 2686 2687 2688 2689 2690
 fail:
    /* close each stream */
    if (is->audio_stream >= 0)
        stream_component_close(is, is->audio_stream);
    if (is->video_stream >= 0)
        stream_component_close(is, is->video_stream);
2691 2692
    if (is->subtitle_stream >= 0)
        stream_component_close(is, is->subtitle_stream);
2693
    if (is->ic) {
2694
        avformat_close_input(&is->ic);
2695
    }
2696

2697 2698
    if (ret != 0) {
        SDL_Event event;
2699

2700 2701 2702 2703
        event.type = FF_QUIT_EVENT;
        event.user.data1 = is;
        SDL_PushEvent(&event);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2704 2705 2706
    return 0;
}

2707
static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
Fabrice Bellard's avatar
Fabrice Bellard committed
2708 2709 2710 2711 2712 2713
{
    VideoState *is;

    is = av_mallocz(sizeof(VideoState));
    if (!is)
        return NULL;
2714
    av_strlcpy(is->filename, filename, sizeof(is->filename));
2715
    is->iformat = iformat;
Aneesh Dogra's avatar
Aneesh Dogra committed
2716 2717
    is->ytop    = 0;
    is->xleft   = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2718 2719 2720

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

2723
    is->subpq_mutex = SDL_CreateMutex();
Aneesh Dogra's avatar
Aneesh Dogra committed
2724
    is->subpq_cond  = SDL_CreateCond();
2725

2726
    is->av_sync_type = av_sync_type;
2727
    is->read_tid     = SDL_CreateThread(read_thread, is);
2728
    if (!is->read_tid) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2729 2730 2731 2732 2733 2734
        av_free(is);
        return NULL;
    }
    return is;
}

2735
static void stream_cycle_channel(VideoState *is, int codec_type)
2736 2737 2738 2739 2740
{
    AVFormatContext *ic = is->ic;
    int start_index, stream_index;
    AVStream *st;

2741
    if (codec_type == AVMEDIA_TYPE_VIDEO)
2742
        start_index = is->video_stream;
2743
    else if (codec_type == AVMEDIA_TYPE_AUDIO)
2744
        start_index = is->audio_stream;
2745 2746
    else
        start_index = is->subtitle_stream;
2747
    if (start_index < (codec_type == AVMEDIA_TYPE_SUBTITLE ? -1 : 0))
2748 2749
        return;
    stream_index = start_index;
Aneesh Dogra's avatar
Aneesh Dogra committed
2750
    for (;;) {
2751
        if (++stream_index >= is->ic->nb_streams)
2752
        {
2753
            if (codec_type == AVMEDIA_TYPE_SUBTITLE)
2754 2755 2756 2757 2758 2759
            {
                stream_index = -1;
                goto the_end;
            } else
                stream_index = 0;
        }
2760 2761 2762
        if (stream_index == start_index)
            return;
        st = ic->streams[stream_index];
2763
        if (st->codec->codec_type == codec_type) {
2764
            /* check that parameters are OK */
Aneesh Dogra's avatar
Aneesh Dogra committed
2765
            switch (codec_type) {
2766
            case AVMEDIA_TYPE_AUDIO:
2767 2768
                if (st->codec->sample_rate != 0 &&
                    st->codec->channels != 0)
2769 2770
                    goto the_end;
                break;
2771 2772
            case AVMEDIA_TYPE_VIDEO:
            case AVMEDIA_TYPE_SUBTITLE:
2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784
                goto the_end;
            default:
                break;
            }
        }
    }
 the_end:
    stream_component_close(is, start_index);
    stream_component_open(is, stream_index);
}


2785
static void toggle_full_screen(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
2786
{
2787
    av_unused int i;
Fabrice Bellard's avatar
Fabrice Bellard committed
2788
    is_full_screen = !is_full_screen;
2789
#if defined(__APPLE__) && SDL_VERSION_ATLEAST(1, 2, 14)
2790
    /* OS X needs to reallocate the SDL overlays */
Michael Niedermayer's avatar
Michael Niedermayer committed
2791
    for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
2792 2793 2794
        is->pictq[i].reallocate = 1;
    }
#endif
2795
    video_open(is, 1);
Fabrice Bellard's avatar
Fabrice Bellard committed
2796 2797
}

2798
static void toggle_pause(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
2799
{
2800 2801
    stream_toggle_pause(is);
    is->step = 0;
2802 2803
}

2804
static void step_to_next_frame(VideoState *is)
2805
{
2806 2807 2808 2809
    /* if the stream is paused unpause it, then step */
    if (is->paused)
        stream_toggle_pause(is);
    is->step = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2810 2811
}

2812
static void toggle_audio_display(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
2813
{
2814 2815 2816 2817 2818 2819
    int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
    is->show_mode = (is->show_mode + 1) % SHOW_MODE_NB;
    fill_rectangle(screen,
                is->xleft, is->ytop, is->width, is->height,
                bgcolor);
    SDL_UpdateRect(screen, is->xleft, is->ytop, is->width, is->height);
Fabrice Bellard's avatar
Fabrice Bellard committed
2820 2821 2822
}

/* handle an event sent by the GUI */
2823
static void event_loop(VideoState *cur_stream)
Fabrice Bellard's avatar
Fabrice Bellard committed
2824 2825
{
    SDL_Event event;
2826
    double incr, pos, frac;
Fabrice Bellard's avatar
Fabrice Bellard committed
2827

Aneesh Dogra's avatar
Aneesh Dogra committed
2828
    for (;;) {
Michael Niedermayer's avatar
Michael Niedermayer committed
2829
        double x;
Fabrice Bellard's avatar
Fabrice Bellard committed
2830
        SDL_WaitEvent(&event);
Aneesh Dogra's avatar
Aneesh Dogra committed
2831
        switch (event.type) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2832
        case SDL_KEYDOWN:
2833
            if (exit_on_keydown) {
2834
                do_exit(cur_stream);
2835 2836
                break;
            }
Aneesh Dogra's avatar
Aneesh Dogra committed
2837
            switch (event.key.keysym.sym) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2838 2839
            case SDLK_ESCAPE:
            case SDLK_q:
2840
                do_exit(cur_stream);
Fabrice Bellard's avatar
Fabrice Bellard committed
2841 2842
                break;
            case SDLK_f:
2843
                toggle_full_screen(cur_stream);
2844
                cur_stream->force_refresh = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2845 2846 2847
                break;
            case SDLK_p:
            case SDLK_SPACE:
2848
                toggle_pause(cur_stream);
Fabrice Bellard's avatar
Fabrice Bellard committed
2849
                break;
Aneesh Dogra's avatar
Aneesh Dogra committed
2850
            case SDLK_s: // S: Step to next frame
2851
                step_to_next_frame(cur_stream);
2852
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2853
            case SDLK_a:
2854
                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
2855 2856
                break;
            case SDLK_v:
2857
                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
2858
                break;
2859
            case SDLK_t:
2860
                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
2861
                break;
2862
            case SDLK_w:
2863
                toggle_audio_display(cur_stream);
2864
                cur_stream->force_refresh = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2865
                break;
2866 2867 2868 2869 2870 2871
            case SDLK_PAGEUP:
                incr = 600.0;
                goto do_seek;
            case SDLK_PAGEDOWN:
                incr = -600.0;
                goto do_seek;
Fabrice Bellard's avatar
Fabrice Bellard committed
2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883
            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:
2884
                    if (seek_by_bytes) {
Aneesh Dogra's avatar
Aneesh Dogra committed
2885 2886 2887 2888 2889
                        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
2890
                            pos = avio_tell(cur_stream->ic->pb);
2891
                        if (cur_stream->ic->bit_rate)
2892
                            incr *= cur_stream->ic->bit_rate / 8.0;
2893 2894 2895
                        else
                            incr *= 180000.0;
                        pos += incr;
2896
                        stream_seek(cur_stream, pos, incr, 1);
2897 2898 2899
                    } else {
                        pos = get_master_clock(cur_stream);
                        pos += incr;
2900
                        stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0);
2901
                    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2902
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2903 2904 2905 2906
            default:
                break;
            }
            break;
2907 2908 2909
        case SDL_VIDEOEXPOSE:
            cur_stream->force_refresh = 1;
            break;
2910
        case SDL_MOUSEBUTTONDOWN:
2911
            if (exit_on_mousedown) {
2912
                do_exit(cur_stream);
2913 2914
                break;
            }
Michael Niedermayer's avatar
Michael Niedermayer committed
2915
        case SDL_MOUSEMOTION:
Aneesh Dogra's avatar
Aneesh Dogra committed
2916 2917 2918 2919
            if (event.type == SDL_MOUSEBUTTONDOWN) {
                x = event.button.x;
            } else {
                if (event.motion.state != SDL_PRESSED)
Michael Niedermayer's avatar
Michael Niedermayer committed
2920
                    break;
Aneesh Dogra's avatar
Aneesh Dogra committed
2921
                x = event.motion.x;
2922
            }
Aneesh Dogra's avatar
Aneesh Dogra committed
2923 2924
                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
2925
                    stream_seek(cur_stream, size*x/cur_stream->width, 0, 1);
Aneesh Dogra's avatar
Aneesh Dogra committed
2926
                } else {
Michael Niedermayer's avatar
Michael Niedermayer committed
2927 2928 2929
                    int64_t ts;
                    int ns, hh, mm, ss;
                    int tns, thh, tmm, tss;
Aneesh Dogra's avatar
Aneesh Dogra committed
2930 2931 2932 2933 2934 2935 2936 2937 2938
                    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
2939 2940
                    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
2941
                    ts = frac * cur_stream->ic->duration;
Michael Niedermayer's avatar
Michael Niedermayer committed
2942 2943 2944
                    if (cur_stream->ic->start_time != AV_NOPTS_VALUE)
                        ts += cur_stream->ic->start_time;
                    stream_seek(cur_stream, ts, 0, 0);
2945
                }
2946
            break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2947
        case SDL_VIDEORESIZE:
2948
                screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 0,
Fabrice Bellard's avatar
Fabrice Bellard committed
2949
                                          SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
Aneesh Dogra's avatar
Aneesh Dogra committed
2950 2951
                screen_width  = cur_stream->width  = event.resize.w;
                screen_height = cur_stream->height = event.resize.h;
2952
                cur_stream->force_refresh = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2953 2954
            break;
        case SDL_QUIT:
2955
        case FF_QUIT_EVENT:
2956
            do_exit(cur_stream);
Fabrice Bellard's avatar
Fabrice Bellard committed
2957 2958
            break;
        case FF_ALLOC_EVENT:
2959
            video_open(event.user.data1, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2960 2961 2962
            alloc_picture(event.user.data1);
            break;
        case FF_REFRESH_EVENT:
2963
            video_refresh(event.user.data1);
Aneesh Dogra's avatar
Aneesh Dogra committed
2964
            cur_stream->refresh = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2965 2966 2967 2968 2969 2970 2971
            break;
        default:
            break;
        }
    }
}

2972
static int opt_frame_size(const char *opt, const char *arg)
2973
{
2974 2975
    av_log(NULL, AV_LOG_WARNING, "Option -s is deprecated, use -video_size.\n");
    return opt_default("video_size", arg);
2976 2977
}

2978
static int opt_width(const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
2979
{
2980 2981
    screen_width = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2982 2983
}

2984
static int opt_height(const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
2985
{
2986 2987
    screen_height = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2988 2989
}

2990
static int opt_format(const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
2991 2992 2993 2994
{
    file_iformat = av_find_input_format(arg);
    if (!file_iformat) {
        fprintf(stderr, "Unknown input format: %s\n", arg);
2995
        return AVERROR(EINVAL);
Fabrice Bellard's avatar
Fabrice Bellard committed
2996
    }
2997
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2998
}
2999

3000
static int opt_frame_pix_fmt(const char *opt, const char *arg)
3001
{
3002 3003
    av_log(NULL, AV_LOG_WARNING, "Option -pix_fmt is deprecated, use -pixel_format.\n");
    return opt_default("pixel_format", arg);
3004 3005
}

3006
static int opt_sync(const char *opt, const char *arg)
3007 3008 3009 3010 3011 3012 3013
{
    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;
3014
    else {
3015
        fprintf(stderr, "Unknown value for %s: %s\n", opt, arg);
3016 3017
        exit(1);
    }
3018
    return 0;
3019 3020
}

3021
static int opt_seek(const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
3022
{
3023 3024
    start_time = parse_time_or_die(opt, arg, 1);
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
3025 3026
}

3027 3028 3029 3030 3031 3032
static int opt_duration(const char *opt, const char *arg)
{
    duration = parse_time_or_die(opt, arg, 1);
    return 0;
}

3033 3034 3035 3036 3037 3038 3039 3040 3041
static int opt_show_mode(const char *opt, const char *arg)
{
    show_mode = !strcmp(arg, "video") ? SHOW_MODE_VIDEO :
                !strcmp(arg, "waves") ? SHOW_MODE_WAVES :
                !strcmp(arg, "rdft" ) ? SHOW_MODE_RDFT  :
                parse_number_or_die(opt, arg, OPT_INT, 0, SHOW_MODE_NB-1);
    return 0;
}

3042
static void opt_input_file(void *optctx, const char *filename)
3043 3044 3045 3046
{
    if (input_filename) {
        fprintf(stderr, "Argument '%s' provided as input filename, but '%s' was already specified.\n",
                filename, input_filename);
3047
        exit_program(1);
3048 3049 3050 3051 3052 3053
    }
    if (!strcmp(filename, "-"))
        filename = "pipe:";
    input_filename = filename;
}

3054 3055 3056 3057 3058 3059 3060 3061 3062 3063
static int opt_codec(void *o, const char *opt, const char *arg)
{
    switch(opt[strlen(opt)-1]){
    case 'a' :    audio_codec_name = arg; break;
    case 's' : subtitle_codec_name = arg; break;
    case 'v' :    video_codec_name = arg; break;
    }
    return 0;
}

3064 3065
static int dummy;

3066
static const OptionDef options[] = {
3067
#include "cmdutils_common_opts.h"
Aneesh Dogra's avatar
Aneesh Dogra committed
3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087
    { "x", HAS_ARG, { (void*)opt_width }, "force displayed width", "width" },
    { "y", HAS_ARG, { (void*)opt_height }, "force displayed height", "height" },
    { "s", HAS_ARG | OPT_VIDEO, { (void*)opt_frame_size }, "set frame size (WxH or abbreviation)", "size" },
    { "fs", OPT_BOOL, { (void*)&is_full_screen }, "force full screen" },
    { "an", OPT_BOOL, { (void*)&audio_disable }, "disable audio" },
    { "vn", OPT_BOOL, { (void*)&video_disable }, "disable video" },
    { "ast", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&wanted_stream[AVMEDIA_TYPE_AUDIO] }, "select desired audio stream", "stream_number" },
    { "vst", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&wanted_stream[AVMEDIA_TYPE_VIDEO] }, "select desired video stream", "stream_number" },
    { "sst", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&wanted_stream[AVMEDIA_TYPE_SUBTITLE] }, "select desired subtitle stream", "stream_number" },
    { "ss", HAS_ARG, { (void*)&opt_seek }, "seek to a given position in seconds", "pos" },
    { "t", HAS_ARG, { (void*)&opt_duration }, "play  \"duration\" seconds of audio/video", "duration" },
    { "bytes", OPT_INT | HAS_ARG, { (void*)&seek_by_bytes }, "seek by bytes 0=off 1=on -1=auto", "val" },
    { "nodisp", OPT_BOOL, { (void*)&display_disable }, "disable graphical display" },
    { "f", HAS_ARG, { (void*)opt_format }, "force format", "fmt" },
    { "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { (void*)opt_frame_pix_fmt }, "set pixel format", "format" },
    { "stats", OPT_BOOL | OPT_EXPERT, { (void*)&show_status }, "show status", "" },
    { "bug", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&workaround_bugs }, "workaround bugs", "" },
    { "fast", OPT_BOOL | OPT_EXPERT, { (void*)&fast }, "non spec compliant optimizations", "" },
    { "genpts", OPT_BOOL | OPT_EXPERT, { (void*)&genpts }, "generate pts", "" },
    { "drp", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&decoder_reorder_pts }, "let decoder reorder pts 0=off 1=on -1=auto", ""},
Michael Niedermayer's avatar
Michael Niedermayer committed
3088
    { "lowres", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&lowres }, "", "" },
Aneesh Dogra's avatar
Aneesh Dogra committed
3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100
    { "skiploop", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&skip_loop_filter }, "", "" },
    { "skipframe", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&skip_frame }, "", "" },
    { "skipidct", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&skip_idct }, "", "" },
    { "idct", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&idct }, "set idct algo",  "algo" },
    { "ec", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&error_concealment }, "set error concealment options",  "bit_mask" },
    { "sync", HAS_ARG | OPT_EXPERT, { (void*)opt_sync }, "set audio-video sync. type (type=audio/video/ext)", "type" },
    { "autoexit", OPT_BOOL | OPT_EXPERT, { (void*)&autoexit }, "exit at the end", "" },
    { "exitonkeydown", OPT_BOOL | OPT_EXPERT, { (void*)&exit_on_keydown }, "exit on key down", "" },
    { "exitonmousedown", OPT_BOOL | OPT_EXPERT, { (void*)&exit_on_mousedown }, "exit on mouse down", "" },
    { "loop", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&loop }, "set number of times the playback shall be looped", "loop count" },
    { "framedrop", OPT_BOOL | OPT_EXPERT, { (void*)&framedrop }, "drop frames when cpu is too slow", "" },
    { "window_title", OPT_STRING | HAS_ARG, { (void*)&window_title }, "set window title", "window title" },
3101
#if CONFIG_AVFILTER
Aneesh Dogra's avatar
Aneesh Dogra committed
3102
    { "vf", OPT_STRING | HAS_ARG, { (void*)&vfilters }, "video filters", "filter list" },
3103
#endif
Aneesh Dogra's avatar
Aneesh Dogra committed
3104
    { "rdftspeed", OPT_INT | HAS_ARG| OPT_AUDIO | OPT_EXPERT, { (void*)&rdftspeed }, "rdft speed", "msecs" },
3105
    { "showmode", HAS_ARG, {(void*)opt_show_mode}, "select show mode (0 = video, 1 = waves, 2 = RDFT)", "mode" },
Aneesh Dogra's avatar
Aneesh Dogra committed
3106
    { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { (void*)opt_default }, "generic catch all option", "" },
3107
    { "i", OPT_BOOL, {(void *)&dummy}, "read specified file", "input_file"},
3108
    { "codec", HAS_ARG | OPT_FUNC2, {(void*)opt_codec}, "force decoder", "decoder" },
Fabrice Bellard's avatar
Fabrice Bellard committed
3109 3110 3111
    { NULL, },
};

3112
static void show_usage(void)
Fabrice Bellard's avatar
Fabrice Bellard committed
3113
{
3114 3115 3116
    av_log(NULL, AV_LOG_INFO, "Simple media player\n");
    av_log(NULL, AV_LOG_INFO, "usage: %s [options] input_file\n", program_name);
    av_log(NULL, AV_LOG_INFO, "\n");
3117 3118
}

3119
static int opt_help(const char *opt, const char *arg)
3120
{
3121
    av_log_set_callback(log_callback_help);
3122
    show_usage();
3123 3124 3125 3126
    show_help_options(options, "Main options:\n",
                      OPT_EXPERT, 0);
    show_help_options(options, "\nAdvanced options:\n",
                      OPT_EXPERT, OPT_EXPERT);
3127
    printf("\n");
3128 3129
    show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM);
    show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
3130
#if !CONFIG_AVFILTER
3131
    show_help_children(sws_get_class(), AV_OPT_FLAG_ENCODING_PARAM);
3132
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3133 3134 3135 3136
    printf("\nWhile playing:\n"
           "q, ESC              quit\n"
           "f                   toggle full screen\n"
           "p, SPC              pause\n"
3137 3138
           "a                   cycle audio channel\n"
           "v                   cycle video channel\n"
3139
           "t                   cycle subtitle channel\n"
3140
           "w                   show audio waves\n"
3141
           "s                   activate frame-step mode\n"
Fabrice Bellard's avatar
Fabrice Bellard committed
3142 3143
           "left/right          seek backward/forward 10 seconds\n"
           "down/up             seek backward/forward 1 minute\n"
3144
           "page down/page up   seek backward/forward 10 minutes\n"
3145
           "mouse click         seek to percentage in file corresponding to fraction of width\n"
Fabrice Bellard's avatar
Fabrice Bellard committed
3146
           );
3147
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
3148 3149
}

3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168
static int lockmgr(void **mtx, enum AVLockOp op)
{
   switch(op) {
      case AV_LOCK_CREATE:
          *mtx = SDL_CreateMutex();
          if(!*mtx)
              return 1;
          return 0;
      case AV_LOCK_OBTAIN:
          return !!SDL_LockMutex(*mtx);
      case AV_LOCK_RELEASE:
          return !!SDL_UnlockMutex(*mtx);
      case AV_LOCK_DESTROY:
          SDL_DestroyMutex(*mtx);
          return 0;
   }
   return 1;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
3169 3170 3171
/* Called from the main */
int main(int argc, char **argv)
{
3172
    int flags;
3173
    VideoState *is;
3174

3175
    av_log_set_flags(AV_LOG_SKIP_REPEATED);
3176
    parse_loglevel(argc, argv, options);
3177

Fabrice Bellard's avatar
Fabrice Bellard committed
3178
    /* register all codecs, demux and protocols */
Luca Abeni's avatar
Luca Abeni committed
3179
    avcodec_register_all();
3180
#if CONFIG_AVDEVICE
Luca Abeni's avatar
Luca Abeni committed
3181
    avdevice_register_all();
3182
#endif
3183 3184 3185
#if CONFIG_AVFILTER
    avfilter_register_all();
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3186
    av_register_all();
3187
    avformat_network_init();
Fabrice Bellard's avatar
Fabrice Bellard committed
3188

3189
    init_opts();
3190

3191 3192 3193
    signal(SIGINT , sigterm_handler); /* Interrupt (ANSI).    */
    signal(SIGTERM, sigterm_handler); /* Termination (ANSI).  */

3194
    show_banner(argc, argv, options);
3195

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

3198
    if (!input_filename) {
3199
        show_usage();
3200
        fprintf(stderr, "An input file must be specified\n");
Anton Khirnov's avatar
Anton Khirnov committed
3201
        fprintf(stderr, "Use -h to get full help or, even better, run 'man %s'\n", program_name);
3202 3203
        exit(1);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
3204 3205 3206 3207

    if (display_disable) {
        video_disable = 1;
    }
3208
    flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
3209 3210
    if (audio_disable)
        flags &= ~SDL_INIT_AUDIO;
3211 3212
#if !defined(__MINGW32__) && !defined(__APPLE__)
    flags |= SDL_INIT_EVENTTHREAD; /* Not supported on Windows or Mac OS X */
3213
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3214
    if (SDL_Init (flags)) {
3215
        fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
3216
        fprintf(stderr, "(Did you set the DISPLAY variable?)\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
3217 3218 3219 3220
        exit(1);
    }

    if (!display_disable) {
3221
#if HAVE_SDL_VIDEO_SIZE
3222 3223 3224
        const SDL_VideoInfo *vi = SDL_GetVideoInfo();
        fs_screen_width = vi->current_w;
        fs_screen_height = vi->current_h;
3225
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3226 3227 3228 3229 3230 3231
    }

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

3232 3233 3234 3235 3236
    if (av_lockmgr_register(lockmgr)) {
        fprintf(stderr, "Could not initialize lock manager!\n");
        do_exit(NULL);
    }

3237
    av_init_packet(&flush_pkt);
3238
    flush_pkt.data = (char *)(intptr_t)"FLUSH";
3239

3240 3241 3242 3243 3244
    is = stream_open(input_filename, file_iformat);
    if (!is) {
        fprintf(stderr, "Failed to initialize VideoState!\n");
        do_exit(NULL);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
3245

3246
    event_loop(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
3247 3248 3249 3250 3251

    /* never returns */

    return 0;
}