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

22 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 "libavutil/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

Michael Niedermayer's avatar
Michael Niedermayer committed
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

Michael Niedermayer's avatar
Michael Niedermayer committed
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
Michael Niedermayer's avatar
Michael Niedermayer committed
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;
Michael Niedermayer's avatar
Michael Niedermayer committed
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
    PtsCorrectionContext pts_ctx;
212

213 214 215
#if CONFIG_AVFILTER
    AVFilterContext *out_video_filter;          ///<the last filter in the video chain
#endif
Michael Niedermayer's avatar
Michael Niedermayer committed
216 217 218 219

    float skip_frames;
    float skip_frames_index;
    int refresh;
Fabrice Bellard's avatar
Fabrice Bellard committed
220 221
} VideoState;

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

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

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

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

280
static AVPacket flush_pkt;
281

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

286
static SDL_Surface *screen;
Fabrice Bellard's avatar
Fabrice Bellard committed
287

288 289
static int packet_queue_put(PacketQueue *q, AVPacket *pkt);

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

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

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

static void packet_queue_end(PacketQueue *q)
{
    packet_queue_flush(q);
Fabrice Bellard's avatar
Fabrice Bellard committed
319 320 321 322 323 324 325 326
    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
327
    /* duplicate the packet */
328
    if (pkt!=&flush_pkt && av_dup_packet(pkt) < 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
329
        return -1;
330

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

Fabrice Bellard's avatar
Fabrice Bellard committed
337

Fabrice Bellard's avatar
Fabrice Bellard committed
338 339 340 341 342 343 344 345 346
    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++;
347
    q->size += pkt1->pkt.size + sizeof(*pkt1);
Fabrice Bellard's avatar
Fabrice Bellard committed
348 349 350 351 352 353 354 355 356 357 358 359
    /* 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;
360

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

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

402
static inline void fill_rectangle(SDL_Surface *screen,
Fabrice Bellard's avatar
Fabrice Bellard committed
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 430 431
                                  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;
432 433 434
    fill_rectangle(screen,
                   s->xleft, s->ytop,
                   w1, s->height,
Fabrice Bellard's avatar
Fabrice Bellard committed
435
                   color);
436 437 438
    fill_rectangle(screen,
                   s->xleft + s->width - w2, s->ytop,
                   w2, s->height,
Fabrice Bellard's avatar
Fabrice Bellard committed
439
                   color);
440 441 442
    fill_rectangle(screen,
                   s->xleft + w1, s->ytop,
                   s->width - w1 - w2, h1,
Fabrice Bellard's avatar
Fabrice Bellard committed
443
                   color);
444
    fill_rectangle(screen,
Fabrice Bellard's avatar
Fabrice Bellard committed
445 446 447 448 449 450
                   s->xleft + w1, s->ytop + s->height - h2,
                   s->width - w1 - w2, h2,
                   color);
}
#endif

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

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

489 490 491 492
    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);
493 494 495 496
    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];

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

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

509
        if (dstx & 1) {
510 511 512 513 514 515 516 517 518
            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;
        }
519
        for(w = dstw - (dstx & 1); w >= 2; w -= 2) {
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542
            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);
543 544
            p++;
            lum++;
545
        }
546 547
        p += wrap3 - dstw * BPP;
        lum += wrap - dstw - dstx;
548 549 550
        cb += dst->linesize[1] - width2 - skip2;
        cr += dst->linesize[2] - width2 - skip2;
    }
551 552
    for(h = dsth - (dsty & 1); h >= 2; h -= 2) {
        lum += dstx;
553 554
        cb += skip2;
        cr += skip2;
555

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

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

597
            YUVA_IN(y, u, v, a, p + BPP, pal);
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 629 630
            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;
        }
631 632
        p += wrap3 + (wrap3 - dstw * BPP);
        lum += wrap + (wrap - dstw - dstx);
633 634 635 636 637
        cb += dst->linesize[1] - width2 - skip2;
        cr += dst->linesize[2] - width2 - skip2;
    }
    /* handle odd height */
    if (h) {
638
        lum += dstx;
639 640
        cb += skip2;
        cr += skip2;
641

642
        if (dstx & 1) {
643 644 645 646 647 648 649 650 651
            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;
        }
652
        for(w = dstw - (dstx & 1); w >= 2; w -= 2) {
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 680 681
            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)
{
682
    avsubtitle_free(&sp->sub);
683 684
}

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

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

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

716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734
        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++)
735
                        blend_subrect(&pict, sp->sub.rects[i],
736
                                      vp->bmp->w, vp->bmp->h);
737 738 739 740 741 742 743

                    SDL_UnlockYUVOverlay (vp->bmp);
                }
            }
        }


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

static inline int compute_mod(int a, int b)
{
    a = a % b;
776
    if (a >= 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
777 778 779 780 781 782 783 784 785 786
        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;
787 788 789 790 791
    int rdft_bits, nb_freq;

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

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

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

809
        delay += 2*data_used;
810 811
        if (delay < data_used)
            delay = data_used;
812 813

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

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

    bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
836
    if(s->show_audio==1){
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 862 863
        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
864 865 866
            }
        }

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

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

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

925 926 927
    if(is_full_screen) flags |= SDL_FULLSCREEN;
    else               flags |= SDL_RESIZABLE;

928 929 930
    if (is_full_screen && fs_screen_width) {
        w = fs_screen_width;
        h = fs_screen_height;
931 932 933
    } else if(!is_full_screen && screen_width){
        w = screen_width;
        h = screen_height;
934 935 936 937 938
#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
939 940 941
    }else if (is->video_st && is->video_st->codec->width){
        w = is->video_st->codec->width;
        h = is->video_st->codec->height;
942
#endif
943
    } else {
944 945
        w = 640;
        h = 480;
946
    }
947 948 949 950
    if(screen && is->width == screen->w && screen->w == w
       && is->height== screen->h && screen->h == h)
        return 0;

951
#ifndef __APPLE__
952 953 954 955 956 957 958 959 960
    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;
    }
961 962 963
    if (!window_title)
        window_title = input_filename;
    SDL_WM_SetCaption(window_title, window_title);
964 965 966 967 968 969

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

    return 0;
}
970

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

Michael Niedermayer's avatar
Michael Niedermayer committed
982
static int refresh_thread(void *opaque)
Fabrice Bellard's avatar
Fabrice Bellard committed
983
{
Michael Niedermayer's avatar
Michael Niedermayer committed
984 985
    VideoState *is= opaque;
    while(!is->abort_request){
986 987 988
        SDL_Event event;
        event.type = FF_REFRESH_EVENT;
        event.user.data1 = opaque;
Michael Niedermayer's avatar
Michael Niedermayer committed
989 990
        if(!is->refresh){
            is->refresh=1;
991
            SDL_PushEvent(&event);
Michael Niedermayer's avatar
Michael Niedermayer committed
992
        }
993
        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
Michael Niedermayer's avatar
Michael Niedermayer committed
994 995
    }
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
996 997
}

998 999 1000 1001 1002 1003 1004 1005 1006
/* 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) {
1007
        bytes_per_sec = is->audio_st->codec->sample_rate *
1008
            2 *