avplay.c 99 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 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>

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

61 62 63
#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
64

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

Michael Niedermayer's avatar
Michael Niedermayer committed
74 75
#define FRAME_SKIP_FACTOR 0.05

76 77 78 79 80 81
/* 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
82
/* NOTE: the size must be big enough to compensate the hardware audio buffersize size */
Aneesh Dogra's avatar
Aneesh Dogra committed
83
#define SAMPLE_ARRAY_SIZE (2 * 65536)
Fabrice Bellard's avatar
Fabrice Bellard committed
84

85 86
static int sws_flags = SWS_BICUBIC;

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

96
#define VIDEO_PICTURE_QUEUE_SIZE 2
97
#define SUBPICTURE_QUEUE_SIZE 4
Fabrice Bellard's avatar
Fabrice Bellard committed
98 99

typedef struct VideoPicture {
Aneesh Dogra's avatar
Aneesh Dogra committed
100 101 102
    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
103 104 105
    SDL_Overlay *bmp;
    int width, height; /* source height & width */
    int allocated;
106
    int reallocate;
107 108 109
    enum PixelFormat pix_fmt;

#if CONFIG_AVFILTER
110
    AVFilterBufferRef *picref;
111
#endif
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 142
    AVFormatContext *ic;
    int dtg_active_format;

    int audio_stream;
143

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

148 149 150 151 152
    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
153 154 155
    AVStream *audio_st;
    PacketQueue audioq;
    int audio_hw_buf_size;
156
    uint8_t silence_buf[SDL_AUDIO_BUFFER_SIZE];
157
    uint8_t *audio_buf;
158
    uint8_t *audio_buf1;
159
    unsigned int audio_buf_size; /* in bytes */
Fabrice Bellard's avatar
Fabrice Bellard committed
160
    int audio_buf_index; /* in bytes */
161
    AVPacket audio_pkt_temp;
Fabrice Bellard's avatar
Fabrice Bellard committed
162
    AVPacket audio_pkt;
163
    enum AVSampleFormat audio_src_fmt;
164
    AVAudioConvert *reformat_ctx;
165
    AVFrame *frame;
166

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

176 177 178 179 180 181 182 183 184
    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;
185

186 187 188
    double frame_timer;
    double frame_last_pts;
    double frame_last_delay;
Aneesh Dogra's avatar
Aneesh Dogra committed
189
    double video_clock;                          ///< pts of last decoded frame / predicted pts of next decoded frame
Fabrice Bellard's avatar
Fabrice Bellard committed
190 191 192
    int video_stream;
    AVStream *video_st;
    PacketQueue videoq;
Aneesh Dogra's avatar
Aneesh Dogra committed
193 194 195
    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
196 197 198 199
    VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE];
    int pictq_size, pictq_rindex, pictq_windex;
    SDL_mutex *pictq_mutex;
    SDL_cond *pictq_cond;
200
#if !CONFIG_AVFILTER
201
    struct SwsContext *img_convert_ctx;
202
#endif
203

Fabrice Bellard's avatar
Fabrice Bellard committed
204 205 206
    //    QETimer *video_timer;
    char filename[1024];
    int width, height, xleft, ytop;
207

208
    PtsCorrectionContext pts_ctx;
209

210
#if CONFIG_AVFILTER
Aneesh Dogra's avatar
Aneesh Dogra committed
211
    AVFilterContext *out_video_filter;          ///< the last filter in the video chain
212
#endif
Michael Niedermayer's avatar
Michael Niedermayer committed
213 214 215 216

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

219
static void show_help(void);
Fabrice Bellard's avatar
Fabrice Bellard committed
220 221 222 223

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

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

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

273
static AVPacket flush_pkt;
274

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

279
static SDL_Surface *screen;
Fabrice Bellard's avatar
Fabrice Bellard committed
280

281 282 283 284 285
void exit_program(int ret)
{
    exit(ret);
}

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

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

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

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

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

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

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

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

Fabrice Bellard's avatar
Fabrice Bellard committed
335

Fabrice Bellard's avatar
Fabrice Bellard committed
336 337 338 339 340 341 342 343 344
    SDL_LockMutex(q->mutex);

    if (!q->last_pkt)

        q->first_pkt = pkt1;
    else
        q->last_pkt->next = pkt1;
    q->last_pkt = pkt1;
    q->nb_packets++;
345
    q->size += pkt1->pkt.size + sizeof(*pkt1);
Fabrice Bellard's avatar
Fabrice Bellard committed
346 347 348 349 350 351 352 353 354 355 356 357
    /* XXX: should duplicate packet data in DV case */
    SDL_CondSignal(q->cond);

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

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

    q->abort_request = 1;
358

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

Fabrice Bellard's avatar
Fabrice Bellard committed
378 379 380 381 382 383
        pkt1 = q->first_pkt;
        if (pkt1) {
            q->first_pkt = pkt1->next;
            if (!q->first_pkt)
                q->last_pkt = NULL;
            q->nb_packets--;
384
            q->size -= pkt1->pkt.size + sizeof(*pkt1);
Fabrice Bellard's avatar
Fabrice Bellard committed
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
            *pkt = pkt1->pkt;
            av_free(pkt1);
            ret = 1;
            break;
        } else if (!block) {
            ret = 0;
            break;
        } else {
            SDL_CondWait(q->cond, q->mutex);
        }
    }
    SDL_UnlockMutex(q->mutex);
    return ret;
}

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

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

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

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

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

464 465
    if (dsty & 1) {
        lum += dstx;
466 467
        cb += skip2;
        cr += skip2;
468

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

516
        if (dstx & 1) {
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
            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
536
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
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);

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

557
            YUVA_IN(y, u, v, a, p + BPP, pal);
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 588 589 590
            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;
        }
591 592
        p += wrap3 + (wrap3 - dstw * BPP);
        lum += wrap + (wrap - dstw - dstx);
593 594 595 596 597
        cb += dst->linesize[1] - width2 - skip2;
        cr += dst->linesize[2] - width2 - skip2;
    }
    /* handle odd height */
    if (h) {
598
        lum += dstx;
599 600
        cb += skip2;
        cr += skip2;
601

602
        if (dstx & 1) {
603 604 605 606 607 608 609 610 611
            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
612
        for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
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 639 640 641
            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)
{
642
    avsubtitle_free(&sp->sub);
643 644
}

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

    vp = &is->pictq[is->pictq_rindex];
    if (vp->bmp) {
657
#if CONFIG_AVFILTER
658
         if (vp->picref->video->pixel_aspect.num == 0)
659 660
             aspect_ratio = 0;
         else
661
             aspect_ratio = av_q2d(vp->picref->video->pixel_aspect);
662 663
#else

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

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

                    SDL_UnlockYUVOverlay (vp->bmp);
                }
            }
        }


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

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

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

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

758 759 760 761
        /* 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;
762
            delay -= (time_diff * s->audio_st->codec->sample_rate) / 1000000;
763
        }
764

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

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

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

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

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

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

                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
872
        if (s->xpos >= s->width)
873 874
            s->xpos= s->xleft;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
875 876
}

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

Aneesh Dogra's avatar
Aneesh Dogra committed
882 883
    if (is_full_screen) flags |= SDL_FULLSCREEN;
    else                flags |= SDL_RESIZABLE;
884

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

908 909
#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 */
910
    screen = SDL_SetVideoMode(w, h, 24, flags);
911 912
#else
    screen = SDL_SetVideoMode(w, h, 0, flags);