arm: fix compile with disable-optimizations on android
[ffmpeg.git] / ffplay.c
index 749cfc7..598ce74 100644 (file)
--- a/ffplay.c
+++ b/ffplay.c
 #include "libavutil/parseutils.h"
 #include "libavutil/samplefmt.h"
 #include "libavutil/avassert.h"
+#include "libavutil/time.h"
 #include "libavformat/avformat.h"
 #include "libavdevice/avdevice.h"
 #include "libswscale/swscale.h"
-#include "libavcodec/audioconvert.h"
 #include "libavutil/opt.h"
 #include "libavcodec/avfft.h"
 #include "libswresample/swresample.h"
@@ -50,6 +50,7 @@
 # include "libavfilter/avfilter.h"
 # include "libavfilter/avfiltergraph.h"
 # include "libavfilter/buffersink.h"
+# include "libavfilter/buffersrc.h"
 #endif
 
 #include <SDL.h>
 
 #include "cmdutils.h"
 
-#include <unistd.h>
 #include <assert.h>
 
 const char program_name[] = "ffplay";
 const int program_birth_year = 2003;
 
 #define MAX_QUEUE_SIZE (15 * 1024 * 1024)
-#define MIN_AUDIOQ_SIZE (20 * 16 * 1024)
 #define MIN_FRAMES 5
 
 /* SDL audio buffer size, in samples. Should be small to have precise
@@ -101,14 +100,13 @@ typedef struct PacketQueue {
 
 typedef struct VideoPicture {
     double pts;                                  ///< presentation time stamp for this picture
-    double duration;                             ///< expected duration of the frame
     int64_t pos;                                 ///< byte position in file
     int skip;
     SDL_Overlay *bmp;
     int width, height; /* source height & width */
+    AVRational sample_aspect_ratio;
     int allocated;
     int reallocate;
-    enum PixelFormat pix_fmt;
 
 #if CONFIG_AVFILTER
     AVFilterBufferRef *picref;
@@ -120,6 +118,13 @@ typedef struct SubPicture {
     AVSubtitle sub;
 } SubPicture;
 
+typedef struct AudioParams {
+    int freq;
+    int channels;
+    int channel_layout;
+    enum AVSampleFormat fmt;
+} AudioParams;
+
 enum {
     AV_SYNC_AUDIO_MASTER, /* default choice */
     AV_SYNC_VIDEO_MASTER,
@@ -133,6 +138,7 @@ typedef struct VideoState {
     AVInputFormat *iformat;
     int no_background;
     int abort_request;
+    int force_refresh;
     int paused;
     int last_paused;
     int seek_req;
@@ -165,14 +171,8 @@ typedef struct VideoState {
     int audio_write_buf_size;
     AVPacket audio_pkt_temp;
     AVPacket audio_pkt;
-    enum AVSampleFormat audio_src_fmt;
-    enum AVSampleFormat audio_tgt_fmt;
-    int audio_src_channels;
-    int audio_tgt_channels;
-    int64_t audio_src_channel_layout;
-    int64_t audio_tgt_channel_layout;
-    int audio_src_freq;
-    int audio_tgt_freq;
+    struct AudioParams audio_src;
+    struct AudioParams audio_tgt;
     struct SwrContext *swr_ctx;
     double audio_current_pts;
     double audio_current_pts_drift;
@@ -228,12 +228,21 @@ typedef struct VideoState {
     int step;
 
 #if CONFIG_AVFILTER
+    AVFilterContext *in_video_filter;           ///< the first filter in the video chain
     AVFilterContext *out_video_filter;          ///< the last filter in the video chain
+    int use_dr1;
+    FrameBuffer *buffer_pool;
 #endif
 
     int refresh;
+    int last_video_stream, last_audio_stream, last_subtitle_stream;
 } VideoState;
 
+typedef struct AllocEventProps {
+    VideoState *is;
+    AVFrame *frame;
+} AllocEventProps;
+
 static int opt_help(const char *opt, const char *arg);
 
 /* options specified by the user */
@@ -265,7 +274,6 @@ static int idct = FF_IDCT_AUTO;
 static enum AVDiscard skip_frame       = AVDISCARD_DEFAULT;
 static enum AVDiscard skip_idct        = AVDISCARD_DEFAULT;
 static enum AVDiscard skip_loop_filter = AVDISCARD_DEFAULT;
-static int error_recognition = FF_ER_CAREFUL;
 static int error_concealment = 3;
 static int decoder_reorder_pts = -1;
 static int autoexit;
@@ -273,6 +281,7 @@ static int exit_on_keydown;
 static int exit_on_mousedown;
 static int loop = 1;
 static int framedrop = -1;
+static int infinite_buffer = 0;
 static enum ShowMode show_mode = SHOW_MODE_NONE;
 static const char *audio_codec_name;
 static const char *subtitle_codec_name;
@@ -299,13 +308,12 @@ void av_noreturn exit_program(int ret)
     exit(ret);
 }
 
-static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
+static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)
 {
     AVPacketList *pkt1;
 
-    /* duplicate the packet */
-    if (pkt != &flush_pkt && av_dup_packet(pkt) < 0)
-        return -1;
+    if (q->abort_request)
+       return -1;
 
     pkt1 = av_malloc(sizeof(AVPacketList));
     if (!pkt1)
@@ -313,11 +321,7 @@ static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
     pkt1->pkt = *pkt;
     pkt1->next = NULL;
 
-
-    SDL_LockMutex(q->mutex);
-
     if (!q->last_pkt)
-
         q->first_pkt = pkt1;
     else
         q->last_pkt->next = pkt1;
@@ -326,9 +330,25 @@ static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
     q->size += pkt1->pkt.size + sizeof(*pkt1);
     /* XXX: should duplicate packet data in DV case */
     SDL_CondSignal(q->cond);
+    return 0;
+}
+
+static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
+{
+    int ret;
+
+    /* 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);
     SDL_UnlockMutex(q->mutex);
-    return 0;
+
+    if (pkt != &flush_pkt && ret < 0)
+        av_free_packet(pkt);
+
+    return ret;
 }
 
 /* packet queue handling */
@@ -337,7 +357,7 @@ static void packet_queue_init(PacketQueue *q)
     memset(q, 0, sizeof(PacketQueue));
     q->mutex = SDL_CreateMutex();
     q->cond = SDL_CreateCond();
-    packet_queue_put(q, &flush_pkt);
+    q->abort_request = 1;
 }
 
 static void packet_queue_flush(PacketQueue *q)
@@ -357,7 +377,7 @@ static void packet_queue_flush(PacketQueue *q)
     SDL_UnlockMutex(q->mutex);
 }
 
-static void packet_queue_end(PacketQueue *q)
+static void packet_queue_destroy(PacketQueue *q)
 {
     packet_queue_flush(q);
     SDL_DestroyMutex(q->mutex);
@@ -375,6 +395,14 @@ static void packet_queue_abort(PacketQueue *q)
     SDL_UnlockMutex(q->mutex);
 }
 
+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);
+}
+
 /* return < 0 if aborted, 0 if no packet and > 0 if packet.  */
 static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
 {
@@ -668,21 +696,11 @@ static void video_image_display(VideoState *is)
 
     vp = &is->pictq[is->pictq_rindex];
     if (vp->bmp) {
-#if CONFIG_AVFILTER
-         if (vp->picref->video->sample_aspect_ratio.num == 0)
-             aspect_ratio = 0;
-         else
-             aspect_ratio = av_q2d(vp->picref->video->sample_aspect_ratio);
-#else
-
-        /* XXX: use variable in the frame */
-        if (is->video_st->sample_aspect_ratio.num)
-            aspect_ratio = av_q2d(is->video_st->sample_aspect_ratio);
-        else if (is->video_st->codec->sample_aspect_ratio.num)
-            aspect_ratio = av_q2d(is->video_st->codec->sample_aspect_ratio);
-        else
+        if (vp->sample_aspect_ratio.num == 0)
             aspect_ratio = 0;
-#endif
+        else
+            aspect_ratio = av_q2d(vp->sample_aspect_ratio);
+
         if (aspect_ratio <= 0.0)
             aspect_ratio = 1.0;
         aspect_ratio *= (float)vp->width / (float)vp->height;
@@ -747,7 +765,7 @@ static void video_audio_display(VideoState *s)
     nb_freq = 1 << (rdft_bits - 1);
 
     /* compute display index : center on currently output samples */
-    channels = s->audio_tgt_channels;
+    channels = s->audio_tgt.channels;
     nb_display_channels = channels;
     if (!s->paused) {
         int data_used= s->show_mode == SHOW_MODE_WAVES ? s->width : (2*nb_freq);
@@ -759,7 +777,7 @@ static void video_audio_display(VideoState *s)
            the last buffer computation */
         if (audio_callback_time) {
             time_diff = av_gettime() - audio_callback_time;
-            delay -= (time_diff * s->audio_tgt_freq) / 1000000;
+            delay -= (time_diff * s->audio_tgt.freq) / 1000000;
         }
 
         delay += 2 * data_used;
@@ -868,7 +886,8 @@ static void video_audio_display(VideoState *s)
             }
         }
         SDL_UpdateRect(screen, s->xpos, s->ytop, 1, s->height);
-        s->xpos++;
+        if (!s->paused)
+            s->xpos++;
         if (s->xpos >= s->width)
             s->xpos= s->xleft;
     }
@@ -882,15 +901,15 @@ static void stream_close(VideoState *is)
     is->abort_request = 1;
     SDL_WaitThread(is->read_tid, NULL);
     SDL_WaitThread(is->refresh_tid, NULL);
+    packet_queue_destroy(&is->videoq);
+    packet_queue_destroy(&is->audioq);
+    packet_queue_destroy(&is->subtitleq);
 
     /* free all pictures */
     for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
         vp = &is->pictq[i];
 #if CONFIG_AVFILTER
-        if (vp->picref) {
-            avfilter_unref_buffer(vp->picref);
-            vp->picref = NULL;
-        }
+        avfilter_unref_bufferp(&vp->picref);
 #endif
         if (vp->bmp) {
             SDL_FreeYUVOverlay(vp->bmp);
@@ -935,6 +954,7 @@ static int video_open(VideoState *is, int force_set_video_mode)
 {
     int flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
     int w,h;
+    VideoPicture *vp = &is->pictq[is->pictq_rindex];
 
     if (is_full_screen) flags |= SDL_FULLSCREEN;
     else                flags |= SDL_RESIZABLE;
@@ -945,15 +965,9 @@ static int video_open(VideoState *is, int force_set_video_mode)
     } else if (!is_full_screen && screen_width) {
         w = screen_width;
         h = screen_height;
-#if CONFIG_AVFILTER
-    } else if (is->out_video_filter && is->out_video_filter->inputs[0]) {
-        w = is->out_video_filter->inputs[0]->w;
-        h = is->out_video_filter->inputs[0]->h;
-#else
-    } else if (is->video_st && is->video_st->codec->width) {
-        w = is->video_st->codec->width;
-        h = is->video_st->codec->height;
-#endif
+    } else if (vp->width) {
+        w = vp->width;
+        h = vp->height;
     } else {
         w = 640;
         h = 480;
@@ -994,12 +1008,12 @@ static int refresh_thread(void *opaque)
         SDL_Event event;
         event.type = FF_REFRESH_EVENT;
         event.user.data1 = opaque;
-        if (!is->refresh) {
+        if (!is->refresh && (!is->paused || is->force_refresh)) {
             is->refresh = 1;
             SDL_PushEvent(&event);
         }
         //FIXME ideally we should wait the correct time but SDLs event passing is so slow it would be silly
-        usleep(is->audio_st && is->show_mode != SHOW_MODE_VIDEO ? rdftspeed*1000 : 5000);
+        av_usleep(is->audio_st && is->show_mode != SHOW_MODE_VIDEO ? rdftspeed*1000 : 5000);
     }
     return 0;
 }
@@ -1157,6 +1171,9 @@ retry:
                 goto retry;
             }
 
+            if (is->paused)
+                goto display;
+
             /* compute nominal last_duration */
             last_duration = vp->pts - is->frame_last_pts;
             if (last_duration > 0 && last_duration < 10.0) {
@@ -1178,13 +1195,8 @@ retry:
 
             if (is->pictq_size > 1) {
                 VideoPicture *nextvp = &is->pictq[(is->pictq_rindex + 1) % VIDEO_PICTURE_QUEUE_SIZE];
-                duration = nextvp->pts - vp->pts; // More accurate this way, 1/time_base is often not reflecting FPS
-            } else {
-                duration = vp->duration;
-            }
-
-            if((framedrop>0 || (framedrop && is->audio_st)) && time > is->frame_timer + duration){
-                if(is->pictq_size > 1){
+                duration = nextvp->pts - vp->pts;
+                if((framedrop>0 || (framedrop && is->audio_st)) && time > is->frame_timer + duration){
                     is->frame_drops_late++;
                     pictq_next_picture(is);
                     goto retry;
@@ -1235,11 +1247,13 @@ retry:
                 }
             }
 
+display:
             /* display picture */
             if (!display_disable)
                 video_display(is);
 
-            pictq_next_picture(is);
+            if (!is->paused)
+                pictq_next_picture(is);
         }
     } else if (is->audio_st) {
         /* draw the next audio frame */
@@ -1251,6 +1265,7 @@ retry:
         if (!display_disable)
             video_display(is);
     }
+    is->force_refresh = 0;
     if (show_status) {
         static int64_t last_time;
         int64_t cur_time;
@@ -1288,9 +1303,10 @@ retry:
 
 /* allocate a picture (needs to do that in main thread to avoid
    potential locking problems */
-static void alloc_picture(void *opaque)
+static void alloc_picture(AllocEventProps *event_props)
 {
-    VideoState *is = opaque;
+    VideoState *is = event_props->is;
+    AVFrame *frame = event_props->frame;
     VideoPicture *vp;
 
     vp = &is->pictq[is->pictq_windex];
@@ -1299,19 +1315,14 @@ static void alloc_picture(void *opaque)
         SDL_FreeYUVOverlay(vp->bmp);
 
 #if CONFIG_AVFILTER
-    if (vp->picref)
-        avfilter_unref_buffer(vp->picref);
-    vp->picref = NULL;
-
-    vp->width   = is->out_video_filter->inputs[0]->w;
-    vp->height  = is->out_video_filter->inputs[0]->h;
-    vp->pix_fmt = is->out_video_filter->inputs[0]->format;
-#else
-    vp->width   = is->video_st->codec->width;
-    vp->height  = is->video_st->codec->height;
-    vp->pix_fmt = is->video_st->codec->pix_fmt;
+    avfilter_unref_bufferp(&vp->picref);
 #endif
 
+    vp->width   = frame->width;
+    vp->height  = frame->height;
+
+    video_open(event_props->is, 0);
+
     vp->bmp = SDL_CreateYUVOverlay(vp->width, vp->height,
                                    SDL_YV12_OVERLAY,
                                    screen);
@@ -1369,26 +1380,24 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts1, int64_
 
     vp = &is->pictq[is->pictq_windex];
 
-    vp->duration = frame_delay;
-
     /* alloc or resize hardware picture buffer */
     if (!vp->bmp || vp->reallocate ||
-#if CONFIG_AVFILTER
-        vp->width  != is->out_video_filter->inputs[0]->w ||
-        vp->height != is->out_video_filter->inputs[0]->h) {
-#else
-        vp->width != is->video_st->codec->width ||
-        vp->height != is->video_st->codec->height) {
-#endif
+        vp->width  != src_frame->width ||
+        vp->height != src_frame->height) {
         SDL_Event event;
+        AllocEventProps event_props;
+
+        event_props.frame = src_frame;
+        event_props.is = is;
 
         vp->allocated  = 0;
         vp->reallocate = 0;
 
         /* the allocation must be done in the main thread to avoid
-           locking problems */
+           locking problems. We wait in this block for the event to complete,
+           so we can pass a pointer to event_props to it. */
         event.type = FF_ALLOC_EVENT;
-        event.user.data1 = is;
+        event.user.data1 = &event_props;
         SDL_PushEvent(&event);
 
         /* wait until the picture is allocated */
@@ -1410,17 +1419,15 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts1, int64_
 
     /* if the frame is not skipped, then display it */
     if (vp->bmp) {
-        AVPicture pict;
+        AVPicture pict = { { 0 } };
 #if CONFIG_AVFILTER
-        if (vp->picref)
-            avfilter_unref_buffer(vp->picref);
+        avfilter_unref_bufferp(&vp->picref);
         vp->picref = src_frame->opaque;
 #endif
 
         /* get a pointer on the bitmap */
         SDL_LockYUVOverlay (vp->bmp);
 
-        memset(&pict, 0, sizeof(AVPicture));
         pict.data[0] = vp->bmp->pixels[0];
         pict.data[1] = vp->bmp->pixels[2];
         pict.data[2] = vp->bmp->pixels[1];
@@ -1432,11 +1439,12 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts1, int64_
 #if CONFIG_AVFILTER
         // FIXME use direct rendering
         av_picture_copy(&pict, (AVPicture *)src_frame,
-                        vp->pix_fmt, vp->width, vp->height);
+                        src_frame->format, vp->width, vp->height);
+        vp->sample_aspect_ratio = vp->picref->video->sample_aspect_ratio;
 #else
         sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
         is->img_convert_ctx = sws_getCachedContext(is->img_convert_ctx,
-            vp->width, vp->height, vp->pix_fmt, vp->width, vp->height,
+            vp->width, vp->height, src_frame->format, vp->width, vp->height,
             PIX_FMT_YUV420P, sws_flags, NULL, NULL, NULL);
         if (is->img_convert_ctx == NULL) {
             fprintf(stderr, "Cannot initialize the conversion context\n");
@@ -1444,6 +1452,7 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts1, int64_
         }
         sws_scale(is->img_convert_ctx, src_frame->data, src_frame->linesize,
                   0, vp->height, pict.data, pict.linesize);
+        vp->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, src_frame);
 #endif
         /* update the bitmap content */
         SDL_UnlockYUVOverlay(vp->bmp);
@@ -1490,13 +1499,14 @@ static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacke
         return 0;
     }
 
-    avcodec_decode_video2(is->video_st->codec, frame, &got_picture, pkt);
+    if(avcodec_decode_video2(is->video_st->codec, frame, &got_picture, pkt) < 0)
+        return 0;
 
     if (got_picture) {
         int ret = 1;
 
         if (decoder_reorder_pts == -1) {
-            *pts = *(int64_t*)av_opt_ptr(avcodec_get_frame_class(), frame, "best_effort_timestamp");
+            *pts = av_frame_get_best_effort_timestamp(frame);
         } else if (decoder_reorder_pts) {
             *pts = frame->pkt_pts;
         } else {
@@ -1526,262 +1536,94 @@ static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacke
             SDL_UnlockMutex(is->pictq_mutex);
         }
 
-        if (ret)
-            is->frame_last_returned_time = av_gettime() / 1000000.0;
-
         return ret;
     }
     return 0;
 }
 
 #if CONFIG_AVFILTER
-typedef struct {
-    VideoState *is;
-    AVFrame *frame;
-    int use_dr1;
-} FilterPriv;
-
-static int input_get_buffer(AVCodecContext *codec, AVFrame *pic)
+static int configure_filtergraph(AVFilterGraph *graph, const char *filtergraph,
+                                 AVFilterContext *source_ctx, AVFilterContext *sink_ctx)
 {
-    AVFilterContext *ctx = codec->opaque;
-    AVFilterBufferRef  *ref;
-    int perms = AV_PERM_WRITE;
-    int i, w, h, stride[4];
-    unsigned edge;
-    int pixel_size;
-
-    av_assert0(codec->flags & CODEC_FLAG_EMU_EDGE);
-
-    if (codec->codec->capabilities & CODEC_CAP_NEG_LINESIZES)
-        perms |= AV_PERM_NEG_LINESIZES;
-
-    if (pic->buffer_hints & FF_BUFFER_HINTS_VALID) {
-        if (pic->buffer_hints & FF_BUFFER_HINTS_READABLE) perms |= AV_PERM_READ;
-        if (pic->buffer_hints & FF_BUFFER_HINTS_PRESERVE) perms |= AV_PERM_PRESERVE;
-        if (pic->buffer_hints & FF_BUFFER_HINTS_REUSABLE) perms |= AV_PERM_REUSE2;
-    }
-    if (pic->reference) perms |= AV_PERM_READ | AV_PERM_PRESERVE;
-
-    w = codec->width;
-    h = codec->height;
-
-    if(av_image_check_size(w, h, 0, codec))
-        return -1;
-
-    avcodec_align_dimensions2(codec, &w, &h, stride);
-    edge = codec->flags & CODEC_FLAG_EMU_EDGE ? 0 : avcodec_get_edge_width();
-    w += edge << 1;
-    h += edge << 1;
-    if (codec->pix_fmt != ctx->outputs[0]->format) {
-        av_log(codec, AV_LOG_ERROR, "Pixel format mismatches %d %d\n", codec->pix_fmt, ctx->outputs[0]->format);
-        return -1;
-    }
-    if (!(ref = avfilter_get_video_buffer(ctx->outputs[0], perms, w, h)))
-        return -1;
-
-    pixel_size = av_pix_fmt_descriptors[ref->format].comp[0].step_minus1 + 1;
-    ref->video->w = codec->width;
-    ref->video->h = codec->height;
-    for (i = 0; i < 4; i ++) {
-        unsigned hshift = (i == 1 || i == 2) ? av_pix_fmt_descriptors[ref->format].log2_chroma_w : 0;
-        unsigned vshift = (i == 1 || i == 2) ? av_pix_fmt_descriptors[ref->format].log2_chroma_h : 0;
+    int ret;
+    AVFilterInOut *outputs = NULL, *inputs = NULL;
 
-        if (ref->data[i]) {
-            ref->data[i]    += ((edge * pixel_size) >> hshift) + ((edge * ref->linesize[i]) >> vshift);
+    if (filtergraph) {
+        outputs = avfilter_inout_alloc();
+        inputs  = avfilter_inout_alloc();
+        if (!outputs || !inputs) {
+            ret = AVERROR(ENOMEM);
+            goto fail;
         }
-        pic->data[i]     = ref->data[i];
-        pic->linesize[i] = ref->linesize[i];
-    }
-    pic->opaque = ref;
-    pic->type   = FF_BUFFER_TYPE_USER;
-    pic->reordered_opaque = codec->reordered_opaque;
-    if (codec->pkt) pic->pkt_pts = codec->pkt->pts;
-    else            pic->pkt_pts = AV_NOPTS_VALUE;
-    return 0;
-}
-
-static void input_release_buffer(AVCodecContext *codec, AVFrame *pic)
-{
-    memset(pic->data, 0, sizeof(pic->data));
-    avfilter_unref_buffer(pic->opaque);
-}
-
-static int input_reget_buffer(AVCodecContext *codec, AVFrame *pic)
-{
-    AVFilterBufferRef *ref = pic->opaque;
-
-    if (pic->data[0] == NULL) {
-        pic->buffer_hints |= FF_BUFFER_HINTS_READABLE;
-        return codec->get_buffer(codec, pic);
-    }
-
-    if ((codec->width != ref->video->w) || (codec->height != ref->video->h) ||
-        (codec->pix_fmt != ref->format)) {
-        av_log(codec, AV_LOG_ERROR, "Picture properties changed.\n");
-        return -1;
-    }
-
-    pic->reordered_opaque = codec->reordered_opaque;
-    if (codec->pkt) pic->pkt_pts = codec->pkt->pts;
-    else            pic->pkt_pts = AV_NOPTS_VALUE;
-    return 0;
-}
-
-static int input_init(AVFilterContext *ctx, const char *args, void *opaque)
-{
-    FilterPriv *priv = ctx->priv;
-    AVCodecContext *codec;
-    if (!opaque) return -1;
-
-    priv->is = opaque;
-    codec    = priv->is->video_st->codec;
-    codec->opaque = ctx;
-    if (codec->codec->capabilities & CODEC_CAP_DR1) {
-        av_assert0(codec->flags & CODEC_FLAG_EMU_EDGE);
-        priv->use_dr1 = 1;
-        codec->get_buffer     = input_get_buffer;
-        codec->release_buffer = input_release_buffer;
-        codec->reget_buffer   = input_reget_buffer;
-        codec->thread_safe_callbacks = 1;
-    }
-
-    priv->frame = avcodec_alloc_frame();
 
-    return 0;
-}
-
-static void input_uninit(AVFilterContext *ctx)
-{
-    FilterPriv *priv = ctx->priv;
-    av_free(priv->frame);
-}
-
-static int input_request_frame(AVFilterLink *link)
-{
-    FilterPriv *priv = link->src->priv;
-    AVFilterBufferRef *picref;
-    int64_t pts = 0;
-    AVPacket pkt;
-    int ret;
+        outputs->name       = av_strdup("in");
+        outputs->filter_ctx = source_ctx;
+        outputs->pad_idx    = 0;
+        outputs->next       = NULL;
 
-    while (!(ret = get_video_frame(priv->is, priv->frame, &pts, &pkt)))
-        av_free_packet(&pkt);
-    if (ret < 0)
-        return -1;
+        inputs->name        = av_strdup("out");
+        inputs->filter_ctx  = sink_ctx;
+        inputs->pad_idx     = 0;
+        inputs->next        = NULL;
 
-    if (priv->use_dr1 && priv->frame->opaque) {
-        picref = avfilter_ref_buffer(priv->frame->opaque, ~0);
+        if ((ret = avfilter_graph_parse(graph, filtergraph, &inputs, &outputs, NULL)) < 0)
+            goto fail;
     } else {
-        picref = avfilter_get_video_buffer(link, AV_PERM_WRITE, link->w, link->h);
-        av_image_copy(picref->data, picref->linesize,
-                      priv->frame->data, priv->frame->linesize,
-                      picref->format, link->w, link->h);
+        if ((ret = avfilter_link(source_ctx, 0, sink_ctx, 0)) < 0)
+            goto fail;
     }
-    av_free_packet(&pkt);
-
-    avfilter_copy_frame_props(picref, priv->frame);
-    picref->pts = pts;
-
-    avfilter_start_frame(link, picref);
-    avfilter_draw_slice(link, 0, link->h, 1);
-    avfilter_end_frame(link);
-
-    return 0;
-}
-
-static int input_query_formats(AVFilterContext *ctx)
-{
-    FilterPriv *priv = ctx->priv;
-    enum PixelFormat pix_fmts[] = {
-        priv->is->video_st->codec->pix_fmt, PIX_FMT_NONE
-    };
-
-    avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
-    return 0;
-}
-
-static int input_config_props(AVFilterLink *link)
-{
-    FilterPriv *priv  = link->src->priv;
-    AVStream *s = priv->is->video_st;
-
-    link->w = s->codec->width;
-    link->h = s->codec->height;
-    link->sample_aspect_ratio = s->sample_aspect_ratio.num ?
-        s->sample_aspect_ratio : s->codec->sample_aspect_ratio;
-    link->time_base = s->time_base;
 
-    return 0;
+    return avfilter_graph_config(graph, NULL);
+fail:
+    avfilter_inout_free(&outputs);
+    avfilter_inout_free(&inputs);
+    return ret;
 }
 
-static AVFilter input_filter =
-{
-    .name      = "ffplay_input",
-
-    .priv_size = sizeof(FilterPriv),
-
-    .init      = input_init,
-    .uninit    = input_uninit,
-
-    .query_formats = input_query_formats,
-
-    .inputs    = (AVFilterPad[]) {{ .name = NULL }},
-    .outputs   = (AVFilterPad[]) {{ .name = "default",
-                                    .type = AVMEDIA_TYPE_VIDEO,
-                                    .request_frame = input_request_frame,
-                                    .config_props  = input_config_props, },
-                                  { .name = NULL }},
-};
-
 static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters)
 {
+    static const enum PixelFormat pix_fmts[] = { PIX_FMT_YUV420P, PIX_FMT_NONE };
     char sws_flags_str[128];
+    char buffersrc_args[256];
     int ret;
-    enum PixelFormat pix_fmts[] = { PIX_FMT_YUV420P, PIX_FMT_NONE };
     AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc();
-    AVFilterContext *filt_src = NULL, *filt_out = NULL;
+    AVFilterContext *filt_src = NULL, *filt_out = NULL, *filt_format;
+    AVCodecContext *codec = is->video_st->codec;
+
     snprintf(sws_flags_str, sizeof(sws_flags_str), "flags=%d", sws_flags);
     graph->scale_sws_opts = av_strdup(sws_flags_str);
 
-    if ((ret = avfilter_graph_create_filter(&filt_src, &input_filter, "src",
-                                            NULL, is, graph)) < 0)
+    snprintf(buffersrc_args, sizeof(buffersrc_args),
+             "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
+             codec->width, codec->height, codec->pix_fmt,
+             is->video_st->time_base.num, is->video_st->time_base.den,
+             codec->sample_aspect_ratio.num, codec->sample_aspect_ratio.den);
+
+    if ((ret = avfilter_graph_create_filter(&filt_src,
+                                            avfilter_get_by_name("buffer"),
+                                            "ffplay_buffer", buffersrc_args, NULL,
+                                            graph)) < 0)
         return ret;
-#if FF_API_OLD_VSINK_API
-    ret = avfilter_graph_create_filter(&filt_out, avfilter_get_by_name("buffersink"), "out",
-                                       NULL, pix_fmts, graph);
-#else
+
     buffersink_params->pixel_fmts = pix_fmts;
-    ret = avfilter_graph_create_filter(&filt_out, avfilter_get_by_name("buffersink"), "out",
-                                       NULL, buffersink_params, graph);
-#endif
+    ret = avfilter_graph_create_filter(&filt_out,
+                                       avfilter_get_by_name("buffersink"),
+                                       "ffplay_buffersink", NULL, buffersink_params, graph);
     av_freep(&buffersink_params);
     if (ret < 0)
         return ret;
 
-    if (vfilters) {
-        AVFilterInOut *outputs = avfilter_inout_alloc();
-        AVFilterInOut *inputs  = avfilter_inout_alloc();
-
-        outputs->name    = av_strdup("in");
-        outputs->filter_ctx = filt_src;
-        outputs->pad_idx = 0;
-        outputs->next    = NULL;
-
-        inputs->name    = av_strdup("out");
-        inputs->filter_ctx = filt_out;
-        inputs->pad_idx = 0;
-        inputs->next    = NULL;
-
-        if ((ret = avfilter_graph_parse(graph, vfilters, &inputs, &outputs, NULL)) < 0)
-            return ret;
-    } else {
-        if ((ret = avfilter_link(filt_src, 0, filt_out, 0)) < 0)
-            return ret;
-    }
+    if ((ret = avfilter_graph_create_filter(&filt_format,
+                                            avfilter_get_by_name("format"),
+                                            "format", "yuv420p", NULL, graph)) < 0)
+        return ret;
+    if ((ret = avfilter_link(filt_format, 0, filt_out, 0)) < 0)
+        return ret;
 
-    if ((ret = avfilter_graph_config(graph, NULL)) < 0)
+    if ((ret = configure_filtergraph(graph, vfilters, filt_src, filt_format)) < 0)
         return ret;
 
+    is->in_video_filter  = filt_src;
     is->out_video_filter = filt_out;
 
     return ret;
@@ -1791,6 +1633,7 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c
 
 static int video_thread(void *arg)
 {
+    AVPacket pkt = { 0 };
     VideoState *is = arg;
     AVFrame *frame = avcodec_alloc_frame();
     int64_t pts_int = AV_NOPTS_VALUE, pos = -1;
@@ -1798,75 +1641,119 @@ static int video_thread(void *arg)
     int ret;
 
 #if CONFIG_AVFILTER
+    AVCodecContext *codec = is->video_st->codec;
     AVFilterGraph *graph = avfilter_graph_alloc();
-    AVFilterContext *filt_out = NULL;
-    int last_w = is->video_st->codec->width;
-    int last_h = is->video_st->codec->height;
+    AVFilterContext *filt_out = NULL, *filt_in = NULL;
+    int last_w = 0;
+    int last_h = 0;
+    enum PixelFormat last_format = -2;
 
-    if ((ret = configure_video_filters(graph, is, vfilters)) < 0)
-        goto the_end;
-    filt_out = is->out_video_filter;
+    if (codec->codec->capabilities & CODEC_CAP_DR1) {
+        is->use_dr1 = 1;
+        codec->get_buffer     = codec_get_buffer;
+        codec->release_buffer = codec_release_buffer;
+        codec->opaque         = &is->buffer_pool;
+    }
 #endif
 
     for (;;) {
-#if !CONFIG_AVFILTER
-        AVPacket pkt;
-#else
+#if CONFIG_AVFILTER
         AVFilterBufferRef *picref;
-        AVRational tb = filt_out->inputs[0]->time_base;
+        AVRational tb;
 #endif
         while (is->paused && !is->videoq.abort_request)
             SDL_Delay(10);
+
+        avcodec_get_frame_defaults(frame);
+        av_free_packet(&pkt);
+
+        ret = get_video_frame(is, frame, &pts_int, &pkt);
+        if (ret < 0)
+            goto the_end;
+
+        if (!ret)
+            continue;
+
 #if CONFIG_AVFILTER
         if (   last_w != is->video_st->codec->width
-            || last_h != is->video_st->codec->height) {
+            || last_h != is->video_st->codec->height
+            || last_format != is->video_st->codec->pix_fmt) {
             av_log(NULL, AV_LOG_INFO, "Frame changed from size:%dx%d to size:%dx%d\n",
                    last_w, last_h, is->video_st->codec->width, is->video_st->codec->height);
             avfilter_graph_free(&graph);
             graph = avfilter_graph_alloc();
-            if ((ret = configure_video_filters(graph, is, vfilters)) < 0)
+            if ((ret = configure_video_filters(graph, is, vfilters)) < 0) {
+                SDL_Event event;
+                event.type = FF_QUIT_EVENT;
+                event.user.data1 = is;
+                SDL_PushEvent(&event);
+                av_free_packet(&pkt);
                 goto the_end;
+            }
+            filt_in  = is->in_video_filter;
             filt_out = is->out_video_filter;
             last_w = is->video_st->codec->width;
             last_h = is->video_st->codec->height;
-        }
-        ret = av_buffersink_get_buffer_ref(filt_out, &picref, 0);
-        if (picref) {
-            avfilter_fill_frame_from_video_buffer_ref(frame, picref);
-            pts_int = picref->pts;
-            pos     = picref->pos;
-            frame->opaque = picref;
+            last_format = is->video_st->codec->pix_fmt;
         }
 
-        if (av_cmp_q(tb, is->video_st->time_base)) {
-            av_unused int64_t pts1 = pts_int;
-            pts_int = av_rescale_q(pts_int, tb, is->video_st->time_base);
-            av_dlog(NULL, "video_thread(): "
-                    "tb:%d/%d pts:%"PRId64" -> tb:%d/%d pts:%"PRId64"\n",
-                    tb.num, tb.den, pts1,
-                    is->video_st->time_base.num, is->video_st->time_base.den, pts_int);
-        }
-#else
-        ret = get_video_frame(is, frame, &pts_int, &pkt);
-        pos = pkt.pos;
+        frame->pts = pts_int;
+        frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, frame);
+        if (is->use_dr1 && frame->opaque) {
+            FrameBuffer      *buf = frame->opaque;
+            AVFilterBufferRef *fb = avfilter_get_video_buffer_ref_from_arrays(
+                                        frame->data, frame->linesize,
+                                        AV_PERM_READ | AV_PERM_PRESERVE,
+                                        frame->width, frame->height,
+                                        frame->format);
+
+            avfilter_copy_frame_props(fb, frame);
+            fb->buf->priv           = buf;
+            fb->buf->free           = filter_release_buffer;
+
+            buf->refcount++;
+            av_buffersrc_add_ref(filt_in, fb, AV_BUFFERSRC_FLAG_NO_COPY);
+
+        } else
+            av_buffersrc_write_frame(filt_in, frame);
+
         av_free_packet(&pkt);
-#endif
 
-        if (ret < 0)
-            goto the_end;
+        while (ret >= 0) {
+            is->frame_last_returned_time = av_gettime() / 1000000.0;
+
+            ret = av_buffersink_get_buffer_ref(filt_out, &picref, 0);
+            if (ret < 0) {
+                ret = 0;
+                break;
+            }
 
-        is->frame_last_filter_delay = av_gettime() / 1000000.0 - is->frame_last_returned_time;
-        if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0)
-            is->frame_last_filter_delay = 0;
+            is->frame_last_filter_delay = av_gettime() / 1000000.0 - is->frame_last_returned_time;
+            if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0)
+                is->frame_last_filter_delay = 0;
 
-#if CONFIG_AVFILTER
-        if (!picref)
-            continue;
-#endif
+            avfilter_copy_buf_props(frame, picref);
 
-        pts = pts_int * av_q2d(is->video_st->time_base);
+            pts_int = picref->pts;
+            tb      = filt_out->inputs[0]->time_base;
+            pos     = picref->pos;
+            frame->opaque = picref;
 
-        ret = queue_picture(is, frame, pts, pos);
+            if (av_cmp_q(tb, is->video_st->time_base)) {
+                av_unused int64_t pts1 = pts_int;
+                pts_int = av_rescale_q(pts_int, tb, is->video_st->time_base);
+                av_dlog(NULL, "video_thread(): "
+                        "tb:%d/%d pts:%"PRId64" -> tb:%d/%d pts:%"PRId64"\n",
+                        tb.num, tb.den, pts1,
+                        is->video_st->time_base.num, is->video_st->time_base.den, pts_int);
+            }
+            pts = pts_int * av_q2d(is->video_st->time_base);
+            ret = queue_picture(is, frame, pts, pos);
+        }
+#else
+        pts = pts_int * av_q2d(is->video_st->time_base);
+        ret = queue_picture(is, frame, pts, pkt.pos);
+#endif
 
         if (ret < 0)
             goto the_end;
@@ -1875,9 +1762,12 @@ static int video_thread(void *arg)
             stream_toggle_pause(is);
     }
  the_end:
+    avcodec_flush_buffers(is->video_st->codec);
 #if CONFIG_AVFILTER
+    av_freep(&vfilters);
     avfilter_graph_free(&graph);
 #endif
+    av_free_packet(&pkt);
     av_free(frame);
     return 0;
 }
@@ -1994,7 +1884,7 @@ static int synchronize_audio(VideoState *is, int nb_samples)
                 avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef);
 
                 if (fabs(avg_diff) >= is->audio_diff_threshold) {
-                    wanted_nb_samples = nb_samples + (int)(diff * is->audio_src_freq);
+                    wanted_nb_samples = nb_samples + (int)(diff * is->audio_src.freq);
                     min_nb_samples = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100));
                     max_nb_samples = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100));
                     wanted_nb_samples = FFMIN(FFMAX(wanted_nb_samples, min_nb_samples), max_nb_samples);
@@ -2037,6 +1927,9 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr)
             } else
                 avcodec_get_frame_defaults(is->frame);
 
+            if (is->paused)
+                return -1;
+
             if (flush_complete)
                 break;
             new_packet = 0;
@@ -2060,66 +1953,64 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr)
                                                    is->frame->nb_samples,
                                                    dec->sample_fmt, 1);
 
-            dec_channel_layout = (dec->channel_layout && dec->channels == av_get_channel_layout_nb_channels(dec->channel_layout)) ? dec->channel_layout : av_get_default_channel_layout(dec->channels);
+            dec_channel_layout =
+                (dec->channel_layout && dec->channels == av_get_channel_layout_nb_channels(dec->channel_layout)) ?
+                dec->channel_layout : av_get_default_channel_layout(dec->channels);
             wanted_nb_samples = synchronize_audio(is, is->frame->nb_samples);
 
-            if (dec->sample_fmt != is->audio_src_fmt ||
-                dec_channel_layout != is->audio_src_channel_layout ||
-                dec->sample_rate != is->audio_src_freq ||
+            if (dec->sample_fmt    != is->audio_src.fmt            ||
+                dec_channel_layout != is->audio_src.channel_layout ||
+                dec->sample_rate   != is->audio_src.freq           ||
                 (wanted_nb_samples != is->frame->nb_samples && !is->swr_ctx)) {
-                if (is->swr_ctx)
-                    swr_free(&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,
+                                                 is->audio_tgt.channel_layout, is->audio_tgt.fmt, is->audio_tgt.freq,
                                                  dec_channel_layout,           dec->sample_fmt,   dec->sample_rate,
                                                  0, NULL);
                 if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) {
                     fprintf(stderr, "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",
-                        dec->sample_rate,
-                        av_get_sample_fmt_name(dec->sample_fmt),
-                        dec->channels,
-                        is->audio_tgt_freq,
-                        av_get_sample_fmt_name(is->audio_tgt_fmt),
-                        is->audio_tgt_channels);
+                        dec->sample_rate,   av_get_sample_fmt_name(dec->sample_fmt),   dec->channels,
+                        is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels);
                     break;
                 }
-                is->audio_src_channel_layout = dec_channel_layout;
-                is->audio_src_channels = dec->channels;
-                is->audio_src_freq = dec->sample_rate;
-                is->audio_src_fmt = dec->sample_fmt;
+                is->audio_src.channel_layout = dec_channel_layout;
+                is->audio_src.channels = dec->channels;
+                is->audio_src.freq = dec->sample_rate;
+                is->audio_src.fmt = dec->sample_fmt;
             }
 
-            resampled_data_size = data_size;
             if (is->swr_ctx) {
-                const uint8_t *in[] = { is->frame->data[0] };
+                const uint8_t **in = (const uint8_t **)is->frame->extended_data;
                 uint8_t *out[] = {is->audio_buf2};
+                int out_count = sizeof(is->audio_buf2) / is->audio_tgt.channels / av_get_bytes_per_sample(is->audio_tgt.fmt);
                 if (wanted_nb_samples != is->frame->nb_samples) {
-                    if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - is->frame->nb_samples) * is->audio_tgt_freq / dec->sample_rate,
-                                                wanted_nb_samples * is->audio_tgt_freq / dec->sample_rate) < 0) {
+                    if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - is->frame->nb_samples) * is->audio_tgt.freq / dec->sample_rate,
+                                                wanted_nb_samples * is->audio_tgt.freq / dec->sample_rate) < 0) {
                         fprintf(stderr, "swr_set_compensation() failed\n");
                         break;
                     }
                 }
-                len2 = swr_convert(is->swr_ctx, out, sizeof(is->audio_buf2) / is->audio_tgt_channels / av_get_bytes_per_sample(is->audio_tgt_fmt),
-                                                in, is->frame->nb_samples);
+                len2 = swr_convert(is->swr_ctx, out, out_count, in, is->frame->nb_samples);
                 if (len2 < 0) {
-                    fprintf(stderr, "audio_resample() failed\n");
+                    fprintf(stderr, "swr_convert() failed\n");
                     break;
                 }
-                if (len2 == sizeof(is->audio_buf2) / is->audio_tgt_channels / av_get_bytes_per_sample(is->audio_tgt_fmt)) {
+                if (len2 == out_count) {
                     fprintf(stderr, "warning: audio buffer is probably too small\n");
                     swr_init(is->swr_ctx);
                 }
                 is->audio_buf = is->audio_buf2;
-                resampled_data_size = len2 * is->audio_tgt_channels * av_get_bytes_per_sample(is->audio_tgt_fmt);
+                resampled_data_size = len2 * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt);
             } else {
                 is->audio_buf = is->frame->data[0];
+                resampled_data_size = data_size;
             }
 
             /* if no pts, then compute it */
             pts = is->audio_clock;
             *pts_ptr = pts;
-            is->audio_clock += (double)data_size / (dec->channels * dec->sample_rate * av_get_bytes_per_sample(dec->sample_fmt));
+            is->audio_clock += (double)data_size /
+                (dec->channels * dec->sample_rate * av_get_bytes_per_sample(dec->sample_fmt));
 #ifdef DEBUG
             {
                 static double last_clock;
@@ -2145,8 +2036,10 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr)
         if ((new_packet = packet_queue_get(&is->audioq, pkt, 1)) < 0)
             return -1;
 
-        if (pkt->data == flush_pkt.data)
+        if (pkt->data == flush_pkt.data) {
             avcodec_flush_buffers(dec);
+            flush_complete = 0;
+        }
 
         *pkt_temp = *pkt;
 
@@ -2163,7 +2056,7 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
     VideoState *is = opaque;
     int audio_size, len1;
     int bytes_per_sec;
-    int frame_size = av_samples_get_buffer_size(NULL, is->audio_tgt_channels, 1, is->audio_tgt_fmt, 1);
+    int frame_size = av_samples_get_buffer_size(NULL, is->audio_tgt.channels, 1, is->audio_tgt.fmt, 1);
     double pts;
 
     audio_callback_time = av_gettime();
@@ -2190,37 +2083,87 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
         stream += len1;
         is->audio_buf_index += len1;
     }
-    bytes_per_sec = is->audio_tgt_freq * is->audio_tgt_channels * av_get_bytes_per_sample(is->audio_tgt_fmt);
+    bytes_per_sec = is->audio_tgt.freq * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt);
     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. */
     is->audio_current_pts = is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / bytes_per_sec;
     is->audio_current_pts_drift = is->audio_current_pts - audio_callback_time / 1000000.0;
 }
 
+static int audio_open(void *opaque, int64_t wanted_channel_layout, int wanted_nb_channels, int wanted_sample_rate, struct AudioParams *audio_hw_params)
+{
+    SDL_AudioSpec wanted_spec, spec;
+    const char *env;
+    const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6};
+
+    env = SDL_getenv("SDL_AUDIO_CHANNELS");
+    if (env) {
+        wanted_nb_channels = SDL_atoi(env);
+        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);
+        wanted_channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX;
+    }
+    wanted_spec.channels = av_get_channel_layout_nb_channels(wanted_channel_layout);
+    wanted_spec.freq = wanted_sample_rate;
+    if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
+        fprintf(stderr, "Invalid sample rate or channel count!\n");
+        return -1;
+    }
+    wanted_spec.format = AUDIO_S16SYS;
+    wanted_spec.silence = 0;
+    wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
+    wanted_spec.callback = sdl_audio_callback;
+    wanted_spec.userdata = opaque;
+    while (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
+        fprintf(stderr, "SDL_OpenAudio (%d channels): %s\n", wanted_spec.channels, SDL_GetError());
+        wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)];
+        if (!wanted_spec.channels) {
+            fprintf(stderr, "No more channel combinations to try, audio open failed\n");
+            return -1;
+        }
+        wanted_channel_layout = av_get_default_channel_layout(wanted_spec.channels);
+    }
+    if (spec.format != AUDIO_S16SYS) {
+        fprintf(stderr, "SDL advised audio format %d is not supported!\n", spec.format);
+        return -1;
+    }
+    if (spec.channels != wanted_spec.channels) {
+        wanted_channel_layout = av_get_default_channel_layout(spec.channels);
+        if (!wanted_channel_layout) {
+            fprintf(stderr, "SDL advised channel count %d is not supported!\n", spec.channels);
+            return -1;
+        }
+    }
+
+    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;
+    return spec.size;
+}
+
 /* open a given stream. Return 0 if OK */
 static int stream_component_open(VideoState *is, int stream_index)
 {
     AVFormatContext *ic = is->ic;
     AVCodecContext *avctx;
     AVCodec *codec;
-    SDL_AudioSpec wanted_spec, spec;
     AVDictionary *opts;
     AVDictionaryEntry *t = NULL;
-    int64_t wanted_channel_layout = 0;
-    int wanted_nb_channels;
-    const char *env;
 
     if (stream_index < 0 || stream_index >= ic->nb_streams)
         return -1;
     avctx = ic->streams[stream_index]->codec;
 
     codec = avcodec_find_decoder(avctx->codec_id);
-    opts = filter_codec_opts(codec_opts, codec, ic, ic->streams[stream_index]);
+    opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], codec);
 
     switch(avctx->codec_type){
-        case AVMEDIA_TYPE_AUDIO   : if(audio_codec_name   ) codec= avcodec_find_decoder_by_name(   audio_codec_name); break;
-        case AVMEDIA_TYPE_SUBTITLE: if(subtitle_codec_name) codec= avcodec_find_decoder_by_name(subtitle_codec_name); break;
-        case AVMEDIA_TYPE_VIDEO   : if(video_codec_name   ) codec= avcodec_find_decoder_by_name(   video_codec_name); break;
+        case AVMEDIA_TYPE_AUDIO   : is->last_audio_stream    = stream_index; if(audio_codec_name   ) codec= avcodec_find_decoder_by_name(   audio_codec_name); break;
+        case AVMEDIA_TYPE_SUBTITLE: is->last_subtitle_stream = stream_index; if(subtitle_codec_name) codec= avcodec_find_decoder_by_name(subtitle_codec_name); break;
+        case AVMEDIA_TYPE_VIDEO   : is->last_video_stream    = stream_index; if(video_codec_name   ) codec= avcodec_find_decoder_by_name(   video_codec_name); break;
     }
     if (!codec)
         return -1;
@@ -2236,7 +2179,6 @@ static int stream_component_open(VideoState *is, int stream_index)
     avctx->skip_frame        = skip_frame;
     avctx->skip_idct         = skip_idct;
     avctx->skip_loop_filter  = skip_loop_filter;
-    avctx->error_recognition = error_recognition;
     avctx->error_concealment = error_concealment;
 
     if(avctx->lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE;
@@ -2244,28 +2186,8 @@ static int stream_component_open(VideoState *is, int stream_index)
     if(codec->capabilities & CODEC_CAP_DR1)
         avctx->flags |= CODEC_FLAG_EMU_EDGE;
 
-    if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
-        env = SDL_getenv("SDL_AUDIO_CHANNELS");
-        if (env)
-            wanted_channel_layout = av_get_default_channel_layout(SDL_atoi(env));
-        if (!wanted_channel_layout) {
-            wanted_channel_layout = (avctx->channel_layout && avctx->channels == av_get_channel_layout_nb_channels(avctx->channel_layout)) ? avctx->channel_layout : av_get_default_channel_layout(avctx->channels);
-            wanted_channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX;
-            wanted_nb_channels = av_get_channel_layout_nb_channels(wanted_channel_layout);
-            /* SDL only supports 1, 2, 4 or 6 channels at the moment, so we have to make sure not to request anything else. */
-            while (wanted_nb_channels > 0 && (wanted_nb_channels == 3 || wanted_nb_channels == 5 || wanted_nb_channels > 6)) {
-                wanted_nb_channels--;
-                wanted_channel_layout = av_get_default_channel_layout(wanted_nb_channels);
-            }
-        }
-        wanted_spec.channels = av_get_channel_layout_nb_channels(wanted_channel_layout);
-        wanted_spec.freq = avctx->sample_rate;
-        if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
-            fprintf(stderr, "Invalid sample rate or channel count!\n");
-            return -1;
-        }
-    }
-
+    if (!av_dict_get(opts, "threads", NULL, 0))
+        av_dict_set(&opts, "threads", "auto", 0);
     if (!codec ||
         avcodec_open2(avctx, codec, &opts) < 0)
         return -1;
@@ -2276,31 +2198,11 @@ static int stream_component_open(VideoState *is, int stream_index)
 
     /* prepare audio output */
     if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
-        wanted_spec.format = AUDIO_S16SYS;
-        wanted_spec.silence = 0;
-        wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
-        wanted_spec.callback = sdl_audio_callback;
-        wanted_spec.userdata = is;
-        if (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
-            fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
-            return -1;
-        }
-        is->audio_hw_buf_size = spec.size;
-        if (spec.format != AUDIO_S16SYS) {
-            fprintf(stderr, "SDL advised audio format %d is not supported!\n", spec.format);
+        int audio_hw_buf_size = audio_open(is, avctx->channel_layout, avctx->channels, avctx->sample_rate, &is->audio_src);
+        if (audio_hw_buf_size < 0)
             return -1;
-        }
-        if (spec.channels != wanted_spec.channels) {
-            wanted_channel_layout = av_get_default_channel_layout(spec.channels);
-            if (!wanted_channel_layout) {
-                fprintf(stderr, "SDL advised channel count %d is not supported!\n", spec.channels);
-                return -1;
-            }
-        }
-        is->audio_src_fmt = is->audio_tgt_fmt = AV_SAMPLE_FMT_S16;
-        is->audio_src_freq = is->audio_tgt_freq = spec.freq;
-        is->audio_src_channel_layout = is->audio_tgt_channel_layout = wanted_channel_layout;
-        is->audio_src_channels = is->audio_tgt_channels = spec.channels;
+        is->audio_hw_buf_size = audio_hw_buf_size;
+        is->audio_tgt = is->audio_src;
     }
 
     ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
@@ -2316,23 +2218,24 @@ static int stream_component_open(VideoState *is, int stream_index)
         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 */
-        is->audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / wanted_spec.freq;
+        is->audio_diff_threshold = 2.0 * is->audio_hw_buf_size / av_samples_get_buffer_size(NULL, is->audio_tgt.channels, is->audio_tgt.freq, is->audio_tgt.fmt, 1);
 
         memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
-        packet_queue_init(&is->audioq);
+        memset(&is->audio_pkt_temp, 0, sizeof(is->audio_pkt_temp));
+        packet_queue_start(&is->audioq);
         SDL_PauseAudio(0);
         break;
     case AVMEDIA_TYPE_VIDEO:
         is->video_stream = stream_index;
         is->video_st = ic->streams[stream_index];
 
-        packet_queue_init(&is->videoq);
+        packet_queue_start(&is->videoq);
         is->video_tid = SDL_CreateThread(video_thread, is);
         break;
     case AVMEDIA_TYPE_SUBTITLE:
         is->subtitle_stream = stream_index;
         is->subtitle_st = ic->streams[stream_index];
-        packet_queue_init(&is->subtitleq);
+        packet_queue_start(&is->subtitleq);
 
         is->subtitle_tid = SDL_CreateThread(subtitle_thread, is);
         break;
@@ -2357,10 +2260,9 @@ static void stream_component_close(VideoState *is, int stream_index)
 
         SDL_CloseAudio();
 
-        packet_queue_end(&is->audioq);
-        if (is->swr_ctx)
-            swr_free(&is->swr_ctx);
+        packet_queue_flush(&is->audioq);
         av_free_packet(&is->audio_pkt);
+        swr_free(&is->swr_ctx);
         av_freep(&is->audio_buf1);
         is->audio_buf = NULL;
         av_freep(&is->frame);
@@ -2383,7 +2285,7 @@ static void stream_component_close(VideoState *is, int stream_index)
 
         SDL_WaitThread(is->video_tid, NULL);
 
-        packet_queue_end(&is->videoq);
+        packet_queue_flush(&is->videoq);
         break;
     case AVMEDIA_TYPE_SUBTITLE:
         packet_queue_abort(&is->subtitleq);
@@ -2398,7 +2300,7 @@ static void stream_component_close(VideoState *is, int stream_index)
 
         SDL_WaitThread(is->subtitle_tid, NULL);
 
-        packet_queue_end(&is->subtitleq);
+        packet_queue_flush(&is->subtitleq);
         break;
     default:
         break;
@@ -2406,6 +2308,9 @@ static void stream_component_close(VideoState *is, int stream_index)
 
     ic->streams[stream_index]->discard = AVDISCARD_ALL;
     avcodec_close(avctx);
+#if CONFIG_AVFILTER
+    free_buffer_pool(&is->buffer_pool);
+#endif
     switch (avctx->codec_type) {
     case AVMEDIA_TYPE_AUDIO:
         is->audio_st = NULL;
@@ -2445,9 +2350,9 @@ static int read_thread(void *arg)
     int orig_nb_streams;
 
     memset(st_index, -1, sizeof(st_index));
-    is->video_stream = -1;
-    is->audio_stream = -1;
-    is->subtitle_stream = -1;
+    is->last_video_stream = is->video_stream = -1;
+    is->last_audio_stream = is->audio_stream = -1;
+    is->last_subtitle_stream = is->subtitle_stream = -1;
 
     ic = avformat_alloc_context();
     ic->interrupt_callback.callback = decode_interrupt_cb;
@@ -2600,10 +2505,11 @@ static int read_thread(void *arg)
         }
 
         /* if the queue are full, no need to read more */
-        if (   is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
-            || (   (is->audioq   .size  > MIN_AUDIOQ_SIZE || is->audio_stream < 0)
-                && (is->videoq   .nb_packets > MIN_FRAMES || is->video_stream < 0)
-                && (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0))) {
+        if (!infinite_buffer &&
+              (is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
+            || (   (is->audioq   .nb_packets > MIN_FRAMES || is->audio_stream < 0 || is->audioq.abort_request)
+                && (is->videoq   .nb_packets > MIN_FRAMES || is->video_stream < 0 || is->videoq.abort_request)
+                && (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0 || is->subtitleq.abort_request)))) {
             /* wait 10 ms */
             SDL_Delay(10);
             continue;
@@ -2708,6 +2614,10 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
     is->subpq_mutex = SDL_CreateMutex();
     is->subpq_cond  = SDL_CreateCond();
 
+    packet_queue_init(&is->videoq);
+    packet_queue_init(&is->audioq);
+    packet_queue_init(&is->subtitleq);
+
     is->av_sync_type = av_sync_type;
     is->read_tid     = SDL_CreateThread(read_thread, is);
     if (!is->read_tid) {
@@ -2721,16 +2631,19 @@ static void stream_cycle_channel(VideoState *is, int codec_type)
 {
     AVFormatContext *ic = is->ic;
     int start_index, stream_index;
+    int old_index;
     AVStream *st;
 
-    if (codec_type == AVMEDIA_TYPE_VIDEO)
-        start_index = is->video_stream;
-    else if (codec_type == AVMEDIA_TYPE_AUDIO)
-        start_index = is->audio_stream;
-    else
-        start_index = is->subtitle_stream;
-    if (start_index < (codec_type == AVMEDIA_TYPE_SUBTITLE ? -1 : 0))
-        return;
+    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;
+    }
     stream_index = start_index;
     for (;;) {
         if (++stream_index >= is->ic->nb_streams)
@@ -2738,9 +2651,12 @@ static void stream_cycle_channel(VideoState *is, int codec_type)
             if (codec_type == AVMEDIA_TYPE_SUBTITLE)
             {
                 stream_index = -1;
+                is->last_subtitle_stream = -1;
                 goto the_end;
-            } else
-                stream_index = 0;
+            }
+            if (start_index == -1)
+                return;
+            stream_index = 0;
         }
         if (stream_index == start_index)
             return;
@@ -2762,21 +2678,20 @@ static void stream_cycle_channel(VideoState *is, int codec_type)
         }
     }
  the_end:
-    stream_component_close(is, start_index);
+    stream_component_close(is, old_index);
     stream_component_open(is, stream_index);
 }
 
 
 static void toggle_full_screen(VideoState *is)
 {
-    int i;
-    is_full_screen = !is_full_screen;
 #if defined(__APPLE__) && SDL_VERSION_ATLEAST(1, 2, 14)
     /* OS X needs to reallocate the SDL overlays */
-    for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
+    int i;
+    for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++)
         is->pictq[i].reallocate = 1;
-    }
 #endif
+    is_full_screen = !is_full_screen;
     video_open(is, 1);
 }
 
@@ -2826,6 +2741,7 @@ static void event_loop(VideoState *cur_stream)
                 break;
             case SDLK_f:
                 toggle_full_screen(cur_stream);
+                cur_stream->force_refresh = 1;
                 break;
             case SDLK_p:
             case SDLK_SPACE:
@@ -2845,6 +2761,7 @@ static void event_loop(VideoState *cur_stream)
                 break;
             case SDLK_w:
                 toggle_audio_display(cur_stream);
+                cur_stream->force_refresh = 1;
                 break;
             case SDLK_PAGEUP:
                 incr = 600.0;
@@ -2887,6 +2804,9 @@ static void event_loop(VideoState *cur_stream)
                 break;
             }
             break;
+        case SDL_VIDEOEXPOSE:
+            cur_stream->force_refresh = 1;
+            break;
         case SDL_MOUSEBUTTONDOWN:
             if (exit_on_mousedown) {
                 do_exit(cur_stream);
@@ -2929,13 +2849,13 @@ static void event_loop(VideoState *cur_stream)
                                           SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
                 screen_width  = cur_stream->width  = event.resize.w;
                 screen_height = cur_stream->height = event.resize.h;
+                cur_stream->force_refresh = 1;
             break;
         case SDL_QUIT:
         case FF_QUIT_EVENT:
             do_exit(cur_stream);
             break;
         case FF_ALLOC_EVENT:
-            video_open(event.user.data1, 0);
             alloc_picture(event.user.data1);
             break;
         case FF_REFRESH_EVENT:
@@ -3069,7 +2989,6 @@ static const OptionDef options[] = {
     { "skipframe", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&skip_frame }, "", "" },
     { "skipidct", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&skip_idct }, "", "" },
     { "idct", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&idct }, "set idct algo",  "algo" },
-    { "er", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&error_recognition }, "set error detection threshold (0-4)",  "threshold" },
     { "ec", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&error_concealment }, "set error concealment options",  "bit_mask" },
     { "sync", HAS_ARG | OPT_EXPERT, { (void*)opt_sync }, "set audio-video sync. type (type=audio/video/ext)", "type" },
     { "autoexit", OPT_BOOL | OPT_EXPERT, { (void*)&autoexit }, "exit at the end", "" },
@@ -3077,6 +2996,7 @@ static const OptionDef options[] = {
     { "exitonmousedown", OPT_BOOL | OPT_EXPERT, { (void*)&exit_on_mousedown }, "exit on mouse down", "" },
     { "loop", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&loop }, "set number of times the playback shall be looped", "loop count" },
     { "framedrop", OPT_BOOL | OPT_EXPERT, { (void*)&framedrop }, "drop frames when cpu is too slow", "" },
+    { "infbuf", OPT_BOOL | OPT_EXPERT, { (void*)&infinite_buffer }, "don't limit the input buffer size (useful with realtime streams)", "" },
     { "window_title", OPT_STRING | HAS_ARG, { (void*)&window_title }, "set window title", "window title" },
 #if CONFIG_AVFILTER
     { "vf", OPT_STRING | HAS_ARG, { (void*)&vfilters }, "video filters", "filter list" },
@@ -3151,6 +3071,7 @@ int main(int argc, char **argv)
 {
     int flags;
     VideoState *is;
+    char dummy_videodriver[] = "SDL_VIDEODRIVER=dummy";
 
     av_log_set_flags(AV_LOG_SKIP_REPEATED);
     parse_loglevel(argc, argv, options);
@@ -3188,6 +3109,8 @@ int main(int argc, char **argv)
     flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
     if (audio_disable)
         flags &= ~SDL_INIT_AUDIO;
+    if (display_disable)
+        SDL_putenv(dummy_videodriver); /* For the event queue, we always need a video driver. */
 #if !defined(__MINGW32__) && !defined(__APPLE__)
     flags |= SDL_INIT_EVENTTHREAD; /* Not supported on Windows or Mac OS X */
 #endif
@@ -3215,7 +3138,7 @@ int main(int argc, char **argv)
     }
 
     av_init_packet(&flush_pkt);
-    flush_pkt.data = "FLUSH";
+    flush_pkt.data = (char *)(intptr_t)"FLUSH";
 
     is = stream_open(input_filename, file_iformat);
     if (!is) {