ffplay.c
01310af2
 /*
  * Copyright (c) 2003 Fabrice Bellard
  *
b78e7197
  * This file is part of FFmpeg.
  *
  * FFmpeg is free software; you can redistribute it and/or
01310af2
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
b78e7197
  * version 2.1 of the License, or (at your option) any later version.
01310af2
  *
b78e7197
  * FFmpeg is distributed in the hope that it will be useful,
01310af2
  * 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
b78e7197
  * License along with FFmpeg; if not, write to the Free Software
5509bffa
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
01310af2
  */
364a9607
 
93613338
 /**
  * @file
  * simple media player based on the FFmpeg libraries
  */
 
ba11257e
 #include "config.h"
8a3ceaf4
 #include <inttypes.h>
0f4e8165
 #include <math.h>
 #include <limits.h>
73f2cf4e
 #include <signal.h>
8f8bc923
 #include <stdint.h>
 
245976da
 #include "libavutil/avstring.h"
f9e80201
 #include "libavutil/eval.h"
0ebcdf5c
 #include "libavutil/mathematics.h"
718c7b18
 #include "libavutil/pixdesc.h"
7ffe76e5
 #include "libavutil/imgutils.h"
b6bde8c7
 #include "libavutil/dict.h"
7ffe76e5
 #include "libavutil/parseutils.h"
 #include "libavutil/samplefmt.h"
f6d71b39
 #include "libavutil/avassert.h"
896bb0d7
 #include "libavutil/time.h"
245976da
 #include "libavformat/avformat.h"
 #include "libavdevice/avdevice.h"
 #include "libswscale/swscale.h"
41d0eb1c
 #include "libavutil/opt.h"
166621ab
 #include "libavcodec/avfft.h"
1dd3c473
 #include "libswresample/swresample.h"
01310af2
 
917d2bb3
 #if CONFIG_AVFILTER
566666ca
 # include "libavfilter/avcodec.h"
917d2bb3
 # include "libavfilter/avfilter.h"
4f7dfe12
 # include "libavfilter/buffersink.h"
67339f6e
 # include "libavfilter/buffersrc.h"
917d2bb3
 #endif
 
01310af2
 #include <SDL.h>
 #include <SDL_thread.h>
 
25c32d08
 #include "cmdutils.h"
31319a8c
 
d38c9e7a
 #include <assert.h>
 
89b503b5
 const char program_name[] = "ffplay";
ea9c581f
 const int program_birth_year = 2003;
4cfac5bc
 
79ee4683
 #define MAX_QUEUE_SIZE (15 * 1024 * 1024)
8628b06b
 #define MIN_FRAMES 25
0166d329
 #define EXTERNAL_CLOCK_MIN_FRAMES 2
 #define EXTERNAL_CLOCK_MAX_FRAMES 10
01310af2
 
371f0238
 /* Minimum SDL audio buffer size, in samples. */
1ca5c178
 #define SDL_AUDIO_MIN_BUFFER_SIZE 512
 /* Calculate actual buffer size keeping in mind not cause too frequent audio callbacks */
371f0238
 #define SDL_AUDIO_MAX_CALLBACKS_PER_SEC 30
638c9d91
 
e341cb11
 /* no AV sync correction is done if below the minimum AV sync threshold */
ae6fe159
 #define AV_SYNC_THRESHOLD_MIN 0.04
e341cb11
 /* AV sync correction is done if above the maximum AV sync threshold */
 #define AV_SYNC_THRESHOLD_MAX 0.1
 /* If a frame duration is longer than this, it will not be duplicated to compensate AV sync */
 #define AV_SYNC_FRAMEDUP_THRESHOLD 0.1
638c9d91
 /* no AV correction is done if too big error */
 #define AV_NOSYNC_THRESHOLD 10.0
 
 /* maximum audio speed change to get correct sync */
 #define SAMPLE_CORRECTION_PERCENT_MAX 10
 
747c749d
 /* external clock speed adjustment constants for realtime sources based on buffer fullness */
 #define EXTERNAL_CLOCK_SPEED_MIN  0.900
 #define EXTERNAL_CLOCK_SPEED_MAX  1.010
 #define EXTERNAL_CLOCK_SPEED_STEP 0.001
 
638c9d91
 /* we use about AUDIO_DIFF_AVG_NB A-V differences to make the average */
 #define AUDIO_DIFF_AVG_NB   20
 
b853cfe7
 /* polls for possible required screen refresh at least this often, should be less than 1/fps */
 #define REFRESH_RATE 0.01
 
01310af2
 /* NOTE: the size must be big enough to compensate the hardware audio buffersize size */
cdea19e7
 /* TODO: We assume that a decoded and resampled frame fits into this buffer */
 #define SAMPLE_ARRAY_SIZE (8 * 65536)
01310af2
 
ef7f3b08
 #define CURSOR_HIDE_DELAY 1000000
 
5edab1d2
 static unsigned sws_flags = SWS_BICUBIC;
03ae87a3
 
2a4c7e65
 typedef struct MyAVPacketList {
     AVPacket pkt;
     struct MyAVPacketList *next;
     int serial;
 } MyAVPacketList;
 
01310af2
 typedef struct PacketQueue {
2a4c7e65
     MyAVPacketList *first_pkt, *last_pkt;
01310af2
     int nb_packets;
     int size;
     int abort_request;
2a4c7e65
     int serial;
01310af2
     SDL_mutex *mutex;
     SDL_cond *cond;
 } PacketQueue;
 
b764b53a
 #define VIDEO_PICTURE_QUEUE_SIZE 3
e5eff191
 #define SUBPICTURE_QUEUE_SIZE 16
631ac655
 #define SAMPLE_QUEUE_SIZE 9
 #define FRAME_QUEUE_SIZE FFMAX(SAMPLE_QUEUE_SIZE, FFMAX(VIDEO_PICTURE_QUEUE_SIZE, SUBPICTURE_QUEUE_SIZE))
72ce053b
 
e1248f5c
 typedef struct AudioParams {
     int freq;
     int channels;
a3fa27e3
     int64_t channel_layout;
e1248f5c
     enum AVSampleFormat fmt;
e98cd24a
     int frame_size;
     int bytes_per_sec;
e1248f5c
 } AudioParams;
 
f2175a62
 typedef struct Clock {
     double pts;           /* clock base */
     double pts_drift;     /* clock base minus time at which we updated the clock */
     double last_updated;
     double speed;
     int serial;           /* clock is based on a packet with this serial */
     int paused;
     int *queue_serial;    /* pointer to the current packet queue serial, used for obsolete clock detection */
 } Clock;
 
5a5128ba
 /* Common struct for handling all types of decoded data and allocated render buffers. */
 typedef struct Frame {
     AVFrame *frame;
     AVSubtitle sub;
     int serial;
     double pts;           /* presentation timestamp for the frame */
     double duration;      /* estimated duration of the frame */
     int64_t pos;          /* byte position of the frame in the input file */
     SDL_Overlay *bmp;
     int allocated;
     int reallocate;
     int width;
     int height;
     AVRational sar;
 } Frame;
 
 typedef struct FrameQueue {
     Frame queue[FRAME_QUEUE_SIZE];
     int rindex;
     int windex;
     int size;
     int max_size;
     int keep_last;
     int rindex_shown;
     SDL_mutex *mutex;
     SDL_cond *cond;
     PacketQueue *pktq;
 } FrameQueue;
 
01310af2
 enum {
     AV_SYNC_AUDIO_MASTER, /* default choice */
     AV_SYNC_VIDEO_MASTER,
638c9d91
     AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */
01310af2
 };
 
9e0d1c00
 typedef struct Decoder {
     AVPacket pkt;
     AVPacket pkt_temp;
     PacketQueue *queue;
     AVCodecContext *avctx;
     int pkt_serial;
     int finished;
     int packet_pending;
     SDL_cond *empty_queue_cond;
1f5a3cf6
     int64_t start_pts;
     AVRational start_pts_tb;
     int64_t next_pts;
     AVRational next_pts_tb;
ef1ccea9
     SDL_Thread *decoder_tid;
9e0d1c00
 } Decoder;
 
01310af2
 typedef struct VideoState {
8adf9bb2
     SDL_Thread *read_tid;
638c9d91
     AVInputFormat *iformat;
01310af2
     int abort_request;
dbe7170e
     int force_refresh;
01310af2
     int paused;
416e3508
     int last_paused;
491ca0e8
     int queue_attachments_req;
72ea344b
     int seek_req;
3ba1438d
     int seek_flags;
72ea344b
     int64_t seek_pos;
4ed29207
     int64_t seek_rel;
f5668147
     int read_pause_return;
01310af2
     AVFormatContext *ic;
747c749d
     int realtime;
01310af2
 
f2175a62
     Clock audclk;
     Clock vidclk;
     Clock extclk;
 
5a5128ba
     FrameQueue pictq;
     FrameQueue subpq;
631ac655
     FrameQueue sampq;
5a5128ba
 
9e0d1c00
     Decoder auddec;
     Decoder viddec;
     Decoder subdec;
 
d64ba25a
     int viddec_width;
     int viddec_height;
 
01310af2
     int audio_stream;
115329f1
 
01310af2
     int av_sync_type;
115329f1
 
638c9d91
     double audio_clock;
26c208cf
     int audio_clock_serial;
638c9d91
     double audio_diff_cum; /* used for AV difference average computation */
     double audio_diff_avg_coef;
     double audio_diff_threshold;
     int audio_diff_avg_count;
01310af2
     AVStream *audio_st;
     PacketQueue audioq;
     int audio_hw_buf_size;
1ca5c178
     uint8_t silence_buf[SDL_AUDIO_MIN_BUFFER_SIZE];
5a4476e2
     uint8_t *audio_buf;
f199f385
     uint8_t *audio_buf1;
7fea94ce
     unsigned int audio_buf_size; /* in bytes */
571ef42d
     unsigned int audio_buf1_size;
01310af2
     int audio_buf_index; /* in bytes */
10b7b4a6
     int audio_write_buf_size;
e1248f5c
     struct AudioParams audio_src;
e96175ad
 #if CONFIG_AVFILTER
     struct AudioParams audio_filter_src;
 #endif
e1248f5c
     struct AudioParams audio_tgt;
1dd3c473
     struct SwrContext *swr_ctx;
d54af906
     int frame_drops_early;
     int frame_drops_late;
115329f1
 
54ad8e06
     enum ShowMode {
1d6c82d4
         SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB
f8b8c694
     } show_mode;
01310af2
     int16_t sample_array[SAMPLE_ARRAY_SIZE];
     int sample_array_index;
5e0257e3
     int last_i_start;
166621ab
     RDFTContext *rdft;
12eeda34
     int rdft_bits;
7dbbf6a1
     FFTSample *rdft_data;
12eeda34
     int xpos;
b853cfe7
     double last_vis_time;
115329f1
 
72ce053b
     int subtitle_stream;
     AVStream *subtitle_st;
     PacketQueue subtitleq;
115329f1
 
638c9d91
     double frame_timer;
8f17a8ef
     double frame_last_returned_time;
     double frame_last_filter_delay;
01310af2
     int video_stream;
     AVStream *video_st;
     PacketQueue videoq;
f7eb50f3
     double max_frame_duration;      // maximum duration of a frame - above this, we consider the jump a timestamp discontinuity
917d2bb3
 #if !CONFIG_AVFILTER
3ac56e28
     struct SwsContext *img_convert_ctx;
917d2bb3
 #endif
d64ba25a
     struct SwsContext *sub_convert_ctx;
65f6c42a
     SDL_Rect last_display_rect;
d6910c4b
     int eof;
115329f1
 
01310af2
     char filename[1024];
     int width, height, xleft, ytop;
5db1f94b
     int step;
41db429d
 
917d2bb3
 #if CONFIG_AVFILTER
a583e2be
     int vfilter_idx;
c1ef30a6
     AVFilterContext *in_video_filter;   // the first filter in the video chain
     AVFilterContext *out_video_filter;  // the last filter in the video chain
e96175ad
     AVFilterContext *in_audio_filter;   // the first filter in the audio chain
     AVFilterContext *out_audio_filter;  // the last filter in the audio chain
     AVFilterGraph *agraph;              // audio filter graph
917d2bb3
 #endif
d38c9e7a
 
8c9971c3
     int last_video_stream, last_audio_stream, last_subtitle_stream;
0e5042be
 
     SDL_cond *continue_read_thread;
01310af2
 } VideoState;
 
 /* options specified by the user */
 static AVInputFormat *file_iformat;
 static const char *input_filename;
076db5ed
 static const char *window_title;
01310af2
 static int fs_screen_width;
 static int fs_screen_height;
5de3f724
 static int default_width  = 640;
 static int default_height = 480;
da7c65f0
 static int screen_width  = 0;
fccb19e3
 static int screen_height = 0;
01310af2
 static int audio_disable;
 static int video_disable;
d0c6ed7d
 static int subtitle_disable;
5e7dcb04
 static const char* wanted_stream_spec[AVMEDIA_TYPE_NB] = {0};
da7c65f0
 static int seek_by_bytes = -1;
01310af2
 static int display_disable;
1e1a0b18
 static int show_status = 1;
638c9d91
 static int av_sync_type = AV_SYNC_AUDIO_MASTER;
72ea344b
 static int64_t start_time = AV_NOPTS_VALUE;
d834d63b
 static int64_t duration = AV_NOPTS_VALUE;
6fc5b059
 static int fast = 0;
30bc6613
 static int genpts = 0;
70d54392
 static int lowres = 0;
da7c65f0
 static int decoder_reorder_pts = -1;
552ce687
 static int autoexit;
066ce8c9
 static int exit_on_keydown;
 static int exit_on_mousedown;
da7c65f0
 static int loop = 1;
41211483
 static int framedrop = -1;
cb3fd029
 static int infinite_buffer = -1;
1d6c82d4
 static enum ShowMode show_mode = SHOW_MODE_NONE;
5eda0967
 static const char *audio_codec_name;
 static const char *subtitle_codec_name;
 static const char *video_codec_name;
b853cfe7
 double rdftspeed = 0.02;
ef7f3b08
 static int64_t cursor_last_shown;
 static int cursor_hidden = 0;
917d2bb3
 #if CONFIG_AVFILTER
a583e2be
 static const char **vfilters_list = NULL;
 static int nb_vfilters = 0;
e96175ad
 static char *afilters = NULL;
917d2bb3
 #endif
08c51e12
 static int autorotate = 1;
01310af2
 
 /* current context */
 static int is_full_screen;
5e0257e3
 static int64_t audio_callback_time;
01310af2
 
2c676c33
 static AVPacket flush_pkt;
39c6a118
 
01310af2
 #define FF_ALLOC_EVENT   (SDL_USEREVENT)
638c9d91
 #define FF_QUIT_EVENT    (SDL_USEREVENT + 2)
01310af2
 
2c676c33
 static SDL_Surface *screen;
01310af2
 
a583e2be
 #if CONFIG_AVFILTER
 static int opt_add_vfilter(void *optctx, const char *opt, const char *arg)
 {
     GROW_ARRAY(vfilters_list, nb_vfilters);
     vfilters_list[nb_vfilters - 1] = arg;
     return 0;
 }
 #endif
 
e96175ad
 static inline
 int cmp_audio_fmts(enum AVSampleFormat fmt1, int64_t channel_count1,
                    enum AVSampleFormat fmt2, int64_t channel_count2)
 {
     /* If channel count == 1, planar and non-planar formats are the same */
     if (channel_count1 == 1 && channel_count2 == 1)
         return av_get_packed_sample_fmt(fmt1) != av_get_packed_sample_fmt(fmt2);
     else
         return channel_count1 != channel_count2 || fmt1 != fmt2;
 }
 
 static inline
 int64_t get_valid_channel_layout(int64_t channel_layout, int channels)
 {
     if (channel_layout && av_get_channel_layout_nb_channels(channel_layout) == channels)
         return channel_layout;
     else
         return 0;
 }
 
5a5128ba
 static void free_picture(Frame *vp);
 
a687acbb
 static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)
eef16966
 {
2a4c7e65
     MyAVPacketList *pkt1;
eef16966
 
a687acbb
     if (q->abort_request)
        return -1;
eef16966
 
2a4c7e65
     pkt1 = av_malloc(sizeof(MyAVPacketList));
eef16966
     if (!pkt1)
         return -1;
     pkt1->pkt = *pkt;
     pkt1->next = NULL;
2a4c7e65
     if (pkt == &flush_pkt)
         q->serial++;
     pkt1->serial = q->serial;
eef16966
 
     if (!q->last_pkt)
         q->first_pkt = pkt1;
     else
         q->last_pkt->next = pkt1;
     q->last_pkt = pkt1;
     q->nb_packets++;
     q->size += pkt1->pkt.size + sizeof(*pkt1);
     /* XXX: should duplicate packet data in DV case */
     SDL_CondSignal(q->cond);
a687acbb
     return 0;
 }
 
 static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
 {
     int ret;
eef16966
 
a687acbb
     /* duplicate the packet */
     if (pkt != &flush_pkt && av_dup_packet(pkt) < 0)
         return -1;
 
     SDL_LockMutex(q->mutex);
     ret = packet_queue_put_private(q, pkt);
eef16966
     SDL_UnlockMutex(q->mutex);
a687acbb
 
     if (pkt != &flush_pkt && ret < 0)
         av_free_packet(pkt);
 
     return ret;
eef16966
 }
515bd00e
 
b118d3e2
 static int packet_queue_put_nullpacket(PacketQueue *q, int stream_index)
 {
     AVPacket pkt1, *pkt = &pkt1;
     av_init_packet(pkt);
     pkt->data = NULL;
     pkt->size = 0;
     pkt->stream_index = stream_index;
     return packet_queue_put(q, pkt);
 }
 
01310af2
 /* packet queue handling */
 static void packet_queue_init(PacketQueue *q)
 {
     memset(q, 0, sizeof(PacketQueue));
     q->mutex = SDL_CreateMutex();
     q->cond = SDL_CreateCond();
a687acbb
     q->abort_request = 1;
01310af2
 }
 
72ea344b
 static void packet_queue_flush(PacketQueue *q)
01310af2
 {
2a4c7e65
     MyAVPacketList *pkt, *pkt1;
01310af2
 
687fae2b
     SDL_LockMutex(q->mutex);
81a663f4
     for (pkt = q->first_pkt; pkt; pkt = pkt1) {
01310af2
         pkt1 = pkt->next;
         av_free_packet(&pkt->pkt);
da6c4573
         av_freep(&pkt);
01310af2
     }
72ea344b
     q->last_pkt = NULL;
     q->first_pkt = NULL;
     q->nb_packets = 0;
     q->size = 0;
687fae2b
     SDL_UnlockMutex(q->mutex);
72ea344b
 }
 
a687acbb
 static void packet_queue_destroy(PacketQueue *q)
72ea344b
 {
     packet_queue_flush(q);
01310af2
     SDL_DestroyMutex(q->mutex);
     SDL_DestroyCond(q->cond);
 }
 
 static void packet_queue_abort(PacketQueue *q)
 {
     SDL_LockMutex(q->mutex);
 
     q->abort_request = 1;
115329f1
 
01310af2
     SDL_CondSignal(q->cond);
 
     SDL_UnlockMutex(q->mutex);
 }
 
a687acbb
 static void packet_queue_start(PacketQueue *q)
 {
     SDL_LockMutex(q->mutex);
     q->abort_request = 0;
     packet_queue_put_private(q, &flush_pkt);
     SDL_UnlockMutex(q->mutex);
 }
 
01310af2
 /* return < 0 if aborted, 0 if no packet and > 0 if packet.  */
2a4c7e65
 static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial)
01310af2
 {
2a4c7e65
     MyAVPacketList *pkt1;
01310af2
     int ret;
 
     SDL_LockMutex(q->mutex);
 
da7c65f0
     for (;;) {
01310af2
         if (q->abort_request) {
             ret = -1;
             break;
         }
115329f1
 
01310af2
         pkt1 = q->first_pkt;
         if (pkt1) {
             q->first_pkt = pkt1->next;
             if (!q->first_pkt)
                 q->last_pkt = NULL;
             q->nb_packets--;
7b776589
             q->size -= pkt1->pkt.size + sizeof(*pkt1);
01310af2
             *pkt = pkt1->pkt;
2a4c7e65
             if (serial)
                 *serial = pkt1->serial;
01310af2
             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;
 }
 
9e0d1c00
 static void decoder_init(Decoder *d, AVCodecContext *avctx, PacketQueue *queue, SDL_cond *empty_queue_cond) {
     memset(d, 0, sizeof(Decoder));
     d->avctx = avctx;
     d->queue = queue;
     d->empty_queue_cond = empty_queue_cond;
1f5a3cf6
     d->start_pts = AV_NOPTS_VALUE;
9e0d1c00
 }
 
2ec4a84d
 static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtitle *sub) {
9e0d1c00
     int got_frame = 0;
 
     do {
         int ret = -1;
 
         if (d->queue->abort_request)
             return -1;
 
         if (!d->packet_pending || d->queue->serial != d->pkt_serial) {
             AVPacket pkt;
             do {
                 if (d->queue->nb_packets == 0)
                     SDL_CondSignal(d->empty_queue_cond);
                 if (packet_queue_get(d->queue, &pkt, 1, &d->pkt_serial) < 0)
                     return -1;
                 if (pkt.data == flush_pkt.data) {
                     avcodec_flush_buffers(d->avctx);
                     d->finished = 0;
1f5a3cf6
                     d->next_pts = d->start_pts;
                     d->next_pts_tb = d->start_pts_tb;
9e0d1c00
                 }
             } while (pkt.data == flush_pkt.data || d->queue->serial != d->pkt_serial);
             av_free_packet(&d->pkt);
             d->pkt_temp = d->pkt = pkt;
             d->packet_pending = 1;
         }
 
         switch (d->avctx->codec_type) {
             case AVMEDIA_TYPE_VIDEO:
1f5a3cf6
                 ret = avcodec_decode_video2(d->avctx, frame, &got_frame, &d->pkt_temp);
                 if (got_frame) {
                     if (decoder_reorder_pts == -1) {
                         frame->pts = av_frame_get_best_effort_timestamp(frame);
                     } else if (decoder_reorder_pts) {
                         frame->pts = frame->pkt_pts;
                     } else {
                         frame->pts = frame->pkt_dts;
                     }
                 }
9e0d1c00
                 break;
             case AVMEDIA_TYPE_AUDIO:
1f5a3cf6
                 ret = avcodec_decode_audio4(d->avctx, frame, &got_frame, &d->pkt_temp);
                 if (got_frame) {
                     AVRational tb = (AVRational){1, frame->sample_rate};
                     if (frame->pts != AV_NOPTS_VALUE)
                         frame->pts = av_rescale_q(frame->pts, d->avctx->time_base, tb);
                     else if (frame->pkt_pts != AV_NOPTS_VALUE)
266b3d4f
                         frame->pts = av_rescale_q(frame->pkt_pts, av_codec_get_pkt_timebase(d->avctx), tb);
1f5a3cf6
                     else if (d->next_pts != AV_NOPTS_VALUE)
                         frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb);
                     if (frame->pts != AV_NOPTS_VALUE) {
                         d->next_pts = frame->pts + frame->nb_samples;
                         d->next_pts_tb = tb;
                     }
                 }
9e0d1c00
                 break;
             case AVMEDIA_TYPE_SUBTITLE:
2ec4a84d
                 ret = avcodec_decode_subtitle2(d->avctx, sub, &got_frame, &d->pkt_temp);
9e0d1c00
                 break;
         }
 
         if (ret < 0) {
             d->packet_pending = 0;
         } else {
             d->pkt_temp.dts =
             d->pkt_temp.pts = AV_NOPTS_VALUE;
             if (d->pkt_temp.data) {
                 if (d->avctx->codec_type != AVMEDIA_TYPE_AUDIO)
                     ret = d->pkt_temp.size;
                 d->pkt_temp.data += ret;
                 d->pkt_temp.size -= ret;
                 if (d->pkt_temp.size <= 0)
                     d->packet_pending = 0;
             } else {
                 if (!got_frame) {
                     d->packet_pending = 0;
                     d->finished = d->pkt_serial;
                 }
             }
         }
     } while (!got_frame && !d->finished);
 
     return got_frame;
 }
 
 static void decoder_destroy(Decoder *d) {
     av_free_packet(&d->pkt);
 }
 
5a5128ba
 static void frame_queue_unref_item(Frame *vp)
 {
     av_frame_unref(vp->frame);
     avsubtitle_free(&vp->sub);
 }
 
 static int frame_queue_init(FrameQueue *f, PacketQueue *pktq, int max_size, int keep_last)
 {
     int i;
     memset(f, 0, sizeof(FrameQueue));
     if (!(f->mutex = SDL_CreateMutex()))
         return AVERROR(ENOMEM);
     if (!(f->cond = SDL_CreateCond()))
         return AVERROR(ENOMEM);
     f->pktq = pktq;
     f->max_size = FFMIN(max_size, FRAME_QUEUE_SIZE);
     f->keep_last = !!keep_last;
     for (i = 0; i < f->max_size; i++)
         if (!(f->queue[i].frame = av_frame_alloc()))
             return AVERROR(ENOMEM);
     return 0;
 }
 
 static void frame_queue_destory(FrameQueue *f)
 {
     int i;
     for (i = 0; i < f->max_size; i++) {
         Frame *vp = &f->queue[i];
         frame_queue_unref_item(vp);
         av_frame_free(&vp->frame);
         free_picture(vp);
     }
     SDL_DestroyMutex(f->mutex);
     SDL_DestroyCond(f->cond);
 }
 
 static void frame_queue_signal(FrameQueue *f)
 {
     SDL_LockMutex(f->mutex);
     SDL_CondSignal(f->cond);
     SDL_UnlockMutex(f->mutex);
 }
 
 static Frame *frame_queue_peek(FrameQueue *f)
 {
     return &f->queue[(f->rindex + f->rindex_shown) % f->max_size];
 }
 
 static Frame *frame_queue_peek_next(FrameQueue *f)
 {
     return &f->queue[(f->rindex + f->rindex_shown + 1) % f->max_size];
 }
 
 static Frame *frame_queue_peek_last(FrameQueue *f)
 {
     return &f->queue[f->rindex];
 }
 
 static Frame *frame_queue_peek_writable(FrameQueue *f)
 {
     /* wait until we have space to put a new frame */
     SDL_LockMutex(f->mutex);
     while (f->size >= f->max_size &&
            !f->pktq->abort_request) {
         SDL_CondWait(f->cond, f->mutex);
     }
     SDL_UnlockMutex(f->mutex);
 
     if (f->pktq->abort_request)
         return NULL;
 
     return &f->queue[f->windex];
 }
 
631ac655
 static Frame *frame_queue_peek_readable(FrameQueue *f)
 {
     /* wait until we have a readable a new frame */
     SDL_LockMutex(f->mutex);
     while (f->size - f->rindex_shown <= 0 &&
            !f->pktq->abort_request) {
         SDL_CondWait(f->cond, f->mutex);
     }
     SDL_UnlockMutex(f->mutex);
 
     if (f->pktq->abort_request)
         return NULL;
 
     return &f->queue[(f->rindex + f->rindex_shown) % f->max_size];
 }
 
5a5128ba
 static void frame_queue_push(FrameQueue *f)
 {
     if (++f->windex == f->max_size)
         f->windex = 0;
     SDL_LockMutex(f->mutex);
     f->size++;
631ac655
     SDL_CondSignal(f->cond);
5a5128ba
     SDL_UnlockMutex(f->mutex);
 }
 
 static void frame_queue_next(FrameQueue *f)
 {
     if (f->keep_last && !f->rindex_shown) {
         f->rindex_shown = 1;
         return;
     }
     frame_queue_unref_item(&f->queue[f->rindex]);
     if (++f->rindex == f->max_size)
         f->rindex = 0;
     SDL_LockMutex(f->mutex);
     f->size--;
     SDL_CondSignal(f->cond);
     SDL_UnlockMutex(f->mutex);
 }
 
 /* jump back to the previous frame if available by resetting rindex_shown */
 static int frame_queue_prev(FrameQueue *f)
 {
     int ret = f->rindex_shown;
     f->rindex_shown = 0;
     return ret;
 }
 
 /* return the number of undisplayed frames in the queue */
 static int frame_queue_nb_remaining(FrameQueue *f)
 {
     return f->size - f->rindex_shown;
 }
 
16437648
 /* return last shown position */
 static int64_t frame_queue_last_pos(FrameQueue *f)
 {
     Frame *fp = &f->queue[f->rindex];
     if (f->rindex_shown && fp->serial == f->pktq->serial)
         return fp->pos;
     else
         return -1;
 }
 
ef1ccea9
 static void decoder_abort(Decoder *d, FrameQueue *fq)
 {
     packet_queue_abort(d->queue);
     frame_queue_signal(fq);
     SDL_WaitThread(d->decoder_tid, NULL);
     d->decoder_tid = NULL;
     packet_queue_flush(d->queue);
 }
 
115329f1
 static inline void fill_rectangle(SDL_Surface *screen,
00b70f8d
                                   int x, int y, int w, int h, int color, int update)
01310af2
 {
     SDL_Rect rect;
     rect.x = x;
     rect.y = y;
     rect.w = w;
     rect.h = h;
     SDL_FillRect(screen, &rect, color);
00b70f8d
     if (update && w > 0 && h > 0)
         SDL_UpdateRect(screen, x, y, w, h);
01310af2
 }
 
65f6c42a
 /* draw only the border of a rectangle */
 static void fill_border(int xleft, int ytop, int width, int height, int x, int y, int w, int h, int color, int update)
 {
     int w1, w2, h1, h2;
 
     /* fill the background */
     w1 = x;
     if (w1 < 0)
         w1 = 0;
     w2 = width - (x + w);
     if (w2 < 0)
         w2 = 0;
     h1 = y;
     if (h1 < 0)
         h1 = 0;
     h2 = height - (y + h);
     if (h2 < 0)
         h2 = 0;
     fill_rectangle(screen,
                    xleft, ytop,
                    w1, height,
                    color, update);
     fill_rectangle(screen,
                    xleft + width - w2, ytop,
                    w2, height,
                    color, update);
     fill_rectangle(screen,
                    xleft + w1, ytop,
                    width - w1 - w2, h1,
                    color, update);
     fill_rectangle(screen,
                    xleft + w1, ytop + height - h2,
                    width - w1 - w2, h2,
                    color, update);
 }
 
72ce053b
 #define ALPHA_BLEND(a, oldp, newp, s)\
 ((((oldp << s) * (255 - (a))) + (newp * (a))) / (255 << s))
 
 
 
 #define BPP 1
 
0a8cd696
 static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, int imgh)
72ce053b
 {
d64ba25a
     int x, y, Y, U, V, A;
72ce053b
     uint8_t *lum, *cb, *cr;
9cb5a11e
     int dstx, dsty, dstw, dsth;
d64ba25a
     const AVPicture *src = &rect->pict;
9cb5a11e
 
7cf9c6ae
     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);
d64ba25a
     lum = dst->data[0] + dstx + dsty * dst->linesize[0];
     cb  = dst->data[1] + dstx/2 + (dsty >> 1) * dst->linesize[1];
     cr  = dst->data[2] + dstx/2 + (dsty >> 1) * dst->linesize[2];
 
     for (y = 0; y<dsth; y++) {
         for (x = 0; x<dstw; x++) {
             Y = src->data[0][x + y*src->linesize[0]];
             A = src->data[3][x + y*src->linesize[3]];
             lum[0] = ALPHA_BLEND(A, lum[0], Y, 0);
72ce053b
             lum++;
         }
d64ba25a
         lum += dst->linesize[0] - dstw;
72ce053b
     }
 
d64ba25a
     for (y = 0; y<dsth/2; y++) {
         for (x = 0; x<dstw/2; x++) {
             U = src->data[1][x + y*src->linesize[1]];
             V = src->data[2][x + y*src->linesize[2]];
             A = src->data[3][2*x     +  2*y   *src->linesize[3]]
               + src->data[3][2*x + 1 +  2*y   *src->linesize[3]]
               + src->data[3][2*x + 1 + (2*y+1)*src->linesize[3]]
               + src->data[3][2*x     + (2*y+1)*src->linesize[3]];
             cb[0] = ALPHA_BLEND(A>>2, cb[0], U, 0);
             cr[0] = ALPHA_BLEND(A>>2, cr[0], V, 0);
72ce053b
             cb++;
             cr++;
         }
d64ba25a
         cb += dst->linesize[1] - dstw/2;
         cr += dst->linesize[2] - dstw/2;
72ce053b
     }
 }
 
5a5128ba
 static void free_picture(Frame *vp)
2d059d8d
 {
      if (vp->bmp) {
          SDL_FreeYUVOverlay(vp->bmp);
          vp->bmp = NULL;
      }
 }
 
ba800def
 static void calculate_display_rect(SDL_Rect *rect,
                                    int scr_xleft, int scr_ytop, int scr_width, int scr_height,
                                    int pic_width, int pic_height, AVRational pic_sar)
bd14d845
 {
     float aspect_ratio;
     int width, height, x, y;
 
ba800def
     if (pic_sar.num == 0)
bd14d845
         aspect_ratio = 0;
     else
ba800def
         aspect_ratio = av_q2d(pic_sar);
bd14d845
 
     if (aspect_ratio <= 0.0)
         aspect_ratio = 1.0;
ba800def
     aspect_ratio *= (float)pic_width / (float)pic_height;
bd14d845
 
     /* XXX: we suppose the screen has a 1.0 pixel ratio */
     height = scr_height;
     width = ((int)rint(height * aspect_ratio)) & ~1;
     if (width > scr_width) {
         width = scr_width;
         height = ((int)rint(width / aspect_ratio)) & ~1;
     }
     x = (scr_width - width) / 2;
     y = (scr_height - height) / 2;
     rect->x = scr_xleft + x;
     rect->y = scr_ytop  + y;
     rect->w = FFMAX(width,  1);
     rect->h = FFMAX(height, 1);
 }
 
01310af2
 static void video_image_display(VideoState *is)
 {
5a5128ba
     Frame *vp;
     Frame *sp;
72ce053b
     AVPicture pict;
01310af2
     SDL_Rect rect;
72ce053b
     int i;
01310af2
 
5a5128ba
     vp = frame_queue_peek(&is->pictq);
01310af2
     if (vp->bmp) {
df149f6c
         if (is->subtitle_st) {
5a5128ba
             if (frame_queue_nb_remaining(&is->subpq) > 0) {
                 sp = frame_queue_peek(&is->subpq);
72ce053b
 
df149f6c
                 if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) {
72ce053b
                     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++)
db4fac64
                         blend_subrect(&pict, sp->sub.rects[i],
0a8cd696
                                       vp->bmp->w, vp->bmp->h);
72ce053b
 
                     SDL_UnlockYUVOverlay (vp->bmp);
                 }
             }
         }
 
ba800def
         calculate_display_rect(&rect, is->xleft, is->ytop, is->width, is->height, vp->width, vp->height, vp->sar);
72ce053b
 
01310af2
         SDL_DisplayYUVOverlay(vp->bmp, &rect);
65f6c42a
 
         if (rect.x != is->last_display_rect.x || rect.y != is->last_display_rect.y || rect.w != is->last_display_rect.w || rect.h != is->last_display_rect.h || is->force_refresh) {
             int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
             fill_border(is->xleft, is->ytop, is->width, is->height, rect.x, rect.y, rect.w, rect.h, bgcolor, 1);
             is->last_display_rect = rect;
         }
01310af2
     }
 }
 
 static inline int compute_mod(int a, int b)
 {
91b27e49
     return a < 0 ? a%b + b : a%b;
01310af2
 }
 
 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;
92b50b71
     int64_t time_diff;
4c7c7645
     int rdft_bits, nb_freq;
 
da7c65f0
     for (rdft_bits = 1; (1 << rdft_bits) < 2 * s->height; rdft_bits++)
4c7c7645
         ;
da7c65f0
     nb_freq = 1 << (rdft_bits - 1);
115329f1
 
01310af2
     /* compute display index : center on currently output samples */
e1248f5c
     channels = s->audio_tgt.channels;
01310af2
     nb_display_channels = channels;
5e0257e3
     if (!s->paused) {
f8b8c694
         int data_used= s->show_mode == SHOW_MODE_WAVES ? s->width : (2*nb_freq);
5e0257e3
         n = 2 * channels;
10b7b4a6
         delay = s->audio_write_buf_size;
5e0257e3
         delay /= n;
115329f1
 
5e0257e3
         /* to be more precise, we take into account the time spent since
            the last buffer computation */
         if (audio_callback_time) {
0ca0b4c2
             time_diff = av_gettime_relative() - audio_callback_time;
e1248f5c
             delay -= (time_diff * s->audio_tgt.freq) / 1000000;
5e0257e3
         }
115329f1
 
da7c65f0
         delay += 2 * data_used;
4c7c7645
         if (delay < data_used)
             delay = data_used;
ac50bcc8
 
         i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
f8b8c694
         if (s->show_mode == SHOW_MODE_WAVES) {
da7c65f0
             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;
6c7165c7
                 }
ac50bcc8
             }
         }
 
5e0257e3
         s->last_i_start = i_start;
     } else {
         i_start = s->last_i_start;
01310af2
     }
 
     bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
f8b8c694
     if (s->show_mode == SHOW_MODE_WAVES) {
6c7165c7
         fill_rectangle(screen,
                        s->xleft, s->ytop, s->width, s->height,
00b70f8d
                        bgcolor, 0);
6c7165c7
 
         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;
da7c65f0
         for (ch = 0; ch < nb_display_channels; ch++) {
6c7165c7
             i = i_start + ch;
             y1 = s->ytop + ch * h + (h / 2); /* position of center line */
da7c65f0
             for (x = 0; x < s->width; x++) {
6c7165c7
                 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,
00b70f8d
                                fgcolor, 0);
6c7165c7
                 i += channels;
                 if (i >= SAMPLE_ARRAY_SIZE)
                     i -= SAMPLE_ARRAY_SIZE;
01310af2
             }
         }
 
6c7165c7
         fgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0xff);
01310af2
 
da7c65f0
         for (ch = 1; ch < nb_display_channels; ch++) {
6c7165c7
             y = s->ytop + ch * h;
             fill_rectangle(screen,
                            s->xleft, y, s->width, 1,
00b70f8d
                            fgcolor, 0);
6c7165c7
         }
         SDL_UpdateRect(screen, s->xleft, s->ytop, s->width, s->height);
da7c65f0
     } else {
12eeda34
         nb_display_channels= FFMIN(nb_display_channels, 2);
da7c65f0
         if (rdft_bits != s->rdft_bits) {
166621ab
             av_rdft_end(s->rdft);
7dbbf6a1
             av_free(s->rdft_data);
166621ab
             s->rdft = av_rdft_init(rdft_bits, DFT_R2C);
da7c65f0
             s->rdft_bits = rdft_bits;
e96109f9
             s->rdft_data = av_malloc_array(nb_freq, 4 *sizeof(*s->rdft_data));
12eeda34
         }
7da7d269
         if (!s->rdft || !s->rdft_data){
             av_log(NULL, AV_LOG_ERROR, "Failed to allocate buffers for RDFT, switching to waves display\n");
             s->show_mode = SHOW_MODE_WAVES;
         } else {
7dbbf6a1
             FFTSample *data[2];
da7c65f0
             for (ch = 0; ch < nb_display_channels; ch++) {
                 data[ch] = s->rdft_data + 2 * nb_freq * ch;
12eeda34
                 i = i_start + ch;
da7c65f0
                 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);
12eeda34
                     i += channels;
                     if (i >= SAMPLE_ARRAY_SIZE)
                         i -= SAMPLE_ARRAY_SIZE;
                 }
166621ab
                 av_rdft_calc(s->rdft, data[ch]);
12eeda34
             }
03039f4c
             /* Least efficient way to do this, we should of course
              * directly access it but it is more than fast enough. */
da7c65f0
             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);
12eeda34
 
                 fill_rectangle(screen,
                             s->xpos, s->height-y, 1, 1,
00b70f8d
                             fgcolor, 0);
12eeda34
             }
         }
         SDL_UpdateRect(screen, s->xpos, s->ytop, 1, s->height);
e6093e36
         if (!s->paused)
             s->xpos++;
da7c65f0
         if (s->xpos >= s->width)
12eeda34
             s->xpos= s->xleft;
     }
01310af2
 }
 
d5708923
 static void stream_close(VideoState *is)
 {
     /* XXX: use a special url_shutdown call to abort parse cleanly */
     is->abort_request = 1;
     SDL_WaitThread(is->read_tid, NULL);
a687acbb
     packet_queue_destroy(&is->videoq);
     packet_queue_destroy(&is->audioq);
     packet_queue_destroy(&is->subtitleq);
d5708923
 
     /* free all pictures */
5a5128ba
     frame_queue_destory(&is->pictq);
631ac655
     frame_queue_destory(&is->sampq);
5a5128ba
     frame_queue_destory(&is->subpq);
0e5042be
     SDL_DestroyCond(is->continue_read_thread);
d5708923
 #if !CONFIG_AVFILTER
c91f1f3f
     sws_freeContext(is->img_convert_ctx);
d5708923
 #endif
d64ba25a
     sws_freeContext(is->sub_convert_ctx);
d5708923
     av_free(is);
 }
 
84506ebd
 static void do_exit(VideoState *is)
d5708923
 {
84506ebd
     if (is) {
         stream_close(is);
d5708923
     }
ee0ff051
     av_lockmgr_register(NULL);
d5708923
     uninit_opts();
 #if CONFIG_AVFILTER
a583e2be
     av_freep(&vfilters_list);
d5708923
 #endif
13b7781e
     avformat_network_deinit();
d5708923
     if (show_status)
         printf("\n");
     SDL_Quit();
4a34e54b
     av_log(NULL, AV_LOG_QUIET, "%s", "");
d5708923
     exit(0);
 }
 
73f2cf4e
 static void sigterm_handler(int sig)
 {
     exit(123);
 }
 
ba800def
 static void set_default_window_size(int width, int height, AVRational sar)
2b377fb4
 {
     SDL_Rect rect;
ba800def
     calculate_display_rect(&rect, 0, 0, INT_MAX, height, width, height, sar);
2b377fb4
     default_width  = rect.w;
     default_height = rect.h;
 }
 
5a5128ba
 static int video_open(VideoState *is, int force_set_video_mode, Frame *vp)
da7c65f0
 {
     int flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
990c8438
     int w,h;
 
da7c65f0
     if (is_full_screen) flags |= SDL_FULLSCREEN;
     else                flags |= SDL_RESIZABLE;
fb84155b
 
2b377fb4
     if (vp && vp->width)
ba800def
         set_default_window_size(vp->width, vp->height, vp->sar);
5de3f724
 
990c8438
     if (is_full_screen && fs_screen_width) {
         w = fs_screen_width;
         h = fs_screen_height;
da7c65f0
     } else if (!is_full_screen && screen_width) {
fb84155b
         w = screen_width;
         h = screen_height;
990c8438
     } else {
5de3f724
         w = default_width;
         h = default_height;
990c8438
     }
87917a32
     w = FFMIN(16383, w);
da7c65f0
     if (screen && is->width == screen->w && screen->w == w
9fb2b412
        && is->height== screen->h && screen->h == h && !force_set_video_mode)
d3d7b12e
         return 0;
990c8438
     screen = SDL_SetVideoMode(w, h, 0, flags);
     if (!screen) {
3b491c5a
         av_log(NULL, AV_LOG_FATAL, "SDL: could not set video mode - exiting\n");
84506ebd
         do_exit(is);
990c8438
     }
076db5ed
     if (!window_title)
         window_title = input_filename;
     SDL_WM_SetCaption(window_title, window_title);
990c8438
 
da7c65f0
     is->width  = screen->w;
990c8438
     is->height = screen->h;
 
     return 0;
 }
8c982c5d
 
01310af2
 /* display the current picture, if any */
 static void video_display(VideoState *is)
 {
da7c65f0
     if (!screen)
5de3f724
         video_open(is, 0, NULL);
f8b8c694
     if (is->audio_st && is->show_mode != SHOW_MODE_VIDEO)
01310af2
         video_audio_display(is);
     else if (is->video_st)
         video_image_display(is);
 }
 
f2175a62
 static double get_clock(Clock *c)
638c9d91
 {
f2175a62
     if (*c->queue_serial != c->serial)
26c208cf
         return NAN;
f2175a62
     if (c->paused) {
         return c->pts;
10b7b4a6
     } else {
0ca0b4c2
         double time = av_gettime_relative() / 1000000.0;
f2175a62
         return c->pts_drift + time - (time - c->last_updated) * (1.0 - c->speed);
638c9d91
     }
 }
 
f2175a62
 static void set_clock_at(Clock *c, double pts, int serial, double time)
638c9d91
 {
f2175a62
     c->pts = pts;
     c->last_updated = time;
     c->pts_drift = c->pts - time;
     c->serial = serial;
638c9d91
 }
 
f2175a62
 static void set_clock(Clock *c, double pts, int serial)
638c9d91
 {
0ca0b4c2
     double time = av_gettime_relative() / 1000000.0;
f2175a62
     set_clock_at(c, pts, serial, time);
 }
 
 static void set_clock_speed(Clock *c, double speed)
 {
     set_clock(c, get_clock(c), c->serial);
     c->speed = speed;
 }
 
 static void init_clock(Clock *c, int *queue_serial)
 {
     c->speed = 1.0;
     c->paused = 0;
     c->queue_serial = queue_serial;
     set_clock(c, NAN, -1);
 }
 
 static void sync_clock_to_slave(Clock *c, Clock *slave)
 {
     double clock = get_clock(c);
     double slave_clock = get_clock(slave);
     if (!isnan(slave_clock) && (isnan(clock) || fabs(clock - slave_clock) > AV_NOSYNC_THRESHOLD))
         set_clock(c, slave_clock, slave->serial);
638c9d91
 }
 
fca16a15
 static int get_master_sync_type(VideoState *is) {
72ea344b
     if (is->av_sync_type == AV_SYNC_VIDEO_MASTER) {
         if (is->video_st)
fca16a15
             return AV_SYNC_VIDEO_MASTER;
72ea344b
         else
fca16a15
             return AV_SYNC_AUDIO_MASTER;
72ea344b
     } else if (is->av_sync_type == AV_SYNC_AUDIO_MASTER) {
         if (is->audio_st)
fca16a15
             return AV_SYNC_AUDIO_MASTER;
72ea344b
         else
3166a6fc
             return AV_SYNC_EXTERNAL_CLOCK;
72ea344b
     } else {
fca16a15
         return AV_SYNC_EXTERNAL_CLOCK;
     }
 }
 
 /* get the current master clock value */
 static double get_master_clock(VideoState *is)
 {
     double val;
 
     switch (get_master_sync_type(is)) {
         case AV_SYNC_VIDEO_MASTER:
f2175a62
             val = get_clock(&is->vidclk);
fca16a15
             break;
         case AV_SYNC_AUDIO_MASTER:
f2175a62
             val = get_clock(&is->audclk);
fca16a15
             break;
         default:
f2175a62
             val = get_clock(&is->extclk);
fca16a15
             break;
72ea344b
     }
638c9d91
     return val;
 }
 
747c749d
 static void check_external_clock_speed(VideoState *is) {
0166d329
    if (is->video_stream >= 0 && is->videoq.nb_packets <= EXTERNAL_CLOCK_MIN_FRAMES ||
        is->audio_stream >= 0 && is->audioq.nb_packets <= EXTERNAL_CLOCK_MIN_FRAMES) {
f2175a62
        set_clock_speed(&is->extclk, FFMAX(EXTERNAL_CLOCK_SPEED_MIN, is->extclk.speed - EXTERNAL_CLOCK_SPEED_STEP));
0166d329
    } else if ((is->video_stream < 0 || is->videoq.nb_packets > EXTERNAL_CLOCK_MAX_FRAMES) &&
               (is->audio_stream < 0 || is->audioq.nb_packets > EXTERNAL_CLOCK_MAX_FRAMES)) {
f2175a62
        set_clock_speed(&is->extclk, FFMIN(EXTERNAL_CLOCK_SPEED_MAX, is->extclk.speed + EXTERNAL_CLOCK_SPEED_STEP));
747c749d
    } else {
f2175a62
        double speed = is->extclk.speed;
747c749d
        if (speed != 1.0)
f2175a62
            set_clock_speed(&is->extclk, speed + EXTERNAL_CLOCK_SPEED_STEP * (1.0 - speed) / fabs(1.0 - speed));
747c749d
    }
 }
 
72ea344b
 /* seek in the stream */
2ef46053
 static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_bytes)
72ea344b
 {
687fae2b
     if (!is->seek_req) {
         is->seek_pos = pos;
4ed29207
         is->seek_rel = rel;
3890dd3a
         is->seek_flags &= ~AVSEEK_FLAG_BYTE;
94b594c6
         if (seek_by_bytes)
             is->seek_flags |= AVSEEK_FLAG_BYTE;
687fae2b
         is->seek_req = 1;
4be7d578
         SDL_CondSignal(is->continue_read_thread);
687fae2b
     }
72ea344b
 }
 
 /* pause or resume the video */
ab7fdbab
 static void stream_toggle_pause(VideoState *is)
72ea344b
 {
68aefbe8
     if (is->paused) {
68850090
         is->frame_timer += av_gettime_relative() / 1000000.0 - is->vidclk.last_updated;
da7c65f0
         if (is->read_pause_return != AVERROR(ENOSYS)) {
f2175a62
             is->vidclk.paused = 0;
f5668147
         }
f2175a62
         set_clock(&is->vidclk, get_clock(&is->vidclk), is->vidclk.serial);
72ea344b
     }
f2175a62
     set_clock(&is->extclk, get_clock(&is->extclk), is->extclk.serial);
     is->paused = is->audclk.paused = is->vidclk.paused = is->extclk.paused = !is->paused;
72ea344b
 }
 
c5eab4bb
 static void toggle_pause(VideoState *is)
 {
     stream_toggle_pause(is);
     is->step = 0;
 }
 
 static void step_to_next_frame(VideoState *is)
 {
     /* if the stream is paused unpause it, then step */
     if (is->paused)
         stream_toggle_pause(is);
     is->step = 1;
 }
 
4e268aae
 static double compute_target_delay(double delay, VideoState *is)
49410784
 {
7ad528cf
     double sync_threshold, diff = 0;
49410784
 
     /* update delay to follow master synchronisation source */
d30c6925
     if (get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER) {
49410784
         /* if video is slave, we try to correct big delays by
            duplicating or deleting a frame */
f2175a62
         diff = get_clock(&is->vidclk) - get_master_clock(is);
49410784
 
         /* skip or repeat frame. We take into account the
            delay to compute the threshold. I still don't know
            if it is the best guess */
e341cb11
         sync_threshold = FFMAX(AV_SYNC_THRESHOLD_MIN, FFMIN(AV_SYNC_THRESHOLD_MAX, delay));
         if (!isnan(diff) && fabs(diff) < is->max_frame_duration) {
49410784
             if (diff <= -sync_threshold)
e341cb11
                 delay = FFMAX(0, delay + diff);
             else if (diff >= sync_threshold && delay > AV_SYNC_FRAMEDUP_THRESHOLD)
                 delay = delay + diff;
49410784
             else if (diff >= sync_threshold)
                 delay = 2 * delay;
         }
     }
8543f0f9
 
40d552da
     av_log(NULL, AV_LOG_TRACE, "video: delay=%0.3f A-V=%f\n",
4e268aae
             delay, -diff);
 
     return delay;
 }
 
5a5128ba
 static double vp_duration(VideoState *is, Frame *vp, Frame *nextvp) {
5ecfcc7d
     if (vp->serial == nextvp->serial) {
         double duration = nextvp->pts - vp->pts;
         if (isnan(duration) || duration <= 0 || duration > is->max_frame_duration)
             return vp->duration;
         else
             return duration;
     } else {
         return 0.0;
     }
 }
 
2a4c7e65
 static void update_video_pts(VideoState *is, double pts, int64_t pos, int serial) {
223cba6e
     /* update current video pts */
f2175a62
     set_clock(&is->vidclk, pts, serial);
     sync_clock_to_slave(&is->extclk, &is->vidclk);
223cba6e
 }
 
01310af2
 /* called to display each frame */
b853cfe7
 static void video_refresh(void *opaque, double *remaining_time)
01310af2
 {
     VideoState *is = opaque;
223cba6e
     double time;
638c9d91
 
5a5128ba
     Frame *sp, *sp2;
01310af2
 
747c749d
     if (!is->paused && get_master_sync_type(is) == AV_SYNC_EXTERNAL_CLOCK && is->realtime)
         check_external_clock_speed(is);
 
b853cfe7
     if (!display_disable && is->show_mode != SHOW_MODE_VIDEO && is->audio_st) {
0ca0b4c2
         time = av_gettime_relative() / 1000000.0;
b853cfe7
         if (is->force_refresh || is->last_vis_time + rdftspeed < time) {
             video_display(is);
             is->last_vis_time = time;
         }
         *remaining_time = FFMIN(*remaining_time, is->last_vis_time + rdftspeed - time);
     }
ec89ea30
 
01310af2
     if (is->video_st) {
38f64966
         int redisplay = 0;
81f26d69
         if (is->force_refresh)
5a5128ba
             redisplay = frame_queue_prev(&is->pictq);
d38c9e7a
 retry:
5a5128ba
         if (frame_queue_nb_remaining(&is->pictq) == 0) {
491ca0e8
             // nothing to do, no picture to display in the queue
01310af2
         } else {
4e268aae
             double last_duration, duration, delay;
5a5128ba
             Frame *vp, *lastvp;
28031404
 
638c9d91
             /* dequeue the picture */
5a5128ba
             lastvp = frame_queue_peek_last(&is->pictq);
             vp = frame_queue_peek(&is->pictq);
638c9d91
 
1427c684
             if (vp->serial != is->videoq.serial) {
5a5128ba
                 frame_queue_next(&is->pictq);
38f64966
                 redisplay = 0;
4e268aae
                 goto retry;
             }
 
318bf57c
             if (lastvp->serial != vp->serial && !redisplay)
0ca0b4c2
                 is->frame_timer = av_gettime_relative() / 1000000.0;
318bf57c
 
dbe7170e
             if (is->paused)
                 goto display;
 
4e268aae
             /* compute nominal last_duration */
28031404
             last_duration = vp_duration(is, lastvp, vp);
3b6f1526
             if (redisplay)
                 delay = 0.0;
             else
28031404
                 delay = compute_target_delay(last_duration, is);
4e268aae
 
0ca0b4c2
             time= av_gettime_relative()/1000000.0;
b764b53a
             if (time < is->frame_timer + delay && !redisplay) {
b853cfe7
                 *remaining_time = FFMIN(is->frame_timer + delay - time, *remaining_time);
d38c9e7a
                 return;
b853cfe7
             }
4e268aae
 
97e42551
             is->frame_timer += delay;
             if (delay > 0 && time - is->frame_timer > AV_SYNC_THRESHOLD_MAX)
                 is->frame_timer = time;
4e268aae
 
5a5128ba
             SDL_LockMutex(is->pictq.mutex);
35b2f30f
             if (!redisplay && !isnan(vp->pts))
d148339d
                 update_video_pts(is, vp->pts, vp->pos, vp->serial);
5a5128ba
             SDL_UnlockMutex(is->pictq.mutex);
4e268aae
 
5a5128ba
             if (frame_queue_nb_remaining(&is->pictq) > 1) {
                 Frame *nextvp = frame_queue_peek_next(&is->pictq);
5ecfcc7d
                 duration = vp_duration(is, vp, nextvp);
38f64966
                 if(!is->step && (redisplay || framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) && time > is->frame_timer + duration){
                     if (!redisplay)
                         is->frame_drops_late++;
5a5128ba
                     frame_queue_next(&is->pictq);
38f64966
                     redisplay = 0;
d38c9e7a
                     goto retry;
                 }
             }
638c9d91
 
da7c65f0
             if (is->subtitle_st) {
5a5128ba
                     while (frame_queue_nb_remaining(&is->subpq) > 0) {
                         sp = frame_queue_peek(&is->subpq);
72ce053b
 
5a5128ba
                         if (frame_queue_nb_remaining(&is->subpq) > 1)
                             sp2 = frame_queue_peek_next(&is->subpq);
72ce053b
                         else
                             sp2 = NULL;
 
9fac752a
                         if (sp->serial != is->subtitleq.serial
                                 || (is->vidclk.pts > (sp->pts + ((float) sp->sub.end_display_time / 1000)))
05f0d531
                                 || (sp2 && is->vidclk.pts > (sp2->pts + ((float) sp2->sub.start_display_time / 1000))))
72ce053b
                         {
5a5128ba
                             frame_queue_next(&is->subpq);
9fac752a
                         } else {
                             break;
72ce053b
                         }
                     }
             }
 
dbe7170e
 display:
01310af2
             /* display picture */
ec89ea30
             if (!display_disable && is->show_mode == SHOW_MODE_VIDEO)
24d13ebc
                 video_display(is);
115329f1
 
5a5128ba
             frame_queue_next(&is->pictq);
97660b8b
 
             if (is->step && !is->paused)
                 stream_toggle_pause(is);
01310af2
         }
     }
dbe7170e
     is->force_refresh = 0;
01310af2
     if (show_status) {
         static int64_t last_time;
         int64_t cur_time;
72ce053b
         int aqsize, vqsize, sqsize;
638c9d91
         double av_diff;
115329f1
 
0ca0b4c2
         cur_time = av_gettime_relative();
1e1a0b18
         if (!last_time || (cur_time - last_time) >= 30000) {
01310af2
             aqsize = 0;
             vqsize = 0;
72ce053b
             sqsize = 0;
01310af2
             if (is->audio_st)
                 aqsize = is->audioq.size;
             if (is->video_st)
                 vqsize = is->videoq.size;
72ce053b
             if (is->subtitle_st)
                 sqsize = is->subtitleq.size;
638c9d91
             av_diff = 0;
             if (is->audio_st && is->video_st)
f2175a62
                 av_diff = get_clock(&is->audclk) - get_clock(&is->vidclk);
5b492720
             else if (is->video_st)
                 av_diff = get_master_clock(is) - get_clock(&is->vidclk);
             else if (is->audio_st)
                 av_diff = get_master_clock(is) - get_clock(&is->audclk);
3b491c5a
             av_log(NULL, AV_LOG_INFO,
                    "%7.2f %s:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64"   \r",
d6705a27
                    get_master_clock(is),
5b492720
                    (is->audio_st && is->video_st) ? "A-V" : (is->video_st ? "M-V" : (is->audio_st ? "M-A" : "   ")),
d6705a27
                    av_diff,
d54af906
                    is->frame_drops_early + is->frame_drops_late,
d6705a27
                    aqsize / 1024,
                    vqsize / 1024,
                    sqsize,
                    is->video_st ? is->video_st->codec->pts_correction_num_faulty_dts : 0,
                    is->video_st ? is->video_st->codec->pts_correction_num_faulty_pts : 0);
01310af2
             fflush(stdout);
             last_time = cur_time;
         }
     }
 }
 
 /* allocate a picture (needs to do that in main thread to avoid
    potential locking problems */
99b01e45
 static void alloc_picture(VideoState *is)
01310af2
 {
5a5128ba
     Frame *vp;
30d724bd
     int64_t bufferdiff;
01310af2
 
5a5128ba
     vp = &is->pictq.queue[is->pictq.windex];
01310af2
 
2d059d8d
     free_picture(vp);
01310af2
 
5de3f724
     video_open(is, 0, vp);
843509e2
 
917d2bb3
     vp->bmp = SDL_CreateYUVOverlay(vp->width, vp->height,
115329f1
                                    SDL_YV12_OVERLAY,
61890b02
                                    screen);
30d724bd
     bufferdiff = vp->bmp ? FFMAX(vp->bmp->pixels[0], vp->bmp->pixels[1]) - FFMIN(vp->bmp->pixels[0], vp->bmp->pixels[1]) : 0;
f73d6d2a
     if (!vp->bmp || vp->bmp->pitches[0] < vp->width || bufferdiff < (int64_t)vp->height * vp->bmp->pitches[0]) {
cb036f90
         /* SDL allocates a buffer smaller than requested if the video
          * overlay hardware is unable to support the requested size. */
3b491c5a
         av_log(NULL, AV_LOG_FATAL,
                "Error: the video system does not support an image\n"
70d54392
                         "size of %dx%d pixels. Try using -lowres or -vf \"scale=w:h\"\n"
cb036f90
                         "to reduce the image size.\n", vp->width, vp->height );
84506ebd
         do_exit(is);
cb036f90
     }
01310af2
 
5a5128ba
     SDL_LockMutex(is->pictq.mutex);
01310af2
     vp->allocated = 1;
5a5128ba
     SDL_CondSignal(is->pictq.cond);
     SDL_UnlockMutex(is->pictq.mutex);
01310af2
 }
 
cf0c63d9
 static void duplicate_right_border_pixels(SDL_Overlay *bmp) {
     int i, width, height;
     Uint8 *p, *maxp;
     for (i = 0; i < 3; i++) {
         width  = bmp->w;
         height = bmp->h;
         if (i > 0) {
             width  >>= 1;
             height >>= 1;
         }
         if (bmp->pitches[i] > width) {
             maxp = bmp->pixels[i] + bmp->pitches[i] * height - 1;
             for (p = bmp->pixels[i] + width - 1; p < maxp; p += bmp->pitches[i])
                 *(p+1) = *p;
         }
     }
 }
 
61dd3197
 static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, double duration, int64_t pos, int serial)
01310af2
 {
5a5128ba
     Frame *vp;
c2606259
 
 #if defined(DEBUG_SYNC) && 0
5534d8f7
     printf("frame_type=%c pts=%0.3f\n",
            av_get_picture_type_char(src_frame->pict_type), pts);
c2606259
 #endif
a6f395d6
 
5a5128ba
     if (!(vp = frame_queue_peek_writable(&is->pictq)))
01310af2
         return -1;
 
32fdfdfb
     vp->sar = src_frame->sample_aspect_ratio;
99b01e45
 
01310af2
     /* alloc or resize hardware picture buffer */
99b01e45
     if (!vp->bmp || vp->reallocate || !vp->allocated ||
843509e2
         vp->width  != src_frame->width ||
         vp->height != src_frame->height) {
01310af2
         SDL_Event event;
 
fec5777e
         vp->allocated  = 0;
8085a5b7
         vp->reallocate = 0;
99b01e45
         vp->width = src_frame->width;
         vp->height = src_frame->height;
01310af2
 
         /* the allocation must be done in the main thread to avoid
99b01e45
            locking problems. */
01310af2
         event.type = FF_ALLOC_EVENT;
99b01e45
         event.user.data1 = is;
01310af2
         SDL_PushEvent(&event);
115329f1
 
01310af2
         /* wait until the picture is allocated */
5a5128ba
         SDL_LockMutex(is->pictq.mutex);
01310af2
         while (!vp->allocated && !is->videoq.abort_request) {
5a5128ba
             SDL_CondWait(is->pictq.cond, is->pictq.mutex);
01310af2
         }
0a1cf662
         /* if the queue is aborted, we have to pop the pending ALLOC event or wait for the allocation to complete */
         if (is->videoq.abort_request && SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_EVENTMASK(FF_ALLOC_EVENT)) != 1) {
ac7b4bfd
             while (!vp->allocated && !is->abort_request) {
5a5128ba
                 SDL_CondWait(is->pictq.cond, is->pictq.mutex);
0a1cf662
             }
         }
5a5128ba
         SDL_UnlockMutex(is->pictq.mutex);
01310af2
 
         if (is->videoq.abort_request)
             return -1;
     }
 
638c9d91
     /* if the frame is not skipped, then display it */
01310af2
     if (vp->bmp) {
a92be9b8
         AVPicture pict = { { 0 } };
fbf1b885
 
01310af2
         /* get a pointer on the bitmap */
         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];
917d2bb3
 
 #if CONFIG_AVFILTER
da7c65f0
         // FIXME use direct rendering
a6f395d6
         av_picture_copy(&pict, (AVPicture *)src_frame,
f1a75aa0
                         src_frame->format, vp->width, vp->height);
917d2bb3
 #else
5edab1d2
         {
             AVDictionaryEntry *e = av_dict_get(sws_dict, "sws_flags", NULL, 0);
             if (e) {
                 const AVClass *class = sws_get_class();
                 const AVOption    *o = av_opt_find(&class, "sws_flags", NULL, 0,
                                                    AV_OPT_SEARCH_FAKE_OBJ);
                 int ret = av_opt_eval_flags(&class, o, e->value, &sws_flags);
                 if (ret < 0)
                     exit(1);
             }
         }
 
3ac56e28
         is->img_convert_ctx = sws_getCachedContext(is->img_convert_ctx,
f1a75aa0
             vp->width, vp->height, src_frame->format, vp->width, vp->height,
ac627b3d
             AV_PIX_FMT_YUV420P, sws_flags, NULL, NULL, NULL);
fb33bff9
         if (!is->img_convert_ctx) {
3b491c5a
             av_log(NULL, AV_LOG_FATAL, "Cannot initialize the conversion context\n");
26ba8235
             exit(1);
         }
3ac56e28
         sws_scale(is->img_convert_ctx, src_frame->data, src_frame->linesize,
917d2bb3
                   0, vp->height, pict.data, pict.linesize);
 #endif
cf0c63d9
         /* workaround SDL PITCH_WORKAROUND */
         duplicate_right_border_pixels(vp->bmp);
01310af2
         /* update the bitmap content */
         SDL_UnlockYUVOverlay(vp->bmp);
 
638c9d91
         vp->pts = pts;
61dd3197
         vp->duration = duration;
1a620dd7
         vp->pos = pos;
2a4c7e65
         vp->serial = serial;
01310af2
 
         /* now we can update the picture count */
5a5128ba
         frame_queue_push(&is->pictq);
01310af2
     }
638c9d91
     return 0;
 }
 
9e0d1c00
 static int get_video_frame(VideoState *is, AVFrame *frame)
01310af2
 {
1427c684
     int got_picture;
01310af2
 
2ec4a84d
     if ((got_picture = decoder_decode_frame(&is->viddec, frame, NULL)) < 0)
199c18a7
         return -1;
6c7d3ead
 
199c18a7
     if (got_picture) {
d148339d
         double dpts = NAN;
223cba6e
 
d148339d
         if (frame->pts != AV_NOPTS_VALUE)
             dpts = av_q2d(is->video_st->time_base) * frame->pts;
41db429d
 
40693ba3
         frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, frame);
 
d64ba25a
         is->viddec_width  = frame->width;
         is->viddec_height = frame->height;
 
d30c6925
         if (framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) {
02b76aa3
             if (frame->pts != AV_NOPTS_VALUE) {
                 double diff = dpts - get_master_clock(is);
                 if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD &&
                     diff - is->frame_last_filter_delay < 0 &&
9e0d1c00
                     is->viddec.pkt_serial == is->vidclk.serial &&
b8facbee
                     is->videoq.nb_packets) {
d54af906
                     is->frame_drops_early++;
c46a8c61
                     av_frame_unref(frame);
9e0d1c00
                     got_picture = 0;
223cba6e
                 }
             }
         }
d38c9e7a
     }
9e0d1c00
 
     return got_picture;
917d2bb3
 }
 
 #if CONFIG_AVFILTER
79a7451d
 static int configure_filtergraph(AVFilterGraph *graph, const char *filtergraph,
                                  AVFilterContext *source_ctx, AVFilterContext *sink_ctx)
 {
cec6dec7
     int ret, i;
     int nb_filters = graph->nb_filters;
79a7451d
     AVFilterInOut *outputs = NULL, *inputs = NULL;
 
     if (filtergraph) {
         outputs = avfilter_inout_alloc();
         inputs  = avfilter_inout_alloc();
         if (!outputs || !inputs) {
             ret = AVERROR(ENOMEM);
             goto fail;
         }
 
         outputs->name       = av_strdup("in");
         outputs->filter_ctx = source_ctx;
         outputs->pad_idx    = 0;
         outputs->next       = NULL;
 
         inputs->name        = av_strdup("out");
         inputs->filter_ctx  = sink_ctx;
         inputs->pad_idx     = 0;
         inputs->next        = NULL;
 
838bd731
         if ((ret = avfilter_graph_parse_ptr(graph, filtergraph, &inputs, &outputs, NULL)) < 0)
79a7451d
             goto fail;
     } else {
         if ((ret = avfilter_link(source_ctx, 0, sink_ctx, 0)) < 0)
             goto fail;
     }
 
cec6dec7
     /* Reorder the filters to ensure that inputs of the custom filters are merged first */
     for (i = 0; i < graph->nb_filters - nb_filters; i++)
         FFSWAP(AVFilterContext*, graph->filters[i], graph->filters[i + nb_filters]);
 
abd49a75
     ret = avfilter_graph_config(graph, NULL);
79a7451d
 fail:
     avfilter_inout_free(&outputs);
     avfilter_inout_free(&inputs);
     return ret;
 }
 
3f72dbe4
 static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters, AVFrame *frame)
917d2bb3
 {
ac627b3d
     static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };
e755954a
     char sws_flags_str[512] = "";
67339f6e
     char buffersrc_args[256];
8904a0f1
     int ret;
08c51e12
     AVFilterContext *filt_src = NULL, *filt_out = NULL, *last_filter = NULL;
67339f6e
     AVCodecContext *codec = is->video_st->codec;
612d9cdb
     AVRational fr = av_guess_frame_rate(is->ic, is->video_st, NULL);
e755954a
     AVDictionaryEntry *e = NULL;
 
     while ((e = av_dict_get(sws_dict, "", e, AV_DICT_IGNORE_SUFFIX))) {
         if (!strcmp(e->key, "sws_flags")) {
             av_strlcatf(sws_flags_str, sizeof(sws_flags_str), "%s=%s:", "flags", e->value);
         } else
             av_strlcatf(sws_flags_str, sizeof(sws_flags_str), "%s=%s:", e->key, e->value);
     }
     if (strlen(sws_flags_str))
         sws_flags_str[strlen(sws_flags_str)-1] = '\0';
67339f6e
 
3f073fa2
     graph->scale_sws_opts = av_strdup(sws_flags_str);
917d2bb3
 
251f3987
     snprintf(buffersrc_args, sizeof(buffersrc_args),
              "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
3f72dbe4
              frame->width, frame->height, frame->format,
67339f6e
              is->video_st->time_base.num, is->video_st->time_base.den,
a63d7213
              codec->sample_aspect_ratio.num, FFMAX(codec->sample_aspect_ratio.den, 1));
612d9cdb
     if (fr.num && fr.den)
         av_strlcatf(buffersrc_args, sizeof(buffersrc_args), ":frame_rate=%d/%d", fr.num, fr.den);
67339f6e
 
     if ((ret = avfilter_graph_create_filter(&filt_src,
                                             avfilter_get_by_name("buffer"),
8f45c314
                                             "ffplay_buffer", buffersrc_args, NULL,
67339f6e
                                             graph)) < 0)
8cb74024
         goto fail;
3c5fe5b5
 
61930bd0
     ret = avfilter_graph_create_filter(&filt_out,
ceac5c54
                                        avfilter_get_by_name("buffersink"),
e87c1cdb
                                        "ffplay_buffersink", NULL, NULL, graph);
c4415f6e
     if (ret < 0)
8cb74024
         goto fail;
917d2bb3
 
e87c1cdb
     if ((ret = av_opt_set_int_list(filt_out, "pix_fmts", pix_fmts,  AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0)
         goto fail;
 
08c51e12
     last_filter = filt_out;
 
 /* Note: this macro adds a filter before the lastly added filter, so the
  * processing order of the filters is in reverse */
e874772f
 #define INSERT_FILT(name, arg) do {                                          \
     AVFilterContext *filt_ctx;                                               \
                                                                              \
     ret = avfilter_graph_create_filter(&filt_ctx,                            \
                                        avfilter_get_by_name(name),           \
                                        "ffplay_" name, arg, NULL, graph);    \
     if (ret < 0)                                                             \
         goto fail;                                                           \
                                                                              \
     ret = avfilter_link(filt_ctx, 0, last_filter, 0);                        \
     if (ret < 0)                                                             \
         goto fail;                                                           \
                                                                              \
     last_filter = filt_ctx;                                                  \
08c51e12
 } while (0)
 
a366beaf
     /* SDL YUV code is not handling odd width/height for some driver
      * combinations, therefore we crop the picture to an even width/height. */
08c51e12
     INSERT_FILT("crop", "floor(in_w/2)*2:floor(in_h/2)*2");
 
     if (autorotate) {
4351c288
         double theta  = get_rotation(is->video_st);
f9e80201
 
         if (fabs(theta - 90) < 1.0) {
             INSERT_FILT("transpose", "clock");
         } else if (fabs(theta - 180) < 1.0) {
             INSERT_FILT("hflip", NULL);
             INSERT_FILT("vflip", NULL);
         } else if (fabs(theta - 270) < 1.0) {
             INSERT_FILT("transpose", "cclock");
         } else if (fabs(theta) > 1.0) {
             char rotate_buf[64];
             snprintf(rotate_buf, sizeof(rotate_buf), "%f*PI/180", theta);
             INSERT_FILT("rotate", rotate_buf);
08c51e12
         }
     }
ac712309
 
08c51e12
     if ((ret = configure_filtergraph(graph, vfilters, filt_src, last_filter)) < 0)
8cb74024
         goto fail;
917d2bb3
 
67339f6e
     is->in_video_filter  = filt_src;
917d2bb3
     is->out_video_filter = filt_out;
71a1d111
 
8cb74024
 fail:
8904a0f1
     return ret;
 }
 
e96175ad
 static int configure_audio_filters(VideoState *is, const char *afilters, int force_output_format)
 {
4d16ba2d
     static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE };
e96175ad
     int sample_rates[2] = { 0, -1 };
     int64_t channel_layouts[2] = { 0, -1 };
     int channels[2] = { 0, -1 };
     AVFilterContext *filt_asrc = NULL, *filt_asink = NULL;
44758b4d
     char aresample_swr_opts[512] = "";
     AVDictionaryEntry *e = NULL;
e96175ad
     char asrc_args[256];
     int ret;
 
     avfilter_graph_free(&is->agraph);
     if (!(is->agraph = avfilter_graph_alloc()))
         return AVERROR(ENOMEM);
 
44758b4d
     while ((e = av_dict_get(swr_opts, "", e, AV_DICT_IGNORE_SUFFIX)))
         av_strlcatf(aresample_swr_opts, sizeof(aresample_swr_opts), "%s=%s:", e->key, e->value);
     if (strlen(aresample_swr_opts))
         aresample_swr_opts[strlen(aresample_swr_opts)-1] = '\0';
     av_opt_set(is->agraph, "aresample_swr_opts", aresample_swr_opts, 0);
 
e96175ad
     ret = snprintf(asrc_args, sizeof(asrc_args),
325846aa
                    "sample_rate=%d:sample_fmt=%s:channels=%d:time_base=%d/%d",
e96175ad
                    is->audio_filter_src.freq, av_get_sample_fmt_name(is->audio_filter_src.fmt),
325846aa
                    is->audio_filter_src.channels,
                    1, is->audio_filter_src.freq);
e96175ad
     if (is->audio_filter_src.channel_layout)
         snprintf(asrc_args + ret, sizeof(asrc_args) - ret,
                  ":channel_layout=0x%"PRIx64,  is->audio_filter_src.channel_layout);
 
     ret = avfilter_graph_create_filter(&filt_asrc,
                                        avfilter_get_by_name("abuffer"), "ffplay_abuffer",
                                        asrc_args, NULL, is->agraph);
     if (ret < 0)
         goto end;
 
e87c1cdb
 
     ret = avfilter_graph_create_filter(&filt_asink,
                                        avfilter_get_by_name("abuffersink"), "ffplay_abuffersink",
                                        NULL, NULL, is->agraph);
     if (ret < 0)
         goto end;
 
     if ((ret = av_opt_set_int_list(filt_asink, "sample_fmts", sample_fmts,  AV_SAMPLE_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0)
         goto end;
     if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 1, AV_OPT_SEARCH_CHILDREN)) < 0)
e96175ad
         goto end;
 
     if (force_output_format) {
         channel_layouts[0] = is->audio_tgt.channel_layout;
e87c1cdb
         channels       [0] = is->audio_tgt.channels;
         sample_rates   [0] = is->audio_tgt.freq;
         if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 0, AV_OPT_SEARCH_CHILDREN)) < 0)
             goto end;
         if ((ret = av_opt_set_int_list(filt_asink, "channel_layouts", channel_layouts,  -1, AV_OPT_SEARCH_CHILDREN)) < 0)
             goto end;
         if ((ret = av_opt_set_int_list(filt_asink, "channel_counts" , channels       ,  -1, AV_OPT_SEARCH_CHILDREN)) < 0)
             goto end;
         if ((ret = av_opt_set_int_list(filt_asink, "sample_rates"   , sample_rates   ,  -1, AV_OPT_SEARCH_CHILDREN)) < 0)
             goto end;
e96175ad
     }
 
 
     if ((ret = configure_filtergraph(is->agraph, afilters, filt_asrc, filt_asink)) < 0)
         goto end;
 
     is->in_audio_filter  = filt_asrc;
     is->out_audio_filter = filt_asink;
 
 end:
     if (ret < 0)
         avfilter_graph_free(&is->agraph);
     return ret;
 }
8904a0f1
 #endif  /* CONFIG_AVFILTER */
 
631ac655
 static int audio_thread(void *arg)
 {
     VideoState *is = arg;
     AVFrame *frame = av_frame_alloc();
     Frame *af;
 #if CONFIG_AVFILTER
     int last_serial = -1;
     int64_t dec_channel_layout;
     int reconfigure;
 #endif
     int got_frame = 0;
     AVRational tb;
     int ret = 0;
 
     if (!frame)
         return AVERROR(ENOMEM);
 
     do {
         if ((got_frame = decoder_decode_frame(&is->auddec, frame, NULL)) < 0)
             goto the_end;
 
         if (got_frame) {
                 tb = (AVRational){1, frame->sample_rate};
 
 #if CONFIG_AVFILTER
                 dec_channel_layout = get_valid_channel_layout(frame->channel_layout, av_frame_get_channels(frame));
 
                 reconfigure =
                     cmp_audio_fmts(is->audio_filter_src.fmt, is->audio_filter_src.channels,
                                    frame->format, av_frame_get_channels(frame))    ||
                     is->audio_filter_src.channel_layout != dec_channel_layout ||
                     is->audio_filter_src.freq           != frame->sample_rate ||
                     is->auddec.pkt_serial               != last_serial;
 
                 if (reconfigure) {
                     char buf1[1024], buf2[1024];
                     av_get_channel_layout_string(buf1, sizeof(buf1), -1, is->audio_filter_src.channel_layout);
                     av_get_channel_layout_string(buf2, sizeof(buf2), -1, dec_channel_layout);
                     av_log(NULL, AV_LOG_DEBUG,
                            "Audio frame changed from rate:%d ch:%d fmt:%s layout:%s serial:%d to rate:%d ch:%d fmt:%s layout:%s serial:%d\n",
                            is->audio_filter_src.freq, is->audio_filter_src.channels, av_get_sample_fmt_name(is->audio_filter_src.fmt), buf1, last_serial,
                            frame->sample_rate, av_frame_get_channels(frame), av_get_sample_fmt_name(frame->format), buf2, is->auddec.pkt_serial);
 
                     is->audio_filter_src.fmt            = frame->format;
                     is->audio_filter_src.channels       = av_frame_get_channels(frame);
                     is->audio_filter_src.channel_layout = dec_channel_layout;
                     is->audio_filter_src.freq           = frame->sample_rate;
                     last_serial                         = is->auddec.pkt_serial;
 
                     if ((ret = configure_audio_filters(is, afilters, 1)) < 0)
                         goto the_end;
                 }
 
             if ((ret = av_buffersrc_add_frame(is->in_audio_filter, frame)) < 0)
                 goto the_end;
 
             while ((ret = av_buffersink_get_frame_flags(is->out_audio_filter, frame, 0)) >= 0) {
                 tb = is->out_audio_filter->inputs[0]->time_base;
 #endif
                 if (!(af = frame_queue_peek_writable(&is->sampq)))
                     goto the_end;
 
                 af->pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);
                 af->pos = av_frame_get_pkt_pos(frame);
                 af->serial = is->auddec.pkt_serial;
                 af->duration = av_q2d((AVRational){frame->nb_samples, frame->sample_rate});
 
                 av_frame_move_ref(af->frame, frame);
                 frame_queue_push(&is->sampq);
 
 #if CONFIG_AVFILTER
                 if (is->audioq.serial != is->auddec.pkt_serial)
                     break;
             }
             if (ret == AVERROR_EOF)
                 is->auddec.finished = is->auddec.pkt_serial;
 #endif
         }
     } while (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF);
  the_end:
 #if CONFIG_AVFILTER
     avfilter_graph_free(&is->agraph);
 #endif
     av_frame_free(&frame);
     return ret;
 }
 
ef1ccea9
 static void decoder_start(Decoder *d, int (*fn)(void *), void *arg)
 {
     packet_queue_start(d->queue);
     d->decoder_tid = SDL_CreateThread(fn, arg);
 }
 
8904a0f1
 static int video_thread(void *arg)
 {
     VideoState *is = arg;
354468fc
     AVFrame *frame = av_frame_alloc();
8904a0f1
     double pts;
61dd3197
     double duration;
8904a0f1
     int ret;
105d4748
     AVRational tb = is->video_st->time_base;
61dd3197
     AVRational frame_rate = av_guess_frame_rate(is->ic, is->video_st, NULL);
8904a0f1
 
 #if CONFIG_AVFILTER
     AVFilterGraph *graph = avfilter_graph_alloc();
67339f6e
     AVFilterContext *filt_out = NULL, *filt_in = NULL;
58f22f70
     int last_w = 0;
     int last_h = 0;
ac627b3d
     enum AVPixelFormat last_format = -2;
f65e5712
     int last_serial = -1;
a583e2be
     int last_vfilter_idx = 0;
eb8756e4
     if (!graph) {
         av_frame_free(&frame);
a821617b
         return AVERROR(ENOMEM);
eb8756e4
     }
a821617b
 
917d2bb3
 #endif
 
eb8756e4
     if (!frame) {
 #if CONFIG_AVFILTER
         avfilter_graph_free(&graph);
 #endif
32b2b7bd
         return AVERROR(ENOMEM);
eb8756e4
     }
32b2b7bd
 
da7c65f0
     for (;;) {
9e0d1c00
         ret = get_video_frame(is, frame);
67339f6e
         if (ret < 0)
             goto the_end;
         if (!ret)
             continue;
 
917d2bb3
 #if CONFIG_AVFILTER
230bef0a
         if (   last_w != frame->width
             || last_h != frame->height
f65e5712
             || last_format != frame->format
9e0d1c00
             || last_serial != is->viddec.pkt_serial
a583e2be
             || last_vfilter_idx != is->vfilter_idx) {
212bb649
             av_log(NULL, AV_LOG_DEBUG,
58c4b0f9
                    "Video frame changed from size:%dx%d format:%s serial:%d to size:%dx%d format:%s serial:%d\n",
                    last_w, last_h,
                    (const char *)av_x_if_null(av_get_pix_fmt_name(last_format), "none"), last_serial,
                    frame->width, frame->height,
9e0d1c00
                    (const char *)av_x_if_null(av_get_pix_fmt_name(frame->format), "none"), is->viddec.pkt_serial);
428c59d9
             avfilter_graph_free(&graph);
             graph = avfilter_graph_alloc();
a583e2be
             if ((ret = configure_video_filters(graph, is, vfilters_list ? vfilters_list[is->vfilter_idx] : NULL, frame)) < 0) {
58f22f70
                 SDL_Event event;
                 event.type = FF_QUIT_EVENT;
                 event.user.data1 = is;
                 SDL_PushEvent(&event);
428c59d9
                 goto the_end;
c9651d4b
             }
cd947e9a
             filt_in  = is->in_video_filter;
428c59d9
             filt_out = is->out_video_filter;
230bef0a
             last_w = frame->width;
             last_h = frame->height;
             last_format = frame->format;
9e0d1c00
             last_serial = is->viddec.pkt_serial;
a583e2be
             last_vfilter_idx = is->vfilter_idx;
61dd3197
             frame_rate = filt_out->inputs[0]->frame_rate;
428c59d9
         }
67339f6e
 
354468fc
         ret = av_buffersrc_add_frame(filt_in, frame);
         if (ret < 0)
             goto the_end;
c9651d4b
 
67339f6e
         while (ret >= 0) {
0ca0b4c2
             is->frame_last_returned_time = av_gettime_relative() / 1000000.0;
a78bc6f7
 
32fdfdfb
             ret = av_buffersink_get_frame_flags(filt_out, frame, 0);
67339f6e
             if (ret < 0) {
18be3fac
                 if (ret == AVERROR_EOF)
9e0d1c00
                     is->viddec.finished = is->viddec.pkt_serial;
67339f6e
                 ret = 0;
                 break;
             }
 
0ca0b4c2
             is->frame_last_filter_delay = av_gettime_relative() / 1000000.0 - is->frame_last_returned_time;
a78bc6f7
             if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0)
                 is->frame_last_filter_delay = 0;
105d4748
             tb = filt_out->inputs[0]->time_base;
 #endif
61dd3197
             duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0);
105d4748
             pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);
9e0d1c00
             ret = queue_picture(is, frame, pts, duration, av_frame_get_pkt_pos(frame), is->viddec.pkt_serial);
32fdfdfb
             av_frame_unref(frame);
105d4748
 #if CONFIG_AVFILTER
387b4ac9
         }
917d2bb3
 #endif
b93e12fd
 
917d2bb3
         if (ret < 0)
             goto the_end;
01310af2
     }
  the_end:
917d2bb3
 #if CONFIG_AVFILTER
ab543afe
     avfilter_graph_free(&graph);
917d2bb3
 #endif
354468fc
     av_frame_free(&frame);
01310af2
     return 0;
 }
 
72ce053b
 static int subtitle_thread(void *arg)
 {
     VideoState *is = arg;
5a5128ba
     Frame *sp;
98704131
     int got_subtitle;
72ce053b
     double pts;
d64ba25a
     int i;
72ce053b
 
da7c65f0
     for (;;) {
5a5128ba
         if (!(sp = frame_queue_peek_writable(&is->subpq)))
71a1d111
             return 0;
115329f1
 
2ec4a84d
         if ((got_subtitle = decoder_decode_frame(&is->subdec, NULL, &sp->sub)) < 0)
9e0d1c00
             break;
 
72ce053b
         pts = 0;
 
         if (got_subtitle && sp->sub.format == 0) {
2939e258
             if (sp->sub.pts != AV_NOPTS_VALUE)
                 pts = sp->sub.pts / (double)AV_TIME_BASE;
72ce053b
             sp->pts = pts;
9e0d1c00
             sp->serial = is->subdec.pkt_serial;
115329f1
 
72ce053b
             for (i = 0; i < sp->sub.num_rects; i++)
             {
d64ba25a
                 int in_w = sp->sub.rects[i]->w;
                 int in_h = sp->sub.rects[i]->h;
                 int subw = is->subdec.avctx->width  ? is->subdec.avctx->width  : is->viddec_width;
                 int subh = is->subdec.avctx->height ? is->subdec.avctx->height : is->viddec_height;
                 int out_w = is->viddec_width  ? in_w * is->viddec_width  / subw : in_w;
                 int out_h = is->viddec_height ? in_h * is->viddec_height / subh : in_h;
                 AVPicture newpic;
 
                 //can not use avpicture_alloc as it is not compatible with avsubtitle_free()
                 av_image_fill_linesizes(newpic.linesize, AV_PIX_FMT_YUVA420P, out_w);
                 newpic.data[0] = av_malloc(newpic.linesize[0] * out_h);
                 newpic.data[3] = av_malloc(newpic.linesize[3] * out_h);
                 newpic.data[1] = av_malloc(newpic.linesize[1] * ((out_h+1)/2));
                 newpic.data[2] = av_malloc(newpic.linesize[2] * ((out_h+1)/2));
 
                 is->sub_convert_ctx = sws_getCachedContext(is->sub_convert_ctx,
                     in_w, in_h, AV_PIX_FMT_PAL8, out_w, out_h,
                     AV_PIX_FMT_YUVA420P, sws_flags, NULL, NULL, NULL);
                 if (!is->sub_convert_ctx || !newpic.data[0] || !newpic.data[3] ||
                     !newpic.data[1] || !newpic.data[2]
                 ) {
                     av_log(NULL, AV_LOG_FATAL, "Cannot initialize the sub conversion context\n");
                     exit(1);
72ce053b
                 }
d64ba25a
                 sws_scale(is->sub_convert_ctx,
                           (void*)sp->sub.rects[i]->pict.data, sp->sub.rects[i]->pict.linesize,
                           0, in_h, newpic.data, newpic.linesize);
 
                 av_free(sp->sub.rects[i]->pict.data[0]);
                 av_free(sp->sub.rects[i]->pict.data[1]);
                 sp->sub.rects[i]->pict = newpic;
                 sp->sub.rects[i]->w = out_w;
                 sp->sub.rects[i]->h = out_h;
                 sp->sub.rects[i]->x = sp->sub.rects[i]->x * out_w / in_w;
                 sp->sub.rects[i]->y = sp->sub.rects[i]->y * out_h / in_h;
72ce053b
             }
 
             /* now we can update the picture count */
5a5128ba
             frame_queue_push(&is->subpq);
608989f6
         } else if (got_subtitle) {
             avsubtitle_free(&sp->sub);
72ce053b
         }
     }
     return 0;
 }
 
01310af2
 /* copy samples for viewing in editor window */
 static void update_sample_display(VideoState *is, short *samples, int samples_size)
 {
705c6520
     int size, len;
01310af2
 
     size = samples_size / sizeof(short);
     while (size > 0) {
         len = SAMPLE_ARRAY_SIZE - is->sample_array_index;
         if (len > size)
             len = size;
         memcpy(is->sample_array + is->sample_array_index, samples, len * sizeof(short));
         samples += len;
         is->sample_array_index += len;
         if (is->sample_array_index >= SAMPLE_ARRAY_SIZE)
             is->sample_array_index = 0;
         size -= len;
     }
 }
 
6f06545b
 /* return the wanted number of samples to get better sync if sync_type is video
  * or external master clock */
 static int synchronize_audio(VideoState *is, int nb_samples)
01310af2
 {
6f06545b
     int wanted_nb_samples = nb_samples;
01310af2
 
     /* if not master, then we try to remove or add samples to correct the clock */
d30c6925
     if (get_master_sync_type(is) != AV_SYNC_AUDIO_MASTER) {
638c9d91
         double diff, avg_diff;
6f06545b
         int min_nb_samples, max_nb_samples;
115329f1
 
f2175a62
         diff = get_clock(&is->audclk) - get_master_clock(is);
115329f1
 
26c208cf
         if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) {
638c9d91
             is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum;
             if (is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) {
                 /* not enough measures to have a correct estimate */
                 is->audio_diff_avg_count++;
             } else {
                 /* estimate the A-V difference */
                 avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef);
 
                 if (fabs(avg_diff) >= is->audio_diff_threshold) {
e1248f5c
                     wanted_nb_samples = nb_samples + (int)(diff * is->audio_src.freq);
6f06545b
                     min_nb_samples = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100));
                     max_nb_samples = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100));
0f6118c5
                     wanted_nb_samples = av_clip(wanted_nb_samples, min_nb_samples, max_nb_samples);
638c9d91
                 }
40d552da
                 av_log(NULL, AV_LOG_TRACE, "diff=%f adiff=%f sample_diff=%d apts=%0.3f %f\n",
6f06545b
                         diff, avg_diff, wanted_nb_samples - nb_samples,
5534d8f7
                         is->audio_clock, is->audio_diff_threshold);
01310af2
             }
638c9d91
         } else {
             /* too big difference : may be initial PTS errors, so
                reset A-V filter */
             is->audio_diff_avg_count = 0;
da7c65f0
             is->audio_diff_cum       = 0;
01310af2
         }
     }
 
6f06545b
     return wanted_nb_samples;
01310af2
 }
 
6032a1c9
 /**
  * Decode one audio frame and return its uncompressed size.
  *
  * The processed audio frame is decoded, converted if required, and
  * stored in is->audio_buf, with size in bytes given by the return
  * value.
  */
6e32b377
 static int audio_decode_frame(VideoState *is)
01310af2
 {
9e0d1c00
     int data_size, resampled_data_size;
a5a1e3cb
     int64_t dec_channel_layout;
02af4e9a
     av_unused double audio_clock0;
6f06545b
     int wanted_nb_samples;
631ac655
     Frame *af;
48e43a19
 
cc474188
     if (is->paused)
         return -1;
 
     do {
b1f78632
 #if defined(_WIN32)
         while (frame_queue_nb_remaining(&is->sampq) == 0) {
             if ((av_gettime_relative() - audio_callback_time) > 1000000LL * is->audio_hw_buf_size / is->audio_tgt.bytes_per_sec / 2)
                 return -1;
             av_usleep (1000);
         }
 #endif
cc474188
         if (!(af = frame_queue_peek_readable(&is->sampq)))
             return -1;
         frame_queue_next(&is->sampq);
     } while (af->serial != is->audioq.serial);
 
     data_size = av_samples_get_buffer_size(NULL, av_frame_get_channels(af->frame),
                                            af->frame->nb_samples,
                                            af->frame->format, 1);
 
     dec_channel_layout =
         (af->frame->channel_layout && av_frame_get_channels(af->frame) == av_get_channel_layout_nb_channels(af->frame->channel_layout)) ?
         af->frame->channel_layout : av_get_default_channel_layout(av_frame_get_channels(af->frame));
     wanted_nb_samples = synchronize_audio(is, af->frame->nb_samples);
 
     if (af->frame->format        != is->audio_src.fmt            ||
         dec_channel_layout       != is->audio_src.channel_layout ||
         af->frame->sample_rate   != is->audio_src.freq           ||
         (wanted_nb_samples       != af->frame->nb_samples && !is->swr_ctx)) {
         swr_free(&is->swr_ctx);
         is->swr_ctx = swr_alloc_set_opts(NULL,
                                          is->audio_tgt.channel_layout, is->audio_tgt.fmt, is->audio_tgt.freq,
                                          dec_channel_layout,           af->frame->format, af->frame->sample_rate,
                                          0, NULL);
         if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) {
             av_log(NULL, AV_LOG_ERROR,
                    "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",
                     af->frame->sample_rate, av_get_sample_fmt_name(af->frame->format), av_frame_get_channels(af->frame),
                     is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels);
             swr_free(&is->swr_ctx);
9e0d1c00
             return -1;
cc474188
         }
         is->audio_src.channel_layout = dec_channel_layout;
         is->audio_src.channels       = av_frame_get_channels(af->frame);
         is->audio_src.freq = af->frame->sample_rate;
         is->audio_src.fmt = af->frame->format;
     }
a6f51de3
 
cc474188
     if (is->swr_ctx) {
         const uint8_t **in = (const uint8_t **)af->frame->extended_data;
         uint8_t **out = &is->audio_buf1;
         int out_count = (int64_t)wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate + 256;
         int out_size  = av_samples_get_buffer_size(NULL, is->audio_tgt.channels, out_count, is->audio_tgt.fmt, 0);
         int len2;
         if (out_size < 0) {
             av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size() failed\n");
             return -1;
         }
         if (wanted_nb_samples != af->frame->nb_samples) {
             if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - af->frame->nb_samples) * is->audio_tgt.freq / af->frame->sample_rate,
                                         wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate) < 0) {
                 av_log(NULL, AV_LOG_ERROR, "swr_set_compensation() failed\n");
631ac655
                 return -1;
5a4476e2
             }
cc474188
         }
         av_fast_malloc(&is->audio_buf1, &is->audio_buf1_size, out_size);
         if (!is->audio_buf1)
             return AVERROR(ENOMEM);
         len2 = swr_convert(is->swr_ctx, out, out_count, in, af->frame->nb_samples);
         if (len2 < 0) {
             av_log(NULL, AV_LOG_ERROR, "swr_convert() failed\n");
             return -1;
         }
         if (len2 == out_count) {
             av_log(NULL, AV_LOG_WARNING, "audio buffer is probably too small\n");
             if (swr_init(is->swr_ctx) < 0)
                 swr_free(&is->swr_ctx);
         }
         is->audio_buf = is->audio_buf1;
         resampled_data_size = len2 * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt);
     } else {
         is->audio_buf = af->frame->data[0];
         resampled_data_size = data_size;
     }
5a4476e2
 
cc474188
     audio_clock0 = is->audio_clock;
     /* update the audio clock with the pts */
     if (!isnan(af->pts))
         is->audio_clock = af->pts + (double) af->frame->nb_samples / af->frame->sample_rate;
     else
         is->audio_clock = NAN;
     is->audio_clock_serial = af->serial;
1f6b9cc3
 #ifdef DEBUG
cc474188
     {
         static double last_clock;
         printf("audio: delay=%0.3f clock=%0.3f clock0=%0.3f\n",
                is->audio_clock - last_clock,
                is->audio_clock, audio_clock0);
         last_clock = is->audio_clock;
01310af2
     }
cc474188
 #endif
     return resampled_data_size;
01310af2
 }
 
 /* prepare a new audio buffer */
358061f6
 static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
01310af2
 {
     VideoState *is = opaque;
     int audio_size, len1;
 
0ca0b4c2
     audio_callback_time = av_gettime_relative();
115329f1
 
01310af2
     while (len > 0) {
         if (is->audio_buf_index >= is->audio_buf_size) {
6e32b377
            audio_size = audio_decode_frame(is);
01310af2
            if (audio_size < 0) {
                 /* if error, just output silence */
e2a2c49f
                is->audio_buf      = is->silence_buf;
e37d4920
                is->audio_buf_size = sizeof(is->silence_buf) / is->audio_tgt.frame_size * is->audio_tgt.frame_size;
01310af2
            } else {
f8b8c694
                if (is->show_mode != SHOW_MODE_VIDEO)
01310af2
                    update_sample_display(is, (int16_t *)is->audio_buf, audio_size);
                is->audio_buf_size = audio_size;
            }
            is->audio_buf_index = 0;
         }
         len1 = is->audio_buf_size - is->audio_buf_index;
         if (len1 > len)
             len1 = len;
         memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
         len -= len1;
         stream += len1;
         is->audio_buf_index += len1;
     }
10b7b4a6
     is->audio_write_buf_size = is->audio_buf_size - is->audio_buf_index;
     /* Let's assume the audio driver that is used by SDL has two periods. */
3886572a
     if (!isnan(is->audio_clock)) {
e37d4920
         set_clock_at(&is->audclk, is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / is->audio_tgt.bytes_per_sec, is->audio_clock_serial, audio_callback_time / 1000000.0);
3886572a
         sync_clock_to_slave(&is->extclk, &is->audclk);
     }
01310af2
 }
 
7821264c
 static int audio_open(void *opaque, int64_t wanted_channel_layout, int wanted_nb_channels, int wanted_sample_rate, struct AudioParams *audio_hw_params)
03095d73
 {
     SDL_AudioSpec wanted_spec, spec;
     const char *env;
5c6a5874
     static const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6};
0c8d8c0c
     static const int next_sample_rates[] = {0, 44100, 48000, 96000, 192000};
     int next_sample_rate_idx = FF_ARRAY_ELEMS(next_sample_rates) - 1;
03095d73
 
     env = SDL_getenv("SDL_AUDIO_CHANNELS");
7821264c
     if (env) {
ab0ea7cb
         wanted_nb_channels = atoi(env);
7821264c
         wanted_channel_layout = av_get_default_channel_layout(wanted_nb_channels);
     }
     if (!wanted_channel_layout || wanted_nb_channels != av_get_channel_layout_nb_channels(wanted_channel_layout)) {
         wanted_channel_layout = av_get_default_channel_layout(wanted_nb_channels);
03095d73
         wanted_channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX;
     }
0c8d8c0c
     wanted_nb_channels = av_get_channel_layout_nb_channels(wanted_channel_layout);
     wanted_spec.channels = wanted_nb_channels;
7821264c
     wanted_spec.freq = wanted_sample_rate;
03095d73
     if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
3b491c5a
         av_log(NULL, AV_LOG_ERROR, "Invalid sample rate or channel count!\n");
03095d73
         return -1;
     }
0c8d8c0c
     while (next_sample_rate_idx && next_sample_rates[next_sample_rate_idx] >= wanted_spec.freq)
         next_sample_rate_idx--;
03095d73
     wanted_spec.format = AUDIO_S16SYS;
     wanted_spec.silence = 0;
1ca5c178
     wanted_spec.samples = FFMAX(SDL_AUDIO_MIN_BUFFER_SIZE, 2 << av_log2(wanted_spec.freq / SDL_AUDIO_MAX_CALLBACKS_PER_SEC));
03095d73
     wanted_spec.callback = sdl_audio_callback;
73420379
     wanted_spec.userdata = opaque;
0dad5292
     while (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
0c8d8c0c
         av_log(NULL, AV_LOG_WARNING, "SDL_OpenAudio (%d channels, %d Hz): %s\n",
                wanted_spec.channels, wanted_spec.freq, SDL_GetError());
0dad5292
         wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)];
         if (!wanted_spec.channels) {
0c8d8c0c
             wanted_spec.freq = next_sample_rates[next_sample_rate_idx--];
             wanted_spec.channels = wanted_nb_channels;
             if (!wanted_spec.freq) {
                 av_log(NULL, AV_LOG_ERROR,
                        "No more combinations to try, audio open failed\n");
                 return -1;
             }
0dad5292
         }
         wanted_channel_layout = av_get_default_channel_layout(wanted_spec.channels);
03095d73
     }
     if (spec.format != AUDIO_S16SYS) {
3b491c5a
         av_log(NULL, AV_LOG_ERROR,
                "SDL advised audio format %d is not supported!\n", spec.format);
03095d73
         return -1;
     }
     if (spec.channels != wanted_spec.channels) {
         wanted_channel_layout = av_get_default_channel_layout(spec.channels);
         if (!wanted_channel_layout) {
3b491c5a
             av_log(NULL, AV_LOG_ERROR,
                    "SDL advised channel count %d is not supported!\n", spec.channels);
03095d73
             return -1;
         }
     }
 
7821264c
     audio_hw_params->fmt = AV_SAMPLE_FMT_S16;
     audio_hw_params->freq = spec.freq;
     audio_hw_params->channel_layout = wanted_channel_layout;
     audio_hw_params->channels =  spec.channels;
e98cd24a
     audio_hw_params->frame_size = av_samples_get_buffer_size(NULL, audio_hw_params->channels, 1, audio_hw_params->fmt, 1);
     audio_hw_params->bytes_per_sec = av_samples_get_buffer_size(NULL, audio_hw_params->channels, audio_hw_params->freq, audio_hw_params->fmt, 1);
     if (audio_hw_params->bytes_per_sec <= 0 || audio_hw_params->frame_size <= 0) {
         av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size failed\n");
         return -1;
     }
73420379
     return spec.size;
03095d73
 }
 
01310af2
 /* open a given stream. Return 0 if OK */
 static int stream_component_open(VideoState *is, int stream_index)
 {
     AVFormatContext *ic = is->ic;
fe74099a
     AVCodecContext *avctx;
01310af2
     AVCodec *codec;
013b7007
     const char *forced_codec_name = NULL;
3009f521
     AVDictionary *opts;
     AVDictionaryEntry *t = NULL;
e96175ad
     int sample_rate, nb_channels;
     int64_t channel_layout;
ee73a690
     int ret = 0;
c7fe2a37
     int stream_lowres = lowres;
01310af2
 
     if (stream_index < 0 || stream_index >= ic->nb_streams)
         return -1;
fe74099a
     avctx = ic->streams[stream_index]->codec;
115329f1
 
fe74099a
     codec = avcodec_find_decoder(avctx->codec_id);
6d13499b
 
5eda0967
     switch(avctx->codec_type){
013b7007
         case AVMEDIA_TYPE_AUDIO   : is->last_audio_stream    = stream_index; forced_codec_name =    audio_codec_name; break;
         case AVMEDIA_TYPE_SUBTITLE: is->last_subtitle_stream = stream_index; forced_codec_name = subtitle_codec_name; break;
         case AVMEDIA_TYPE_VIDEO   : is->last_video_stream    = stream_index; forced_codec_name =    video_codec_name; break;
5eda0967
     }
013b7007
     if (forced_codec_name)
         codec = avcodec_find_decoder_by_name(forced_codec_name);
     if (!codec) {
3b491c5a
         if (forced_codec_name) av_log(NULL, AV_LOG_WARNING,
                                       "No codec could be found with name '%s'\n", forced_codec_name);
         else                   av_log(NULL, AV_LOG_WARNING,
                                       "No codec could be found with id %d\n", avctx->codec_id);
99119bdf
         return -1;
013b7007
     }
99119bdf
 
1cbb11cd
     avctx->codec_id = codec->id;
c7fe2a37
     if(stream_lowres > av_codec_get_max_lowres(codec)){
d8407ee2
         av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n",
b72040da
                 av_codec_get_max_lowres(codec));
c7fe2a37
         stream_lowres = av_codec_get_max_lowres(codec);
d8407ee2
     }
c7fe2a37
     av_codec_set_lowres(avctx, stream_lowres);
fe74099a
 
2fb593dc
 #if FF_API_EMU_EDGE
c7fe2a37
     if(stream_lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE;
2fb593dc
 #endif
94d68a41
     if (fast)
         avctx->flags2 |= AV_CODEC_FLAG2_FAST;
2fb593dc
 #if FF_API_EMU_EDGE
444e9874
     if(codec->capabilities & AV_CODEC_CAP_DR1)
175714c0
         avctx->flags |= CODEC_FLAG_EMU_EDGE;
2fb593dc
 #endif
175714c0
 
fdb93344
     opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], codec);
2473a45c
     if (!av_dict_get(opts, "threads", NULL, 0))
         av_dict_set(&opts, "threads", "auto", 0);
c7fe2a37
     if (stream_lowres)
a0941c8a
         av_dict_set_int(&opts, "lowres", stream_lowres, 0);
738487f8
     if (avctx->codec_type == AVMEDIA_TYPE_VIDEO || avctx->codec_type == AVMEDIA_TYPE_AUDIO)
354468fc
         av_dict_set(&opts, "refcounted_frames", "1", 0);
ee73a690
     if ((ret = avcodec_open2(avctx, codec, &opts)) < 0) {
         goto fail;
     }
3009f521
     if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
         av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
ee73a690
         ret =  AVERROR_OPTION_NOT_FOUND;
         goto fail;
3009f521
     }
51b73087
 
d6910c4b
     is->eof = 0;
3f3fe38d
     ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
da7c65f0
     switch (avctx->codec_type) {
72415b2a
     case AVMEDIA_TYPE_AUDIO:
e96175ad
 #if CONFIG_AVFILTER
         {
             AVFilterLink *link;
 
             is->audio_filter_src.freq           = avctx->sample_rate;
             is->audio_filter_src.channels       = avctx->channels;
             is->audio_filter_src.channel_layout = get_valid_channel_layout(avctx->channel_layout, avctx->channels);
             is->audio_filter_src.fmt            = avctx->sample_fmt;
             if ((ret = configure_audio_filters(is, afilters, 0)) < 0)
ee73a690
                 goto fail;
e96175ad
             link = is->out_audio_filter->inputs[0];
             sample_rate    = link->sample_rate;
             nb_channels    = link->channels;
             channel_layout = link->channel_layout;
         }
 #else
         sample_rate    = avctx->sample_rate;
         nb_channels    = avctx->channels;
         channel_layout = avctx->channel_layout;
 #endif
 
1822519d
         /* prepare audio output */
e96175ad
         if ((ret = audio_open(is, channel_layout, nb_channels, sample_rate, &is->audio_tgt)) < 0)
ee73a690
             goto fail;
1822519d
         is->audio_hw_buf_size = ret;
         is->audio_src = is->audio_tgt;
da7c65f0
         is->audio_buf_size  = 0;
01310af2
         is->audio_buf_index = 0;
638c9d91
 
         /* init averaging filter */
da7c65f0
         is->audio_diff_avg_coef  = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
638c9d91
         is->audio_diff_avg_count = 0;
         /* since we do not have a precise anough audio fifo fullness,
            we correct audio sync only if larger than this threshold */
e281671e
         is->audio_diff_threshold = (double)(is->audio_hw_buf_size) / is->audio_tgt.bytes_per_sec;
638c9d91
 
1822519d
         is->audio_stream = stream_index;
         is->audio_st = ic->streams[stream_index];
 
9e0d1c00
         decoder_init(&is->auddec, avctx, &is->audioq, is->continue_read_thread);
1f5a3cf6
         if ((is->ic->iformat->flags & (AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK)) && !is->ic->iformat->read_seek) {
             is->auddec.start_pts = is->audio_st->start_time;
             is->auddec.start_pts_tb = is->audio_st->time_base;
         }
ef1ccea9
         decoder_start(&is->auddec, audio_thread, is);
bb270c08
         SDL_PauseAudio(0);
01310af2
         break;
72415b2a
     case AVMEDIA_TYPE_VIDEO:
01310af2
         is->video_stream = stream_index;
         is->video_st = ic->streams[stream_index];
 
d64ba25a
         is->viddec_width  = avctx->width;
         is->viddec_height = avctx->height;
 
9e0d1c00
         decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread);
ef1ccea9
         decoder_start(&is->viddec, video_thread, is);
1c2ac449
         is->queue_attachments_req = 1;
01310af2
         break;
72415b2a
     case AVMEDIA_TYPE_SUBTITLE:
72ce053b
         is->subtitle_stream = stream_index;
         is->subtitle_st = ic->streams[stream_index];
115329f1
 
9e0d1c00
         decoder_init(&is->subdec, avctx, &is->subtitleq, is->continue_read_thread);
ef1ccea9
         decoder_start(&is->subdec, subtitle_thread, is);
72ce053b
         break;
01310af2
     default:
         break;
     }
ee73a690
 
 fail:
     av_dict_free(&opts);
 
     return ret;
01310af2
 }
 
 static void stream_component_close(VideoState *is, int stream_index)
 {
     AVFormatContext *ic = is->ic;
fe74099a
     AVCodecContext *avctx;
115329f1
 
72ce053b
     if (stream_index < 0 || stream_index >= ic->nb_streams)
         return;
fe74099a
     avctx = ic->streams[stream_index]->codec;
01310af2
 
da7c65f0
     switch (avctx->codec_type) {
72415b2a
     case AVMEDIA_TYPE_AUDIO:
ef1ccea9
         decoder_abort(&is->auddec, &is->sampq);
eaf4ab98
         SDL_CloseAudio();
9e0d1c00
         decoder_destroy(&is->auddec);
4fd07b93
         swr_free(&is->swr_ctx);
f199f385
         av_freep(&is->audio_buf1);
571ef42d
         is->audio_buf1_size = 0;
f199f385
         is->audio_buf = NULL;
cb2c4de3
 
         if (is->rdft) {
             av_rdft_end(is->rdft);
             av_freep(&is->rdft_data);
f9324d5a
             is->rdft = NULL;
             is->rdft_bits = 0;
cb2c4de3
         }
01310af2
         break;
72415b2a
     case AVMEDIA_TYPE_VIDEO:
ef1ccea9
         decoder_abort(&is->viddec, &is->pictq);
9e0d1c00
         decoder_destroy(&is->viddec);
01310af2
         break;
72415b2a
     case AVMEDIA_TYPE_SUBTITLE:
ef1ccea9
         decoder_abort(&is->subdec, &is->subpq);
9e0d1c00
         decoder_destroy(&is->subdec);
72ce053b
         break;
01310af2
     default:
         break;
     }
 
3f3fe38d
     ic->streams[stream_index]->discard = AVDISCARD_ALL;
fe74099a
     avcodec_close(avctx);
da7c65f0
     switch (avctx->codec_type) {
72415b2a
     case AVMEDIA_TYPE_AUDIO:
01310af2
         is->audio_st = NULL;
         is->audio_stream = -1;
         break;
72415b2a
     case AVMEDIA_TYPE_VIDEO:
01310af2
         is->video_st = NULL;
         is->video_stream = -1;
         break;
72415b2a
     case AVMEDIA_TYPE_SUBTITLE:
72ce053b
         is->subtitle_st = NULL;
         is->subtitle_stream = -1;
         break;
01310af2
     default:
         break;
     }
 }
 
40972f7c
 static int decode_interrupt_cb(void *ctx)
416e3508
 {
708df4ac
     VideoState *is = ctx;
     return is->abort_request;
416e3508
 }
01310af2
 
2e8dcde1
 static int is_realtime(AVFormatContext *s)
 {
     if(   !strcmp(s->iformat->name, "rtp")
        || !strcmp(s->iformat->name, "rtsp")
        || !strcmp(s->iformat->name, "sdp")
     )
         return 1;
 
     if(s->pb && (   !strncmp(s->filename, "rtp:", 4)
                  || !strncmp(s->filename, "udp:", 4)
                 )
     )
         return 1;
     return 0;
 }
 
01310af2
 /* this thread gets the stream from the disk or the network */
8adf9bb2
 static int read_thread(void *arg)
01310af2
 {
     VideoState *is = arg;
b6bde8c7
     AVFormatContext *ic = NULL;
6625a3de
     int err, i, ret;
72415b2a
     int st_index[AVMEDIA_TYPE_NB];
01310af2
     AVPacket pkt1, *pkt = &pkt1;
f07cb53a
     int64_t stream_start_time;
d834d63b
     int pkt_in_play_range = 0;
b6bde8c7
     AVDictionaryEntry *t;
3009f521
     AVDictionary **opts;
     int orig_nb_streams;
0e5042be
     SDL_mutex *wait_mutex = SDL_CreateMutex();
e971eef8
     int scan_all_pmts_set = 0;
17d87571
     int64_t pkt_ts;
6299a229
 
6625a3de
     memset(st_index, -1, sizeof(st_index));
8c9971c3
     is->last_video_stream = is->video_stream = -1;
     is->last_audio_stream = is->audio_stream = -1;
     is->last_subtitle_stream = is->subtitle_stream = -1;
d6910c4b
     is->eof = 0;
01310af2
 
40972f7c
     ic = avformat_alloc_context();
79216a18
     if (!ic) {
         av_log(NULL, AV_LOG_FATAL, "Could not allocate context.\n");
         ret = AVERROR(ENOMEM);
         goto fail;
     }
40972f7c
     ic->interrupt_callback.callback = decode_interrupt_cb;
708df4ac
     ic->interrupt_callback.opaque = is;
e971eef8
     if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
         av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
         scan_all_pmts_set = 1;
     }
b6bde8c7
     err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts);
638c9d91
     if (err < 0) {
         print_error(is->filename, err);
         ret = -1;
         goto fail;
     }
e971eef8
     if (scan_all_pmts_set)
         av_dict_set(&format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE);
 
b6bde8c7
     if ((t = av_dict_get(format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
         av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
         ret = AVERROR_OPTION_NOT_FOUND;
         goto fail;
     }
01310af2
     is->ic = ic;
30bc6613
 
da7c65f0
     if (genpts)
30bc6613
         ic->flags |= AVFMT_FLAG_GENPTS;
 
ef818d8b
     av_format_inject_global_side_data(ic);
 
8ec19f84
     opts = setup_find_stream_info_opts(ic, codec_opts);
3009f521
     orig_nb_streams = ic->nb_streams;
bc778a0c
 
3009f521
     err = avformat_find_stream_info(ic, opts);
019ff7a0
 
     for (i = 0; i < orig_nb_streams; i++)
         av_dict_free(&opts[i]);
     av_freep(&opts);
 
24c07998
     if (err < 0) {
3b491c5a
         av_log(NULL, AV_LOG_WARNING,
                "%s: could not find codec parameters\n", is->filename);
24c07998
         ret = -1;
         goto fail;
     }
3009f521
 
da7c65f0
     if (ic->pb)
d34ec64a
         ic->pb->eof_reached = 0; // FIXME hack, ffplay maybe should not use avio_feof() to test for the end
72ea344b
 
da7c65f0
     if (seek_by_bytes < 0)
7f4b588f
         seek_by_bytes = !!(ic->iformat->flags & AVFMT_TS_DISCONT) && strcmp("ogg", ic->iformat->name);
70a4764d
 
f7eb50f3
     is->max_frame_duration = (ic->iformat->flags & AVFMT_TS_DISCONT) ? 10.0 : 3600.0;
 
9db6aaeb
     if (!window_title && (t = av_dict_get(ic->metadata, "title", NULL, 0)))
         window_title = av_asprintf("%s - %s", t->value, input_filename);
 
72ea344b
     /* if seeking requested, we execute it */
     if (start_time != AV_NOPTS_VALUE) {
         int64_t timestamp;
 
         timestamp = start_time;
         /* add the stream start time */
         if (ic->start_time != AV_NOPTS_VALUE)
             timestamp += ic->start_time;
4ed29207
         ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0);
72ea344b
         if (ret < 0) {
3b491c5a
             av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n",
72ea344b
                     is->filename, (double)timestamp / AV_TIME_BASE);
         }
     }
 
747c749d
     is->realtime = is_realtime(ic);
 
46aa75ee
     if (show_status)
         av_dump_format(ic, 0, is->filename, 0);
 
5e7dcb04
     for (i = 0; i < ic->nb_streams; i++) {
         AVStream *st = ic->streams[i];
         enum AVMediaType type = st->codec->codec_type;
         st->discard = AVDISCARD_ALL;
         if (wanted_stream_spec[type] && st_index[type] == -1)
             if (avformat_match_stream_specifier(ic, st, wanted_stream_spec[type]) > 0)
                 st_index[type] = i;
     }
     for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
         if (wanted_stream_spec[i] && st_index[i] == -1) {
             av_log(NULL, AV_LOG_ERROR, "Stream specifier %s does not match any %s stream\n", wanted_stream_spec[i], av_get_media_type_string(i));
             st_index[i] = INT_MAX;
         }
     }
 
be732b70
     if (!video_disable)
406f0f1b
         st_index[AVMEDIA_TYPE_VIDEO] =
             av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,
5e7dcb04
                                 st_index[AVMEDIA_TYPE_VIDEO], -1, NULL, 0);
be732b70
     if (!audio_disable)
406f0f1b
         st_index[AVMEDIA_TYPE_AUDIO] =
             av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO,
5e7dcb04
                                 st_index[AVMEDIA_TYPE_AUDIO],
406f0f1b
                                 st_index[AVMEDIA_TYPE_VIDEO],
                                 NULL, 0);
d0c6ed7d
     if (!video_disable && !subtitle_disable)
406f0f1b
         st_index[AVMEDIA_TYPE_SUBTITLE] =
             av_find_best_stream(ic, AVMEDIA_TYPE_SUBTITLE,
5e7dcb04
                                 st_index[AVMEDIA_TYPE_SUBTITLE],
406f0f1b
                                 (st_index[AVMEDIA_TYPE_AUDIO] >= 0 ?
                                  st_index[AVMEDIA_TYPE_AUDIO] :
                                  st_index[AVMEDIA_TYPE_VIDEO]),
                                 NULL, 0);
01310af2
 
f521746b
     is->show_mode = show_mode;
ad01fae8
     if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
         AVStream *st = ic->streams[st_index[AVMEDIA_TYPE_VIDEO]];
         AVCodecContext *avctx = st->codec;
ba800def
         AVRational sar = av_guess_sample_aspect_ratio(ic, st, NULL);
         if (avctx->width)
             set_default_window_size(avctx->width, avctx->height, sar);
ad01fae8
     }
f521746b
 
01310af2
     /* open the streams */
72415b2a
     if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {
         stream_component_open(is, st_index[AVMEDIA_TYPE_AUDIO]);
01310af2
     }
 
da7c65f0
     ret = -1;
72415b2a
     if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
da7c65f0
         ret = stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO]);
077a8d61
     }
1d6c82d4
     if (is->show_mode == SHOW_MODE_NONE)
         is->show_mode = ret >= 0 ? SHOW_MODE_VIDEO : SHOW_MODE_RDFT;
01310af2
 
72415b2a
     if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) {
         stream_component_open(is, st_index[AVMEDIA_TYPE_SUBTITLE]);
16a59a7b
     }
 
01310af2
     if (is->video_stream < 0 && is->audio_stream < 0) {
f9f7f4c9
         av_log(NULL, AV_LOG_FATAL, "Failed to open file '%s' or configure filtergraph\n",
                is->filename);
638c9d91
         ret = -1;
01310af2
         goto fail;
     }
 
747c749d
     if (infinite_buffer < 0 && is->realtime)
2e8dcde1
         infinite_buffer = 1;
 
da7c65f0
     for (;;) {
01310af2
         if (is->abort_request)
             break;
416e3508
         if (is->paused != is->last_paused) {
             is->last_paused = is->paused;
72ea344b
             if (is->paused)
da7c65f0
                 is->read_pause_return = av_read_pause(ic);
72ea344b
             else
                 av_read_play(ic);
416e3508
         }
df98446b
 #if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL
         if (is->paused &&
                 (!strcmp(ic->iformat->name, "rtsp") ||
304ec08f
                  (ic->pb && !strncmp(input_filename, "mmsh:", 5)))) {
416e3508
             /* wait 10 ms to avoid trying to get another packet */
             /* XXX: horrible */
             SDL_Delay(10);
             continue;
         }
400738b1
 #endif
72ea344b
         if (is->seek_req) {
da7c65f0
             int64_t seek_target = is->seek_pos;
             int64_t seek_min    = is->seek_rel > 0 ? seek_target - is->seek_rel + 2: INT64_MIN;
             int64_t seek_max    = is->seek_rel < 0 ? seek_target - is->seek_rel - 2: INT64_MAX;
 // FIXME the +-2 is due to rounding being not done in the correct direction in generation
4ed29207
 //      of the seek_pos/seek_rel variables
8e606cc8
 
4ed29207
             ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags);
72ea344b
             if (ret < 0) {
3b491c5a
                 av_log(NULL, AV_LOG_ERROR,
                        "%s: error while seeking\n", is->ic->filename);
da7c65f0
             } else {
e6c0297f
                 if (is->audio_stream >= 0) {
                     packet_queue_flush(&is->audioq);
39c6a118
                     packet_queue_put(&is->audioq, &flush_pkt);
e6c0297f
                 }
72ce053b
                 if (is->subtitle_stream >= 0) {
                     packet_queue_flush(&is->subtitleq);
39c6a118
                     packet_queue_put(&is->subtitleq, &flush_pkt);
72ce053b
                 }
e6c0297f
                 if (is->video_stream >= 0) {
                     packet_queue_flush(&is->videoq);
39c6a118
                     packet_queue_put(&is->videoq, &flush_pkt);
e6c0297f
                 }
2efd01a3
                 if (is->seek_flags & AVSEEK_FLAG_BYTE) {
f2175a62
                    set_clock(&is->extclk, NAN, 0);
2efd01a3
                 } else {
f2175a62
                    set_clock(&is->extclk, seek_target / (double)AV_TIME_BASE, 0);
2efd01a3
                 }
72ea344b
             }
             is->seek_req = 0;
1c2ac449
             is->queue_attachments_req = 1;
d6910c4b
             is->eof = 0;
4ea7fbb2
             if (is->paused)
                 step_to_next_frame(is);
72ea344b
         }
491ca0e8
         if (is->queue_attachments_req) {
1c2ac449
             if (is->video_st && is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC) {
                 AVPacket copy;
                 if ((ret = av_copy_packet(&copy, &is->video_st->attached_pic)) < 0)
                     goto fail;
                 packet_queue_put(&is->videoq, &copy);
0258e4dc
                 packet_queue_put_nullpacket(&is->videoq, is->video_stream);
1c2ac449
             }
491ca0e8
             is->queue_attachments_req = 0;
c151e0ca
         }
416e3508
 
01310af2
         /* if the queue are full, no need to read more */
cb3fd029
         if (infinite_buffer<1 &&
296d0da8
               (is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
a687acbb
             || (   (is->audioq   .nb_packets > MIN_FRAMES || is->audio_stream < 0 || is->audioq.abort_request)
1c2ac449
                 && (is->videoq   .nb_packets > MIN_FRAMES || is->video_stream < 0 || is->videoq.abort_request
                     || (is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC))
039e9fe0
                 && (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0 || is->subtitleq.abort_request)))) {
01310af2
             /* wait 10 ms */
0e5042be
             SDL_LockMutex(wait_mutex);
             SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
             SDL_UnlockMutex(wait_mutex);
01310af2
             continue;
         }
e84ca8d3
         if (!is->paused &&
631ac655
             (!is->audio_st || (is->auddec.finished == is->audioq.serial && frame_queue_nb_remaining(&is->sampq) == 0)) &&
9e0d1c00
             (!is->video_st || (is->viddec.finished == is->videoq.serial && frame_queue_nb_remaining(&is->pictq) == 0))) {
e84ca8d3
             if (loop != 1 && (!loop || --loop)) {
                 stream_seek(is, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0);
             } else if (autoexit) {
                 ret = AVERROR_EOF;
                 goto fail;
             }
         }
72ea344b
         ret = av_read_frame(ic, pkt);
01310af2
         if (ret < 0) {
d6910c4b
             if ((ret == AVERROR_EOF || avio_feof(ic->pb)) && !is->eof) {
7ba72777
                 if (is->video_stream >= 0)
                     packet_queue_put_nullpacket(&is->videoq, is->video_stream);
                 if (is->audio_stream >= 0)
                     packet_queue_put_nullpacket(&is->audioq, is->audio_stream);
                 if (is->subtitle_stream >= 0)
                     packet_queue_put_nullpacket(&is->subtitleq, is->subtitle_stream);
d6910c4b
                 is->eof = 1;
7ba72777
             }
eb4d1cb9
             if (ic->pb && ic->pb->error)
bb270c08
                 break;
d8f8e911
             SDL_LockMutex(wait_mutex);
             SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
             SDL_UnlockMutex(wait_mutex);
75bb7b0a
             continue;
7ba72777
         } else {
d6910c4b
             is->eof = 0;
01310af2
         }
d834d63b
         /* check if packet is in play range specified by user, then queue, otherwise discard */
f07cb53a
         stream_start_time = ic->streams[pkt->stream_index]->start_time;
17d87571
         pkt_ts = pkt->pts == AV_NOPTS_VALUE ? pkt->dts : pkt->pts;
d834d63b
         pkt_in_play_range = duration == AV_NOPTS_VALUE ||
17d87571
                 (pkt_ts - (stream_start_time != AV_NOPTS_VALUE ? stream_start_time : 0)) *
d834d63b
                 av_q2d(ic->streams[pkt->stream_index]->time_base) -
da7c65f0
                 (double)(start_time != AV_NOPTS_VALUE ? start_time : 0) / 1000000
                 <= ((double)duration / 1000000);
d834d63b
         if (pkt->stream_index == is->audio_stream && pkt_in_play_range) {
01310af2
             packet_queue_put(&is->audioq, pkt);
1c2ac449
         } else if (pkt->stream_index == is->video_stream && pkt_in_play_range
                    && !(is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC)) {
01310af2
             packet_queue_put(&is->videoq, pkt);
d834d63b
         } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {
72ce053b
             packet_queue_put(&is->subtitleq, pkt);
01310af2
         } else {
             av_free_packet(pkt);
         }
     }
     /* wait until the end */
     while (!is->abort_request) {
         SDL_Delay(100);
     }
 
638c9d91
     ret = 0;
01310af2
  fail:
     /* close each stream */
     if (is->audio_stream >= 0)
         stream_component_close(is, is->audio_stream);
     if (is->video_stream >= 0)
         stream_component_close(is, is->video_stream);
72ce053b
     if (is->subtitle_stream >= 0)
         stream_component_close(is, is->subtitle_stream);
90c9b494
     if (ic) {
         avformat_close_input(&ic);
         is->ic = NULL;
638c9d91
     }
416e3508
 
638c9d91
     if (ret != 0) {
         SDL_Event event;
115329f1
 
638c9d91
         event.type = FF_QUIT_EVENT;
         event.user.data1 = is;
         SDL_PushEvent(&event);
     }
0e5042be
     SDL_DestroyMutex(wait_mutex);
01310af2
     return 0;
 }
 
638c9d91
 static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
01310af2
 {
     VideoState *is;
 
     is = av_mallocz(sizeof(VideoState));
     if (!is)
         return NULL;
f7d78f36
     av_strlcpy(is->filename, filename, sizeof(is->filename));
638c9d91
     is->iformat = iformat;
da7c65f0
     is->ytop    = 0;
     is->xleft   = 0;
01310af2
 
     /* start video display */
5a5128ba
     if (frame_queue_init(&is->pictq, &is->videoq, VIDEO_PICTURE_QUEUE_SIZE, 1) < 0)
         goto fail;
     if (frame_queue_init(&is->subpq, &is->subtitleq, SUBPICTURE_QUEUE_SIZE, 0) < 0)
         goto fail;
631ac655
     if (frame_queue_init(&is->sampq, &is->audioq, SAMPLE_QUEUE_SIZE, 1) < 0)
         goto fail;
115329f1
 
a687acbb
     packet_queue_init(&is->videoq);
     packet_queue_init(&is->audioq);
     packet_queue_init(&is->subtitleq);
 
0e5042be
     is->continue_read_thread = SDL_CreateCond();
 
f2175a62
     init_clock(&is->vidclk, &is->videoq.serial);
     init_clock(&is->audclk, &is->audioq.serial);
     init_clock(&is->extclk, &is->extclk.serial);
26c208cf
     is->audio_clock_serial = -1;
638c9d91
     is->av_sync_type = av_sync_type;
41211483
     is->read_tid     = SDL_CreateThread(read_thread, is);
8adf9bb2
     if (!is->read_tid) {
5a5128ba
 fail:
         stream_close(is);
01310af2
         return NULL;
     }
     return is;
 }
 
7b49ce2e
 static void stream_cycle_channel(VideoState *is, int codec_type)
638c9d91
 {
     AVFormatContext *ic = is->ic;
     int start_index, stream_index;
8c9971c3
     int old_index;
638c9d91
     AVStream *st;
543d81a7
     AVProgram *p = NULL;
     int nb_streams = is->ic->nb_streams;
638c9d91
 
8c9971c3
     if (codec_type == AVMEDIA_TYPE_VIDEO) {
         start_index = is->last_video_stream;
         old_index = is->video_stream;
     } else if (codec_type == AVMEDIA_TYPE_AUDIO) {
         start_index = is->last_audio_stream;
         old_index = is->audio_stream;
     } else {
         start_index = is->last_subtitle_stream;
         old_index = is->subtitle_stream;
     }
638c9d91
     stream_index = start_index;
543d81a7
 
     if (codec_type != AVMEDIA_TYPE_VIDEO && is->video_stream != -1) {
         p = av_find_program_from_stream(ic, NULL, is->video_stream);
         if (p) {
             nb_streams = p->nb_stream_indexes;
             for (start_index = 0; start_index < nb_streams; start_index++)
                 if (p->stream_index[start_index] == stream_index)
                     break;
             if (start_index == nb_streams)
                 start_index = -1;
             stream_index = start_index;
         }
     }
 
da7c65f0
     for (;;) {
543d81a7
         if (++stream_index >= nb_streams)
72ce053b
         {
72415b2a
             if (codec_type == AVMEDIA_TYPE_SUBTITLE)
72ce053b
             {
                 stream_index = -1;
8c9971c3
                 is->last_subtitle_stream = -1;
72ce053b
                 goto the_end;
8c9971c3
             }
             if (start_index == -1)
                 return;
             stream_index = 0;
72ce053b
         }
638c9d91
         if (stream_index == start_index)
             return;
543d81a7
         st = is->ic->streams[p ? p->stream_index[stream_index] : stream_index];
01f4895c
         if (st->codec->codec_type == codec_type) {
638c9d91
             /* check that parameters are OK */
da7c65f0
             switch (codec_type) {
72415b2a
             case AVMEDIA_TYPE_AUDIO:
01f4895c
                 if (st->codec->sample_rate != 0 &&
                     st->codec->channels != 0)
638c9d91
                     goto the_end;
                 break;
72415b2a
             case AVMEDIA_TYPE_VIDEO:
             case AVMEDIA_TYPE_SUBTITLE:
638c9d91
                 goto the_end;
             default:
                 break;
             }
         }
     }
  the_end:
543d81a7
     if (p && stream_index != -1)
         stream_index = p->stream_index[stream_index];
77466876
     av_log(NULL, AV_LOG_INFO, "Switch %s stream from #%d to #%d\n",
            av_get_media_type_string(codec_type),
            old_index,
            stream_index);
 
8c9971c3
     stream_component_close(is, old_index);
638c9d91
     stream_component_open(is, stream_index);
 }
 
 
84506ebd
 static void toggle_full_screen(VideoState *is)
01310af2
 {
8085a5b7
 #if defined(__APPLE__) && SDL_VERSION_ATLEAST(1, 2, 14)
bed04e2b
     /* OS X needs to reallocate the SDL overlays */
d246c18e
     int i;
     for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++)
9ffa705e
         is->pictq.queue[i].reallocate = 1;
8085a5b7
 #endif
d246c18e
     is_full_screen = !is_full_screen;
5de3f724
     video_open(is, 1, NULL);
01310af2
 }
 
84506ebd
 static void toggle_audio_display(VideoState *is)
01310af2
 {
84506ebd
     int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
ac37d21f
     int next = is->show_mode;
     do {
         next = (next + 1) % SHOW_MODE_NB;
     } while (next != is->show_mode && (next == SHOW_MODE_VIDEO && !is->video_st || next != SHOW_MODE_VIDEO && !is->audio_st));
     if (is->show_mode != next) {
         fill_rectangle(screen,
                     is->xleft, is->ytop, is->width, is->height,
                     bgcolor, 1);
         is->force_refresh = 1;
         is->show_mode = next;
     }
01310af2
 }
 
b853cfe7
 static void refresh_loop_wait_event(VideoState *is, SDL_Event *event) {
77ab702a
     double remaining_time = 0.0;
     SDL_PumpEvents();
     while (!SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_ALLEVENTS)) {
0ca0b4c2
         if (!cursor_hidden && av_gettime_relative() - cursor_last_shown > CURSOR_HIDE_DELAY) {
b853cfe7
             SDL_ShowCursor(0);
             cursor_hidden = 1;
         }
77ab702a
         if (remaining_time > 0.0)
             av_usleep((int64_t)(remaining_time * 1000000.0));
b853cfe7
         remaining_time = REFRESH_RATE;
         if (is->show_mode != SHOW_MODE_NONE && (!is->paused || is->force_refresh))
             video_refresh(is, &remaining_time);
         SDL_PumpEvents();
77ab702a
     }
b853cfe7
 }
 
6fb8684a
 static void seek_chapter(VideoState *is, int incr)
 {
     int64_t pos = get_master_clock(is) * AV_TIME_BASE;
     int i;
 
     if (!is->ic->nb_chapters)
         return;
 
     /* find the current chapter */
     for (i = 0; i < is->ic->nb_chapters; i++) {
         AVChapter *ch = is->ic->chapters[i];
         if (av_compare_ts(pos, AV_TIME_BASE_Q, ch->start, ch->time_base) < 0) {
             i--;
             break;
         }
     }
 
     i += incr;
     i = FFMAX(i, 0);
     if (i >= is->ic->nb_chapters)
         return;
 
     av_log(NULL, AV_LOG_VERBOSE, "Seeking to chapter %d.\n", i);
     stream_seek(is, av_rescale_q(is->ic->chapters[i]->start, is->ic->chapters[i]->time_base,
                                  AV_TIME_BASE_Q), 0, 0);
 }
 
01310af2
 /* handle an event sent by the GUI */
84506ebd
 static void event_loop(VideoState *cur_stream)
01310af2
 {
     SDL_Event event;
a11d11aa
     double incr, pos, frac;
01310af2
 
da7c65f0
     for (;;) {
d52ec002
         double x;
b853cfe7
         refresh_loop_wait_event(cur_stream, &event);
da7c65f0
         switch (event.type) {
01310af2
         case SDL_KEYDOWN:
066ce8c9
             if (exit_on_keydown) {
84506ebd
                 do_exit(cur_stream);
066ce8c9
                 break;
             }
da7c65f0
             switch (event.key.keysym.sym) {
01310af2
             case SDLK_ESCAPE:
             case SDLK_q:
84506ebd
                 do_exit(cur_stream);
01310af2
                 break;
             case SDLK_f:
84506ebd
                 toggle_full_screen(cur_stream);
dbe7170e
                 cur_stream->force_refresh = 1;
01310af2
                 break;
             case SDLK_p:
             case SDLK_SPACE:
ba571f6b
                 toggle_pause(cur_stream);
01310af2
                 break;
da7c65f0
             case SDLK_s: // S: Step to next frame
ba571f6b
                 step_to_next_frame(cur_stream);
bba04f1e
                 break;
01310af2
             case SDLK_a:
ba571f6b
                 stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
638c9d91
                 break;
             case SDLK_v:
ba571f6b
                 stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
638c9d91
                 break;
3130416a
             case SDLK_c:
                 stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
                 stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
                 stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
                 break;
72ce053b
             case SDLK_t:
ba571f6b
                 stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
72ce053b
                 break;
638c9d91
             case SDLK_w:
a583e2be
 #if CONFIG_AVFILTER
                 if (cur_stream->show_mode == SHOW_MODE_VIDEO && cur_stream->vfilter_idx < nb_vfilters - 1) {
                     if (++cur_stream->vfilter_idx >= nb_vfilters)
                         cur_stream->vfilter_idx = 0;
                 } else {
                     cur_stream->vfilter_idx = 0;
                     toggle_audio_display(cur_stream);
                 }
 #else
ba571f6b
                 toggle_audio_display(cur_stream);
a583e2be
 #endif
01310af2
                 break;
91a3ea67
             case SDLK_PAGEUP:
6fb8684a
                 if (cur_stream->ic->nb_chapters <= 1) {
                     incr = 600.0;
                     goto do_seek;
                 }
                 seek_chapter(cur_stream, 1);
                 break;
91a3ea67
             case SDLK_PAGEDOWN:
6fb8684a
                 if (cur_stream->ic->nb_chapters <= 1) {
                     incr = -600.0;
                     goto do_seek;
                 }
                 seek_chapter(cur_stream, -1);
                 break;
72ea344b
             case SDLK_LEFT:
                 incr = -10.0;
                 goto do_seek;
             case SDLK_RIGHT:
                 incr = 10.0;
                 goto do_seek;
             case SDLK_UP:
                 incr = 60.0;
                 goto do_seek;
             case SDLK_DOWN:
                 incr = -60.0;
             do_seek:
94b594c6
                     if (seek_by_bytes) {
16437648
                         pos = -1;
                         if (pos < 0 && cur_stream->video_stream >= 0)
                             pos = frame_queue_last_pos(&cur_stream->pictq);
631ac655
                         if (pos < 0 && cur_stream->audio_stream >= 0)
                             pos = frame_queue_last_pos(&cur_stream->sampq);
16437648
                         if (pos < 0)
a2704c97
                             pos = avio_tell(cur_stream->ic->pb);
94b594c6
                         if (cur_stream->ic->bit_rate)
566cd2cb
                             incr *= cur_stream->ic->bit_rate / 8.0;
94b594c6
                         else
                             incr *= 180000.0;
                         pos += incr;
2ef46053
                         stream_seek(cur_stream, pos, incr, 1);
94b594c6
                     } else {
                         pos = get_master_clock(cur_stream);
26c208cf
                         if (isnan(pos))
                             pos = (double)cur_stream->seek_pos / AV_TIME_BASE;
94b594c6
                         pos += incr;
fc38bbcd
                         if (cur_stream->ic->start_time != AV_NOPTS_VALUE && pos < cur_stream->ic->start_time / (double)AV_TIME_BASE)
                             pos = cur_stream->ic->start_time / (double)AV_TIME_BASE;
2ef46053
                         stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0);
94b594c6
                     }
72ea344b
                 break;
01310af2
             default:
                 break;
             }
             break;
dbe7170e
         case SDL_VIDEOEXPOSE:
             cur_stream->force_refresh = 1;
             break;
a11d11aa
         case SDL_MOUSEBUTTONDOWN:
066ce8c9
             if (exit_on_mousedown) {
84506ebd
                 do_exit(cur_stream);
066ce8c9
                 break;
             }
d52ec002
         case SDL_MOUSEMOTION:
ef7f3b08
             if (cursor_hidden) {
                 SDL_ShowCursor(1);
                 cursor_hidden = 0;
             }
0ca0b4c2
             cursor_last_shown = av_gettime_relative();
da7c65f0
             if (event.type == SDL_MOUSEBUTTONDOWN) {
                 x = event.button.x;
             } else {
                 if (event.motion.state != SDL_PRESSED)
d52ec002
                     break;
da7c65f0
                 x = event.motion.x;
bb270c08
             }
da7c65f0
                 if (seek_by_bytes || cur_stream->ic->duration <= 0) {
                     uint64_t size =  avio_size(cur_stream->ic->pb);
d52ec002
                     stream_seek(cur_stream, size*x/cur_stream->width, 0, 1);
da7c65f0
                 } else {
6371c81a
                     int64_t ts;
                     int ns, hh, mm, ss;
                     int tns, thh, tmm, tss;
da7c65f0
                     tns  = cur_stream->ic->duration / 1000000LL;
                     thh  = tns / 3600;
                     tmm  = (tns % 3600) / 60;
                     tss  = (tns % 60);
                     frac = x / cur_stream->width;
                     ns   = frac * tns;
                     hh   = ns / 3600;
                     mm   = (ns % 3600) / 60;
                     ss   = (ns % 60);
3b491c5a
                     av_log(NULL, AV_LOG_INFO,
                            "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d)       \n", frac*100,
6371c81a
                             hh, mm, ss, thh, tmm, tss);
da7c65f0
                     ts = frac * cur_stream->ic->duration;
6371c81a
                     if (cur_stream->ic->start_time != AV_NOPTS_VALUE)
                         ts += cur_stream->ic->start_time;
                     stream_seek(cur_stream, ts, 0, 0);
2ef46053
                 }
bb270c08
             break;
01310af2
         case SDL_VIDEORESIZE:
87917a32
                 screen = SDL_SetVideoMode(FFMIN(16383, event.resize.w), event.resize.h, 0,
32f1a288
                                           SDL_HWSURFACE|(is_full_screen?SDL_FULLSCREEN:SDL_RESIZABLE)|SDL_ASYNCBLIT|SDL_HWACCEL);
87917a32
                 if (!screen) {
3b491c5a
                     av_log(NULL, AV_LOG_FATAL, "Failed to set video mode\n");
87917a32
                     do_exit(cur_stream);
                 }
                 screen_width  = cur_stream->width  = screen->w;
                 screen_height = cur_stream->height = screen->h;
dbe7170e
                 cur_stream->force_refresh = 1;
01310af2
             break;
         case SDL_QUIT:
638c9d91
         case FF_QUIT_EVENT:
84506ebd
             do_exit(cur_stream);
01310af2
             break;
         case FF_ALLOC_EVENT:
             alloc_picture(event.user.data1);
             break;
         default:
             break;
         }
     }
 }
 
b1034505
 static int opt_frame_size(void *optctx, const char *opt, const char *arg)
e4b89522
 {
940a116b
     av_log(NULL, AV_LOG_WARNING, "Option -s is deprecated, use -video_size.\n");
98298eb1
     return opt_default(NULL, "video_size", arg);
e4b89522
 }
 
b1034505
 static int opt_width(void *optctx, const char *opt, const char *arg)
01310af2
 {
a5b3b5f6
     screen_width = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
     return 0;
01310af2
 }
 
b1034505
 static int opt_height(void *optctx, const char *opt, const char *arg)
01310af2
 {
a5b3b5f6
     screen_height = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
     return 0;
01310af2
 }
 
b1034505
 static int opt_format(void *optctx, const char *opt, const char *arg)
01310af2
 {
     file_iformat = av_find_input_format(arg);
     if (!file_iformat) {
3b491c5a
         av_log(NULL, AV_LOG_FATAL, "Unknown input format: %s\n", arg);
eb8bc572
         return AVERROR(EINVAL);
01310af2
     }
eb8bc572
     return 0;
01310af2
 }
61890b02
 
b1034505
 static int opt_frame_pix_fmt(void *optctx, const char *opt, const char *arg)
e4b89522
 {
940a116b
     av_log(NULL, AV_LOG_WARNING, "Option -pix_fmt is deprecated, use -pixel_format.\n");
98298eb1
     return opt_default(NULL, "pixel_format", arg);
e4b89522
 }
 
b1034505
 static int opt_sync(void *optctx, const char *opt, const char *arg)
638c9d91
 {
     if (!strcmp(arg, "audio"))
         av_sync_type = AV_SYNC_AUDIO_MASTER;
     else if (!strcmp(arg, "video"))
         av_sync_type = AV_SYNC_VIDEO_MASTER;
     else if (!strcmp(arg, "ext"))
         av_sync_type = AV_SYNC_EXTERNAL_CLOCK;
aab1b7e5
     else {
3b491c5a
         av_log(NULL, AV_LOG_ERROR, "Unknown value for %s: %s\n", opt, arg);
aab1b7e5
         exit(1);
     }
b81d6235
     return 0;
638c9d91
 }
 
b1034505
 static int opt_seek(void *optctx, const char *opt, const char *arg)
72ea344b
 {
e11bc2c6
     start_time = parse_time_or_die(opt, arg, 1);
     return 0;
72ea344b
 }
 
98298eb1
 static int opt_duration(void *optctx, const char *opt, const char *arg)
d834d63b
 {
     duration = parse_time_or_die(opt, arg, 1);
     return 0;
 }
 
b1034505
 static int opt_show_mode(void *optctx, const char *opt, const char *arg)
f521746b
 {
     show_mode = !strcmp(arg, "video") ? SHOW_MODE_VIDEO :
                 !strcmp(arg, "waves") ? SHOW_MODE_WAVES :
                 !strcmp(arg, "rdft" ) ? SHOW_MODE_RDFT  :
                 parse_number_or_die(opt, arg, OPT_INT, 0, SHOW_MODE_NB-1);
     return 0;
 }
 
d2084402
 static void opt_input_file(void *optctx, const char *filename)
b4af3cf3
 {
     if (input_filename) {
3b491c5a
         av_log(NULL, AV_LOG_FATAL,
                "Argument '%s' provided as input filename, but '%s' was already specified.\n",
b4af3cf3
                 filename, input_filename);
032ba74e
         exit(1);
b4af3cf3
     }
     if (!strcmp(filename, "-"))
         filename = "pipe:";
     input_filename = filename;
 }
 
cb0f97b5
 static int opt_codec(void *optctx, const char *opt, const char *arg)
5eda0967
 {
cb0f97b5
    const char *spec = strchr(opt, ':');
    if (!spec) {
3b491c5a
        av_log(NULL, AV_LOG_ERROR,
               "No media specifier was specified in '%s' in option '%s'\n",
cb0f97b5
                arg, opt);
        return AVERROR(EINVAL);
    }
    spec++;
    switch (spec[0]) {
    case 'a' :    audio_codec_name = arg; break;
    case 's' : subtitle_codec_name = arg; break;
    case 'v' :    video_codec_name = arg; break;
    default:
3b491c5a
        av_log(NULL, AV_LOG_ERROR,
               "Invalid media specifier '%s' in option '%s'\n", spec, opt);
cb0f97b5
        return AVERROR(EINVAL);
    }
    return 0;
5eda0967
 }
 
d2084402
 static int dummy;
 
358061f6
 static const OptionDef options[] = {
992f8eae
 #include "cmdutils_common_opts.h"
a9a1bc56
     { "x", HAS_ARG, { .func_arg = opt_width }, "force displayed width", "width" },
     { "y", HAS_ARG, { .func_arg = opt_height }, "force displayed height", "height" },
     { "s", HAS_ARG | OPT_VIDEO, { .func_arg = opt_frame_size }, "set frame size (WxH or abbreviation)", "size" },
     { "fs", OPT_BOOL, { &is_full_screen }, "force full screen" },
     { "an", OPT_BOOL, { &audio_disable }, "disable audio" },
     { "vn", OPT_BOOL, { &video_disable }, "disable video" },
d0c6ed7d
     { "sn", OPT_BOOL, { &subtitle_disable }, "disable subtitling" },
5e7dcb04
     { "ast", OPT_STRING | HAS_ARG | OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_AUDIO] }, "select desired audio stream", "stream_specifier" },
     { "vst", OPT_STRING | HAS_ARG | OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_VIDEO] }, "select desired video stream", "stream_specifier" },
     { "sst", OPT_STRING | HAS_ARG | OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_SUBTITLE] }, "select desired subtitle stream", "stream_specifier" },
a9a1bc56
     { "ss", HAS_ARG, { .func_arg = opt_seek }, "seek to a given position in seconds", "pos" },
     { "t", HAS_ARG, { .func_arg = opt_duration }, "play  \"duration\" seconds of audio/video", "duration" },
     { "bytes", OPT_INT | HAS_ARG, { &seek_by_bytes }, "seek by bytes 0=off 1=on -1=auto", "val" },
     { "nodisp", OPT_BOOL, { &display_disable }, "disable graphical display" },
     { "f", HAS_ARG, { .func_arg = opt_format }, "force format", "fmt" },
     { "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_frame_pix_fmt }, "set pixel format", "format" },
     { "stats", OPT_BOOL | OPT_EXPERT, { &show_status }, "show status", "" },
     { "fast", OPT_BOOL | OPT_EXPERT, { &fast }, "non spec compliant optimizations", "" },
     { "genpts", OPT_BOOL | OPT_EXPERT, { &genpts }, "generate pts", "" },
     { "drp", OPT_INT | HAS_ARG | OPT_EXPERT, { &decoder_reorder_pts }, "let decoder reorder pts 0=off 1=on -1=auto", ""},
     { "lowres", OPT_INT | HAS_ARG | OPT_EXPERT, { &lowres }, "", "" },
     { "sync", HAS_ARG | OPT_EXPERT, { .func_arg = opt_sync }, "set audio-video sync. type (type=audio/video/ext)", "type" },
     { "autoexit", OPT_BOOL | OPT_EXPERT, { &autoexit }, "exit at the end", "" },
     { "exitonkeydown", OPT_BOOL | OPT_EXPERT, { &exit_on_keydown }, "exit on key down", "" },
     { "exitonmousedown", OPT_BOOL | OPT_EXPERT, { &exit_on_mousedown }, "exit on mouse down", "" },
     { "loop", OPT_INT | HAS_ARG | OPT_EXPERT, { &loop }, "set number of times the playback shall be looped", "loop count" },
     { "framedrop", OPT_BOOL | OPT_EXPERT, { &framedrop }, "drop frames when cpu is too slow", "" },
     { "infbuf", OPT_BOOL | OPT_EXPERT, { &infinite_buffer }, "don't limit the input buffer size (useful with realtime streams)", "" },
     { "window_title", OPT_STRING | HAS_ARG, { &window_title }, "set window title", "window title" },
917d2bb3
 #if CONFIG_AVFILTER
a583e2be
     { "vf", OPT_EXPERT | HAS_ARG, { .func_arg = opt_add_vfilter }, "set video filters", "filter_graph" },
e96175ad
     { "af", OPT_STRING | HAS_ARG, { &afilters }, "set audio filters", "filter_graph" },
917d2bb3
 #endif
a9a1bc56
     { "rdftspeed", OPT_INT | HAS_ARG| OPT_AUDIO | OPT_EXPERT, { &rdftspeed }, "rdft speed", "msecs" },
     { "showmode", HAS_ARG, { .func_arg = opt_show_mode}, "select show mode (0 = video, 1 = waves, 2 = RDFT)", "mode" },
     { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { .func_arg = opt_default }, "generic catch all option", "" },
     { "i", OPT_BOOL, { &dummy}, "read specified file", "input_file"},
cb0f97b5
     { "codec", HAS_ARG, { .func_arg = opt_codec}, "force decoder", "decoder_name" },
     { "acodec", HAS_ARG | OPT_STRING | OPT_EXPERT, {    &audio_codec_name }, "force audio decoder",    "decoder_name" },
     { "scodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &subtitle_codec_name }, "force subtitle decoder", "decoder_name" },
     { "vcodec", HAS_ARG | OPT_STRING | OPT_EXPERT, {    &video_codec_name }, "force video decoder",    "decoder_name" },
08c51e12
     { "autorotate", OPT_BOOL, { &autorotate }, "automatically rotate video", "" },
01310af2
     { NULL, },
 };
 
0c2a18cb
 static void show_usage(void)
01310af2
 {
ceef1ee7
     av_log(NULL, AV_LOG_INFO, "Simple media player\n");
     av_log(NULL, AV_LOG_INFO, "usage: %s [options] input_file\n", program_name);
     av_log(NULL, AV_LOG_INFO, "\n");
0c2a18cb
 }
 
a3ad68d3
 void show_help_default(const char *opt, const char *arg)
0c2a18cb
 {
f66eb58e
     av_log_set_callback(log_callback_help);
0c2a18cb
     show_usage();
f9fada27
     show_help_options(options, "Main options:", 0, OPT_EXPERT, 0);
     show_help_options(options, "Advanced options:", OPT_EXPERT, 0, 0);
f66eb58e
     printf("\n");
7a6cd995
     show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM);
     show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
f66eb58e
 #if !CONFIG_AVFILTER
7a6cd995
     show_help_children(sws_get_class(), AV_OPT_FLAG_ENCODING_PARAM);
5296d7b9
 #else
     show_help_children(avfilter_get_class(), AV_OPT_FLAG_FILTERING_PARAM);
f66eb58e
 #endif
01310af2
     printf("\nWhile playing:\n"
            "q, ESC              quit\n"
            "f                   toggle full screen\n"
            "p, SPC              pause\n"
060c42bc
            "a                   cycle audio channel in the current program\n"
638c9d91
            "v                   cycle video channel\n"
060c42bc
            "t                   cycle subtitle channel in the current program\n"
3130416a
            "c                   cycle program\n"
a583e2be
            "w                   cycle video filters or show modes\n"
79f8b328
            "s                   activate frame-step mode\n"
72ea344b
            "left/right          seek backward/forward 10 seconds\n"
            "down/up             seek backward/forward 1 minute\n"
91a3ea67
            "page down/page up   seek backward/forward 10 minutes\n"
a11d11aa
            "mouse click         seek to percentage in file corresponding to fraction of width\n"
01310af2
            );
 }
 
ee0ff051
 static int lockmgr(void **mtx, enum AVLockOp op)
 {
    switch(op) {
       case AV_LOCK_CREATE:
           *mtx = SDL_CreateMutex();
           if(!*mtx)
               return 1;
           return 0;
       case AV_LOCK_OBTAIN:
           return !!SDL_LockMutex(*mtx);
       case AV_LOCK_RELEASE:
           return !!SDL_UnlockMutex(*mtx);
       case AV_LOCK_DESTROY:
           SDL_DestroyMutex(*mtx);
           return 0;
    }
    return 1;
 }
 
01310af2
 /* Called from the main */
 int main(int argc, char **argv)
 {
a5c33faa
     int flags;
84506ebd
     VideoState *is;
1372c826
     char dummy_videodriver[] = "SDL_VIDEODRIVER=dummy";
115329f1
 
6b6bca64
     av_log_set_flags(AV_LOG_SKIP_REPEATED);
182cbe43
     parse_loglevel(argc, argv, options);
6b6bca64
 
01310af2
     /* register all codecs, demux and protocols */
9b157b0c
 #if CONFIG_AVDEVICE
c721d803
     avdevice_register_all();
9b157b0c
 #endif
917d2bb3
 #if CONFIG_AVFILTER
     avfilter_register_all();
 #endif
01310af2
     av_register_all();
776f2bb9
     avformat_network_init();
01310af2
 
a5c33faa
     init_opts();
e43d7a18
 
73f2cf4e
     signal(SIGINT , sigterm_handler); /* Interrupt (ANSI).    */
     signal(SIGTERM, sigterm_handler); /* Termination (ANSI).  */
 
452406bd
     show_banner(argc, argv, options);
4cfac5bc
 
7cc8d638
     parse_options(NULL, argc, argv, options, opt_input_file);
01310af2
 
aab1b7e5
     if (!input_filename) {
7f11e745
         show_usage();
3b491c5a
         av_log(NULL, AV_LOG_FATAL, "An input file must be specified\n");
         av_log(NULL, AV_LOG_FATAL,
                "Use -h to get full help or, even better, run 'man %s'\n", program_name);
aab1b7e5
         exit(1);
     }
01310af2
 
     if (display_disable) {
         video_disable = 1;
     }
31319a8c
     flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
86824c1d
     if (audio_disable)
         flags &= ~SDL_INIT_AUDIO;
1372c826
     if (display_disable)
         SDL_putenv(dummy_videodriver); /* For the event queue, we always need a video driver. */
e1169775
 #if !defined(_WIN32) && !defined(__APPLE__)
c97f5402
     flags |= SDL_INIT_EVENTTHREAD; /* Not supported on Windows or Mac OS X */
31319a8c
 #endif
01310af2
     if (SDL_Init (flags)) {
3b491c5a
         av_log(NULL, AV_LOG_FATAL, "Could not initialize SDL - %s\n", SDL_GetError());
         av_log(NULL, AV_LOG_FATAL, "(Did you set the DISPLAY variable?)\n");
01310af2
         exit(1);
     }
 
     if (!display_disable) {
3ef17d62
         const SDL_VideoInfo *vi = SDL_GetVideoInfo();
         fs_screen_width = vi->current_w;
         fs_screen_height = vi->current_h;
01310af2
     }
 
     SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
     SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
     SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
 
ee0ff051
     if (av_lockmgr_register(lockmgr)) {
3b491c5a
         av_log(NULL, AV_LOG_FATAL, "Could not initialize lock manager!\n");
ee0ff051
         do_exit(NULL);
     }
 
39c6a118
     av_init_packet(&flush_pkt);
26a44143
     flush_pkt.data = (uint8_t *)&flush_pkt;
39c6a118
 
84506ebd
     is = stream_open(input_filename, file_iformat);
     if (!is) {
3b491c5a
         av_log(NULL, AV_LOG_FATAL, "Failed to initialize VideoState!\n");
84506ebd
         do_exit(NULL);
     }
01310af2
 
84506ebd
     event_loop(is);
01310af2
 
     /* never returns */
 
     return 0;
 }