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

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

42 43 44
#if CONFIG_AVFILTER
# include "libavfilter/avfilter.h"
# include "libavfilter/avfiltergraph.h"
45
# include "libavfilter/buffersink.h"
46
# include "libavfilter/buffersrc.h"
47 48
#endif

Fabrice Bellard's avatar
Fabrice Bellard committed
49 50 51 52 53
#include "cmdutils.h"

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

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

Michael Niedermayer's avatar
Michael Niedermayer committed
58 59
#include <assert.h>

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

63 64 65
#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
66

67 68 69 70 71
/* 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 */
72
#define AV_SYNC_THRESHOLD 0.01
73 74 75
/* no AV correction is done if too big error */
#define AV_NOSYNC_THRESHOLD 10.0

Michael Niedermayer's avatar
Michael Niedermayer committed
76 77
#define FRAME_SKIP_FACTOR 0.05

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

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

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

87
static int64_t sws_flags = SWS_BICUBIC;
88

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

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

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

111
    AVRational sar;
Fabrice Bellard's avatar
Fabrice Bellard committed
112 113
} VideoPicture;

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

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

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

    int audio_stream;
142

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

147 148 149 150 151
    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
152 153 154
    AVStream *audio_st;
    PacketQueue audioq;
    int audio_hw_buf_size;
155
    uint8_t silence_buf[SDL_AUDIO_BUFFER_SIZE];
156
    uint8_t *audio_buf;
157
    uint8_t *audio_buf1;
158
    unsigned int audio_buf_size; /* in bytes */
Fabrice Bellard's avatar
Fabrice Bellard committed
159
    int audio_buf_index; /* in bytes */
160
    AVPacket audio_pkt_temp;
Fabrice Bellard's avatar
Fabrice Bellard committed
161
    AVPacket audio_pkt;
162 163 164
    enum AVSampleFormat sdl_sample_fmt;
    uint64_t sdl_channel_layout;
    int sdl_channels;
165
    int sdl_sample_rate;
166 167
    enum AVSampleFormat resample_sample_fmt;
    uint64_t resample_channel_layout;
168
    int resample_sample_rate;
169
    AVAudioResampleContext *avr;
170
    AVFrame *frame;
171

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

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

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

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

213
    PtsCorrectionContext pts_ctx;
214

215
#if CONFIG_AVFILTER
216 217
    AVFilterContext *in_video_filter;   // the first filter in the video chain
    AVFilterContext *out_video_filter;  // the last filter in the video chain
218
#endif
Michael Niedermayer's avatar
Michael Niedermayer committed
219 220 221 222

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

/* 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;
Aneesh Dogra's avatar
Aneesh Dogra committed
231
static int screen_width  = 0;
232
static int screen_height = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
233 234
static int audio_disable;
static int video_disable;
Aneesh Dogra's avatar
Aneesh Dogra committed
235 236 237 238
static int wanted_stream[AVMEDIA_TYPE_NB] = {
    [AVMEDIA_TYPE_AUDIO]    = -1,
    [AVMEDIA_TYPE_VIDEO]    = -1,
    [AVMEDIA_TYPE_SUBTITLE] = -1,
239
};
Aneesh Dogra's avatar
Aneesh Dogra committed
240
static int seek_by_bytes = -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
241
static int display_disable;
242
static int show_status = 1;
243
static int av_sync_type = AV_SYNC_AUDIO_MASTER;
Fabrice Bellard's avatar
Fabrice Bellard committed
244
static int64_t start_time = AV_NOPTS_VALUE;
Robert Krüger's avatar
Robert Krüger committed
245
static int64_t duration = AV_NOPTS_VALUE;
246
static int debug = 0;
247
static int debug_mv = 0;
248
static int step = 0;
Michael Niedermayer's avatar
-bug  
Michael Niedermayer committed
249
static int workaround_bugs = 1;
250
static int fast = 0;
251
static int genpts = 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
252
static int idct = FF_IDCT_AUTO;
Aneesh Dogra's avatar
Aneesh Dogra committed
253 254 255
static enum AVDiscard skip_frame       = AVDISCARD_DEFAULT;
static enum AVDiscard skip_idct        = AVDISCARD_DEFAULT;
static enum AVDiscard skip_loop_filter = AVDISCARD_DEFAULT;
256
static int error_concealment = 3;
Aneesh Dogra's avatar
Aneesh Dogra committed
257
static int decoder_reorder_pts = -1;
Michael Niedermayer's avatar
Michael Niedermayer committed
258
static int autoexit;
259 260
static int exit_on_keydown;
static int exit_on_mousedown;
Aneesh Dogra's avatar
Aneesh Dogra committed
261 262
static int loop = 1;
static int framedrop = 1;
263
static int infinite_buffer = 0;
264

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

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

275
static AVPacket flush_pkt;
276

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

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

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

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

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

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

static void packet_queue_end(PacketQueue *q)
{
    packet_queue_flush(q);
Fabrice Bellard's avatar
Fabrice Bellard committed
314 315 316 317 318 319 320 321
    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
322
    /* duplicate the packet */
Aneesh Dogra's avatar
Aneesh Dogra committed
323
    if (pkt != &flush_pkt && av_dup_packet(pkt) < 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
324
        return -1;
325

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

Fabrice Bellard's avatar
Fabrice Bellard committed
332

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

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

    SDL_UnlockMutex(q->mutex);
}

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

    SDL_LockMutex(q->mutex);

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

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

397
static inline void fill_rectangle(SDL_Surface *screen,
Fabrice Bellard's avatar
Fabrice Bellard committed
398 399 400 401 402 403 404 405 406 407
                                  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);
}

408 409 410 411 412 413 414 415 416 417 418 419 420 421
#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)\
{\
422
    unsigned int val = ((const uint32_t *)(pal))[*(const uint8_t*)(s)];\
423 424 425 426 427 428 429 430 431 432 433 434 435 436
    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

437
static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, int imgh)
438 439 440 441 442 443
{
    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;
444 445
    int dstx, dsty, dstw, dsth;

446 447 448 449
    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);
450
    lum = dst->data[0] + dsty * dst->linesize[0];
Aneesh Dogra's avatar
Aneesh Dogra committed
451 452
    cb  = dst->data[1] + (dsty >> 1) * dst->linesize[1];
    cr  = dst->data[2] + (dsty >> 1) * dst->linesize[2];
453

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

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

466
        if (dstx & 1) {
467 468 469 470 471 472 473 474 475
            YUVA_IN(y, u, v, a, p, pal);
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
            cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
            cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
            cb++;
            cr++;
            lum++;
            p += BPP;
        }
Aneesh Dogra's avatar
Aneesh Dogra committed
476
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
            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);
500 501
            p++;
            lum++;
502
        }
503 504
        p += wrap3 - dstw * BPP;
        lum += wrap - dstw - dstx;
505 506 507
        cb += dst->linesize[1] - width2 - skip2;
        cr += dst->linesize[2] - width2 - skip2;
    }
Aneesh Dogra's avatar
Aneesh Dogra committed
508
    for (h = dsth - (dsty & 1); h >= 2; h -= 2) {
509
        lum += dstx;
510 511
        cb += skip2;
        cr += skip2;
512

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

540
            YUVA_IN(y, u, v, a, p + BPP, pal);
541 542 543 544 545 546 547 548 549 550 551 552 553
            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);

554
            YUVA_IN(y, u, v, a, p + BPP, pal);
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
            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;
        }
588 589
        p += wrap3 + (wrap3 - dstw * BPP);
        lum += wrap + (wrap - dstw - dstx);
590 591 592 593 594
        cb += dst->linesize[1] - width2 - skip2;
        cr += dst->linesize[2] - width2 - skip2;
    }
    /* handle odd height */
    if (h) {
595
        lum += dstx;
596 597
        cb += skip2;
        cr += skip2;
598

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

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

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

Fabrice Bellard's avatar
Fabrice Bellard committed
661
        /* XXX: use variable in the frame */
662 663 664 665
        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
666
        else
667
            aspect_ratio = 0;
668
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
669
        if (aspect_ratio <= 0.0)
670
            aspect_ratio = 1.0;
671
        aspect_ratio *= (float)vp->width / (float)vp->height;
Fabrice Bellard's avatar
Fabrice Bellard committed
672

673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691
        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++)
692
                        blend_subrect(&pict, sp->sub.rects[i],
693
                                      vp->bmp->w, vp->bmp->h);
694 695 696 697 698 699 700

                    SDL_UnlockYUVOverlay (vp->bmp);
                }
            }
        }


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

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

Fabrice Bellard's avatar
Fabrice Bellard committed
726 727 728
static inline int compute_mod(int a, int b)
{
    a = a % b;
729
    if (a >= 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
730 731 732 733 734 735 736 737 738 739
        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;
740 741
    int rdft_bits, nb_freq;

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

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

755 756 757 758
        /* 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;
759
            delay -= (time_diff * s->sdl_sample_rate) / 1000000;
760
        }
761

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

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

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

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

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

        /* total height for one channel */
        h = s->height / nb_display_channels;
        /* graph height / 2 */
        h2 = (h * 9) / 20;
Aneesh Dogra's avatar
Aneesh Dogra committed
800
        for (ch = 0; ch < nb_display_channels; ch++) {
801 802
            i = i_start + ch;
            y1 = s->ytop + ch * h + (h / 2); /* position of center line */
Aneesh Dogra's avatar
Aneesh Dogra committed
803
            for (x = 0; x < s->width; x++) {
804 805 806 807 808 809 810 811 812 813 814 815 816
                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
817 818 819
            }
        }

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

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

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

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

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

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

905 906
#if defined(__APPLE__) && !SDL_VERSION_ATLEAST(1, 2, 14)
    /* setting bits_per_pixel = 0 or 32 causes blank video on OS X and older SDL */