avplay.c 97.6 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 88
static int sws_flags = SWS_BICUBIC;

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

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

typedef struct VideoPicture {
Aneesh Dogra's avatar
Aneesh Dogra committed
102 103 104
    double pts;                                  ///< presentation time stamp 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 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
    AVFormatContext *ic;

    int audio_stream;
144

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

149 150 151 152 153
    double audio_clock;
    double audio_diff_cum; /* used for AV difference average computation */
    double audio_diff_avg_coef;
    double audio_diff_threshold;
    int audio_diff_avg_count;
Fabrice Bellard's avatar
Fabrice Bellard committed
154 155 156
    AVStream *audio_st;
    PacketQueue audioq;
    int audio_hw_buf_size;
157
    uint8_t silence_buf[SDL_AUDIO_BUFFER_SIZE];
158
    uint8_t *audio_buf;
159
    uint8_t *audio_buf1;
160
    unsigned int audio_buf_size; /* in bytes */
Fabrice Bellard's avatar
Fabrice Bellard committed
161
    int audio_buf_index; /* in bytes */
162
    AVPacket audio_pkt_temp;
Fabrice Bellard's avatar
Fabrice Bellard committed
163
    AVPacket audio_pkt;
164 165 166 167 168 169
    enum AVSampleFormat sdl_sample_fmt;
    uint64_t sdl_channel_layout;
    int sdl_channels;
    enum AVSampleFormat resample_sample_fmt;
    uint64_t resample_channel_layout;
    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;
Aneesh Dogra's avatar
Aneesh Dogra committed
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;
Aneesh Dogra's avatar
Aneesh Dogra committed
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
    AVFilterContext *in_video_filter;           ///< the first filter in the video chain
Aneesh Dogra's avatar
Aneesh Dogra committed
217
    AVFilterContext *out_video_filter;          ///< the last filter in the video chain
218 219
    int use_dr1;
    FrameBuffer *buffer_pool;
220
#endif
Michael Niedermayer's avatar
Michael Niedermayer committed
221 222 223 224

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

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

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

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

277
static AVPacket flush_pkt;
278

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

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

285 286 287 288 289
void exit_program(int ret)
{
    exit(ret);
}

290 291
static int packet_queue_put(PacketQueue *q, AVPacket *pkt);

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

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

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

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

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

Fabrice Bellard's avatar
Fabrice Bellard committed
339

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

Fabrice Bellard's avatar
Fabrice Bellard committed
363 364 365 366 367 368 369 370 371 372 373 374 375
    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
376
    for (;;) {
Fabrice Bellard's avatar
Fabrice Bellard committed
377 378 379 380
        if (q->abort_request) {
            ret = -1;
            break;
        }
381

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

404
static inline void fill_rectangle(SDL_Surface *screen,
Fabrice Bellard's avatar
Fabrice Bellard committed
405 406 407 408 409 410 411 412 413 414
                                  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);
}

415 416 417 418 419 420 421 422 423 424 425 426 427 428
#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)\
{\
429
    unsigned int val = ((const uint32_t *)(pal))[*(const uint8_t*)(s)];\
430 431 432 433 434 435 436 437 438 439 440 441 442 443
    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

444
static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, int imgh)
445 446 447 448 449 450
{
    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;
451 452
    int dstx, dsty, dstw, dsth;

453 454 455 456
    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);
457
    lum = dst->data[0] + dsty * dst->linesize[0];
Aneesh Dogra's avatar
Aneesh Dogra committed
458 459
    cb  = dst->data[1] + (dsty >> 1) * dst->linesize[1];
    cr  = dst->data[2] + (dsty >> 1) * dst->linesize[2];
460

461
    width2 = ((dstw + 1) >> 1) + (dstx & ~dstw & 1);
462
    skip2 = dstx >> 1;
463
    wrap = dst->linesize[0];
464 465 466
    wrap3 = rect->pict.linesize[0];
    p = rect->pict.data[0];
    pal = (const uint32_t *)rect->pict.data[1];  /* Now in YCrCb! */
467

468 469
    if (dsty & 1) {
        lum += dstx;
470 471
        cb += skip2;
        cr += skip2;
472

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

520
        if (dstx & 1) {
521 522 523 524 525 526 527 528 529 530 531 532 533 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);
            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
540
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
541 542 543 544 545 546
            YUVA_IN(y, u, v, a, p, pal);
            u1 = u;
            v1 = v;
            a1 = a;
            lum[0] = ALPHA_BLEND(a, lum[0], y, 0);

547
            YUVA_IN(y, u, v, a, p + BPP, pal);
548 549 550 551 552 553 554 555 556 557 558 559 560
            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);

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

606
        if (dstx & 1) {
607 608 609 610 611 612 613 614 615
            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
616
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
            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)
{
646
    avsubtitle_free(&sp->sub);
647 648
}

Fabrice Bellard's avatar
Fabrice Bellard committed
649 650 651
static void video_image_display(VideoState *is)
{
    VideoPicture *vp;
652 653
    SubPicture *sp;
    AVPicture pict;
Fabrice Bellard's avatar
Fabrice Bellard committed
654 655 656
    float aspect_ratio;
    int width, height, x, y;
    SDL_Rect rect;
657
    int i;
Fabrice Bellard's avatar
Fabrice Bellard committed
658 659 660

    vp = &is->pictq[is->pictq_rindex];
    if (vp->bmp) {
661
#if CONFIG_AVFILTER
662
         if (vp->picref->video->pixel_aspect.num == 0)
663 664
             aspect_ratio = 0;
         else
665
             aspect_ratio = av_q2d(vp->picref->video->pixel_aspect);
666 667
#else

Fabrice Bellard's avatar
Fabrice Bellard committed
668
        /* XXX: use variable in the frame */
669 670 671 672
        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
673
        else
674
            aspect_ratio = 0;
675
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
676
        if (aspect_ratio <= 0.0)
677
            aspect_ratio = 1.0;
678
        aspect_ratio *= (float)vp->width / (float)vp->height;
Fabrice Bellard's avatar
Fabrice Bellard committed
679

680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698
        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++)
699
                        blend_subrect(&pict, sp->sub.rects[i],
700
                                      vp->bmp->w, vp->bmp->h);
701 702 703 704 705 706 707

                    SDL_UnlockYUVOverlay (vp->bmp);
                }
            }
        }


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

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

Aneesh Dogra's avatar
Aneesh Dogra committed
749
    for (rdft_bits = 1; (1 << rdft_bits) < 2 * s->height; rdft_bits++)
750
        ;
Aneesh Dogra's avatar
Aneesh Dogra committed
751
    nb_freq = 1 << (rdft_bits - 1);
752

Fabrice Bellard's avatar
Fabrice Bellard committed
753
    /* compute display index : center on currently output samples */
754
    channels = s->sdl_channels;
Fabrice Bellard's avatar
Fabrice Bellard committed
755
    nb_display_channels = channels;
756
    if (!s->paused) {
Aneesh Dogra's avatar
Aneesh Dogra committed
757
        int data_used = s->show_audio == 1 ? s->width : (2 * nb_freq);
758 759 760
        n = 2 * channels;
        delay = audio_write_get_buf_size(s);
        delay /= n;
761

762 763 764 765
        /* 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;
766
            delay -= (time_diff * s->audio_st->codec->sample_rate) / 1000000;
767
        }
768

Aneesh Dogra's avatar
Aneesh Dogra committed
769
        delay += 2 * data_used;
770 771
        if (delay < data_used)
            delay = data_used;
772 773

        i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
Aneesh Dogra's avatar
Aneesh Dogra committed
774 775 776 777 778 779 780 781 782 783 784 785
        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;
786
                }
787 788 789
            }
        }

790 791 792
        s->last_i_start = i_start;
    } else {
        i_start = s->last_i_start;
Fabrice Bellard's avatar
Fabrice Bellard committed
793 794 795
    }

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

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

Aneesh Dogra's avatar
Aneesh Dogra committed
829
        for (ch = 1; ch < nb_display_channels; ch++) {
830 831 832 833 834 835
            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
836
    } else {
837
        nb_display_channels= FFMIN(nb_display_channels, 2);
Aneesh Dogra's avatar
Aneesh Dogra committed
838
        if (rdft_bits != s->rdft_bits) {
839
            av_rdft_end(s->rdft);
Måns Rullgård's avatar
Måns Rullgård committed
840
            av_free(s->rdft_data);
841
            s->rdft = av_rdft_init(rdft_bits, DFT_R2C);
Aneesh Dogra's avatar
Aneesh Dogra committed
842 843
            s->rdft_bits = rdft_bits;
            s->rdft_data = av_malloc(4 * nb_freq * sizeof(*s->rdft_data));
844 845
        }
        {
Måns Rullgård's avatar
Måns Rullgård committed
846
            FFTSample *data[2];
Aneesh Dogra's avatar
Aneesh Dogra committed
847 848
            for (ch = 0; ch < nb_display_channels; ch++) {
                data[ch] = s->rdft_data + 2 * nb_freq * ch;
849
                i = i_start + ch;
Aneesh Dogra's avatar
Aneesh Dogra committed
850 851 852
                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);
853 854 855 856
                    i += channels;
                    if (i >= SAMPLE_ARRAY_SIZE)
                        i -= SAMPLE_ARRAY_SIZE;
                }
857
                av_rdft_calc(s->rdft, data[ch]);
858
            }
Aneesh Dogra's avatar
Aneesh Dogra committed
859 860 861 862 863 864 865 866 867
            // 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);
868 869 870 871 872 873 874 875

                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
876
        if (s->xpos >= s->width)
877 878
            s->xpos= s->xleft;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
879 880
}

Aneesh Dogra's avatar
Aneesh Dogra committed
881 882 883
static int video_open(VideoState *is)
{
    int flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
884 885
    int w,h;

Aneesh Dogra's avatar
Aneesh Dogra committed
886 887
    if (is_full_screen) flags |= SDL_FULLSCREEN;
    else                flags |= SDL_RESIZABLE;
888

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

912 913
#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 */
914
    screen = SDL_SetVideoMode(w, h, 24, flags);
915 916
#else
    screen = SDL_SetVideoMode(w, h, 0, flags);
917 918 919 920 921
#endif
    if (!screen) {
        fprintf(stderr, "SDL: could not set video mode - exiting\n");
        return -1;
    }
922 923 924
    if (!window_title)
        window_title = input_filename;
    SDL_WM_SetCaption(window_title, window_title);
925

Aneesh Dogra's avatar
Aneesh Dogra committed
926
    is->width  = screen->w;
927 928 929 930
    is->height = screen->h;

    return 0;
}
931

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

Michael Niedermayer's avatar
Michael Niedermayer committed
943
static int refresh_thread(void *opaque)
Fabrice Bellard's avatar
Fabrice Bellard committed
944
{
Michael Niedermayer's avatar
Michael Niedermayer committed
945
    VideoState *is= opaque;