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

22 23
#define _XOPEN_SOURCE 600

24
#include "config.h"
25
#include <inttypes.h>
26 27
#include <math.h>
#include <limits.h>
28
#include "libavutil/avstring.h"
29
#include "libavutil/colorspace.h"
30
#include "libavutil/pixdesc.h"
31 32 33
#include "libavutil/imgutils.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
34 35 36
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
37
#include "libavcodec/audioconvert.h"
38
#include "libavcodec/opt.h"
39
#include "libavcodec/avfft.h"
Fabrice Bellard's avatar
Fabrice Bellard committed
40

41 42 43 44 45
#if CONFIG_AVFILTER
# include "libavfilter/avfilter.h"
# include "libavfilter/avfiltergraph.h"
#endif

Fabrice Bellard's avatar
Fabrice Bellard committed
46 47 48 49 50
#include "cmdutils.h"

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

51
#ifdef __MINGW32__
52 53 54
#undef main /* We don't want SDL to override our main() */
#endif

55 56 57
#include <unistd.h>
#include <assert.h>

58
const char program_name[] = "FFplay";
59
const int program_birth_year = 2003;
60

61
//#define DEBUG
62 63
//#define DEBUG_SYNC

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

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

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

77 78
#define FRAME_SKIP_FACTOR 0.05

79 80 81 82 83 84
/* 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
85 86 87
/* NOTE: the size must be big enough to compensate the hardware audio buffersize size */
#define SAMPLE_ARRAY_SIZE (2*65536)

88 89
static int sws_flags = SWS_BICUBIC;

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

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

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

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

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

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

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

    int audio_stream;
145

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

150 151 152 153 154
    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
155 156 157 158 159
    AVStream *audio_st;
    PacketQueue audioq;
    int audio_hw_buf_size;
    /* samples output by the codec. we reserve more space for avsync
       compensation */
160 161
    DECLARE_ALIGNED(16,uint8_t,audio_buf1)[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
    DECLARE_ALIGNED(16,uint8_t,audio_buf2)[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
162
    uint8_t *audio_buf;
163
    unsigned int audio_buf_size; /* in bytes */
Fabrice Bellard's avatar
Fabrice Bellard committed
164
    int audio_buf_index; /* in bytes */
165
    AVPacket audio_pkt_temp;
Fabrice Bellard's avatar
Fabrice Bellard committed
166
    AVPacket audio_pkt;
167
    enum AVSampleFormat audio_src_fmt;
168
    AVAudioConvert *reformat_ctx;
169

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

179 180 181 182 183 184 185 186 187
    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;
188

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

Fabrice Bellard's avatar
Fabrice Bellard committed
207 208 209
    //    QETimer *video_timer;
    char filename[1024];
    int width, height, xleft, ytop;
210

211 212 213
#if CONFIG_AVFILTER
    AVFilterContext *out_video_filter;          ///<the last filter in the video chain
#endif
214 215 216 217

    float skip_frames;
    float skip_frames_index;
    int refresh;
Fabrice Bellard's avatar
Fabrice Bellard committed
218 219
} VideoState;

220
static void show_help(void);
221
static int audio_write_get_buf_size(VideoState *is);
Fabrice Bellard's avatar
Fabrice Bellard committed
222 223 224 225

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

static int rdftspeed=20;
269 270 271
#if CONFIG_AVFILTER
static char *vfilters = NULL;
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
272 273 274 275

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

278
static AVPacket flush_pkt;
279

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

284
static SDL_Surface *screen;
Fabrice Bellard's avatar
Fabrice Bellard committed
285

286 287
static int packet_queue_put(PacketQueue *q, AVPacket *pkt);

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

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

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

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

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

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

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

Fabrice Bellard's avatar
Fabrice Bellard committed
335

Fabrice Bellard's avatar
Fabrice Bellard committed
336 337 338 339 340 341 342 343 344
    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++;
345
    q->size += pkt1->pkt.size + sizeof(*pkt1);
Fabrice Bellard's avatar
Fabrice Bellard committed
346 347 348 349 350 351 352 353 354 355 356 357
    /* XXX: should duplicate packet data in DV case */
    SDL_CondSignal(q->cond);

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

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

    q->abort_request = 1;
358

Fabrice Bellard's avatar
Fabrice Bellard committed
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
    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);

    for(;;) {
        if (q->abort_request) {
            ret = -1;
            break;
        }
377

Fabrice Bellard's avatar
Fabrice Bellard committed
378 379 380 381 382 383
        pkt1 = q->first_pkt;
        if (pkt1) {
            q->first_pkt = pkt1->next;
            if (!q->first_pkt)
                q->last_pkt = NULL;
            q->nb_packets--;
384
            q->size -= pkt1->pkt.size + sizeof(*pkt1);
Fabrice Bellard's avatar
Fabrice Bellard committed
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
            *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;
}

400
static inline void fill_rectangle(SDL_Surface *screen,
Fabrice Bellard's avatar
Fabrice Bellard committed
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
                                  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);
}

#if 0
/* draw only the border of a rectangle */
void fill_border(VideoState *s, int x, int y, int w, int h, int color)
{
    int w1, w2, h1, h2;

    /* fill the background */
    w1 = x;
    if (w1 < 0)
        w1 = 0;
    w2 = s->width - (x + w);
    if (w2 < 0)
        w2 = 0;
    h1 = y;
    if (h1 < 0)
        h1 = 0;
    h2 = s->height - (y + h);
    if (h2 < 0)
        h2 = 0;
430 431 432
    fill_rectangle(screen,
                   s->xleft, s->ytop,
                   w1, s->height,
Fabrice Bellard's avatar
Fabrice Bellard committed
433
                   color);
434 435 436
    fill_rectangle(screen,
                   s->xleft + s->width - w2, s->ytop,
                   w2, s->height,
Fabrice Bellard's avatar
Fabrice Bellard committed
437
                   color);
438 439 440
    fill_rectangle(screen,
                   s->xleft + w1, s->ytop,
                   s->width - w1 - w2, h1,
Fabrice Bellard's avatar
Fabrice Bellard committed
441
                   color);
442
    fill_rectangle(screen,
Fabrice Bellard's avatar
Fabrice Bellard committed
443 444 445 446 447 448
                   s->xleft + w1, s->ytop + s->height - h2,
                   s->width - w1 - w2, h2,
                   color);
}
#endif

449 450 451 452 453 454 455 456 457 458 459 460 461 462
#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)\
{\
463
    unsigned int val = ((const uint32_t *)(pal))[*(const uint8_t*)(s)];\
464 465 466 467 468 469 470 471 472 473 474 475 476 477
    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

478
static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, int imgh)
479 480 481 482 483 484
{
    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;
485 486
    int dstx, dsty, dstw, dsth;

487 488 489 490
    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);
491 492 493 494
    lum = dst->data[0] + dsty * dst->linesize[0];
    cb = dst->data[1] + (dsty >> 1) * dst->linesize[1];
    cr = dst->data[2] + (dsty >> 1) * dst->linesize[2];

495
    width2 = ((dstw + 1) >> 1) + (dstx & ~dstw & 1);
496
    skip2 = dstx >> 1;
497
    wrap = dst->linesize[0];
498 499 500
    wrap3 = rect->pict.linesize[0];
    p = rect->pict.data[0];
    pal = (const uint32_t *)rect->pict.data[1];  /* Now in YCrCb! */
501

502 503
    if (dsty & 1) {
        lum += dstx;
504 505
        cb += skip2;
        cr += skip2;
506

507
        if (dstx & 1) {
508 509 510 511 512 513 514 515 516
            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;
        }
517
        for(w = dstw - (dstx & 1); w >= 2; w -= 2) {
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
            YUVA_IN(y, u, v, a, p, pal);
            u1 = u;
            v1 = v;
            a1 = a;
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);

            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);
541 542
            p++;
            lum++;
543
        }
544 545
        p += wrap3 - dstw * BPP;
        lum += wrap - dstw - dstx;
546 547 548
        cb += dst->linesize[1] - width2 - skip2;
        cr += dst->linesize[2] - width2 - skip2;
    }
549 550
    for(h = dsth - (dsty & 1); h >= 2; h -= 2) {
        lum += dstx;
551 552
        cb += skip2;
        cr += skip2;
553

554
        if (dstx & 1) {
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
            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;
        }
574
        for(w = dstw - (dstx & 1); w >= 2; w -= 2) {
575 576 577 578 579 580
            YUVA_IN(y, u, v, a, p, pal);
            u1 = u;
            v1 = v;
            a1 = a;
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);

581
            YUVA_IN(y, u, v, a, p + BPP, pal);
582 583 584 585 586 587 588 589 590 591 592 593 594
            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);

595
            YUVA_IN(y, u, v, a, p + BPP, pal);
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
            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;
        }
629 630
        p += wrap3 + (wrap3 - dstw * BPP);
        lum += wrap + (wrap - dstw - dstx);
631 632 633 634 635
        cb += dst->linesize[1] - width2 - skip2;
        cr += dst->linesize[2] - width2 - skip2;
    }
    /* handle odd height */
    if (h) {
636
        lum += dstx;
637 638
        cb += skip2;
        cr += skip2;
639

640
        if (dstx & 1) {
641 642 643 644 645 646 647 648 649
            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;
        }
650
        for(w = dstw - (dstx & 1); w >= 2; w -= 2) {
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
            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)
{
680
    avsubtitle_free(&sp->sub);
681 682
}

Fabrice Bellard's avatar
Fabrice Bellard committed
683 684 685
static void video_image_display(VideoState *is)
{
    VideoPicture *vp;
686 687
    SubPicture *sp;
    AVPicture pict;
Fabrice Bellard's avatar
Fabrice Bellard committed
688 689 690
    float aspect_ratio;
    int width, height, x, y;
    SDL_Rect rect;
691
    int i;
Fabrice Bellard's avatar
Fabrice Bellard committed
692 693 694

    vp = &is->pictq[is->pictq_rindex];
    if (vp->bmp) {
695
#if CONFIG_AVFILTER
696
         if (vp->picref->video->pixel_aspect.num == 0)
697 698
             aspect_ratio = 0;
         else
699
             aspect_ratio = av_q2d(vp->picref->video->pixel_aspect);
700 701
#else

Fabrice Bellard's avatar
Fabrice Bellard committed
702
        /* XXX: use variable in the frame */
703 704 705 706
        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
707
        else
708
            aspect_ratio = 0;
709
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
710
        if (aspect_ratio <= 0.0)
711
            aspect_ratio = 1.0;
712
        aspect_ratio *= (float)vp->width / (float)vp->height;
Fabrice Bellard's avatar
Fabrice Bellard committed
713

714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
        if (is->subtitle_st)
        {
            if (is->subpq_size > 0)
            {
                sp = &is->subpq[is->subpq_rindex];

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

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

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

                    for (i = 0; i < sp->sub.num_rects; i++)
733
                        blend_subrect(&pict, sp->sub.rects[i],
734
                                      vp->bmp->w, vp->bmp->h);
735 736 737 738 739 740 741

                    SDL_UnlockYUVOverlay (vp->bmp);
                }
            }
        }


Fabrice Bellard's avatar
Fabrice Bellard committed
742 743
        /* XXX: we suppose the screen has a 1.0 pixel ratio */
        height = is->height;
744
        width = ((int)rint(height * aspect_ratio)) & ~1;
Fabrice Bellard's avatar
Fabrice Bellard committed
745 746
        if (width > is->width) {
            width = is->width;
747
            height = ((int)rint(width / aspect_ratio)) & ~1;
Fabrice Bellard's avatar
Fabrice Bellard committed
748 749 750 751 752 753 754 755 756 757
        }
        x = (is->width - width) / 2;
        y = (is->height - height) / 2;
        if (!is->no_background) {
            /* fill the background */
            //            fill_border(is, x, y, width, height, QERGB(0x00, 0x00, 0x00));
        } else {
            is->no_background = 0;
        }
        rect.x = is->xleft + x;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
758
        rect.y = is->ytop  + y;
Fabrice Bellard's avatar
Fabrice Bellard committed
759 760 761 762 763
        rect.w = width;
        rect.h = height;
        SDL_DisplayYUVOverlay(vp->bmp, &rect);
    } else {
#if 0
764 765
        fill_rectangle(screen,
                       is->xleft, is->ytop, is->width, is->height,
Fabrice Bellard's avatar
Fabrice Bellard committed
766 767 768 769 770 771 772 773
                       QERGB(0x00, 0x00, 0x00));
#endif
    }
}

static inline int compute_mod(int a, int b)
{
    a = a % b;
774
    if (a >= 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
775 776 777 778 779 780 781 782 783 784
        return a;
    else
        return a + b;
}

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

    for(rdft_bits=1; (1<<rdft_bits)<2*s->height; rdft_bits++)
        ;
    nb_freq= 1<<(rdft_bits-1);
790

Fabrice Bellard's avatar
Fabrice Bellard committed
791
    /* compute display index : center on currently output samples */
792
    channels = s->audio_st->codec->channels;
Fabrice Bellard's avatar
Fabrice Bellard committed
793
    nb_display_channels = channels;
794
    if (!s->paused) {
795
        int data_used= s->show_audio==1 ? s->width : (2*nb_freq);
796 797 798
        n = 2 * channels;
        delay = audio_write_get_buf_size(s);
        delay /= n;
799

800 801 802 803
        /* 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;
804
            delay -= (time_diff * s->audio_st->codec->sample_rate) / 1000000;
805
        }
806

807
        delay += 2*data_used;
808 809
        if (delay < data_used)
            delay = data_used;
810 811

        i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
812
        if(s->show_audio==1){
813 814 815 816 817 818 819 820 821 822 823 824
            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;
                }
825 826 827
            }
        }

828 829 830
        s->last_i_start = i_start;
    } else {
        i_start = s->last_i_start;
Fabrice Bellard's avatar
Fabrice Bellard committed
831 832 833
    }

    bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
834
    if(s->show_audio==1){
835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
        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;
        for(ch = 0;ch < nb_display_channels; ch++) {
            i = i_start + ch;
            y1 = s->ytop + ch * h + (h / 2); /* position of center line */
            for(x = 0; x < s->width; x++) {
                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
862 863 864
            }
        }

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

867 868 869 870 871 872 873
        for(ch = 1;ch < nb_display_channels; ch++) {
            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);
874 875 876
    }else{
        nb_display_channels= FFMIN(nb_display_channels, 2);
        if(rdft_bits != s->rdft_bits){
877
            av_rdft_end(s->rdft);
Måns Rullgård's avatar
Måns Rullgård committed
878
            av_free(s->rdft_data);
879
            s->rdft = av_rdft_init(rdft_bits, DFT_R2C);
880
            s->rdft_bits= rdft_bits;
Måns Rullgård's avatar
Måns Rullgård committed
881
            s->rdft_data= av_malloc(4*nb_freq*sizeof(*s->rdft_data));
882 883
        }
        {
Måns Rullgård's avatar
Måns Rullgård committed
884
            FFTSample *data[2];
885
            for(ch = 0;ch < nb_display_channels; ch++) {
Måns Rullgård's avatar
Måns Rullgård committed
886
                data[ch] = s->rdft_data + 2*nb_freq*ch;
887 888 889 890 891 892 893 894
                i = i_start + ch;
                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);
                    i += channels;
                    if (i >= SAMPLE_ARRAY_SIZE)
                        i -= SAMPLE_ARRAY_SIZE;
                }
895
                av_rdft_calc(s->rdft, data[ch]);
896 897
            }
            //least efficient way to do this, we should of course directly access it but its more than fast enough
898
            for(y=0; y<s->height; y++){
899 900
                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]));
901 902
                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;
903 904 905 906 907 908 909 910 911 912 913 914 915 916
                a= FFMIN(a,255);
                b= FFMIN(b,255);
                fgcolor = SDL_MapRGB(screen->format, a, b, (a+b)/2);

                fill_rectangle(screen,
                            s->xpos, s->height-y, 1, 1,
                            fgcolor);
            }
        }
        SDL_UpdateRect(screen, s->xpos, s->ytop, 1, s->height);
        s->xpos++;
        if(s->xpos >= s->width)
            s->xpos= s->xleft;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
917 918
}

919 920 921 922
static int video_open(VideoState *is){
    int flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
    int w,h;

923 924 925
    if(is_full_screen) flags |= SDL_FULLSCREEN;
    else               flags |= SDL_RESIZABLE;

926 927 928
    if (is_full_screen && fs_screen_width) {
        w = fs_screen_width;
        h = fs_screen_height;
929 930 931
    } else if(!is_full_screen && screen_width){
        w = screen_width;
        h = screen_height;
932 933 934 935 936
#if CONFIG_AVFILTER
    }else if (is->out_video_filter && is->out_video_filter->inputs[0]){
        w = is->out_video_filter->inputs[0]->w;
        h = is->out_video_filter->inputs[0]->h;
#else
937 938 939
    }else if (is->video_st && is->video_st->codec->width){
        w = is->video_st->codec->width;
        h = is->video_st->codec->height;
940
#endif
941
    } else {
942 943
        w = 640;
        h = 480;
944
    }
945 946 947 948
    if(screen && is->width == screen->w && screen->w == w
       && is->height== screen->h && screen->h == h)
        return 0;

949
#ifndef __APPLE__
950 951 952 953 954 955 956 957 958
    screen = SDL_SetVideoMode(w, h, 0, flags);
#else
    /* setting bits_per_pixel = 0 or 32 causes blank video on OS X */
    screen = SDL_SetVideoMode(w, h, 24, flags);
#endif
    if (!screen) {
        fprintf(stderr, "SDL: could not set video mode - exiting\n");
        return -1;
    }
959 960 961
    if (!window_title)
        window_title = input_filename;
    SDL_WM_SetCaption(window_title, window_title);
962 963 964 965 966 967

    is->width = screen->w;
    is->height = screen->h;

    return 0;
}
968

Fabrice Bellard's avatar
Fabrice Bellard committed
969 970 971
/* display the current picture, if any */
static void video_display(VideoState *is)
{
972 973
    if(!screen)
        video_open(cur_stream);
974
    if (is->audio_st && is->show_audio)
Fabrice Bellard's avatar
Fabrice Bellard committed
975 976 977 978 979
        video_audio_display(is);
    else if (is->video_st)
        video_image_display(is);
}

980
static int refresh_thread(void *opaque)
Fabrice Bellard's avatar
Fabrice Bellard committed
981
{
982 983
    VideoState *is= opaque;
    while(!is->abort_request){
984 985 986
        SDL_Event event;
        event.type = FF_REFRESH_EVENT;
        event.user.data1 = opaque;
987 988
        if(!is->refresh){
            is->refresh=1;
989
            SDL_PushEvent(&event);
990
        }
991
        usleep(is->audio_st && is->show_audio ? rdftspeed*1000 : 5000); //FIXME ideally we should wait the correct time but SDLs event passing is so slow it would be silly
992 993
    }
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
994 995
}

996 997 998 999 1000 1001 1002 1003 1004
/* get the current audio clock value */
static double get_audio_clock(VideoState *is)
{
    double pts;
    int hw_buf_size, bytes_per_sec;
    pts = is->audio_clock;
    hw_buf_size = audio_write_get_buf_size(is);
    bytes_per_sec = 0;
    if (is->audio_st) {
1005
        bytes_per_sec = is->audio_st->codec->sample_rate *
1006
            2 * is->audio_st->codec->channels;
1007 1008 1009 1010 1011 1012 1013 1014 1015
    }
    if (bytes_per_sec)
        pts -= (double)hw_buf_size / bytes_per_sec;
    return pts;
}

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

/* 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
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
    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 {
1047
        val = get_external_clock(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
1048
    }
1049 1050 1051
    return val;
}

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

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

1078
static double compute_target_time(double frame_current_pts, VideoState *is)
1079
{
1080
    double delay, sync_threshold, diff;
1081 1082 1083 1084 1085 1086

    /* compute nominal delay */
    delay = frame_current_pts - is->frame_last_pts;
    if (delay <= 0 || delay >= 10.0) {
        /* if incorrect delay, use previous one */
        delay = is->frame_last_delay;
1087
    } else {
1088
        is->frame_last_delay = delay;
1089
    }
1090 1091 1092 1093 1094 1095 1096
    is->frame_last_pts = frame_current_pts;

    /* update delay to follow master synchronisation source */
    if (((is->av_sync_type == AV_SYNC_AUDIO_MASTER && is->audio_st) ||
         is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {
        /* if video is slave, we try to correct big delays by
           duplicating or deleting a frame */
1097
        diff = get_video_clock(is) - get_master_clock(is);
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110

        /* skip or repeat frame. We take into account the
           delay to compute the threshold. I still don't know
           if it is the best guess */
        sync_threshold = FFMAX(AV_SYNC_THRESHOLD, delay);
        if (fabs(diff) < AV_NOSYNC_THRESHOLD) {
            if (diff <= -sync_threshold)
                delay = 0;
            else if (diff >= sync_threshold)
                delay = 2 * delay;
        }
    }
    is->frame_timer += delay;
1111 1112 1113 1114 1115
#if defined(DEBUG_SYNC)
    printf("video: delay=%0.3f actual_delay=%0.3f pts=%0.3f A-V=%f\n",
            delay, actual_delay, frame_current_pts, -diff);
#endif

1116
    return is->frame_timer;
1117 1118
}

Fabrice Bellard's avatar
Fabrice Bellard committed
1119 1120 1121 1122 1123
/* called to display each frame */
static void video_refresh_timer(void *opaque)
{
    VideoState *is = opaque;
    VideoPicture *vp;
1124

1125
    SubPicture *sp, *sp2;
Fabrice Bellard's avatar
Fabrice Bellard committed
1126 1127

    if (is->video_st) {
1128
retry:
Fabrice Bellard's avatar
Fabrice Bellard committed
1129
        if (is->pictq_size == 0) {
1130
            //nothing to do, no picture to display in the que
Fabrice Bellard's avatar
Fabrice Bellard committed
1131
        } else {
1132 1133
            double time= av_gettime()/1000000.0;
            double next_target;
1134
            /* dequeue the picture */
Fabrice Bellard's avatar
Fabrice Bellard committed
1135
            vp = &is->pictq[is->pictq_rindex];
1136

1137 1138
            if(time < vp->target_clock)
                return;
1139 1140
            /* update current video pts */
            is->video_current_pts = vp->pts;
1141
            is->video_current_pts_drift = is->video_current_pts - time;
1142
            is->video_current_pos = vp->pos;
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
            if(is->pictq_size > 1){
                VideoPicture *nextvp= &is->pictq[(is->pictq_rindex+1)%VIDEO_PICTURE_QUEUE_SIZE];
                assert(nextvp->target_clock >= vp->target_clock);
                next_target= nextvp->target_clock;
            }else{
                next_target= vp->target_clock + is->video_clock - vp->pts; //FIXME pass durations cleanly
            }
            if(framedrop && time > next_target){
                is->skip_frames *= 1.0 + FRAME_SKIP_FACTOR;
                if(is->pictq_size > 1 || time > next_target + 0.5){
                    /* update queue size and signal for next picture */
                    if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
                        is->pictq_rindex = 0;

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

1165 1166 1167
            if(is->subtitle_st) {
                if (is->subtitle_stream_changed) {
                    SDL_LockMutex(is->subpq_mutex);
1168

1169 1170
                    while (is->subpq_size) {
                        free_subpicture(&is->subpq[is->subpq_rindex]);
1171

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

1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208
                        is->subpq_size--;
                    }
                    is->subtitle_stream_changed = 0;

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

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

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

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

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

Fabrice Bellard's avatar
Fabrice Bellard committed
1209
            /* display picture */
1210
            if (!display_disable)
1211
                video_display(is);
1212

Fabrice Bellard's avatar
Fabrice Bellard committed
1213 1214 1215
            /* update queue size and signal for next picture */
            if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
                is->pictq_rindex = 0;
1216

Fabrice Bellard's avatar
Fabrice Bellard committed
1217 1218 1219 1220 1221 1222 1223 1224 1225 1226
            SDL_LockMutex(is->pictq_mutex);
            is->pictq_size--;
            SDL_CondSignal(is->pictq_cond);
            SDL_UnlockMutex(is->pictq_mutex);
        }
    } else if (is->audio_st) {
        /* draw the next audio frame */

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

Fabrice Bellard's avatar
Fabrice Bellard committed
1228
        /* display picture */
1229
        if (!display_disable)
1230
            video_display(is);
Fabrice Bellard's avatar
Fabrice Bellard committed
1231 1232 1233 1234
    }
    if (show_status) {
        static int64_t last_time;
        int64_t cur_time;
1235
        int aqsize, vqsize, sqsize;
1236
        double av_diff;
1237

Fabrice Bellard's avatar
Fabrice Bellard committed
1238
        cur_time = av_gettime();
1239
        if (!last_time || (cur_time - last_time) >= 30000) {
Fabrice Bellard's avatar
Fabrice Bellard committed
1240 1241
            aqsize = 0;
            vqsize = 0;
1242
            sqsize = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1243 1244 1245 1246
            if (is->audio_st)
                aqsize = is->audioq.size;
            if (is->video_st)
                vqsize = is->videoq.size;
1247 1248
            if (is->subtitle_st)
                sqsize = is->subtitleq.size;
1249 1250 1251
            av_diff = 0;
            if (is->audio_st && is->video_st)
                av_diff = get_audio_clock(is) - get_video_clock(is);
1252
            printf("%7.2f A-V:%7.3f s:%3.1f aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64"   \r",
1253 1254 1255 1256 1257 1258 1259 1260
                   get_master_clock(is),
                   av_diff,
                   FFMAX(is->skip_frames-1, 0),
                   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
1261 1262 1263 1264 1265 1266
            fflush(stdout);
            last_time = cur_time;
        }
    }
}

1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306
static void stream_close(VideoState *is)
{
    VideoPicture *vp;
    int i;
    /* XXX: use a special url_shutdown call to abort parse cleanly */
    is->abort_request = 1;
    SDL_WaitThread(is->parse_tid, NULL);
    SDL_WaitThread(is->refresh_tid, NULL);

    /* free all pictures */
    for(i=0;i<VIDEO_PICTURE_QUEUE_SIZE; i++) {
        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);
}

static void do_exit(void)
{
    if (cur_stream) {
        stream_close(cur_stream);
        cur_stream = NULL;
    }
1307
    uninit_opts();
1308 1309 1310 1311 1312 1313
#if CONFIG_AVFILTER
    avfilter_uninit();
#endif
    if (show_status)
        printf("\n");
    SDL_Quit();
1314
    av_log(NULL, AV_LOG_QUIET, "");
1315 1316 1317
    exit(0);
}

Fabrice Bellard's avatar
Fabrice Bellard committed
1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329
/* 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);

1330 1331
#if CONFIG_AVFILTER
    if (vp->picref)
1332
        avfilter_unref_buffer(vp->picref);
1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344
    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,
1345
                                   SDL_YV12_OVERLAY,
1346
                                   screen);
1347 1348 1349 1350
    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"
1351
                        "size of %dx%d pixels. Try using -lowres or -vf \"scale=w:h\"\n"
1352 1353 1354
                        "to reduce the image size.\n", vp->width, vp->height );
        do_exit();
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
1355 1356 1357 1358 1359 1360 1361

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

1362 1363 1364 1365
/**
 *
 * @param pts the dts of the pkt / pts of the frame and guessed if not known
 */
1366
static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t pos)
Fabrice Bellard's avatar
Fabrice Bellard committed
1367 1368 1369
{
    VideoPicture *vp;
    int dst_pix_fmt;
1370 1371 1372
#if CONFIG_AVFILTER
    AVPicture pict_src;
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
1373 1374
    /* wait until we have space to put a new picture */
    SDL_LockMutex(is->pictq_mutex);
1375 1376 1377 1378

    if(is->pictq_size>=VIDEO_PICTURE_QUEUE_SIZE && !is->refresh)
        is->skip_frames= FFMAX(1.0 - FRAME_SKIP_FACTOR, is->skip_frames * (1.0-FRAME_SKIP_FACTOR));

Fabrice Bellard's avatar
Fabrice Bellard committed
1379 1380 1381 1382 1383
    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);
1384

Fabrice Bellard's avatar
Fabrice Bellard committed
1385 1386 1387 1388 1389 1390
    if (is->videoq.abort_request)
        return -1;

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

    /* alloc or resize hardware picture buffer */
1391
    if (!vp->bmp ||
1392 1393 1394 1395
#if CONFIG_AVFILTER
        vp->width  != is->out_video_filter->inputs[0]->w ||
        vp->height != is->out_video_filter->inputs[0]->h) {
#else
1396 1397
        vp->width != is->video_st->codec->width ||
        vp->height != is->video_st->codec->height) {
1398
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
1399 1400 1401 1402 1403 1404 1405 1406 1407
        SDL_Event event;

        vp->allocated = 0;

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

Fabrice Bellard's avatar
Fabrice Bellard committed
1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419
        /* wait until the picture is allocated */
        SDL_LockMutex(is->pictq_mutex);
        while (!vp->allocated && !is->videoq.abort_request) {
            SDL_CondWait(is->pictq_cond, is->pictq_mutex);
        }
        SDL_UnlockMutex(is->pictq_mutex);

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

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

Fabrice Bellard's avatar
Fabrice Bellard committed
1429 1430 1431 1432
        /* get a pointer on the bitmap */
        SDL_LockYUVOverlay (vp->bmp);

        dst_pix_fmt = PIX_FMT_YUV420P;
1433
        memset(&pict,0,sizeof(AVPicture));
Fabrice Bellard's avatar
Fabrice Bellard committed
1434 1435 1436 1437 1438 1439 1440
        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];
1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454

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

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

        //FIXME use direct rendering
        av_picture_copy(&pict, &pict_src,
                        vp->pix_fmt, vp->width, vp->height);
#else
1455
        sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
1456
        is->img_convert_ctx = sws_getCachedContext(is->img_convert_ctx,
1457
            vp->width, vp->height, vp->pix_fmt, vp->width, vp->height,
1458
            dst_pix_fmt, sws_flags, NULL, NULL, NULL);
1459
        if (is->img_convert_ctx == NULL) {
1460 1461 1462
            fprintf(stderr, "Cannot initialize the conversion context\n");
            exit(1);
        }
1463
        sws_scale(is->img_convert_ctx, src_frame->data, src_frame->linesize,
1464 1465
                  0, vp->height, pict.data, pict.linesize);
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
1466 1467 1468
        /* update the bitmap content */
        SDL_UnlockYUVOverlay(vp->bmp);

1469
        vp->pts = pts;
1470
        vp->pos = pos;
Fabrice Bellard's avatar
Fabrice Bellard committed
1471 1472 1473 1474 1475

        /* now we can update the picture count */
        if (++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE)
            is->pictq_windex = 0;
        SDL_LockMutex(is->pictq_mutex);
1476 1477
        vp->target_clock= compute_target_time(vp->pts, is);

Fabrice Bellard's avatar
Fabrice Bellard committed
1478 1479 1480
        is->pictq_size++;
        SDL_UnlockMutex(is->pictq_mutex);
    }
1481 1482 1483
    return 0;
}

1484 1485
/**
 * compute the exact PTS for the picture if it is omitted in the stream
1486 1487
 * @param pts1 the dts of the pkt / pts of the frame
 */
1488
static int output_picture2(VideoState *is, AVFrame *src_frame, double pts1, int64_t pos)
1489 1490
{
    double frame_delay, pts;
1491

1492 1493
    pts = pts1;

Fabrice Bellard's avatar
Fabrice Bellard committed
1494
    if (pts != 0) {
1495
        /* update video clock with pts, if present */
Fabrice Bellard's avatar
Fabrice Bellard committed
1496 1497
        is->video_clock = pts;
    } else {
Fabrice Bellard's avatar
Fabrice Bellard committed
1498 1499 1500
        pts = is->video_clock;
    }
    /* update video clock for next frame */
1501
    frame_delay = av_q2d(is->video_st->codec->time_base);
Fabrice Bellard's avatar
Fabrice Bellard committed
1502 1503
    /* for MPEG2, the frame can be repeated, so we update the
       clock accordingly */
1504
    frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);
Fabrice Bellard's avatar
Fabrice Bellard committed
1505
    is->video_clock += frame_delay;
1506 1507

#if defined(DEBUG_SYNC) && 0
1508 1509
    printf("frame_type=%c clock=%0.3f pts=%0.3f\n",
           av_get_pict_type_char(src_frame->pict_type), pts, pts1);
1510
#endif
1511
    return queue_picture(is, src_frame, pts, pos);
Fabrice Bellard's avatar
Fabrice Bellard committed
1512 1513
}

1514
static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacket *pkt)
Fabrice Bellard's avatar
Fabrice Bellard committed
1515
{
1516
    int len1, got_picture, i;
Fabrice Bellard's avatar
Fabrice Bellard committed
1517

1518 1519
    if (packet_queue_get(&is->videoq, pkt, 1) < 0)
        return -1;
1520

1521 1522
    if (pkt->data == flush_pkt.data) {
        avcodec_flush_buffers(is->video_st->codec);
1523

1524 1525 1526 1527 1528 1529 1530
        SDL_LockMutex(is->pictq_mutex);
        //Make sure there are no long delay timers (ideally we should just flush the que but thats harder)
        for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
            is->pictq[i].target_clock= 0;
        }
        while (is->pictq_size && !is->videoq.abort_request) {
            SDL_CondWait(is->pictq_cond, is->pictq_mutex);
1531
        }
1532 1533
        is->video_current_pos = -1;
        SDL_UnlockMutex(is->pictq_mutex);
1534

1535 1536 1537 1538 1539 1540 1541
        is->frame_last_pts = AV_NOPTS_VALUE;
        is->frame_last_delay = 0;
        is->frame_timer = (double)av_gettime() / 1000000.0;
        is->skip_frames = 1;
        is->skip_frames_index = 0;
        return 0;
    }
1542

1543 1544 1545 1546 1547 1548
    len1 = avcodec_decode_video2(is->video_st->codec,
                                 frame, &got_picture,
                                 pkt);

    if (got_picture) {
        if (decoder_reorder_pts == -1) {
1549
            *pts = frame->best_effort_timestamp;
1550
        } else if (decoder_reorder_pts) {
1551
            *pts = frame->pkt_pts;
1552
        } else {
1553
            *pts = frame->pkt_dts;
1554 1555 1556 1557
        }

        if (*pts == AV_NOPTS_VALUE) {
            *pts = 0;
1558
        }
1559

1560 1561 1562 1563 1564 1565 1566
        is->skip_frames_index += 1;
        if(is->skip_frames_index >= is->skip_frames){
            is->skip_frames_index -= FFMAX(is->skip_frames, 1.0);
            return 1;
        }

    }
1567 1568 1569 1570 1571 1572 1573
    return 0;
}

#if CONFIG_AVFILTER
typedef struct {
    VideoState *is;
    AVFrame *frame;
1574
    int use_dr1;
1575 1576
} FilterPriv;

1577 1578 1579
static int input_get_buffer(AVCodecContext *codec, AVFrame *pic)
{
    AVFilterContext *ctx = codec->opaque;
1580
    AVFilterBufferRef  *ref;
1581
    int perms = AV_PERM_WRITE;
1582
    int i, w, h, stride[4];
1583 1584
    unsigned edge;

1585 1586 1587
    if (codec->codec->capabilities & CODEC_CAP_NEG_LINESIZES)
        perms |= AV_PERM_NEG_LINESIZES;

1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604
    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;
    }
    if(pic->reference) perms |= AV_PERM_READ | AV_PERM_PRESERVE;

    w = codec->width;
    h = codec->height;
    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;

    if(!(ref = avfilter_get_video_buffer(ctx->outputs[0], perms, w, h)))
        return -1;

1605 1606
    ref->video->w = codec->width;
    ref->video->h = codec->height;
1607
    for(i = 0; i < 4; i ++) {
1608 1609
        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;
1610

1611
        if (ref->data[i]) {
1612
            ref->data[i]    += (edge >> hshift) + ((edge * ref->linesize[i]) >> vshift);
1613
        }
1614 1615 1616 1617 1618 1619
        pic->data[i]     = ref->data[i];
        pic->linesize[i] = ref->linesize[i];
    }
    pic->opaque = ref;
    pic->age    = INT_MAX;
    pic->type   = FF_BUFFER_TYPE_USER;
1620
    pic->reordered_opaque = codec->reordered_opaque;
1621 1622
    if(codec->pkt) pic->pkt_pts = codec->pkt->pts;
    else           pic->pkt_pts = AV_NOPTS_VALUE;
1623 1624 1625 1626 1627 1628
    return 0;
}

static void input_release_buffer(AVCodecContext *codec, AVFrame *pic)
{
    memset(pic->data, 0, sizeof(pic->data));
1629
    avfilter_unref_buffer(pic->opaque);
1630 1631
}

1632 1633
static int input_reget_buffer(AVCodecContext *codec, AVFrame *pic)
{
1634
    AVFilterBufferRef *ref = pic->opaque;
1635 1636 1637 1638 1639 1640

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

1641
    if ((codec->width != ref->video->w) || (codec->height != ref->video->h) ||
1642
        (codec->pix_fmt != ref->format)) {
1643 1644 1645 1646 1647
        av_log(codec, AV_LOG_ERROR, "Picture properties changed.\n");
        return -1;
    }

    pic->reordered_opaque = codec->reordered_opaque;
1648 1649
    if(codec->pkt) pic->pkt_pts = codec->pkt->pts;
    else           pic->pkt_pts = AV_NOPTS_VALUE;
1650 1651 1652
    return 0;
}

1653 1654 1655
static int input_init(AVFilterContext *ctx, const char *args, void *opaque)
{
    FilterPriv *priv = ctx->priv;
1656
    AVCodecContext *codec;
1657 1658 1659
    if(!opaque) return -1;

    priv->is = opaque;
1660 1661 1662 1663 1664 1665
    codec    = priv->is->video_st->codec;
    codec->opaque = ctx;
    if(codec->codec->capabilities & CODEC_CAP_DR1) {
        priv->use_dr1 = 1;
        codec->get_buffer     = input_get_buffer;
        codec->release_buffer = input_release_buffer;
1666
        codec->reget_buffer   = input_reget_buffer;
1667
        codec->thread_safe_callbacks = 1;
1668 1669
    }

1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683
    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;
1684
    AVFilterBufferRef *picref;
1685
    int64_t pts = 0;
1686 1687 1688 1689 1690 1691 1692 1693
    AVPacket pkt;
    int ret;

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

1694
    if(priv->use_dr1) {
1695
        picref = avfilter_ref_buffer(priv->frame->opaque, ~0);
1696
    } else {
Bobby Bingham's avatar
Bobby Bingham committed
1697
        picref = avfilter_get_video_buffer(link, AV_PERM_WRITE, link->w, link->h);
1698
        av_image_copy(picref->data, picref->linesize,
Stefano Sabatini's avatar
Stefano Sabatini committed
1699 1700
                      priv->frame->data, priv->frame->linesize,
                      picref->format, link->w, link->h);
1701
    }
1702 1703 1704
    av_free_packet(&pkt);

    picref->pts = pts;
1705
    picref->pos = pkt.pos;
1706
    picref->video->pixel_aspect = priv->is->video_st->codec->sample_aspect_ratio;
1707
    avfilter_start_frame(link, picref);
1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731
    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
    };

    avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts));
    return 0;
}

static int input_config_props(AVFilterLink *link)
{
    FilterPriv *priv  = link->src->priv;
    AVCodecContext *c = priv->is->video_st->codec;

    link->w = c->width;
    link->h = c->height;
1732
    link->time_base = priv->is->video_st->time_base;
1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749

    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",
1750
                                    .type = AVMEDIA_TYPE_VIDEO,
1751 1752 1753 1754 1755
                                    .request_frame = input_request_frame,
                                    .config_props  = input_config_props, },
                                  { .name = NULL }},
};

1756
static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters)
1757
{
Stefano Sabatini's avatar
Stefano Sabatini committed
1758
    char sws_flags_str[128];
1759
    int ret;
1760
    FFSinkContext ffsink_ctx = { .pix_fmt = PIX_FMT_YUV420P };
1761
    AVFilterContext *filt_src = NULL, *filt_out = NULL;
Stefano Sabatini's avatar
Stefano Sabatini committed
1762 1763
    snprintf(sws_flags_str, sizeof(sws_flags_str), "flags=%d", sws_flags);
    graph->scale_sws_opts = av_strdup(sws_flags_str);
1764

1765 1766
    if ((ret = avfilter_graph_create_filter(&filt_src, &input_filter, "src",
                                            NULL, is, graph)) < 0)
1767
        goto the_end;
1768 1769
    if ((ret = avfilter_graph_create_filter(&filt_out, &ffsink, "out",
                                            NULL, &ffsink_ctx, graph)) < 0)
1770
        goto the_end;
1771 1772 1773 1774 1775 1776

    if(vfilters) {
        AVFilterInOut *outputs = av_malloc(sizeof(AVFilterInOut));
        AVFilterInOut *inputs  = av_malloc(sizeof(AVFilterInOut));

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

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

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

1794
    if ((ret = avfilter_graph_config(graph, NULL)) < 0)
1795
        goto the_end;
1796 1797

    is->out_video_filter = filt_out;
1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819
the_end:
    return ret;
}

#endif  /* CONFIG_AVFILTER */

static int video_thread(void *arg)
{
    VideoState *is = arg;
    AVFrame *frame= avcodec_alloc_frame();
    int64_t pts_int;
    double pts;
    int ret;

#if CONFIG_AVFILTER
    AVFilterGraph *graph = avfilter_graph_alloc();
    AVFilterContext *filt_out = NULL;
    int64_t pos;

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

    for(;;) {
#if !CONFIG_AVFILTER
        AVPacket pkt;
1825
#else
1826
        AVFilterBufferRef *picref;
1827
        AVRational tb;
1828 1829 1830 1831
#endif
        while (is->paused && !is->videoq.abort_request)
            SDL_Delay(10);
#if CONFIG_AVFILTER
1832 1833 1834 1835 1836 1837
        ret = get_filtered_video_frame(filt_out, frame, &picref, &tb);
        if (picref) {
            pts_int = picref->pts;
            pos     = picref->pos;
            frame->opaque = picref;
        }
1838 1839

        if (av_cmp_q(tb, is->video_st->time_base)) {
1840
            av_unused int64_t pts1 = pts_int;
1841
            pts_int = av_rescale_q(pts_int, tb, is->video_st->time_base);
1842 1843 1844 1845
            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);
1846
        }
1847 1848 1849 1850 1851 1852 1853 1854 1855
#else
        ret = get_video_frame(is, frame, &pts_int, &pkt);
#endif

        if (ret < 0) goto the_end;

        if (!ret)
            continue;

1856
        pts = pts_int*av_q2d(is->video_st->time_base);
1857 1858

#if CONFIG_AVFILTER
1859
        ret = output_picture2(is, frame, pts, pos);
1860
#else
1861
        ret = output_picture2(is, frame, pts,  pkt.pos);
1862 1863 1864 1865 1866
        av_free_packet(&pkt);
#endif
        if (ret < 0)
            goto the_end;

1867
        if (step)
1868 1869
            if (cur_stream)
                stream_pause(cur_stream);
Fabrice Bellard's avatar
Fabrice Bellard committed
1870 1871
    }
 the_end:
1872
#if CONFIG_AVFILTER
1873
    avfilter_graph_free(&graph);
1874
#endif
1875
    av_free(frame);
Fabrice Bellard's avatar
Fabrice Bellard committed
1876 1877 1878
    return 0;
}

1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894
static int subtitle_thread(void *arg)
{
    VideoState *is = arg;
    SubPicture *sp;
    AVPacket pkt1, *pkt = &pkt1;
    int len1, got_subtitle;
    double pts;
    int i, j;
    int r, g, b, y, u, v, a;

    for(;;) {
        while (is->paused && !is->subtitleq.abort_request) {
            SDL_Delay(10);
        }
        if (packet_queue_get(&is->subtitleq, pkt, 1) < 0)
            break;
1895

1896 1897 1898 1899
        if(pkt->data == flush_pkt.data){
            avcodec_flush_buffers(is->subtitle_st->codec);
            continue;
        }
1900 1901 1902 1903 1904 1905
        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);
1906

1907 1908
        if (is->subtitleq.abort_request)
            goto the_end;
1909

1910 1911 1912 1913 1914 1915 1916 1917
        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)
            pts = av_q2d(is->subtitle_st->time_base)*pkt->pts;

1918
        len1 = avcodec_decode_subtitle2(is->subtitle_st->codec,
1919
                                    &sp->sub, &got_subtitle,
1920
                                    pkt);
1921 1922 1923 1924
//            if (len1 < 0)
//                break;
        if (got_subtitle && sp->sub.format == 0) {
            sp->pts = pts;
1925

1926 1927
            for (i = 0; i < sp->sub.num_rects; i++)
            {
1928
                for (j = 0; j < sp->sub.rects[i]->nb_colors; j++)
1929
                {
1930
                    RGBA_IN(r, g, b, a, (uint32_t*)sp->sub.rects[i]->pict.data[1] + j);
1931 1932 1933
                    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);
1934
                    YUVA_OUT((uint32_t*)sp->sub.rects[i]->pict.data[1] + j, y, u, v, a);
1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945
                }
            }

            /* 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);
1946
//        if (step)
1947 1948 1949 1950 1951 1952 1953
//            if (cur_stream)
//                stream_pause(cur_stream);
    }
 the_end:
    return 0;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
1954 1955 1956 1957 1958
/* copy samples for viewing in editor window */
static void update_sample_display(VideoState *is, short *samples, int samples_size)
{
    int size, len, channels;

1959
    channels = is->audio_st->codec->channels;
Fabrice Bellard's avatar
Fabrice Bellard committed
1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976

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

/* return the new audio buffer size (samples can be added or deleted
   to get better sync if video or external master clock) */
1977
static int synchronize_audio(VideoState *is, short *samples,
1978
                             int samples_size1, double pts)
Fabrice Bellard's avatar
Fabrice Bellard committed
1979
{
1980
    int n, samples_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
1981
    double ref_clock;
1982

1983
    n = 2 * is->audio_st->codec->channels;
1984
    samples_size = samples_size1;
Fabrice Bellard's avatar
Fabrice Bellard committed
1985 1986 1987

    /* 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) ||
1988 1989
         is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {
        double diff, avg_diff;
Fabrice Bellard's avatar
Fabrice Bellard committed
1990
        int wanted_size, min_size, max_size, nb_samples;
1991

1992 1993
        ref_clock = get_master_clock(is);
        diff = get_audio_clock(is) - ref_clock;
1994

1995 1996 1997 1998 1999 2000 2001 2002 2003 2004
        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) {
2005
                    wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n);
2006
                    nb_samples = samples_size / n;
2007

2008 2009 2010 2011 2012 2013
                    min_size = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n;
                    max_size = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n;
                    if (wanted_size < min_size)
                        wanted_size = min_size;
                    else if (wanted_size > max_size)
                        wanted_size = max_size;
2014

2015 2016 2017 2018 2019 2020 2021
                    /* add or remove samples to correction the synchro */
                    if (wanted_size < samples_size) {
                        /* remove samples */
                        samples_size = wanted_size;
                    } else if (wanted_size > samples_size) {
                        uint8_t *samples_end, *q;
                        int nb;
2022

2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035
                        /* add samples */
                        nb = (samples_size - wanted_size);
                        samples_end = (uint8_t *)samples + samples_size - n;
                        q = samples_end + n;
                        while (nb > 0) {
                            memcpy(q, samples_end, n);
                            q += n;
                            nb -= n;
                        }
                        samples_size = wanted_size;
                    }
                }
#if 0
2036 2037
                printf("diff=%f adiff=%f sample_diff=%d apts=%0.3f vpts=%0.3f %f\n",
                       diff, avg_diff, samples_size - samples_size1,
2038 2039
                       is->audio_clock, is->video_clock, is->audio_diff_threshold);
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
2040
            }
2041 2042 2043 2044 2045
        } else {
            /* too big difference : may be initial PTS errors, so
               reset A-V filter */
            is->audio_diff_avg_count = 0;
            is->audio_diff_cum = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2046 2047 2048 2049 2050 2051 2052
        }
    }

    return samples_size;
}

/* decode one audio frame and returns its uncompressed size */
2053
static int audio_decode_frame(VideoState *is, double *pts_ptr)
Fabrice Bellard's avatar
Fabrice Bellard committed
2054
{
2055
    AVPacket *pkt_temp = &is->audio_pkt_temp;
Fabrice Bellard's avatar
Fabrice Bellard committed
2056
    AVPacket *pkt = &is->audio_pkt;
2057
    AVCodecContext *dec= is->audio_st->codec;
Fabrice Bellard's avatar
Fabrice Bellard committed
2058
    int n, len1, data_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
2059 2060 2061
    double pts;

    for(;;) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2062
        /* NOTE: the audio packet can contain several frames */
2063
        while (pkt_temp->size > 0) {
2064
            data_size = sizeof(is->audio_buf1);
2065
            len1 = avcodec_decode_audio3(dec,
2066
                                        (int16_t *)is->audio_buf1, &data_size,
2067
                                        pkt_temp);
Fabrice Bellard's avatar
Fabrice Bellard committed
2068 2069
            if (len1 < 0) {
                /* if error, we skip the frame */
2070
                pkt_temp->size = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2071
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2072
            }
2073

2074 2075
            pkt_temp->data += len1;
            pkt_temp->size -= len1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2076 2077
            if (data_size <= 0)
                continue;
2078 2079 2080 2081

            if (dec->sample_fmt != is->audio_src_fmt) {
                if (is->reformat_ctx)
                    av_audio_convert_free(is->reformat_ctx);
2082
                is->reformat_ctx= av_audio_convert_alloc(AV_SAMPLE_FMT_S16, 1,
2083 2084 2085
                                                         dec->sample_fmt, 1, NULL, 0);
                if (!is->reformat_ctx) {
                    fprintf(stderr, "Cannot convert %s sample format to %s sample format\n",
2086
                        av_get_sample_fmt_name(dec->sample_fmt),
2087
                        av_get_sample_fmt_name(AV_SAMPLE_FMT_S16));
2088 2089 2090 2091 2092 2093 2094 2095
                        break;
                }
                is->audio_src_fmt= dec->sample_fmt;
            }

            if (is->reformat_ctx) {
                const void *ibuf[6]= {is->audio_buf1};
                void *obuf[6]= {is->audio_buf2};
2096
                int istride[6]= {av_get_bits_per_sample_fmt(dec->sample_fmt)/8};
2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110
                int ostride[6]= {2};
                int len= data_size/istride[0];
                if (av_audio_convert(is->reformat_ctx, obuf, ostride, ibuf, istride, len)<0) {
                    printf("av_audio_convert() failed\n");
                    break;
                }
                is->audio_buf= is->audio_buf2;
                /* FIXME: existing code assume that data_size equals framesize*channels*2
                          remove this legacy cruft */
                data_size= len*2;
            }else{
                is->audio_buf= is->audio_buf1;
            }

Fabrice Bellard's avatar
Fabrice Bellard committed
2111 2112 2113
            /* if no pts, then compute it */
            pts = is->audio_clock;
            *pts_ptr = pts;
2114
            n = 2 * dec->channels;
2115
            is->audio_clock += (double)data_size /
2116
                (double)(n * dec->sample_rate);
2117
#if defined(DEBUG_SYNC)
Fabrice Bellard's avatar
Fabrice Bellard committed
2118 2119 2120 2121 2122 2123
            {
                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
2124
            }
Fabrice Bellard's avatar
Fabrice Bellard committed
2125 2126
#endif
            return data_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
2127 2128
        }

Fabrice Bellard's avatar
Fabrice Bellard committed
2129 2130
        /* free the current packet */
        if (pkt->data)
Fabrice Bellard's avatar
Fabrice Bellard committed
2131
            av_free_packet(pkt);
2132

Fabrice Bellard's avatar
Fabrice Bellard committed
2133 2134 2135
        if (is->paused || is->audioq.abort_request) {
            return -1;
        }
2136

Fabrice Bellard's avatar
Fabrice Bellard committed
2137 2138 2139
        /* read next packet */
        if (packet_queue_get(&is->audioq, pkt, 1) < 0)
            return -1;
2140
        if(pkt->data == flush_pkt.data){
2141
            avcodec_flush_buffers(dec);
2142 2143 2144
            continue;
        }

2145 2146
        pkt_temp->data = pkt->data;
        pkt_temp->size = pkt->size;
2147

Fabrice Bellard's avatar
Fabrice Bellard committed
2148 2149
        /* if update the audio clock with the pts */
        if (pkt->pts != AV_NOPTS_VALUE) {
2150
            is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts;
Fabrice Bellard's avatar
Fabrice Bellard committed
2151
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
2152 2153 2154
    }
}

2155 2156 2157
/* get the current audio output buffer size, in samples. With SDL, we
   cannot have a precise information */
static int audio_write_get_buf_size(VideoState *is)
Fabrice Bellard's avatar
Fabrice Bellard committed
2158
{
2159
    return is->audio_buf_size - is->audio_buf_index;
Fabrice Bellard's avatar
Fabrice Bellard committed
2160 2161 2162 2163
}


/* prepare a new audio buffer */
2164
static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
Fabrice Bellard's avatar
Fabrice Bellard committed
2165 2166 2167 2168 2169 2170
{
    VideoState *is = opaque;
    int audio_size, len1;
    double pts;

    audio_callback_time = av_gettime();
2171

Fabrice Bellard's avatar
Fabrice Bellard committed
2172 2173
    while (len > 0) {
        if (is->audio_buf_index >= is->audio_buf_size) {
2174
           audio_size = audio_decode_frame(is, &pts);
Fabrice Bellard's avatar
Fabrice Bellard committed
2175 2176
           if (audio_size < 0) {
                /* if error, just output silence */
2177
               is->audio_buf = is->audio_buf1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2178 2179 2180 2181 2182
               is->audio_buf_size = 1024;
               memset(is->audio_buf, 0, is->audio_buf_size);
           } else {
               if (is->show_audio)
                   update_sample_display(is, (int16_t *)is->audio_buf, audio_size);
2183
               audio_size = synchronize_audio(is, (int16_t *)is->audio_buf, audio_size,
Fabrice Bellard's avatar
Fabrice Bellard committed
2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202
                                              pts);
               is->audio_buf_size = audio_size;
           }
           is->audio_buf_index = 0;
        }
        len1 = is->audio_buf_size - is->audio_buf_index;
        if (len1 > len)
            len1 = len;
        memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
        len -= len1;
        stream += len1;
        is->audio_buf_index += len1;
    }
}

/* open a given stream. Return 0 if OK */
static int stream_component_open(VideoState *is, int stream_index)
{
    AVFormatContext *ic = is->ic;
2203
    AVCodecContext *avctx;
Fabrice Bellard's avatar
Fabrice Bellard committed
2204 2205 2206 2207 2208
    AVCodec *codec;
    SDL_AudioSpec wanted_spec, spec;

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

Fabrice Bellard's avatar
Fabrice Bellard committed
2211
    /* prepare audio output */
2212
    if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
2213 2214
        if (avctx->channels > 0) {
            avctx->request_channels = FFMIN(2, avctx->channels);
2215
        } else {
2216
            avctx->request_channels = 2;
2217
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
2218 2219
    }

2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232
    codec = avcodec_find_decoder(avctx->codec_id);
    avctx->debug_mv = debug_mv;
    avctx->debug = debug;
    avctx->workaround_bugs = workaround_bugs;
    avctx->lowres = lowres;
    if(lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE;
    avctx->idct_algo= idct;
    if(fast) avctx->flags2 |= CODEC_FLAG2_FAST;
    avctx->skip_frame= skip_frame;
    avctx->skip_idct= skip_idct;
    avctx->skip_loop_filter= skip_loop_filter;
    avctx->error_recognition= error_recognition;
    avctx->error_concealment= error_concealment;
2233
    avctx->thread_count= thread_count;
2234

2235
    set_context_opts(avctx, avcodec_opts[avctx->codec_type], 0, codec);
2236

Fabrice Bellard's avatar
Fabrice Bellard committed
2237
    if (!codec ||
2238
        avcodec_open(avctx, codec) < 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
2239
        return -1;
2240 2241

    /* prepare audio output */
2242
    if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
2243
        wanted_spec.freq = avctx->sample_rate;
2244
        wanted_spec.format = AUDIO_S16SYS;
2245
        wanted_spec.channels = avctx->channels;
2246 2247 2248 2249 2250 2251 2252 2253 2254
        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;
2255
        is->audio_src_fmt= AV_SAMPLE_FMT_S16;
2256 2257
    }

2258
    ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
2259
    switch(avctx->codec_type) {
2260
    case AVMEDIA_TYPE_AUDIO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2261 2262 2263 2264
        is->audio_stream = stream_index;
        is->audio_st = ic->streams[stream_index];
        is->audio_buf_size = 0;
        is->audio_buf_index = 0;
2265 2266 2267 2268 2269 2270

        /* init averaging filter */
        is->audio_diff_avg_coef = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
        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 */
2271
        is->audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / avctx->sample_rate;
2272

Fabrice Bellard's avatar
Fabrice Bellard committed
2273 2274
        memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
        packet_queue_init(&is->audioq);
2275
        SDL_PauseAudio(0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2276
        break;
2277
    case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2278 2279 2280
        is->video_stream = stream_index;
        is->video_st = ic->streams[stream_index];

2281
//        is->video_current_pts_time = av_gettime();
2282

Fabrice Bellard's avatar
Fabrice Bellard committed
2283 2284 2285
        packet_queue_init(&is->videoq);
        is->video_tid = SDL_CreateThread(video_thread, is);
        break;
2286
    case AVMEDIA_TYPE_SUBTITLE:
2287 2288 2289
        is->subtitle_stream = stream_index;
        is->subtitle_st = ic->streams[stream_index];
        packet_queue_init(&is->subtitleq);
2290

2291 2292
        is->subtitle_tid = SDL_CreateThread(subtitle_thread, is);
        break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2293 2294 2295 2296 2297 2298 2299 2300 2301
    default:
        break;
    }
    return 0;
}

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

2304 2305
    if (stream_index < 0 || stream_index >= ic->nb_streams)
        return;
2306
    avctx = ic->streams[stream_index]->codec;
Fabrice Bellard's avatar
Fabrice Bellard committed
2307

2308
    switch(avctx->codec_type) {
2309
    case AVMEDIA_TYPE_AUDIO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2310 2311 2312 2313 2314
        packet_queue_abort(&is->audioq);

        SDL_CloseAudio();

        packet_queue_end(&is->audioq);
2315 2316
        if (is->reformat_ctx)
            av_audio_convert_free(is->reformat_ctx);
2317
        is->reformat_ctx = NULL;
Fabrice Bellard's avatar
Fabrice Bellard committed
2318
        break;
2319
    case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331
        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;
2332
    case AVMEDIA_TYPE_SUBTITLE:
2333
        packet_queue_abort(&is->subtitleq);
2334

2335 2336 2337 2338
        /* 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;
2339

2340 2341 2342 2343 2344 2345 2346
        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
2347 2348 2349 2350
    default:
        break;
    }

2351
    ic->streams[stream_index]->discard = AVDISCARD_ALL;
2352 2353
    avcodec_close(avctx);
    switch(avctx->codec_type) {
2354
    case AVMEDIA_TYPE_AUDIO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2355 2356 2357
        is->audio_st = NULL;
        is->audio_stream = -1;
        break;
2358
    case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
2359 2360 2361
        is->video_st = NULL;
        is->video_stream = -1;
        break;
2362
    case AVMEDIA_TYPE_SUBTITLE:
2363 2364 2365
        is->subtitle_st = NULL;
        is->subtitle_stream = -1;
        break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2366 2367 2368 2369 2370
    default:
        break;
    }
}

2371 2372 2373 2374 2375 2376 2377 2378
/* since we have only one decoding thread, we can use a global
   variable instead of a thread local variable */
static VideoState *global_video_state;

static int decode_interrupt_cb(void)
{
    return (global_video_state && global_video_state->abort_request);
}
Fabrice Bellard's avatar
Fabrice Bellard committed
2379 2380 2381 2382 2383 2384

/* this thread gets the stream from the disk or the network */
static int decode_thread(void *arg)
{
    VideoState *is = arg;
    AVFormatContext *ic;
2385
    int err, i, ret;
2386
    int st_index[AVMEDIA_TYPE_NB];
Fabrice Bellard's avatar
Fabrice Bellard committed
2387
    AVPacket pkt1, *pkt = &pkt1;
2388
    AVFormatParameters params, *ap = &params;
2389
    int eof=0;
2390
    int pkt_in_play_range = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2391

2392 2393
    ic = avformat_alloc_context();

2394
    memset(st_index, -1, sizeof(st_index));
Fabrice Bellard's avatar
Fabrice Bellard committed
2395 2396
    is->video_stream = -1;
    is->audio_stream = -1;
2397
    is->subtitle_stream = -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2398

2399 2400 2401
    global_video_state = is;
    url_set_interrupt_cb(decode_interrupt_cb);

2402
    memset(ap, 0, sizeof(*ap));
2403

2404
    ap->prealloced_context = 1;
2405 2406
    ap->width = frame_width;
    ap->height= frame_height;
Michael Niedermayer's avatar
Michael Niedermayer committed
2407
    ap->time_base= (AVRational){1, 25};
2408
    ap->pix_fmt = frame_pix_fmt;
Michael Niedermayer's avatar
Michael Niedermayer committed
2409

2410
    set_context_opts(ic, avformat_opts, AV_OPT_FLAG_DECODING_PARAM, NULL);
2411

2412
    err = av_open_input_file(&ic, is->filename, is->iformat, 0, ap);
2413 2414 2415 2416 2417
    if (err < 0) {
        print_error(is->filename, err);
        ret = -1;
        goto fail;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2418
    is->ic = ic;
2419 2420 2421 2422

    if(genpts)
        ic->flags |= AVFMT_FLAG_GENPTS;

2423 2424 2425 2426 2427 2428
    err = av_find_stream_info(ic);
    if (err < 0) {
        fprintf(stderr, "%s: could not find codec parameters\n", is->filename);
        ret = -1;
        goto fail;
    }
2429 2430
    if(ic->pb)
        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
2431

2432 2433 2434
    if(seek_by_bytes<0)
        seek_by_bytes= !!(ic->iformat->flags & AVFMT_TS_DISCONT);

Fabrice Bellard's avatar
Fabrice Bellard committed
2435 2436 2437 2438 2439 2440 2441 2442
    /* 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;
2443
        ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2444
        if (ret < 0) {
2445
            fprintf(stderr, "%s: could not seek to position %0.3f\n",
Fabrice Bellard's avatar
Fabrice Bellard committed
2446 2447 2448 2449
                    is->filename, (double)timestamp / AV_TIME_BASE);
        }
    }

2450
    for (i = 0; i < ic->nb_streams; i++)
2451
        ic->streams[i]->discard = AVDISCARD_ALL;
2452
    if (!video_disable)
2453 2454 2455
        st_index[AVMEDIA_TYPE_VIDEO] =
            av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,
                                wanted_stream[AVMEDIA_TYPE_VIDEO], -1, NULL, 0);
2456
    if (!audio_disable)
2457 2458 2459 2460 2461
        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);
2462
    if (!video_disable)
2463 2464 2465 2466 2467 2468 2469
        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
2470
    if (show_status) {
2471
        av_dump_format(ic, 0, is->filename, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
2472 2473 2474
    }

    /* open the streams */
2475 2476
    if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {
        stream_component_open(is, st_index[AVMEDIA_TYPE_AUDIO]);
Fabrice Bellard's avatar
Fabrice Bellard committed
2477 2478
    }

Michael Niedermayer's avatar
Michael Niedermayer committed
2479
    ret=-1;
2480 2481
    if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
        ret= stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO]);
Michael Niedermayer's avatar
Michael Niedermayer committed
2482
    }
2483
    is->refresh_tid = SDL_CreateThread(refresh_thread, is);
Michael Niedermayer's avatar
Michael Niedermayer committed
2484
    if(ret<0) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2485
        if (!display_disable)
2486
            is->show_audio = 2;
Fabrice Bellard's avatar
Fabrice Bellard committed
2487 2488
    }

2489 2490
    if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) {
        stream_component_open(is, st_index[AVMEDIA_TYPE_SUBTITLE]);
2491 2492
    }

Fabrice Bellard's avatar
Fabrice Bellard committed
2493
    if (is->video_stream < 0 && is->audio_stream < 0) {
2494 2495
        fprintf(stderr, "%s: could not open codecs\n", is->filename);
        ret = -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2496 2497 2498 2499 2500 2501
        goto fail;
    }

    for(;;) {
        if (is->abort_request)
            break;
2502 2503
        if (is->paused != is->last_paused) {
            is->last_paused = is->paused;
Fabrice Bellard's avatar
Fabrice Bellard committed
2504
            if (is->paused)
2505
                is->read_pause_return= av_read_pause(ic);
Fabrice Bellard's avatar
Fabrice Bellard committed
2506 2507
            else
                av_read_play(ic);
2508
        }
2509 2510
#if CONFIG_RTSP_DEMUXER
        if (is->paused && !strcmp(ic->iformat->name, "rtsp")) {
2511 2512 2513 2514 2515
            /* wait 10 ms to avoid trying to get another packet */
            /* XXX: horrible */
            SDL_Delay(10);
            continue;
        }
2516
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
2517
        if (is->seek_req) {
2518
            int64_t seek_target= is->seek_pos;
2519 2520 2521 2522
            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
//      of the seek_pos/seek_rel variables
2523

2524
            ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags);
Fabrice Bellard's avatar
Fabrice Bellard committed
2525 2526
            if (ret < 0) {
                fprintf(stderr, "%s: error while seeking\n", is->ic->filename);
2527 2528 2529
            }else{
                if (is->audio_stream >= 0) {
                    packet_queue_flush(&is->audioq);
2530
                    packet_queue_put(&is->audioq, &flush_pkt);
2531
                }
2532 2533
                if (is->subtitle_stream >= 0) {
                    packet_queue_flush(&is->subtitleq);
2534
                    packet_queue_put(&is->subtitleq, &flush_pkt);
2535
                }
2536 2537
                if (is->video_stream >= 0) {
                    packet_queue_flush(&is->videoq);
2538
                    packet_queue_put(&is->videoq, &flush_pkt);
2539
                }
Fabrice Bellard's avatar
Fabrice Bellard committed
2540 2541
            }
            is->seek_req = 0;
2542
            eof= 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2543
        }
2544

Fabrice Bellard's avatar
Fabrice Bellard committed
2545
        /* if the queue are full, no need to read more */
2546 2547 2548 2549
        if (   is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
            || (   (is->audioq   .size  > MIN_AUDIOQ_SIZE || is->audio_stream<0)
                && (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
2550 2551 2552 2553
            /* wait 10 ms */
            SDL_Delay(10);
            continue;
        }
2554
        if(eof) {
2555
            if(is->video_stream >= 0){
Michael Niedermayer's avatar
Michael Niedermayer committed
2556 2557 2558 2559 2560
                av_init_packet(pkt);
                pkt->data=NULL;
                pkt->size=0;
                pkt->stream_index= is->video_stream;
                packet_queue_put(&is->videoq, pkt);
2561
            }
2562
            SDL_Delay(10);
2563 2564 2565 2566 2567 2568 2569
            if(is->audioq.size + is->videoq.size + is->subtitleq.size ==0){
                if(loop!=1 && (!loop || --loop)){
                    stream_seek(cur_stream, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0);
                }else if(autoexit){
                    ret=AVERROR_EOF;
                    goto fail;
                }
Michael Niedermayer's avatar
Michael Niedermayer committed
2570
            }
2571
            eof=0;
2572 2573
            continue;
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
2574
        ret = av_read_frame(ic, pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
2575
        if (ret < 0) {
2576
            if (ret == AVERROR_EOF || url_feof(ic->pb))
2577
                eof=1;
2578
            if (ic->pb && ic->pb->error)
2579
                break;
2580 2581
            SDL_Delay(100); /* wait for user event */
            continue;
Fabrice Bellard's avatar
Fabrice Bellard committed
2582
        }
2583 2584 2585 2586 2587 2588 2589
        /* 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) -
                (double)(start_time != AV_NOPTS_VALUE ? start_time : 0)/1000000
                <= ((double)duration/1000000);
        if (pkt->stream_index == is->audio_stream && pkt_in_play_range) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2590
            packet_queue_put(&is->audioq, pkt);
2591
        } else if (pkt->stream_index == is->video_stream && pkt_in_play_range) {
Fabrice Bellard's avatar
Fabrice Bellard committed
2592
            packet_queue_put(&is->videoq, pkt);
2593
        } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {
2594
            packet_queue_put(&is->subtitleq, pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
2595 2596 2597 2598 2599 2600 2601 2602 2603
        } else {
            av_free_packet(pkt);
        }
    }
    /* wait until the end */
    while (!is->abort_request) {
        SDL_Delay(100);
    }

2604
    ret = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2605
 fail:
2606 2607 2608
    /* disable interrupting */
    global_video_state = NULL;

Fabrice Bellard's avatar
Fabrice Bellard committed
2609 2610 2611 2612 2613
    /* 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);
2614 2615
    if (is->subtitle_stream >= 0)
        stream_component_close(is, is->subtitle_stream);
2616 2617 2618 2619
    if (is->ic) {
        av_close_input_file(is->ic);
        is->ic = NULL; /* safety */
    }
2620 2621
    url_set_interrupt_cb(NULL);

2622 2623
    if (ret != 0) {
        SDL_Event event;
2624

2625 2626 2627 2628
        event.type = FF_QUIT_EVENT;
        event.user.data1 = is;
        SDL_PushEvent(&event);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2629 2630 2631
    return 0;
}

2632
static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
Fabrice Bellard's avatar
Fabrice Bellard committed
2633 2634 2635 2636 2637 2638
{
    VideoState *is;

    is = av_mallocz(sizeof(VideoState));
    if (!is)
        return NULL;
2639
    av_strlcpy(is->filename, filename, sizeof(is->filename));
2640
    is->iformat = iformat;
Fabrice Bellard's avatar
Fabrice Bellard committed
2641 2642 2643 2644 2645 2646
    is->ytop = 0;
    is->xleft = 0;

    /* start video display */
    is->pictq_mutex = SDL_CreateMutex();
    is->pictq_cond = SDL_CreateCond();
2647

2648 2649
    is->subpq_mutex = SDL_CreateMutex();
    is->subpq_cond = SDL_CreateCond();
2650

2651
    is->av_sync_type = av_sync_type;
Fabrice Bellard's avatar
Fabrice Bellard committed
2652 2653 2654 2655 2656 2657 2658 2659
    is->parse_tid = SDL_CreateThread(decode_thread, is);
    if (!is->parse_tid) {
        av_free(is);
        return NULL;
    }
    return is;
}

2660
static void stream_cycle_channel(VideoState *is, int codec_type)
2661 2662 2663 2664 2665
{
    AVFormatContext *ic = is->ic;
    int start_index, stream_index;
    AVStream *st;

2666
    if (codec_type == AVMEDIA_TYPE_VIDEO)
2667
        start_index = is->video_stream;
2668
    else if (codec_type == AVMEDIA_TYPE_AUDIO)
2669
        start_index = is->audio_stream;
2670 2671
    else
        start_index = is->subtitle_stream;
2672
    if (start_index < (codec_type == AVMEDIA_TYPE_SUBTITLE ? -1 : 0))
2673 2674 2675 2676
        return;
    stream_index = start_index;
    for(;;) {
        if (++stream_index >= is->ic->nb_streams)
2677
        {
2678
            if (codec_type == AVMEDIA_TYPE_SUBTITLE)
2679 2680 2681 2682 2683 2684
            {
                stream_index = -1;
                goto the_end;
            } else
                stream_index = 0;
        }
2685 2686 2687
        if (stream_index == start_index)
            return;
        st = ic->streams[stream_index];
2688
        if (st->codec->codec_type == codec_type) {
2689 2690
            /* check that parameters are OK */
            switch(codec_type) {
2691
            case AVMEDIA_TYPE_AUDIO:
2692 2693
                if (st->codec->sample_rate != 0 &&
                    st->codec->channels != 0)
2694 2695
                    goto the_end;
                break;
2696 2697
            case AVMEDIA_TYPE_VIDEO:
            case AVMEDIA_TYPE_SUBTITLE:
2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709
                goto the_end;
            default:
                break;
            }
        }
    }
 the_end:
    stream_component_close(is, start_index);
    stream_component_open(is, stream_index);
}


2710
static void toggle_full_screen(void)
Fabrice Bellard's avatar
Fabrice Bellard committed
2711 2712
{
    is_full_screen = !is_full_screen;
2713 2714
    if (!fs_screen_width) {
        /* use default SDL method */
2715
//        SDL_WM_ToggleFullScreen(screen);
Fabrice Bellard's avatar
Fabrice Bellard committed
2716
    }
2717
    video_open(cur_stream);
Fabrice Bellard's avatar
Fabrice Bellard committed
2718 2719
}

2720
static void toggle_pause(void)
Fabrice Bellard's avatar
Fabrice Bellard committed
2721 2722 2723
{
    if (cur_stream)
        stream_pause(cur_stream);
2724 2725 2726
    step = 0;
}

2727
static void step_to_next_frame(void)
2728 2729
{
    if (cur_stream) {
2730
        /* if the stream is paused unpause it, then step */
2731
        if (cur_stream->paused)
2732
            stream_pause(cur_stream);
2733 2734
    }
    step = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
2735 2736
}

2737
static void toggle_audio_display(void)
Fabrice Bellard's avatar
Fabrice Bellard committed
2738 2739
{
    if (cur_stream) {
2740
        int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
2741
        cur_stream->show_audio = (cur_stream->show_audio + 1) % 3;
2742 2743 2744 2745
        fill_rectangle(screen,
                    cur_stream->xleft, cur_stream->ytop, cur_stream->width, cur_stream->height,
                    bgcolor);
        SDL_UpdateRect(screen, cur_stream->xleft, cur_stream->ytop, cur_stream->width, cur_stream->height);
Fabrice Bellard's avatar
Fabrice Bellard committed
2746 2747 2748 2749
    }
}

/* handle an event sent by the GUI */
2750
static void event_loop(void)
Fabrice Bellard's avatar
Fabrice Bellard committed
2751 2752
{
    SDL_Event event;
2753
    double incr, pos, frac;
Fabrice Bellard's avatar
Fabrice Bellard committed
2754 2755

    for(;;) {
Michael Niedermayer's avatar
Michael Niedermayer committed
2756
        double x;
Fabrice Bellard's avatar
Fabrice Bellard committed
2757 2758 2759
        SDL_WaitEvent(&event);
        switch(event.type) {
        case SDL_KEYDOWN:
2760 2761 2762 2763
            if (exit_on_keydown) {
                do_exit();
                break;
            }
Fabrice Bellard's avatar
Fabrice Bellard committed
2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775
            switch(event.key.keysym.sym) {
            case SDLK_ESCAPE:
            case SDLK_q:
                do_exit();
                break;
            case SDLK_f:
                toggle_full_screen();
                break;
            case SDLK_p:
            case SDLK_SPACE:
                toggle_pause();
                break;
2776 2777 2778
            case SDLK_s: //S: Step to next frame
                step_to_next_frame();
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2779
            case SDLK_a:
2780
                if (cur_stream)
2781
                    stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
2782 2783
                break;
            case SDLK_v:
2784
                if (cur_stream)
2785
                    stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
2786
                break;
2787
            case SDLK_t:
2788
                if (cur_stream)
2789
                    stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
2790
                break;
2791
            case SDLK_w:
Fabrice Bellard's avatar
Fabrice Bellard committed
2792 2793
                toggle_audio_display();
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806
            case SDLK_LEFT:
                incr = -10.0;
                goto do_seek;
            case SDLK_RIGHT:
                incr = 10.0;
                goto do_seek;
            case SDLK_UP:
                incr = 60.0;
                goto do_seek;
            case SDLK_DOWN:
                incr = -60.0;
            do_seek:
                if (cur_stream) {
2807
                    if (seek_by_bytes) {
2808 2809 2810 2811 2812
                        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
2813
                            pos = avio_tell(cur_stream->ic->pb);
2814
                        if (cur_stream->ic->bit_rate)
2815
                            incr *= cur_stream->ic->bit_rate / 8.0;
2816 2817 2818
                        else
                            incr *= 180000.0;
                        pos += incr;
2819
                        stream_seek(cur_stream, pos, incr, 1);
2820 2821 2822
                    } else {
                        pos = get_master_clock(cur_stream);
                        pos += incr;
2823
                        stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0);
2824
                    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2825 2826
                }
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2827 2828 2829 2830
            default:
                break;
            }
            break;
2831
        case SDL_MOUSEBUTTONDOWN:
2832 2833 2834 2835
            if (exit_on_mousedown) {
                do_exit();
                break;
            }
Michael Niedermayer's avatar
Michael Niedermayer committed
2836 2837 2838 2839 2840 2841 2842 2843
        case SDL_MOUSEMOTION:
            if(event.type ==SDL_MOUSEBUTTONDOWN){
                x= event.button.x;
            }else{
                if(event.motion.state != SDL_PRESSED)
                    break;
                x= event.motion.x;
            }
2844
            if (cur_stream) {
2845
                if(seek_by_bytes || cur_stream->ic->duration<=0){
2846
                    uint64_t size=  avio_size(cur_stream->ic->pb);
Michael Niedermayer's avatar
Michael Niedermayer committed
2847
                    stream_seek(cur_stream, size*x/cur_stream->width, 0, 1);
2848
                }else{
Michael Niedermayer's avatar
Michael Niedermayer committed
2849 2850 2851 2852 2853 2854 2855
                    int64_t ts;
                    int ns, hh, mm, ss;
                    int tns, thh, tmm, tss;
                    tns = cur_stream->ic->duration/1000000LL;
                    thh = tns/3600;
                    tmm = (tns%3600)/60;
                    tss = (tns%60);
Michael Niedermayer's avatar
Michael Niedermayer committed
2856
                    frac = x/cur_stream->width;
Michael Niedermayer's avatar
Michael Niedermayer committed
2857 2858 2859 2860 2861 2862 2863 2864 2865 2866
                    ns = frac*tns;
                    hh = ns/3600;
                    mm = (ns%3600)/60;
                    ss = (ns%60);
                    fprintf(stderr, "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d)       \n", frac*100,
                            hh, mm, ss, thh, tmm, tss);
                    ts = frac*cur_stream->ic->duration;
                    if (cur_stream->ic->start_time != AV_NOPTS_VALUE)
                        ts += cur_stream->ic->start_time;
                    stream_seek(cur_stream, ts, 0, 0);
2867
                }
2868 2869
            }
            break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2870 2871
        case SDL_VIDEORESIZE:
            if (cur_stream) {
2872
                screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 0,
Fabrice Bellard's avatar
Fabrice Bellard committed
2873
                                          SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
2874 2875
                screen_width = cur_stream->width = event.resize.w;
                screen_height= cur_stream->height= event.resize.h;
Fabrice Bellard's avatar
Fabrice Bellard committed
2876 2877 2878
            }
            break;
        case SDL_QUIT:
2879
        case FF_QUIT_EVENT:
Fabrice Bellard's avatar
Fabrice Bellard committed
2880 2881 2882
            do_exit();
            break;
        case FF_ALLOC_EVENT:
2883
            video_open(event.user.data1);
Fabrice Bellard's avatar
Fabrice Bellard committed
2884 2885 2886 2887
            alloc_picture(event.user.data1);
            break;
        case FF_REFRESH_EVENT:
            video_refresh_timer(event.user.data1);
2888
            cur_stream->refresh=0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2889 2890 2891 2892 2893 2894 2895
            break;
        default:
            break;
        }
    }
}

2896 2897
static void opt_frame_size(const char *arg)
{
2898
    if (av_parse_video_size(&frame_width, &frame_height, arg) < 0) {
2899 2900 2901 2902 2903 2904 2905 2906 2907
        fprintf(stderr, "Incorrect frame size\n");
        exit(1);
    }
    if ((frame_width % 2) != 0 || (frame_height % 2) != 0) {
        fprintf(stderr, "Frame size must be a multiple of 2\n");
        exit(1);
    }
}

2908
static int opt_width(const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
2909
{
2910 2911
    screen_width = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2912 2913
}

2914
static int opt_height(const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
2915
{
2916 2917
    screen_height = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2918 2919 2920 2921 2922 2923 2924 2925 2926 2927
}

static void opt_format(const char *arg)
{
    file_iformat = av_find_input_format(arg);
    if (!file_iformat) {
        fprintf(stderr, "Unknown input format: %s\n", arg);
        exit(1);
    }
}
2928

2929 2930
static void opt_frame_pix_fmt(const char *arg)
{
2931
    frame_pix_fmt = av_get_pix_fmt(arg);
2932 2933
}

2934
static int opt_sync(const char *opt, const char *arg)
2935 2936 2937 2938 2939 2940 2941
{
    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;
2942
    else {
2943
        fprintf(stderr, "Unknown value for %s: %s\n", opt, arg);
2944 2945
        exit(1);
    }
2946
    return 0;
2947 2948
}

2949
static int opt_seek(const char *opt, const char *arg)
Fabrice Bellard's avatar
Fabrice Bellard committed
2950
{
2951 2952
    start_time = parse_time_or_die(opt, arg, 1);
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2953 2954
}

2955 2956 2957 2958 2959 2960
static int opt_duration(const char *opt, const char *arg)
{
    duration = parse_time_or_die(opt, arg, 1);
    return 0;
}

2961
static int opt_debug(const char *opt, const char *arg)
2962
{
2963
    av_log_set_level(99);
2964 2965
    debug = parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX);
    return 0;
2966
}
2967

2968
static int opt_vismv(const char *opt, const char *arg)
2969
{
2970 2971
    debug_mv = parse_number_or_die(opt, arg, OPT_INT64, INT_MIN, INT_MAX);
    return 0;
2972
}
2973

2974
static int opt_thread_count(const char *opt, const char *arg)
2975
{
2976
    thread_count= parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX);
2977
#if !HAVE_THREADS
2978 2979
    fprintf(stderr, "Warning: not compiled with thread support, using thread emulation\n");
#endif
2980
    return 0;
2981
}
2982

2983
static const OptionDef options[] = {
2984
#include "cmdutils_common_opts.h"
2985 2986
    { "x", HAS_ARG | OPT_FUNC2, {(void*)opt_width}, "force displayed width", "width" },
    { "y", HAS_ARG | OPT_FUNC2, {(void*)opt_height}, "force displayed height", "height" },
2987
    { "s", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_size}, "set frame size (WxH or abbreviation)", "size" },
2988
    { "fs", OPT_BOOL, {(void*)&is_full_screen}, "force full screen" },
Fabrice Bellard's avatar
Fabrice Bellard committed
2989 2990
    { "an", OPT_BOOL, {(void*)&audio_disable}, "disable audio" },
    { "vn", OPT_BOOL, {(void*)&video_disable}, "disable video" },
2991 2992 2993
    { "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" },
2994
    { "ss", HAS_ARG | OPT_FUNC2, {(void*)&opt_seek}, "seek to a given position in seconds", "pos" },
2995
    { "t", HAS_ARG | OPT_FUNC2, {(void*)&opt_duration}, "play  \"duration\" seconds of audio/video", "duration" },
2996
    { "bytes", OPT_INT | HAS_ARG, {(void*)&seek_by_bytes}, "seek by bytes 0=off 1=on -1=auto", "val" },
Fabrice Bellard's avatar
Fabrice Bellard committed
2997 2998
    { "nodisp", OPT_BOOL, {(void*)&display_disable}, "disable graphical display" },
    { "f", HAS_ARG, {(void*)opt_format}, "force format", "fmt" },
2999
    { "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_frame_pix_fmt}, "set pixel format", "format" },
3000
    { "stats", OPT_BOOL | OPT_EXPERT, {(void*)&show_status}, "show status", "" },
3001
    { "debug", HAS_ARG | OPT_FUNC2 | OPT_EXPERT, {(void*)opt_debug}, "print specific debug info", "" },
Michael Niedermayer's avatar
Michael Niedermayer committed
3002
    { "bug", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&workaround_bugs}, "workaround bugs", "" },
3003
    { "vismv", HAS_ARG | OPT_FUNC2 | OPT_EXPERT, {(void*)opt_vismv}, "visualize motion vectors", "" },
3004
    { "fast", OPT_BOOL | OPT_EXPERT, {(void*)&fast}, "non spec compliant optimizations", "" },
3005
    { "genpts", OPT_BOOL | OPT_EXPERT, {(void*)&genpts}, "generate pts", "" },
3006
    { "drp", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&decoder_reorder_pts}, "let decoder reorder pts 0=off 1=on -1=auto", ""},
3007
    { "lowres", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&lowres}, "", "" },
Michael Niedermayer's avatar
Michael Niedermayer committed
3008 3009 3010
    { "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}, "", "" },
3011
    { "idct", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&idct}, "set idct algo",  "algo" },
3012
    { "er", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&error_recognition}, "set error detection threshold (0-4)",  "threshold" },
3013
    { "ec", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&error_concealment}, "set error concealment options",  "bit_mask" },
3014
    { "sync", HAS_ARG | OPT_FUNC2 | OPT_EXPERT, {(void*)opt_sync}, "set audio-video sync. type (type=audio/video/ext)", "type" },
3015
    { "threads", HAS_ARG | OPT_FUNC2 | OPT_EXPERT, {(void*)opt_thread_count}, "thread count", "count" },
Michael Niedermayer's avatar
Michael Niedermayer committed
3016
    { "autoexit", OPT_BOOL | OPT_EXPERT, {(void*)&autoexit}, "exit at the end", "" },
3017 3018
    { "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", "" },
3019
    { "loop", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&loop}, "set number of times the playback shall be looped", "loop count" },
3020
    { "framedrop", OPT_BOOL | OPT_EXPERT, {(void*)&framedrop}, "drop frames when cpu is too slow", "" },
3021
    { "window_title", OPT_STRING | HAS_ARG, {(void*)&window_title}, "set window title", "window title" },
3022
#if CONFIG_AVFILTER
3023
    { "vf", OPT_STRING | HAS_ARG, {(void*)&vfilters}, "video filters", "filter list" },
3024
#endif
3025
    { "rdftspeed", OPT_INT | HAS_ARG| OPT_AUDIO | OPT_EXPERT, {(void*)&rdftspeed}, "rdft speed", "msecs" },
3026
    { "default", OPT_FUNC2 | HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {(void*)opt_default}, "generic catch all option", "" },
3027
    { "i", OPT_DUMMY, NULL, "ffmpeg compatibility dummy option", ""},
Fabrice Bellard's avatar
Fabrice Bellard committed
3028 3029 3030
    { NULL, },
};

3031
static void show_usage(void)
Fabrice Bellard's avatar
Fabrice Bellard committed
3032
{
3033 3034
    printf("Simple media player\n");
    printf("usage: ffplay [options] input_file\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
3035
    printf("\n");
3036 3037 3038 3039
}

static void show_help(void)
{
3040
    av_log_set_callback(log_callback_help);
3041
    show_usage();
3042 3043 3044 3045
    show_help_options(options, "Main options:\n",
                      OPT_EXPERT, 0);
    show_help_options(options, "\nAdvanced options:\n",
                      OPT_EXPERT, OPT_EXPERT);
3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056
    printf("\n");
    av_opt_show2(avcodec_opts[0], NULL,
                 AV_OPT_FLAG_DECODING_PARAM, 0);
    printf("\n");
    av_opt_show2(avformat_opts, NULL,
                 AV_OPT_FLAG_DECODING_PARAM, 0);
#if !CONFIG_AVFILTER
    printf("\n");
    av_opt_show2(sws_opts, NULL,
                 AV_OPT_FLAG_ENCODING_PARAM, 0);
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3057 3058 3059 3060
    printf("\nWhile playing:\n"
           "q, ESC              quit\n"
           "f                   toggle full screen\n"
           "p, SPC              pause\n"
3061 3062
           "a                   cycle audio channel\n"
           "v                   cycle video channel\n"
3063
           "t                   cycle subtitle channel\n"
3064
           "w                   show audio waves\n"
3065
           "s                   activate frame-step mode\n"
Fabrice Bellard's avatar
Fabrice Bellard committed
3066 3067
           "left/right          seek backward/forward 10 seconds\n"
           "down/up             seek backward/forward 1 minute\n"
3068
           "mouse click         seek to percentage in file corresponding to fraction of width\n"
Fabrice Bellard's avatar
Fabrice Bellard committed
3069 3070 3071
           );
}

3072
static void opt_input_file(const char *filename)
Fabrice Bellard's avatar
Fabrice Bellard committed
3073
{
3074 3075 3076 3077 3078
    if (input_filename) {
        fprintf(stderr, "Argument '%s' provided as input filename, but '%s' was already specified.\n",
                filename, input_filename);
        exit(1);
    }
3079
    if (!strcmp(filename, "-"))
3080
        filename = "pipe:";
Fabrice Bellard's avatar
Fabrice Bellard committed
3081 3082 3083 3084 3085 3086
    input_filename = filename;
}

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

3089 3090
    av_log_set_flags(AV_LOG_SKIP_REPEATED);

Fabrice Bellard's avatar
Fabrice Bellard committed
3091
    /* register all codecs, demux and protocols */
Luca Abeni's avatar
Luca Abeni committed
3092
    avcodec_register_all();
3093
#if CONFIG_AVDEVICE
Luca Abeni's avatar
Luca Abeni committed
3094
    avdevice_register_all();
3095
#endif
3096 3097 3098
#if CONFIG_AVFILTER
    avfilter_register_all();
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3099 3100
    av_register_all();

3101
    init_opts();
3102

3103
    show_banner();
3104

3105
    parse_options(argc, argv, options, opt_input_file);
Fabrice Bellard's avatar
Fabrice Bellard committed
3106

3107
    if (!input_filename) {
3108
        show_usage();
3109
        fprintf(stderr, "An input file must be specified\n");
3110
        fprintf(stderr, "Use -h to get full help or, even better, run 'man ffplay'\n");
3111 3112
        exit(1);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
3113 3114 3115 3116

    if (display_disable) {
        video_disable = 1;
    }
3117
    flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
3118 3119
#if !defined(__MINGW32__) && !defined(__APPLE__)
    flags |= SDL_INIT_EVENTTHREAD; /* Not supported on Windows or Mac OS X */
3120
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3121
    if (SDL_Init (flags)) {
3122
        fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
Fabrice Bellard's avatar
Fabrice Bellard committed
3123 3124 3125 3126
        exit(1);
    }

    if (!display_disable) {
3127
#if HAVE_SDL_VIDEO_SIZE
3128 3129 3130
        const SDL_VideoInfo *vi = SDL_GetVideoInfo();
        fs_screen_width = vi->current_w;
        fs_screen_height = vi->current_h;
3131
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
3132 3133 3134 3135 3136 3137
    }

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

3138 3139 3140
    av_init_packet(&flush_pkt);
    flush_pkt.data= "FLUSH";

3141
    cur_stream = stream_open(input_filename, file_iformat);
Fabrice Bellard's avatar
Fabrice Bellard committed
3142 3143 3144 3145 3146 3147 3148

    event_loop();

    /* never returns */

    return 0;
}