Merge commit '7c5012127fb7e18f0616011257bb4248f6a8b608'
authorMichael Niedermayer <michaelni@gmx.at>
Mon, 20 Aug 2012 14:52:42 +0000 (16:52 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Mon, 20 Aug 2012 14:55:08 +0000 (16:55 +0200)
* commit '7c5012127fb7e18f0616011257bb4248f6a8b608':
  cmdutils: change semantics of show_help_options() and document it.
  avtools: move some newlines to show_help_options().
  avconv: deprecate -isync.

Conflicts:
ffmpeg_opt.c
ffserver.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
cmdutils.c
cmdutils.h
doc/ffmpeg.texi
ffmpeg_opt.c
ffplay.c
ffprobe.c
ffserver.c

diff --combined cmdutils.c
@@@ -2,20 -2,20 +2,20 @@@
   * Various utilities for command line tools
   * Copyright (c) 2000-2003 Fabrice Bellard
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * FFmpeg is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * FFmpeg is distributed in the hope that it will be useful,
   * 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
 - * License along with Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
  #include "libavdevice/avdevice.h"
  #include "libavresample/avresample.h"
  #include "libswscale/swscale.h"
 +#include "libswresample/swresample.h"
 +#if CONFIG_POSTPROC
 +#include "libpostproc/postprocess.h"
 +#endif
  #include "libavutil/avassert.h"
  #include "libavutil/avstring.h"
  #include "libavutil/mathematics.h"
  #endif
  
  struct SwsContext *sws_opts;
 +SwrContext *swr_opts;
  AVDictionary *format_opts, *codec_opts;
  
 -static const int this_year = 2012;
 +const int this_year = 2012;
 +
 +static FILE *report_file;
  
  void init_opts(void)
  {
 -#if CONFIG_SWSCALE
 -    sws_opts = sws_getContext(16, 16, 0, 16, 16, 0, SWS_BICUBIC,
 +
 +    if(CONFIG_SWSCALE)
 +        sws_opts = sws_getContext(16, 16, 0, 16, 16, 0, SWS_BICUBIC,
                                NULL, NULL, NULL);
 -#endif
 +
 +    if(CONFIG_SWRESAMPLE)
 +        swr_opts = swr_alloc();
  }
  
  void uninit_opts(void)
      sws_freeContext(sws_opts);
      sws_opts = NULL;
  #endif
 +
 +    if(CONFIG_SWRESAMPLE)
 +        swr_free(&swr_opts);
 +
      av_dict_free(&format_opts);
      av_dict_free(&codec_opts);
  }
@@@ -94,20 -80,6 +94,20 @@@ void log_callback_help(void *ptr, int l
      vfprintf(stdout, fmt, vl);
  }
  
 +static void log_callback_report(void *ptr, int level, const char *fmt, va_list vl)
 +{
 +    va_list vl2;
 +    char line[1024];
 +    static int print_prefix = 1;
 +
 +    va_copy(vl2, vl);
 +    av_log_default_callback(ptr, level, fmt, vl);
 +    av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);
 +    va_end(vl2);
 +    fputs(line, report_file);
 +    fflush(report_file);
 +}
 +
  double parse_number_or_die(const char *context, const char *numstr, int type,
                             double min, double max)
  {
@@@ -141,8 -113,8 +141,8 @@@ int64_t parse_time_or_die(const char *c
      return us;
  }
  
- void show_help_options(const OptionDef *options, const char *msg, int mask,
-                        int value)
+ void show_help_options(const OptionDef *options, const char *msg, int req_flags,
+                        int rej_flags)
  {
      const OptionDef *po;
      int first;
      first = 1;
      for (po = options; po->name != NULL; po++) {
          char buf[64];
-         if ((po->flags & mask) == value) {
-             if (first) {
-                 printf("%s", msg);
-                 first = 0;
-             }
-             av_strlcpy(buf, po->name, sizeof(buf));
-             if (po->flags & HAS_ARG) {
-                 av_strlcat(buf, " ", sizeof(buf));
-                 av_strlcat(buf, po->argname, sizeof(buf));
-             }
-             printf("-%-17s  %s\n", buf, po->help);
+         if (((po->flags & req_flags) != req_flags) ||
+             (po->flags & rej_flags))
+             continue;
+         if (first) {
+             printf("%s\n", msg);
+             first = 0;
+         }
+         av_strlcpy(buf, po->name, sizeof(buf));
+         if (po->flags & HAS_ARG) {
+             av_strlcat(buf, " ", sizeof(buf));
+             av_strlcat(buf, po->argname, sizeof(buf));
          }
+         printf("-%-17s  %s\n", buf, po->help);
      }
+     printf("\n");
  }
  
  void show_help_children(const AVClass *class, int flags)
  {
      const AVClass *child = NULL;
 -    av_opt_show2(&class, NULL, flags, 0);
 -    printf("\n");
 +    if (class->option) {
 +        av_opt_show2(&class, NULL, flags, 0);
 +        printf("\n");
 +    }
  
      while (child = av_opt_child_class_next(class, child))
          show_help_children(child, flags);
@@@ -380,30 -354,6 +384,30 @@@ int locate_option(int argc, char **argv
      return 0;
  }
  
 +static void dump_argument(const char *a)
 +{
 +    const unsigned char *p;
 +
 +    for (p = a; *p; p++)
 +        if (!((*p >= '+' && *p <= ':') || (*p >= '@' && *p <= 'Z') ||
 +              *p == '_' || (*p >= 'a' && *p <= 'z')))
 +            break;
 +    if (!*p) {
 +        fputs(a, report_file);
 +        return;
 +    }
 +    fputc('"', report_file);
 +    for (p = a; *p; p++) {
 +        if (*p == '\\' || *p == '"' || *p == '$' || *p == '`')
 +            fprintf(report_file, "\\%c", *p);
 +        else if (*p < ' ' || *p > '~')
 +            fprintf(report_file, "\\x%02x", *p);
 +        else
 +            fputc(*p, report_file);
 +    }
 +    fputc('"', report_file);
 +}
 +
  void parse_loglevel(int argc, char **argv, const OptionDef *options)
  {
      int idx = locate_option(argc, argv, options, "loglevel");
          idx = locate_option(argc, argv, options, "v");
      if (idx && argv[idx + 1])
          opt_loglevel("loglevel", argv[idx + 1]);
 +    idx = locate_option(argc, argv, options, "report");
 +    if (idx || getenv("FFREPORT")) {
 +        opt_report("report");
 +        if (report_file) {
 +            int i;
 +            fprintf(report_file, "Command line:\n");
 +            for (i = 0; i < argc; i++) {
 +                dump_argument(argv[i]);
 +                fputc(i < argc - 1 ? ' ' : '\n', report_file);
 +            }
 +            fflush(report_file);
 +        }
 +    }
  }
  
  #define FLAGS (o->type == AV_OPT_TYPE_FLAGS) ? AV_DICT_APPEND : 0
@@@ -432,7 -369,7 +436,7 @@@ int opt_default(const char *opt, const 
      const AVOption *o;
      char opt_stripped[128];
      const char *p;
 -    const AVClass *cc = avcodec_get_class(), *fc = avformat_get_class(), *sc = sws_get_class();
 +    const AVClass *cc = avcodec_get_class(), *fc = avformat_get_class(), *sc, *swr_class;
  
      if (!(p = strchr(opt, ':')))
          p = opt + strlen(opt);
      else if ((o = av_opt_find(&fc, opt, NULL, 0,
                                AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)))
          av_dict_set(&format_opts, opt, arg, FLAGS);
 -    else if ((o = av_opt_find(&sc, opt, NULL, 0,
 -                              AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {
 +#if CONFIG_SWSCALE
 +    sc = sws_get_class();
 +    if (!o && (o = av_opt_find(&sc, opt, NULL, 0,
 +                         AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {
          // XXX we only support sws_flags, not arbitrary sws options
          int ret = av_opt_set(sws_opts, opt, arg, 0);
          if (ret < 0) {
              return ret;
          }
      }
 +#endif
 +#if CONFIG_SWRESAMPLE
 +    swr_class = swr_get_class();
 +    if (!o && (o = av_opt_find(&swr_class, opt, NULL, 0,
 +                               AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {
 +        int ret = av_opt_set(swr_opts, opt, arg, 0);
 +        if (ret < 0) {
 +            av_log(NULL, AV_LOG_ERROR, "Error setting option %s.\n", opt);
 +            return ret;
 +        }
 +    }
 +#endif
  
      if (o)
          return 0;
@@@ -511,70 -434,6 +515,70 @@@ int opt_loglevel(const char *opt, cons
      return 0;
  }
  
 +int opt_report(const char *opt)
 +{
 +    char filename[64];
 +    time_t now;
 +    struct tm *tm;
 +
 +    if (report_file) /* already opened */
 +        return 0;
 +    time(&now);
 +    tm = localtime(&now);
 +    snprintf(filename, sizeof(filename), "%s-%04d%02d%02d-%02d%02d%02d.log",
 +             program_name,
 +             tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
 +             tm->tm_hour, tm->tm_min, tm->tm_sec);
 +    report_file = fopen(filename, "w");
 +    if (!report_file) {
 +        av_log(NULL, AV_LOG_ERROR, "Failed to open report \"%s\": %s\n",
 +               filename, strerror(errno));
 +        return AVERROR(errno);
 +    }
 +    av_log_set_callback(log_callback_report);
 +    av_log(NULL, AV_LOG_INFO,
 +           "%s started on %04d-%02d-%02d at %02d:%02d:%02d\n"
 +           "Report written to \"%s\"\n",
 +           program_name,
 +           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
 +           tm->tm_hour, tm->tm_min, tm->tm_sec,
 +           filename);
 +    av_log_set_level(FFMAX(av_log_get_level(), AV_LOG_VERBOSE));
 +    return 0;
 +}
 +
 +int opt_max_alloc(const char *opt, const char *arg)
 +{
 +    char *tail;
 +    size_t max;
 +
 +    max = strtol(arg, &tail, 10);
 +    if (*tail) {
 +        av_log(NULL, AV_LOG_FATAL, "Invalid max_alloc \"%s\".\n", arg);
 +        exit_program(1);
 +    }
 +    av_max_alloc(max);
 +    return 0;
 +}
 +
 +int opt_cpuflags(const char *opt, const char *arg)
 +{
 +    int ret;
 +    unsigned flags = av_get_cpu_flags();
 +
 +    if ((ret = av_parse_cpu_caps(&flags, arg)) < 0)
 +        return ret;
 +
 +    av_force_cpu_flags(flags);
 +    return 0;
 +}
 +
 +int opt_codec_debug(const char *opt, const char *arg)
 +{
 +    av_log_set_level(AV_LOG_DEBUG);
 +    return opt_default(opt, arg);
 +}
 +
  int opt_timelimit(const char *opt, const char *arg)
  {
  #if HAVE_SETRLIMIT
@@@ -603,7 -462,6 +607,7 @@@ static int warned_cfg = 0
  #define INDENT        1
  #define SHOW_VERSION  2
  #define SHOW_CONFIG   4
 +#define SHOW_COPYRIGHT 8
  
  #define PRINT_LIB_INFO(libname, LIBNAME, flags, level)                  \
      if (CONFIG_##LIBNAME) {                                             \
          if (flags & SHOW_VERSION) {                                     \
              unsigned int version = libname##_version();                 \
              av_log(NULL, level,                                         \
 -                   "%slib%-10s %2d.%3d.%2d / %2d.%3d.%2d\n",            \
 +                   "%slib%-11s %2d.%3d.%3d / %2d.%3d.%3d\n",            \
                     indent, #libname,                                    \
                     LIB##LIBNAME##_VERSION_MAJOR,                        \
                     LIB##LIBNAME##_VERSION_MINOR,                        \
          }                                                               \
          if (flags & SHOW_CONFIG) {                                      \
              const char *cfg = libname##_configuration();                \
 -            if (strcmp(LIBAV_CONFIGURATION, cfg)) {                     \
 +            if (strcmp(FFMPEG_CONFIGURATION, cfg)) {                    \
                  if (!warned_cfg) {                                      \
                      av_log(NULL, level,                                 \
                              "%sWARNING: library configuration mismatch\n", \
@@@ -640,44 -498,26 +644,44 @@@ static void print_all_libs_info(int fla
      PRINT_LIB_INFO(avformat, AVFORMAT, flags, level);
      PRINT_LIB_INFO(avdevice, AVDEVICE, flags, level);
      PRINT_LIB_INFO(avfilter, AVFILTER, flags, level);
 -    PRINT_LIB_INFO(avresample, AVRESAMPLE, flags, level);
 +//    PRINT_LIB_INFO(avresample, AVRESAMPLE, flags, level);
      PRINT_LIB_INFO(swscale,  SWSCALE,  flags, level);
 +    PRINT_LIB_INFO(swresample,SWRESAMPLE,  flags, level);
 +#if CONFIG_POSTPROC
 +    PRINT_LIB_INFO(postproc, POSTPROC, flags, level);
 +#endif
  }
  
 -void show_banner(void)
 +static void print_program_info(int flags, int level)
  {
 -    av_log(NULL, AV_LOG_INFO,
 -           "%s version " LIBAV_VERSION ", Copyright (c) %d-%d the Libav developers\n",
 -           program_name, program_birth_year, this_year);
 -    av_log(NULL, AV_LOG_INFO, "  built on %s %s with %s\n",
 -           __DATE__, __TIME__, CC_IDENT);
 -    av_log(NULL, AV_LOG_VERBOSE, "  configuration: " LIBAV_CONFIGURATION "\n");
 -    print_all_libs_info(INDENT|SHOW_CONFIG,  AV_LOG_VERBOSE);
 -    print_all_libs_info(INDENT|SHOW_VERSION, AV_LOG_VERBOSE);
 +    const char *indent = flags & INDENT? "  " : "";
 +
 +    av_log(NULL, level, "%s version " FFMPEG_VERSION, program_name);
 +    if (flags & SHOW_COPYRIGHT)
 +        av_log(NULL, level, " Copyright (c) %d-%d the FFmpeg developers",
 +               program_birth_year, this_year);
 +    av_log(NULL, level, "\n");
 +    av_log(NULL, level, "%sbuilt on %s %s with %s\n",
 +           indent, __DATE__, __TIME__, CC_IDENT);
 +
 +    av_log(NULL, level, "%sconfiguration: " FFMPEG_CONFIGURATION "\n", indent);
 +}
 +
 +void show_banner(int argc, char **argv, const OptionDef *options)
 +{
 +    int idx = locate_option(argc, argv, options, "version");
 +    if (idx)
 +        return;
 +
 +    print_program_info (INDENT|SHOW_COPYRIGHT, AV_LOG_INFO);
 +    print_all_libs_info(INDENT|SHOW_CONFIG,  AV_LOG_INFO);
 +    print_all_libs_info(INDENT|SHOW_VERSION, AV_LOG_INFO);
  }
  
  int show_version(const char *opt, const char *arg)
  {
      av_log_set_callback(log_callback_help);
 -    printf("%s " LIBAV_VERSION "\n", program_name);
 +    print_program_info (0           , AV_LOG_INFO);
      print_all_libs_info(SHOW_VERSION, AV_LOG_INFO);
  
      return 0;
@@@ -807,9 -647,7 +811,9 @@@ static char get_media_type_char(enum AV
      switch (type) {
          case AVMEDIA_TYPE_VIDEO:    return 'V';
          case AVMEDIA_TYPE_AUDIO:    return 'A';
 +        case AVMEDIA_TYPE_DATA:     return 'D';
          case AVMEDIA_TYPE_SUBTITLE: return 'S';
 +        case AVMEDIA_TYPE_ATTACHMENT:return 'T';
          default:                    return '?';
      }
  }
@@@ -886,15 -724,13 +890,15 @@@ static void print_codecs(int encoder
      const AVCodecDescriptor *desc = NULL;
  
      printf("%s:\n"
 -           " V... = Video\n"
 -           " A... = Audio\n"
 -           " S... = Subtitle\n"
 -           " .F.. = Frame-level multithreading\n"
 -           " ..S. = Slice-level multithreading\n"
 -           " ...X = Codec is experimental\n"
 -           " ---\n",
 +           " V..... = Video\n"
 +           " A..... = Audio\n"
 +           " S..... = Subtitle\n"
 +           " .F.... = Frame-level multithreading\n"
 +           " ..S... = Slice-level multithreading\n"
 +           " ...X.. = Codec is experimental\n"
 +           " ....B. = Supports draw_horiz_band\n"
 +           " .....D = Supports direct rendering method 1\n"
 +           " ------\n",
             encoder ? "Encoders" : "Decoders");
      while ((desc = avcodec_descriptor_next(desc))) {
          const AVCodec *codec = NULL;
              printf((codec->capabilities & CODEC_CAP_FRAME_THREADS) ? "F" : ".");
              printf((codec->capabilities & CODEC_CAP_SLICE_THREADS) ? "S" : ".");
              printf((codec->capabilities & CODEC_CAP_EXPERIMENTAL)  ? "X" : ".");
 +            printf((codec->capabilities & CODEC_CAP_DRAW_HORIZ_BAND)?"B" : ".");
 +            printf((codec->capabilities & CODEC_CAP_DR1)           ? "D" : ".");
  
              printf(" %-20s %s", codec->name, codec->long_name ? codec->long_name : "");
              if (strcmp(codec->name, desc->name))
@@@ -957,31 -791,11 +961,31 @@@ int show_protocols(const char *opt, con
  int show_filters(const char *opt, const char *arg)
  {
      AVFilter av_unused(**filter) = NULL;
 +    char descr[64], *descr_cur;
 +    int i, j;
 +    const AVFilterPad *pad;
  
      printf("Filters:\n");
  #if CONFIG_AVFILTER
 -    while ((filter = av_filter_next(filter)) && *filter)
 -        printf("%-16s %s\n", (*filter)->name, (*filter)->description);
 +    while ((filter = av_filter_next(filter)) && *filter) {
 +        descr_cur = descr;
 +        for (i = 0; i < 2; i++) {
 +            if (i) {
 +                *(descr_cur++) = '-';
 +                *(descr_cur++) = '>';
 +            }
 +            pad = i ? (*filter)->outputs : (*filter)->inputs;
 +            for (j = 0; pad[j].name; j++) {
 +                if (descr_cur >= descr + sizeof(descr) - 4)
 +                    break;
 +                *(descr_cur++) = get_media_type_char(pad[j].type);
 +            }
 +            if (!j)
 +                *(descr_cur++) = '|';
 +        }
 +        *descr_cur = 0;
 +        printf("%-16s %-10s %s\n", (*filter)->name, descr, (*filter)->description);
 +    }
  #endif
      return 0;
  }
@@@ -1006,8 -820,6 +1010,8 @@@ int show_pix_fmts(const char *opt, cons
  
      for (pix_fmt = 0; pix_fmt < PIX_FMT_NB; pix_fmt++) {
          const AVPixFmtDescriptor *pix_desc = &av_pix_fmt_descriptors[pix_fmt];
 +        if(!pix_desc->name)
 +            continue;
          printf("%c%c%c%c%c %-16s       %d            %2d\n",
                 sws_isSupportedInput (pix_fmt)      ? 'I' : '.',
                 sws_isSupportedOutput(pix_fmt)      ? 'O' : '.',
@@@ -1078,47 -890,58 +1082,47 @@@ int cmdutils_read_file(const char *file
      return ret;
  }
  
 -void init_pts_correction(PtsCorrectionContext *ctx)
 -{
 -    ctx->num_faulty_pts = ctx->num_faulty_dts = 0;
 -    ctx->last_pts = ctx->last_dts = INT64_MIN;
 -}
 -
 -int64_t guess_correct_pts(PtsCorrectionContext *ctx, int64_t reordered_pts,
 -                          int64_t dts)
 -{
 -    int64_t pts = AV_NOPTS_VALUE;
 -
 -    if (dts != AV_NOPTS_VALUE) {
 -        ctx->num_faulty_dts += dts <= ctx->last_dts;
 -        ctx->last_dts = dts;
 -    }
 -    if (reordered_pts != AV_NOPTS_VALUE) {
 -        ctx->num_faulty_pts += reordered_pts <= ctx->last_pts;
 -        ctx->last_pts = reordered_pts;
 -    }
 -    if ((ctx->num_faulty_pts<=ctx->num_faulty_dts || dts == AV_NOPTS_VALUE)
 -        && reordered_pts != AV_NOPTS_VALUE)
 -        pts = reordered_pts;
 -    else
 -        pts = dts;
 -
 -    return pts;
 -}
 -
  FILE *get_preset_file(char *filename, size_t filename_size,
                        const char *preset_name, int is_path,
                        const char *codec_name)
  {
      FILE *f = NULL;
      int i;
 -    const char *base[3] = { getenv("AVCONV_DATADIR"),
 +    const char *base[3] = { getenv("FFMPEG_DATADIR"),
                              getenv("HOME"),
 -                            AVCONV_DATADIR, };
 +                            FFMPEG_DATADIR, };
  
      if (is_path) {
          av_strlcpy(filename, preset_name, filename_size);
          f = fopen(filename, "r");
      } else {
 +#ifdef _WIN32
 +        char datadir[MAX_PATH], *ls;
 +        base[2] = NULL;
 +
 +        if (GetModuleFileNameA(GetModuleHandleA(NULL), datadir, sizeof(datadir) - 1))
 +        {
 +            for (ls = datadir; ls < datadir + strlen(datadir); ls++)
 +                if (*ls == '\\') *ls = '/';
 +
 +            if (ls = strrchr(datadir, '/'))
 +            {
 +                *ls = 0;
 +                strncat(datadir, "/ffpresets",  sizeof(datadir) - 1 - strlen(datadir));
 +                base[2] = datadir;
 +            }
 +        }
 +#endif
          for (i = 0; i < 3 && !f; i++) {
              if (!base[i])
                  continue;
 -            snprintf(filename, filename_size, "%s%s/%s.avpreset", base[i],
 -                     i != 1 ? "" : "/.avconv", preset_name);
 +            snprintf(filename, filename_size, "%s%s/%s.ffpreset", base[i],
 +                     i != 1 ? "" : "/.ffmpeg", preset_name);
              f = fopen(filename, "r");
              if (!f && codec_name) {
                  snprintf(filename, filename_size,
 -                         "%s%s/%s-%s.avpreset",
 -                         base[i], i != 1 ? "" : "/.avconv", codec_name,
 +                         "%s%s/%s-%s.ffpreset",
 +                         base[i], i != 1 ? "" : "/.ffmpeg", codec_name,
                           preset_name);
                  f = fopen(filename, "r");
              }
  
  int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec)
  {
 -    if (*spec <= '9' && *spec >= '0') /* opt:index */
 -        return strtol(spec, NULL, 0) == st->index;
 -    else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' ||
 -             *spec == 't') { /* opt:[vasdt] */
 -        enum AVMediaType type;
 -
 -        switch (*spec++) {
 -        case 'v': type = AVMEDIA_TYPE_VIDEO;      break;
 -        case 'a': type = AVMEDIA_TYPE_AUDIO;      break;
 -        case 's': type = AVMEDIA_TYPE_SUBTITLE;   break;
 -        case 'd': type = AVMEDIA_TYPE_DATA;       break;
 -        case 't': type = AVMEDIA_TYPE_ATTACHMENT; break;
 -        default:  av_assert0(0);
 -        }
 -        if (type != st->codec->codec_type)
 -            return 0;
 -        if (*spec++ == ':') { /* possibly followed by :index */
 -            int i, index = strtol(spec, NULL, 0);
 -            for (i = 0; i < s->nb_streams; i++)
 -                if (s->streams[i]->codec->codec_type == type && index-- == 0)
 -                   return i == st->index;
 -            return 0;
 -        }
 -        return 1;
 -    } else if (*spec == 'p' && *(spec + 1) == ':') {
 -        int prog_id, i, j;
 -        char *endptr;
 -        spec += 2;
 -        prog_id = strtol(spec, &endptr, 0);
 -        for (i = 0; i < s->nb_programs; i++) {
 -            if (s->programs[i]->id != prog_id)
 -                continue;
 -
 -            if (*endptr++ == ':') {
 -                int stream_idx = strtol(endptr, NULL, 0);
 -                return stream_idx >= 0 &&
 -                    stream_idx < s->programs[i]->nb_stream_indexes &&
 -                    st->index == s->programs[i]->stream_index[stream_idx];
 -            }
 -
 -            for (j = 0; j < s->programs[i]->nb_stream_indexes; j++)
 -                if (st->index == s->programs[i]->stream_index[j])
 -                    return 1;
 -        }
 -        return 0;
 -    } else if (!*spec) /* empty specifier, matches everything */
 -        return 1;
 -
 -    av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec);
 -    return AVERROR(EINVAL);
 +    int ret = avformat_match_stream_specifier(s, st, spec);
 +    if (ret < 0)
 +        av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec);
 +    return ret;
  }
  
  AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,
@@@ -1245,17 -1114,15 +1249,17 @@@ static int alloc_buffer(FrameBuffer **p
      if (!buf)
          return AVERROR(ENOMEM);
  
 +    avcodec_align_dimensions(s, &w, &h);
 +
      if (!(s->flags & CODEC_FLAG_EMU_EDGE)) {
          w += 2*edge;
          h += 2*edge;
      }
  
 -    avcodec_align_dimensions(s, &w, &h);
      if ((ret = av_image_alloc(buf->base, buf->linesize, w, h,
                                s->pix_fmt, 32)) < 0) {
          av_freep(&buf);
 +        av_log(s, AV_LOG_ERROR, "alloc_buffer: av_image_alloc() failed\n");
          return ret;
      }
      /* XXX this shouldn't be needed, but some tests break without this line
      for (i = 0; i < FF_ARRAY_ELEMS(buf->data); i++) {
          const int h_shift = i==0 ? 0 : h_chroma_shift;
          const int v_shift = i==0 ? 0 : v_chroma_shift;
 -        if (s->flags & CODEC_FLAG_EMU_EDGE)
 +        if ((s->flags & CODEC_FLAG_EMU_EDGE) || !buf->linesize[i] || !buf->base[i])
              buf->data[i] = buf->base[i];
          else
              buf->data[i] = buf->base[i] +
@@@ -1291,11 -1158,6 +1295,11 @@@ int codec_get_buffer(AVCodecContext *s
      FrameBuffer *buf;
      int ret, i;
  
 +    if(av_image_check_size(s->width, s->height, 0, s) || s->pix_fmt<0) {
 +        av_log(s, AV_LOG_ERROR, "codec_get_buffer: image parameters invalid\n");
 +        return -1;
 +    }
 +
      if (!*pool && (ret = alloc_buffer(pool, s, pool)) < 0)
          return ret;
  
          if ((ret = alloc_buffer(pool, s, &buf)) < 0)
              return ret;
      }
 +    av_assert0(!buf->refcount);
      buf->refcount++;
  
      frame->opaque        = buf;
@@@ -1333,13 -1194,9 +1337,13 @@@ static void unref_buffer(FrameBuffer *b
  {
      FrameBuffer **pool = buf->pool;
  
 -    av_assert0(buf->refcount);
 +    av_assert0(buf->refcount > 0);
      buf->refcount--;
      if (!buf->refcount) {
 +        FrameBuffer *tmp;
 +        for(tmp= *pool; tmp; tmp= tmp->next)
 +            av_assert1(tmp != buf);
 +
          buf->next = *pool;
          *pool = buf;
      }
@@@ -1350,11 -1207,6 +1354,11 @@@ void codec_release_buffer(AVCodecContex
      FrameBuffer *buf = frame->opaque;
      int i;
  
 +    if(frame->type!=FF_BUFFER_TYPE_USER) {
 +        avcodec_default_release_buffer(s, frame);
 +        return;
 +    }
 +
      for (i = 0; i < FF_ARRAY_ELEMS(frame->data); i++)
          frame->data[i] = NULL;
  
diff --combined cmdutils.h
@@@ -2,25 -2,25 +2,25 @@@
   * Various utilities for command line tools
   * copyright (c) 2003 Fabrice Bellard
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * FFmpeg is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * FFmpeg is distributed in the hope that it will be useful,
   * 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
 - * License along with Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
 -#ifndef LIBAV_CMDUTILS_H
 -#define LIBAV_CMDUTILS_H
 +#ifndef FFMPEG_CMDUTILS_H
 +#define FFMPEG_CMDUTILS_H
  
  #include <stdint.h>
  
  #include "libavformat/avformat.h"
  #include "libswscale/swscale.h"
  
 +#ifdef __MINGW32__
 +#undef main /* We don't want SDL to override our main() */
 +#endif
 +
  /**
   * program name, defined by the program for show_version().
   */
@@@ -43,15 -39,9 +43,15 @@@ extern const char program_name[]
   */
  extern const int program_birth_year;
  
 +/**
 + * this year, defined by the program for show_banner()
 + */
 +extern const int this_year;
 +
  extern AVCodecContext *avcodec_opts[AVMEDIA_TYPE_NB];
  extern AVFormatContext *avformat_opts;
  extern struct SwsContext *sws_opts;
 +extern struct SwrContext *swr_opts;
  extern AVDictionary *format_opts, *codec_opts;
  
  /**
@@@ -67,7 -57,7 +67,7 @@@ void uninit_opts(void)
  
  /**
   * Trivial log callback.
 - * Only suitable for show_help and similar since it lacks prefix handling.
 + * Only suitable for opt_help and similar since it lacks prefix handling.
   */
  void log_callback_help(void* ptr, int level, const char* fmt, va_list vl);
  
@@@ -82,14 -72,6 +82,14 @@@ int opt_default(const char *opt, const 
   */
  int opt_loglevel(const char *opt, const char *arg);
  
 +int opt_report(const char *opt);
 +
 +int opt_max_alloc(const char *opt, const char *arg);
 +
 +int opt_cpuflags(const char *opt, const char *arg);
 +
 +int opt_codec_debug(const char *opt, const char *arg);
 +
  /**
   * Limit the execution time.
   */
@@@ -148,7 -130,6 +148,6 @@@ typedef struct 
  #define OPT_STRING 0x0008
  #define OPT_VIDEO  0x0010
  #define OPT_AUDIO  0x0020
- #define OPT_GRAB   0x0040
  #define OPT_INT    0x0080
  #define OPT_FLOAT  0x0100
  #define OPT_SUBTITLE 0x0200
      const char *argname;
  } OptionDef;
  
- void show_help_options(const OptionDef *options, const char *msg, int mask,
-                        int value);
+ /**
+  * Print help for all options matching specified flags.
+  *
+  * @param options a list of options
+  * @param msg title of this group. Only printed if at least one option matches.
+  * @param req_flags print only options which have all those flags set.
+  * @param rej_flags don't print options which have any of those flags set.
+  */
+ void show_help_options(const OptionDef *options, const char *msg, int req_flags,
+                        int rej_flags);
  
  /**
   * Show help for all options with given flags in class and all its
@@@ -269,34 -258,30 +276,34 @@@ void print_error(const char *filename, 
   * current version of the repository and of the libav* libraries used by
   * the program.
   */
 -void show_banner(void);
 +void show_banner(int argc, char **argv, const OptionDef *options);
  
  /**
   * Print the version of the program to stdout. The version message
   * depends on the current versions of the repository and of the libav*
   * libraries.
 + * This option processing function does not utilize the arguments.
   */
  int show_version(const char *opt, const char *arg);
  
  /**
   * Print the license of the program to stdout. The license depends on
   * the license of the libraries compiled into the program.
 + * This option processing function does not utilize the arguments.
   */
  int show_license(const char *opt, const char *arg);
  
  /**
   * Print a listing containing all the formats supported by the
   * program.
 + * This option processing function does not utilize the arguments.
   */
  int show_formats(const char *opt, const char *arg);
  
  /**
   * Print a listing containing all the codecs supported by the
   * program.
 + * This option processing function does not utilize the arguments.
   */
  int show_codecs(const char *opt, const char *arg);
  
@@@ -315,28 -300,24 +322,28 @@@ int show_encoders(const char *opt, cons
  /**
   * Print a listing containing all the filters supported by the
   * program.
 + * This option processing function does not utilize the arguments.
   */
  int show_filters(const char *opt, const char *arg);
  
  /**
   * Print a listing containing all the bit stream filters supported by the
   * program.
 + * This option processing function does not utilize the arguments.
   */
  int show_bsfs(const char *opt, const char *arg);
  
  /**
   * Print a listing containing all the protocols supported by the
   * program.
 + * This option processing function does not utilize the arguments.
   */
  int show_protocols(const char *opt, const char *arg);
  
  /**
   * Print a listing containing all the pixel formats supported by the
   * program.
 + * This option processing function does not utilize the arguments.
   */
  int show_pix_fmts(const char *opt, const char *arg);
  
@@@ -363,14 -344,37 +370,14 @@@ int read_yesno(void)
   */
  int cmdutils_read_file(const char *filename, char **bufptr, size_t *size);
  
 -typedef struct {
 -    int64_t num_faulty_pts; /// Number of incorrect PTS values so far
 -    int64_t num_faulty_dts; /// Number of incorrect DTS values so far
 -    int64_t last_pts;       /// PTS of the last frame
 -    int64_t last_dts;       /// DTS of the last frame
 -} PtsCorrectionContext;
 -
 -/**
 - * Reset the state of the PtsCorrectionContext.
 - */
 -void init_pts_correction(PtsCorrectionContext *ctx);
 -
 -/**
 - * Attempt to guess proper monotonic timestamps for decoded video frames
 - * which might have incorrect times. Input timestamps may wrap around, in
 - * which case the output will as well.
 - *
 - * @param pts the pts field of the decoded AVPacket, as passed through
 - * AVCodecContext.reordered_opaque
 - * @param dts the dts field of the decoded AVPacket
 - * @return one of the input values, may be AV_NOPTS_VALUE
 - */
 -int64_t guess_correct_pts(PtsCorrectionContext *ctx, int64_t pts, int64_t dts);
 -
  /**
   * Get a file corresponding to a preset file.
   *
   * If is_path is non-zero, look for the file in the path preset_name.
 - * Otherwise search for a file named arg.avpreset in the directories
 - * $AVCONV_DATADIR (if set), $HOME/.avconv, and in the datadir defined
 - * at configuration time, in that order. If no such file is found and
 + * Otherwise search for a file named arg.ffpreset in the directories
 + * $FFMPEG_DATADIR (if set), $HOME/.ffmpeg, and in the datadir defined
 + * at configuration time or in a "ffpresets" folder along the executable
 + * on win32, in that order. If no such file is found and
   * codec_name is defined, then search for a file named
   * codec_name-preset_name.avpreset in the above-mentioned directories.
   *
@@@ -442,4 -446,4 +449,4 @@@ void filter_release_buffer(AVFilterBuff
   * buffers have been released.
   */
  void free_buffer_pool(FrameBuffer **pool);
 -#endif /* LIBAV_CMDUTILS_H */
 +#endif /* CMDUTILS_H */
diff --combined doc/ffmpeg.texi
@@@ -1,8 -1,8 +1,8 @@@
  \input texinfo @c -*- texinfo -*-
  
 -@settitle avconv Documentation
 +@settitle ffmpeg Documentation
  @titlepage
 -@center @titlefont{avconv Documentation}
 +@center @titlefont{ffmpeg Documentation}
  @end titlepage
  
  @top
@@@ -15,18 -15,18 +15,18 @@@ The generic syntax is
  
  @example
  @c man begin SYNOPSIS
 -avconv [global options] [[infile options][@option{-i} @var{infile}]]... @{[outfile options] @var{outfile}@}...
 +ffmpeg [global options] [[infile options][@option{-i} @var{infile}]]... @{[outfile options] @var{outfile}@}...
  @c man end
  @end example
  
  @chapter Description
  @c man begin DESCRIPTION
  
 -avconv is a very fast video and audio converter that can also grab from
 +ffmpeg is a very fast video and audio converter that can also grab from
  a live audio/video source. It can also convert between arbitrary sample
  rates and resize video on the fly with a high quality polyphase filter.
  
 -avconv reads from an arbitrary number of input "files" (which can be regular
 +ffmpeg reads from an arbitrary number of input "files" (which can be regular
  files, pipes, network streams, grabbing devices, etc.), specified by the
  @code{-i} option, and writes to an arbitrary number of output "files", which are
  specified by a plain output filename. Anything found on the command line which
@@@ -58,20 -58,20 +58,20 @@@ options apply ONLY to the next input o
  @item
  To set the video bitrate of the output file to 64kbit/s:
  @example
 -avconv -i input.avi -b 64k output.avi
 +ffmpeg -i input.avi -b:v 64k output.avi
  @end example
  
  @item
  To force the frame rate of the output file to 24 fps:
  @example
 -avconv -i input.avi -r 24 output.avi
 +ffmpeg -i input.avi -r 24 output.avi
  @end example
  
  @item
  To force the frame rate of the input file (valid for raw formats only)
  to 1 fps and the frame rate of the output file to 24 fps:
  @example
 -avconv -r 1 -i input.m2v -r 24 output.avi
 +ffmpeg -r 1 -i input.m2v -r 24 output.avi
  @end example
  @end itemize
  
@@@ -82,7 -82,7 +82,7 @@@ The format option may be needed for ra
  @chapter Detailed description
  @c man begin DETAILED DESCRIPTION
  
 -The transcoding process in @command{avconv} for each output can be described by
 +The transcoding process in @command{ffmpeg} for each output can be described by
  the following diagram:
  
  @example
@@@ -94,9 -94,9 +94,9 @@@
  
  @end example
  
 -@command{avconv} calls the libavformat library (containing demuxers) to read
 +@command{ffmpeg} calls the libavformat library (containing demuxers) to read
  input files and get packets containing encoded data from them. When there are
 -multiple input files, @command{avconv} tries to keep them synchronized by
 +multiple input files, @command{ffmpeg} tries to keep them synchronized by
  tracking lowest timestamp on any active input stream.
  
  Encoded packets are then passed to the decoder (unless streamcopy is selected
@@@ -107,9 -107,9 +107,9 @@@ encoder, which encodes them and output
  passed to the muxer, which writes the encoded packets to the output file.
  
  @section Filtering
 -Before encoding, @command{avconv} can process raw audio and video frames using
 +Before encoding, @command{ffmpeg} can process raw audio and video frames using
  filters from the libavfilter library. Several chained filters form a filter
 -graph.  @command{avconv} distinguishes between two types of filtergraphs -
 +graph.  @command{ffmpeg} distinguishes between two types of filtergraphs -
  simple and complex.
  
  @subsection Simple filtergraphs
@@@ -179,7 -179,7 +179,7 @@@ of the other. Its audio counterpart is 
  
  @section Stream copy
  Stream copy is a mode selected by supplying the @code{copy} parameter to the
 -@option{-codec} option. It makes @command{avconv} omit the decoding and encoding
 +@option{-codec} option. It makes @command{ffmpeg} omit the decoding and encoding
  step for the specified stream, so it does only demuxing and muxing. It is useful
  for changing the container format or modifying container-level metadata. The
  diagram above will in this case simplify to this:
@@@ -202,12 -202,10 +202,12 @@@ filters is obviously also impossible, s
  @chapter Stream selection
  @c man begin STREAM SELECTION
  
 -By default avconv tries to pick the "best" stream of each type present in input
 -files and add them to each output file. For video, this means the highest
 -resolution, for audio the highest channel count. For subtitle it's simply the
 -first subtitle stream.
 +By default ffmpeg includes only one stream of each type (video, audio, subtitle)
 +present in the input files and adds them to each output file.  It picks the
 +"best" of each based upon the following criteria; for video it is the stream
 +with the highest resolution, for audio the stream with the most channels, for
 +subtitle it's the first subtitle stream. In the case where several streams of
 +the same type rate equally, the lowest numbered stream is chosen.
  
  You can disable some of those defaults by using @code{-vn/-an/-sn} options. For
  full manual control, use the @code{-map} option, which disables the defaults just
@@@ -225,7 -223,7 +225,7 @@@ described
  @table @option
  
  @item -f @var{fmt} (@emph{input/output})
 -Force input or output file format. The format is normally autodetected for input
 +Force input or output file format. The format is normally auto detected for input
  files and guessed from file extension for output files, so this option is not
  needed in most cases.
  
@@@ -235,25 -233,22 +235,25 @@@ input file nam
  @item -y (@emph{global})
  Overwrite output files without asking.
  
 +@item -n (@emph{global})
 +Do not overwrite output files but exit if file exists.
 +
  @item -c[:@var{stream_specifier}] @var{codec} (@emph{input/output,per-stream})
  @itemx -codec[:@var{stream_specifier}] @var{codec} (@emph{input/output,per-stream})
  Select an encoder (when used before an output file) or a decoder (when used
  before an input file) for one or more streams. @var{codec} is the name of a
  decoder/encoder or a special value @code{copy} (output only) to indicate that
 -the stream is not to be reencoded.
 +the stream is not to be re-encoded.
  
  For example
  @example
 -avconv -i INPUT -map 0 -c:v libx264 -c:a copy OUTPUT
 +ffmpeg -i INPUT -map 0 -c:v libx264 -c:a copy OUTPUT
  @end example
  encodes all video streams with libx264 and copies all audio streams.
  
  For each stream, the last matching @code{c} option is applied, so
  @example
 -avconv -i INPUT -map 0 -c copy -c:v:1 libx264 -c:a:137 libvorbis OUTPUT
 +ffmpeg -i INPUT -map 0 -c copy -c:v:1 libx264 -c:a:137 libvorbis OUTPUT
  @end example
  will copy all the streams except the second video, which will be encoded with
  libx264, and the 138th audio, which will be encoded with libvorbis.
@@@ -263,7 -258,7 +263,7 @@@ Stop writing the output after its durat
  @var{duration} may be a number in seconds, or in @code{hh:mm:ss[.xxx]} form.
  
  @item -fs @var{limit_size} (@emph{output})
 -Set the file size limit.
 +Set the file size limit, expressed in bytes.
  
  @item -ss @var{position} (@emph{input/output})
  When used as an input option (before @code{-i}), seeks in this input file to
@@@ -280,18 -275,6 +280,18 @@@ The offset is added to the timestamps o
  Specifying a positive offset means that the corresponding
  streams are delayed by @var{offset} seconds.
  
 +@item -timestamp @var{time} (@emph{output})
 +Set the recording timestamp in the container.
 +The syntax for @var{time} is:
 +@example
 +now|([(YYYY-MM-DD|YYYYMMDD)[T|t| ]]((HH:MM:SS[.m...])|(HHMMSS[.m...]))[Z|z])
 +@end example
 +If the value is "now" it takes the current time.
 +Time is local time unless 'Z' or 'z' is appended, in which case it is
 +interpreted as UTC.
 +If the year-month-day part is not specified it takes the current
 +year-month-day.
 +
  @item -metadata[:metadata_specifier] @var{key}=@var{value} (@emph{output,per-metadata})
  Set a metadata key/value pair.
  
@@@ -304,12 -287,12 +304,12 @@@ also possible to delete metadata by usi
  
  For example, for setting the title in the output file:
  @example
 -avconv -i in.avi -metadata title="my title" out.flv
 +ffmpeg -i in.avi -metadata title="my title" out.flv
  @end example
  
  To set the language of the first audio stream:
  @example
 -avconv -i INPUT -metadata:s:a:0 language=eng OUTPUT
 +ffmpeg -i INPUT -metadata:s:a:1 language=eng OUTPUT
  @end example
  
  @item -target @var{type} (@emph{output})
@@@ -319,14 -302,14 +319,14 @@@ Specify target file type (@code{vcd}, @
  (bitrate, codecs, buffer sizes) are then set automatically. You can just type:
  
  @example
 -avconv -i myfile.avi -target vcd /tmp/vcd.mpg
 +ffmpeg -i myfile.avi -target vcd /tmp/vcd.mpg
  @end example
  
  Nevertheless you can specify additional options as long as you know
  they do not conflict with the standard, as in:
  
  @example
 -avconv -i myfile.avi -target vcd -bf 2 /tmp/vcd.mpg
 +ffmpeg -i myfile.avi -target vcd -bf 2 /tmp/vcd.mpg
  @end example
  
  @item -dframes @var{number} (@emph{output})
@@@ -353,30 -336,6 +353,30 @@@ Specify the preset for matching stream(
  @item -stats (@emph{global})
  Print encoding progress/statistics. On by default.
  
 +@item -progress @var{url} (@emph{global})
 +Send program-friendly progress information to @var{url}.
 +
 +Progress information is written approximately every second and at the end of
 +the encoding process. It is made of "@var{key}=@var{value}" lines. @var{key}
 +consists of only alphanumeric characters. The last key of a sequence of
 +progress information is always "progress".
 +
 +@item -stdin
 +Enable interaction on standard input. On by default unless standard input is
 +used as an input.
 +
 +Useful, for example, if ffmpeg is in the background process group. Roughly
 +the same result can be achieved with @code{ffmpeg ... < /dev/null} but it
 +requires a shell.
 +
 +@item -debug_ts (@emph{global})
 +Print timestamp information. It is off by default. This option is
 +mostly useful for testing and debugging purposes, and the output
 +format may change from one version to another, so it should not be
 +employed by portable scripts.
 +
 +See also the option @code{-fdebug ts}.
 +
  @item -attach @var{filename} (@emph{output})
  Add an attachment to the output file. This is supported by a few formats
  like Matroska for e.g. fonts used in rendering subtitles. Attachments
@@@ -388,7 -347,7 +388,7 @@@ with @code{-map} or automatic mappings)
  
  Note that for Matroska you also have to set the mimetype metadata tag:
  @example
 -avconv -i INPUT -attach DejaVuSans.ttf -metadata:s:2 mimetype=application/x-truetype-font out.mkv
 +ffmpeg -i INPUT -attach DejaVuSans.ttf -metadata:s:2 mimetype=application/x-truetype-font out.mkv
  @end example
  (assuming that the attachment stream will be third in the output file).
  
@@@ -399,11 -358,11 +399,11 @@@ will be used
  
  E.g. to extract the first attachment to a file named 'out.ttf':
  @example
 -avconv -dump_attachment:t:0 out.ttf INPUT
 +ffmpeg -dump_attachment:t:0 out.ttf INPUT
  @end example
  To extract all attachments to files determined by the @code{filename} tag:
  @example
 -avconv -dump_attachment:t "" INPUT
 +ffmpeg -dump_attachment:t "" INPUT
  @end example
  
  Technical note -- attachments are implemented as codec extradata, so this
@@@ -438,7 -397,68 +438,7 @@@ As an output option, this inserts the @
  @emph{end} of the corresponding filtergraph. Please use the @code{scale} filter
  directly to insert it at the beginning or some other place.
  
 -The format is @samp{wxh} (default - same as source).  The following
 -abbreviations are recognized:
 -@table @samp
 -@item sqcif
 -128x96
 -@item qcif
 -176x144
 -@item cif
 -352x288
 -@item 4cif
 -704x576
 -@item 16cif
 -1408x1152
 -@item qqvga
 -160x120
 -@item qvga
 -320x240
 -@item vga
 -640x480
 -@item svga
 -800x600
 -@item xga
 -1024x768
 -@item uxga
 -1600x1200
 -@item qxga
 -2048x1536
 -@item sxga
 -1280x1024
 -@item qsxga
 -2560x2048
 -@item hsxga
 -5120x4096
 -@item wvga
 -852x480
 -@item wxga
 -1366x768
 -@item wsxga
 -1600x1024
 -@item wuxga
 -1920x1200
 -@item woxga
 -2560x1600
 -@item wqsxga
 -3200x2048
 -@item wquxga
 -3840x2400
 -@item whsxga
 -6400x4096
 -@item whuxga
 -7680x4800
 -@item cga
 -320x200
 -@item ega
 -640x350
 -@item hd480
 -852x480
 -@item hd720
 -1280x720
 -@item hd1080
 -1920x1080
 -@end table
 +The format is @samp{wxh} (default - same as source).
  
  @item -aspect[:@var{stream_specifier}] @var{aspect} (@emph{output,per-stream})
  Set the video display aspect ratio specified by @var{aspect}.
@@@ -448,21 -468,6 +448,21 @@@ form @var{num}:@var{den}, where @var{nu
  numerator and denominator of the aspect ratio. For example "4:3",
  "16:9", "1.3333", and "1.7777" are valid argument values.
  
 +@item -croptop @var{size}
 +@item -cropbottom @var{size}
 +@item -cropleft @var{size}
 +@item -cropright @var{size}
 +All the crop options have been removed. Use -vf
 +crop=width:height:x:y instead.
 +
 +@item -padtop @var{size}
 +@item -padbottom @var{size}
 +@item -padleft @var{size}
 +@item -padright @var{size}
 +@item -padcolor @var{hex_color}
 +All the pad options have been removed. Use -vf
 +pad=width:height:x:y:color instead.
 +
  @item -vn (@emph{output})
  Disable video recording.
  
@@@ -483,18 -488,15 +483,18 @@@ at the exact requested bitrate
  On pass 1, you may just deactivate audio and set output to null,
  examples for Windows and Unix:
  @example
 -avconv -i foo.mov -c:v libxvid -pass 1 -an -f rawvideo -y NUL
 -avconv -i foo.mov -c:v libxvid -pass 1 -an -f rawvideo -y /dev/null
 +ffmpeg -i foo.mov -c:v libxvid -pass 1 -an -f rawvideo -y NUL
 +ffmpeg -i foo.mov -c:v libxvid -pass 1 -an -f rawvideo -y /dev/null
  @end example
  
  @item -passlogfile @var{prefix} (@emph{global})
  Set two-pass log file name prefix to @var{prefix}, the default file name
 -prefix is ``av2pass''. The complete file name will be
 +prefix is ``ffmpeg2pass''. The complete file name will be
  @file{PREFIX-N.log}, where N is a number specific to the output
 -stream.
 +stream
 +
 +@item -vlang @var{code}
 +Set the ISO 639 language code (3 letters) of the current video stream.
  
  @item -vf @var{filter_graph} (@emph{output})
  @var{filter_graph} is a description of the filter graph to apply to
@@@ -510,37 -512,18 +510,37 @@@ also sources and sinks).  This is an al
  @item -pix_fmt[:@var{stream_specifier}] @var{format} (@emph{input/output,per-stream})
  Set pixel format. Use @code{-pix_fmts} to show all the supported
  pixel formats.
 +If the selected pixel format can not be selected, ffmpeg will print a
 +warning and select the best pixel format supported by the encoder.
 +If @var{pix_fmt} is prefixed by a @code{+}, ffmpeg will exit with an error
 +if the requested pixel format can not be selected, and automatic conversions
 +inside filter graphs are disabled.
 +If @var{pix_fmt} is a single @code{+}, ffmpeg selects the same pixel format
 +as the input (or graph output) and automatic conversions are disabled.
 +
  @item -sws_flags @var{flags} (@emph{input/output})
  Set SwScaler flags.
  @item -vdt @var{n}
  Discard threshold.
  
  @item -rc_override[:@var{stream_specifier}] @var{override} (@emph{output,per-stream})
 -rate control override for specific intervals
 +Rate control override for specific intervals, formatted as "int,int,int"
 +list separated with slashes. Two first values are the beginning and
 +end frame numbers, last one is quantizer to use if positive, or quality
 +factor if negative.
  
  @item -deinterlace
  Deinterlace pictures.
  This option is deprecated since the deinterlacing is very low quality.
  Use the yadif filter with @code{-filter:v yadif}.
 +@item -ilme
 +Force interlacing support in encoder (MPEG-2 and MPEG-4 only).
 +Use this option if your input file is interlaced and you want
 +to keep the interlaced format for minimum losses.
 +The alternative is to deinterlace the input stream with
 +@option{-deinterlace}, but deinterlacing introduces losses.
 +@item -psnr
 +Calculate PSNR of compressed frames.
  @item -vstats
  Dump video coding statistics to @file{vstats_HHMMSS.log}.
  @item -vstats_file @var{file}
@@@ -552,9 -535,7 +552,9 @@@ Intra_dc_precision
  @item -vtag @var{fourcc/tag} (@emph{output})
  Force video tag/fourcc. This is an alias for @code{-tag:v}.
  @item -qphist (@emph{global})
 -Show QP histogram.
 +Show QP histogram
 +@item -vbsf @var{bitstream_filter}
 +Deprecated see -bsf
  @item -force_key_frames[:@var{stream_specifier}] @var{time}[,@var{time}...] (@emph{output,per-stream})
  Force key frames at the specified timestamps, more precisely at the first
  frames after each specified time.
@@@ -603,49 -584,17 +603,42 @@@ also sources and sinks).  This is an al
  @table @option
  @item -atag @var{fourcc/tag} (@emph{output})
  Force audio tag/fourcc. This is an alias for @code{-tag:a}.
 +@item -absf @var{bitstream_filter}
 +Deprecated, see -bsf
  @end table
  
  @section Subtitle options:
  
  @table @option
 +@item -slang @var{code}
 +Set the ISO 639 language code (3 letters) of the current subtitle stream.
  @item -scodec @var{codec} (@emph{input/output})
  Set the subtitle codec. This is an alias for @code{-codec:s}.
  @item -sn (@emph{output})
  Disable subtitle recording.
 +@item -sbsf @var{bitstream_filter}
 +Deprecated, see -bsf
 +@end table
 +
 +@section Advanced Subtitle options:
 +
 +@table @option
 +
 +@item -fix_sub_duration
 +Fix subtitles durations. For each subtitle, wait for the next packet in the
 +same stream and adjust the duration of the first to avoid overlap. This is
 +necessary with some subtitles codecs, especially DVB subtitles, because the
 +duration in the original packet is only a rough estimate and the end is
 +actually marked by an empty subtitle frame. Failing to use this option when
 +necessary can result in exaggerated durations or muxing failures due to
 +non-monotonic timestamps.
 +
 +Note that this option will delay the output of all data until the next
 +subtitle packet is decoded: it may increase memory consumption and latency a
 +lot.
 +
  @end table
  
- @section Audio/Video grab options
- @table @option
- @item -isync (@emph{global})
- Synchronize read on input.
- @end table
  @section Advanced options
  
  @table @option
@@@ -671,7 -620,7 +664,7 @@@ graphs (see the @option{-filter_complex
  
  For example, to map ALL streams from the first input file to output
  @example
 -avconv -i INPUT -map 0 output
 +ffmpeg -i INPUT -map 0 output
  @end example
  
  For example, if you have two audio streams in the first input file,
@@@ -679,7 -628,7 +672,7 @@@ these streams are identified by "0:0" a
  @code{-map} to select which streams to place in an output file. For
  example:
  @example
 -avconv -i INPUT -map 0:1 out.wav
 +ffmpeg -i INPUT -map 0:1 out.wav
  @end example
  will map the input stream in @file{INPUT} identified by "0:1" to
  the (single) output stream in @file{out.wav}.
@@@ -689,77 -638,21 +682,77 @@@ For example, to select the stream with 
  index 6 from input @file{b.mov} (specified by the identifier "1:6"),
  and copy them to the output file @file{out.mov}:
  @example
 -avconv -i a.mov -i b.mov -c copy -map 0:2 -map 1:6 out.mov
 +ffmpeg -i a.mov -i b.mov -c copy -map 0:2 -map 1:6 out.mov
  @end example
  
  To select all video and the third audio stream from an input file:
  @example
 -avconv -i INPUT -map 0:v -map 0:a:2 OUTPUT
 +ffmpeg -i INPUT -map 0:v -map 0:a:2 OUTPUT
  @end example
  
  To map all the streams except the second audio, use negative mappings
  @example
 -avconv -i INPUT -map 0 -map -0:a:1 OUTPUT
 +ffmpeg -i INPUT -map 0 -map -0:a:1 OUTPUT
  @end example
  
  Note that using this option disables the default mappings for this output file.
  
 +@item -map_channel [@var{input_file_id}.@var{stream_specifier}.@var{channel_id}|-1][:@var{output_file_id}.@var{stream_specifier}]
 +Map an audio channel from a given input to an output. If
 +@var{output_file_id}.@var{stream_specifier} is not set, the audio channel will
 +be mapped on all the audio streams.
 +
 +Using "-1" instead of
 +@var{input_file_id}.@var{stream_specifier}.@var{channel_id} will map a muted
 +channel.
 +
 +For example, assuming @var{INPUT} is a stereo audio file, you can switch the
 +two audio channels with the following command:
 +@example
 +ffmpeg -i INPUT -map_channel 0.0.1 -map_channel 0.0.0 OUTPUT
 +@end example
 +
 +If you want to mute the first channel and keep the second:
 +@example
 +ffmpeg -i INPUT -map_channel -1 -map_channel 0.0.1 OUTPUT
 +@end example
 +
 +The order of the "-map_channel" option specifies the order of the channels in
 +the output stream. The output channel layout is guessed from the number of
 +channels mapped (mono if one "-map_channel", stereo if two, etc.). Using "-ac"
 +in combination of "-map_channel" makes the channel gain levels to be updated if
 +input and output channel layouts don't match (for instance two "-map_channel"
 +options and "-ac 6").
 +
 +You can also extract each channel of an input to specific outputs; the following
 +command extracts two channels of the @var{INPUT} audio stream (file 0, stream 0)
 +to the respective @var{OUTPUT_CH0} and @var{OUTPUT_CH1} outputs:
 +@example
 +ffmpeg -i INPUT -map_channel 0.0.0 OUTPUT_CH0 -map_channel 0.0.1 OUTPUT_CH1
 +@end example
 +
 +The following example splits the channels of a stereo input into two separate
 +streams, which are put into the same output file:
 +@example
 +ffmpeg -i stereo.wav -map 0:0 -map 0:0 -map_channel 0.0.0:0.0 -map_channel 0.0.1:0.1 -y out.ogg
 +@end example
 +
 +Note that currently each output stream can only contain channels from a single
 +input stream; you can't for example use "-map_channel" to pick multiple input
 +audio channels contained in different streams (from the same or different files)
 +and merge them into a single output stream. It is therefore not currently
 +possible, for example, to turn two separate mono streams into a single stereo
 +stream. However splitting a stereo stream into two single channel mono streams
 +is possible.
 +
 +If you need this feature, a possible workaround is to use the @emph{amerge}
 +filter. For example, if you need to merge a media (here @file{input.mkv}) with 2
 +mono audio streams into one single stereo channel audio stream (and keep the
 +video stream), you can use the following command:
 +@example
 +ffmpeg -i input.mkv -filter_complex "[0:1] [0:2] amerge" -c:a pcm_s16le -c:v copy output.mkv
 +@end example
 +
  @item -map_metadata[:@var{metadata_spec_out}] @var{infile}[:@var{metadata_spec_in}] (@emph{output,per-metadata})
  Set metadata information of the next output file from @var{infile}. Note that
  those are file indices (zero-based), not filenames.
@@@ -791,12 -684,12 +784,12 @@@ file index can be used to create a dumm
  For example to copy metadata from the first stream of the input file to global metadata
  of the output file:
  @example
 -avconv -i in.ogg -map_metadata 0:s:0 out.mp3
 +ffmpeg -i in.ogg -map_metadata 0:s:0 out.mp3
  @end example
  
  To do the reverse, i.e. copy global metadata to all audio streams:
  @example
 -avconv -i in.mkv -map_metadata:s:a 0:g out.mkv
 +ffmpeg -i in.mkv -map_metadata:s:a 0:g out.mkv
  @end example
  Note that simple @code{0} would work as well in this example, since global
  metadata is assumed by default.
@@@ -806,88 -699,34 +799,88 @@@ Copy chapters from input file with inde
  output file. If no chapter mapping is specified, then chapters are copied from
  the first input file with at least one chapter. Use a negative file index to
  disable any chapter copying.
 -@item -debug
 +@item -debug @var{category}
  Print specific debug info.
 +@var{category} is a number or a string containing one of the following values:
 +@table @samp
 +@item bitstream
 +@item buffers
 +picture buffer allocations
 +@item bugs
 +@item dct_coeff
 +@item er
 +error recognition
 +@item mb_type
 +macroblock (MB) type
 +@item mmco
 +memory management control operations (H.264)
 +@item mv
 +motion vector
 +@item pict
 +picture info
 +@item pts
 +@item qp
 +per-block quantization parameter (QP)
 +@item rc
 +rate control
 +@item skip
 +@item startcode
 +@item thread_ops
 +threading operations
 +@item vis_mb_type
 +visualize block types
 +@item vis_qp
 +visualize quantization parameter (QP), lower QP are tinted greener
 +@end table
  @item -benchmark (@emph{global})
  Show benchmarking information at the end of an encode.
  Shows CPU time used and maximum memory consumption.
  Maximum memory consumption is not supported on all systems,
  it will usually display as 0 if not supported.
 +@item -benchmark_all (@emph{global})
 +Show benchmarking information during the encode.
 +Shows CPU time used in various steps (audio/video encode/decode).
  @item -timelimit @var{duration} (@emph{global})
 -Exit after avconv has been running for @var{duration} seconds.
 +Exit after ffmpeg has been running for @var{duration} seconds.
  @item -dump (@emph{global})
  Dump each input packet to stderr.
  @item -hex (@emph{global})
  When dumping packets, also dump the payload.
  @item -re (@emph{input})
  Read input at native frame rate. Mainly used to simulate a grab device.
 +By default @command{ffmpeg} attempts to read the input(s) as fast as possible.
 +This option will slow down the reading of the input(s) to the native frame rate
 +of the input(s). It is useful for real-time output (e.g. live streaming). If
 +your input(s) is coming from some other live streaming source (through HTTP or
 +UDP for example) the server might already be in real-time, thus the option will
 +likely not be required. On the other hand, this is meaningful if your input(s)
 +is a file you are trying to push in real-time.
 +@item -loop_input
 +Loop over the input stream. Currently it works only for image
 +streams. This option is used for automatic FFserver testing.
 +This option is deprecated, use -loop 1.
 +@item -loop_output @var{number_of_times}
 +Repeatedly loop output for formats that support looping such as animated GIF
 +(0 will loop the output infinitely).
 +This option is deprecated, use -loop.
  @item -vsync @var{parameter}
  Video sync method.
 +For compatibility reasons old values can be specified as numbers.
 +Newly added values will have to be specified as strings always.
  
  @table @option
 -@item passthrough
 +@item 0, passthrough
  Each frame is passed with its timestamp from the demuxer to the muxer.
 -@item cfr
 +@item 1, cfr
  Frames will be duplicated and dropped to achieve exactly the requested
  constant framerate.
 -@item vfr
 +@item 2, vfr
  Frames are passed through with their timestamp or dropped so as to
  prevent 2 frames from having the same timestamp.
 -@item auto
 +@item drop
 +As passthrough but destroys all timestamps, making the muxer generate
 +fresh timestamps based on frame-rate.
 +@item -1, auto
  Chooses between 1 and 2 depending on muxer capabilities. This is the
  default method.
  @end table
@@@ -904,30 -743,8 +897,30 @@@ without any later correction
  This option has been deprecated. Use the @code{asyncts} audio filter instead.
  @item -copyts
  Copy timestamps from input to output.
 -@item -copytb
 -Copy input stream time base from input to output when stream copying.
 +@item -copytb @var{mode}
 +Specify how to set the encoder timebase when stream copying.  @var{mode} is an
 +integer numeric value, and can assume one of the following values:
 +
 +@table @option
 +@item 1
 +Use the demuxer timebase.
 +
 +The time base is copied to the output encoder from the corresponding input
 +demuxer. This is sometimes required to avoid non monotonically increasing
 +timestamps when copying video streams with variable frame rate.
 +
 +@item 0
 +Use the decoder timebase.
 +
 +The time base is copied to the output encoder from the corresponding input
 +decoder.
 +
 +@item -1
 +Try to make the choice automatically, in order to generate a sane output.
 +@end table
 +
 +Default value is -1.
 +
  @item -shortest (@emph{output})
  Finish encoding when the shortest input stream ends.
  @item -dts_delta_threshold
@@@ -945,7 -762,7 +938,7 @@@ may be reassigned to a different value
  For example, to set the stream 0 PID to 33 and the stream 1 PID to 36 for
  an output mpegts file:
  @example
 -avconv -i infile -streamid 0:33 -streamid 1:36 out.ts
 +ffmpeg -i infile -streamid 0:33 -streamid 1:36 out.ts
  @end example
  
  @item -bsf[:@var{stream_specifier}] @var{bitstream_filters} (@emph{output,per-stream})
@@@ -953,21 -770,18 +946,21 @@@ Set bitstream filters for matching stre
  a comma-separated list of bitstream filters. Use the @code{-bsfs} option
  to get the list of bitstream filters.
  @example
 -avconv -i h264.mp4 -c:v copy -bsf:v h264_mp4toannexb -an out.h264
 +ffmpeg -i h264.mp4 -c:v copy -bsf:v h264_mp4toannexb -an out.h264
  @end example
  @example
 -avconv -i file.mov -an -vn -bsf:s mov2textsub -c:s copy -f rawvideo sub.txt
 +ffmpeg -i file.mov -an -vn -bsf:s mov2textsub -c:s copy -f rawvideo sub.txt
  @end example
  
 -@item -tag[:@var{stream_specifier}] @var{codec_tag} (@emph{output,per-stream})
 +@item -tag[:@var{stream_specifier}] @var{codec_tag} (@emph{per-stream})
  Force a tag/fourcc for matching streams.
  
 -@item -cpuflags mask (@emph{global})
 -Set a mask that's applied to autodetected CPU flags.  This option is intended
 -for testing. Do not use it unless you know what you're doing.
 +@item -timecode @var{hh}:@var{mm}:@var{ss}SEP@var{ff}
 +Specify Timecode for writing. @var{SEP} is ':' for non drop timecode and ';'
 +(or '.') for drop.
 +@example
 +ffmpeg -i input.mpg -timecode 01:02:03.04 -r 30000/1001 -s ntsc output.mpg
 +@end example
  
  @item -filter_complex @var{filtergraph} (@emph{global})
  Define a complex filter graph, i.e. one with arbitrary number of inputs and/or
@@@ -989,7 -803,7 +982,7 @@@ normal input files
  
  For example, to overlay an image over video
  @example
 -avconv -i video.mkv -i image.png -filter_complex '[0:v][1:v]overlay[out]' -map
 +ffmpeg -i video.mkv -i image.png -filter_complex '[0:v][1:v]overlay[out]' -map
  '[out]' out.mkv
  @end example
  Here @code{[0:v]} refers to the first video stream in the first input file,
@@@ -1000,70 -814,21 +993,70 @@@ of overlay
  Assuming there is only one video stream in each input file, we can omit input
  labels, so the above is equivalent to
  @example
 -avconv -i video.mkv -i image.png -filter_complex 'overlay[out]' -map
 +ffmpeg -i video.mkv -i image.png -filter_complex 'overlay[out]' -map
  '[out]' out.mkv
  @end example
  
  Furthermore we can omit the output label and the single output from the filter
  graph will be added to the output file automatically, so we can simply write
  @example
 -avconv -i video.mkv -i image.png -filter_complex 'overlay' out.mkv
 +ffmpeg -i video.mkv -i image.png -filter_complex 'overlay' out.mkv
  @end example
  
  To generate 5 seconds of pure red video using lavfi @code{color} source:
  @example
 -avconv -filter_complex 'color=red' -t 5 out.mkv
 +ffmpeg -filter_complex 'color=red' -t 5 out.mkv
  @end example
  @end table
 +
 +As a special exception, you can use a bitmap subtitle stream as input: it
 +will be converted into a video with the same size as the largest video in
 +the file, or 720×576 if no video is present. Note that this is an
 +experimental and temporary solution. It will be removed once libavfilter has
 +proper support for subtitles.
 +
 +For example, to hardcode subtitles on top of a DVB-T recording stored in
 +MPEG-TS format, delaying the subtitles by 1 second:
 +@example
 +ffmpeg -i input.ts -filter_complex \
 +  '[#0x2ef] setpts=PTS+1/TB [sub] ; [#0x2d0] [sub] overlay' \
 +  -sn -map '#0x2dc' output.mkv
 +@end example
 +(0x2d0, 0x2dc and 0x2ef are the MPEG-TS PIDs of respectively the video,
 +audio and subtitles streams; 0:0, 0:3 and 0:7 would have worked too)
 +
 +@section Preset files
 +A preset file contains a sequence of @var{option}=@var{value} pairs,
 +one for each line, specifying a sequence of options which would be
 +awkward to specify on the command line. Lines starting with the hash
 +('#') character are ignored and are used to provide comments. Check
 +the @file{presets} directory in the FFmpeg source tree for examples.
 +
 +Preset files are specified with the @code{vpre}, @code{apre},
 +@code{spre}, and @code{fpre} options. The @code{fpre} option takes the
 +filename of the preset instead of a preset name as input and can be
 +used for any kind of codec. For the @code{vpre}, @code{apre}, and
 +@code{spre} options, the options specified in a preset file are
 +applied to the currently selected codec of the same type as the preset
 +option.
 +
 +The argument passed to the @code{vpre}, @code{apre}, and @code{spre}
 +preset options identifies the preset file to use according to the
 +following rules:
 +
 +First ffmpeg searches for a file named @var{arg}.ffpreset in the
 +directories @file{$FFMPEG_DATADIR} (if set), and @file{$HOME/.ffmpeg}, and in
 +the datadir defined at configuration time (usually @file{PREFIX/share/ffmpeg})
 +or in a @file{ffpresets} folder along the executable on win32,
 +in that order. For example, if the argument is @code{libvpx-1080p}, it will
 +search for the file @file{libvpx-1080p.ffpreset}.
 +
 +If no such file is found, then ffmpeg will search for a file named
 +@var{codec_name}-@var{arg}.ffpreset in the above-mentioned
 +directories, where @var{codec_name} is the name of the codec to which
 +the preset file options will be applied. For example, if you select
 +the video codec with @code{-vcodec libvpx} and use @code{-vpre 1080p},
 +then it will search for the file @file{libvpx-1080p.ffpreset}.
  @c man end OPTIONS
  
  @chapter Tips
@@@ -1077,7 -842,7 +1070,7 @@@ the Linux player does not seem to be ve
  frames. An example is:
  
  @example
 -avconv -g 3 -r 3 -t 10 -b 50k -s qcif -f rv10 /tmp/b.rm
 +ffmpeg -g 3 -r 3 -t 10 -b:v 50k -s qcif -f rv10 /tmp/b.rm
  @end example
  
  @item
@@@ -1116,48 -881,43 +1109,48 @@@ A preset file contains a sequence of @v
  each line, specifying a sequence of options which can be specified also on
  the command line. Lines starting with the hash ('#') character are ignored and
  are used to provide comments. Empty lines are also ignored. Check the
 -@file{presets} directory in the Libav source tree for examples.
 +@file{presets} directory in the FFmpeg source tree for examples.
  
  Preset files are specified with the @code{pre} option, this option takes a
 -preset name as input.  Avconv searches for a file named @var{preset_name}.avpreset in
 -the directories @file{$AVCONV_DATADIR} (if set), and @file{$HOME/.avconv}, and in
 -the data directory defined at configuration time (usually @file{$PREFIX/share/avconv})
 +preset name as input.  FFmpeg searches for a file named @var{preset_name}.avpreset in
 +the directories @file{$AVCONV_DATADIR} (if set), and @file{$HOME/.ffmpeg}, and in
 +the data directory defined at configuration time (usually @file{$PREFIX/share/ffmpeg})
  in that order.  For example, if the argument is @code{libx264-max}, it will
  search for the file @file{libx264-max.avpreset}.
  
  @section Video and Audio grabbing
  
 -If you specify the input format and device then avconv can grab video
 +If you specify the input format and device then ffmpeg can grab video
  and audio directly.
  
  @example
 -avconv -f oss -i /dev/dsp -f video4linux2 -i /dev/video0 /tmp/out.mpg
 +ffmpeg -f oss -i /dev/dsp -f video4linux2 -i /dev/video0 /tmp/out.mpg
 +@end example
 +
 +Or with an ALSA audio source (mono input, card id 1) instead of OSS:
 +@example
 +ffmpeg -f alsa -ac 1 -i hw:1 -f video4linux2 -i /dev/video0 /tmp/out.mpg
  @end example
  
  Note that you must activate the right video source and channel before
 -launching avconv with any TV viewer such as
 +launching ffmpeg with any TV viewer such as
  @uref{http://linux.bytesex.org/xawtv/, xawtv} by Gerd Knorr. You also
  have to set the audio recording levels correctly with a
  standard mixer.
  
  @section X11 grabbing
  
 -Grab the X11 display with avconv via
 +Grab the X11 display with ffmpeg via
  
  @example
 -avconv -f x11grab -s cif -r 25 -i :0.0 /tmp/out.mpg
 +ffmpeg -f x11grab -s cif -r 25 -i :0.0 /tmp/out.mpg
  @end example
  
  0.0 is display.screen number of your X11 server, same as
  the DISPLAY environment variable.
  
  @example
 -avconv -f x11grab -s cif -r 25 -i :0.0+10,20 /tmp/out.mpg
 +ffmpeg -f x11grab -s cif -r 25 -i :0.0+10,20 /tmp/out.mpg
  @end example
  
  0.0 is display.screen number of your X11 server, same as the DISPLAY environment
@@@ -1165,7 -925,7 +1158,7 @@@ variable. 10 is the x-offset and 20 th
  
  @section Video and Audio file format conversion
  
 -Any supported file format and protocol can serve as input to avconv:
 +Any supported file format and protocol can serve as input to ffmpeg:
  
  Examples:
  @itemize
  You can use YUV files as input:
  
  @example
 -avconv -i /tmp/test%d.Y /tmp/out.mpg
 +ffmpeg -i /tmp/test%d.Y /tmp/out.mpg
  @end example
  
  It will use the files:
  The Y files use twice the resolution of the U and V files. They are
  raw files, without header. They can be generated by all decent video
  decoders. You must specify the size of the image with the @option{-s} option
 -if avconv cannot guess it.
 +if ffmpeg cannot guess it.
  
  @item
  You can input from a raw YUV420P file:
  
  @example
 -avconv -i /tmp/test.yuv /tmp/out.avi
 +ffmpeg -i /tmp/test.yuv /tmp/out.avi
  @end example
  
  test.yuv is a file containing raw YUV planar data. Each frame is composed
@@@ -1202,14 -962,14 +1195,14 @@@ horizontal resolution
  You can output to a raw YUV420P file:
  
  @example
 -avconv -i mydivx.avi hugefile.yuv
 +ffmpeg -i mydivx.avi hugefile.yuv
  @end example
  
  @item
  You can set several input files and output files:
  
  @example
 -avconv -i /tmp/a.wav -s 640x480 -i /tmp/a.yuv /tmp/a.mpg
 +ffmpeg -i /tmp/a.wav -s 640x480 -i /tmp/a.yuv /tmp/a.mpg
  @end example
  
  Converts the audio file a.wav and the raw YUV video file a.yuv
@@@ -1219,7 -979,7 +1212,7 @@@ to MPEG file a.mpg
  You can also do audio and video conversions at the same time:
  
  @example
 -avconv -i /tmp/a.wav -ar 22050 /tmp/a.mp2
 +ffmpeg -i /tmp/a.wav -ar 22050 /tmp/a.mp2
  @end example
  
  Converts a.wav to MPEG audio at 22050 Hz sample rate.
@@@ -1229,7 -989,7 +1222,7 @@@ You can encode to several formats at th
  mapping from input stream to output streams:
  
  @example
 -avconv -i /tmp/a.wav -map 0:a -b 64k /tmp/a.mp2 -map 0:a -b 128k /tmp/b.mp2
 +ffmpeg -i /tmp/a.wav -map 0:a -b:a 64k /tmp/a.mp2 -map 0:a -b:a 128k /tmp/b.mp2
  @end example
  
  Converts a.wav to a.mp2 at 64 kbits and to b.mp2 at 128 kbits. '-map
@@@ -1240,7 -1000,7 +1233,7 @@@ stream, in the order of the definition 
  You can transcode decrypted VOBs:
  
  @example
 -avconv -i snatch_1.vob -f avi -c:v mpeg4 -b:v 800k -g 300 -bf 2 -c:a libmp3lame -b:a 128k snatch.avi
 +ffmpeg -i snatch_1.vob -f avi -c:v mpeg4 -b:v 800k -g 300 -bf 2 -c:a libmp3lame -b:a 128k snatch.avi
  @end example
  
  This is a typical DVD ripping example; the input is a VOB file, the
@@@ -1252,14 -1012,14 +1245,14 @@@ to enable LAME support by passing @code
  The mapping is particularly useful for DVD transcoding
  to get the desired audio language.
  
 -NOTE: To see the supported input formats, use @code{avconv -formats}.
 +NOTE: To see the supported input formats, use @code{ffmpeg -formats}.
  
  @item
  You can extract images from a video, or create a video from many images:
  
  For extracting images from a video:
  @example
 -avconv -i foo.avi -r 1 -s WxH -f image2 foo-%03d.jpeg
 +ffmpeg -i foo.avi -r 1 -s WxH -f image2 foo-%03d.jpeg
  @end example
  
  This will extract one video frame per second from the video and will
@@@ -1272,7 -1032,7 +1265,7 @@@ combination with -ss to start extractin
  
  For creating a video from many images:
  @example
 -avconv -f image2 -i foo-%03d.jpeg -r 12 -s WxH foo.avi
 +ffmpeg -f image2 -i foo-%03d.jpeg -r 12 -s WxH foo.avi
  @end example
  
  The syntax @code{foo-%03d.jpeg} specifies to use a decimal number
@@@ -1280,21 -1040,11 +1273,21 @@@ composed of three digits padded with ze
  number. It is the same syntax supported by the C printf function, but
  only formats accepting a normal integer are suitable.
  
 +When importing an image sequence, -i also supports expanding
 +shell-like wildcard patterns (globbing) internally, by selecting the
 +image2-specific @code{-pattern_type glob} option.
 +
 +For example, for creating a video from filenames matching the glob pattern
 +@code{foo-*.jpeg}:
 +@example
 +ffmpeg -f image2 -pattern_type glob -i 'foo-*.jpeg' -r 12 -s WxH foo.avi
 +@end example
 +
  @item
  You can put many streams of the same type in the output:
  
  @example
 -avconv -i test1.avi -i test2.avi -map 0.3 -map 0.2 -map 0.1 -map 0.0 -c copy test12.nut
 +ffmpeg -i test1.avi -i test2.avi -map 0.3 -map 0.2 -map 0.1 -map 0.0 -c copy test12.nut
  @end example
  
  The resulting output file @file{test12.avi} will contain first four streams from
@@@ -1303,22 -1053,20 +1296,22 @@@ the input file in reverse order
  @item
  To force CBR video output:
  @example
 -avconv -i myfile.avi -b 4000k -minrate 4000k -maxrate 4000k -bufsize 1835k out.m2v
 +ffmpeg -i myfile.avi -b 4000k -minrate 4000k -maxrate 4000k -bufsize 1835k out.m2v
  @end example
  
  @item
  The four options lmin, lmax, mblmin and mblmax use 'lambda' units,
  but you may use the QP2LAMBDA constant to easily convert from 'q' units:
  @example
 -avconv -i src.ext -lmax 21*QP2LAMBDA dst.ext
 +ffmpeg -i src.ext -lmax 21*QP2LAMBDA dst.ext
  @end example
  
  @end itemize
  @c man end EXAMPLES
  
 +@include syntax.texi
  @include eval.texi
 +@include decoders.texi
  @include encoders.texi
  @include demuxers.texi
  @include muxers.texi
  
  @ignore
  
 -@setfilename avconv
 -@settitle avconv video converter
 +@setfilename ffmpeg
 +@settitle ffmpeg video converter
  
  @c man begin SEEALSO
 -avplay(1), avprobe(1) and the Libav HTML documentation
 +ffplay(1), ffprobe(1), ffserver(1) and the FFmpeg HTML documentation
  @c man end
  
  @c man begin AUTHORS
 -The Libav developers
 +See git history
  @c man end
  
  @end ignore
diff --combined ffmpeg_opt.c
@@@ -1,26 -1,26 +1,26 @@@
  /*
 - * avconv option parsing
 + * ffmpeg option parsing
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * FFmpeg is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * FFmpeg is distributed in the hope that it will be useful,
   * 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
 - * License along with Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
  #include <stdint.h>
  
 -#include "avconv.h"
 +#include "ffmpeg.h"
  #include "cmdutils.h"
  
  #include "libavformat/avformat.h"
      }\
  }
  
 -char *pass_logfilename_prefix = NULL;
 +const char *pass_logfilename_prefix;
  char *vstats_filename;
  
  float audio_drift_threshold = 0.1;
  float dts_delta_threshold   = 10;
 +float dts_error_threshold   = 3600*30;
  
  int audio_volume      = 256;
  int audio_sync_method = 0;
  int video_sync_method = VSYNC_AUTO;
  int do_deinterlace    = 0;
  int do_benchmark      = 0;
 +int do_benchmark_all  = 0;
  int do_hex_dump       = 0;
  int do_pkt_dump       = 0;
  int copy_ts           = 0;
 -int copy_tb           = 1;
 +int copy_tb           = -1;
 +int debug_ts          = 0;
  int opt_shortest      = 0;
  int exit_on_error     = 0;
  int print_stats       = 1;
  int qp_hist           = 0;
  int same_quant        = 0;
 +int stdin_interaction = 1;
 +int frame_bits_per_raw_sample = 0;
  
 +
 +static int intra_only         = 0;
 +static const char *video_codec_name    = NULL;
 +static const char *audio_codec_name    = NULL;
 +static const char *subtitle_codec_name = NULL;
  static int file_overwrite     = 0;
 +static int no_file_overwrite  = 0;
  static int video_discard      = 0;
  static int intra_dc_precision = 8;
 +static int do_psnr            = 0;
  static int do_pass            = 0;
 -static int using_stdin        = 0;
  static int input_sync;
  
 -void reset_options(OptionsContext *o)
 +void reset_options(OptionsContext *o, int is_input)
  {
      const OptionDef *po = options;
 +    OptionsContext bak= *o;
      int i;
  
      /* all OPT_SPEC and OPT_STRING can be freed in generic way */
      for (i = 0; i < o->nb_stream_maps; i++)
          av_freep(&o->stream_maps[i].linklabel);
      av_freep(&o->stream_maps);
 -    av_freep(&o->meta_data_maps);
 +    av_freep(&o->audio_channel_maps);
      av_freep(&o->streamid_map);
  
      memset(o, 0, sizeof(*o));
  
 -    o->mux_max_delay  = 0.7;
 +    if (is_input) {
 +        o->recording_time = bak.recording_time;
 +        if (o->recording_time != INT64_MAX)
 +            av_log(NULL, AV_LOG_WARNING,
 +                   "-t is not an input option, keeping it for the next output;"
 +                   " consider fixing your command line.\n");
 +    } else
      o->recording_time = INT64_MAX;
 +    o->mux_max_delay  = 0.7;
      o->limit_filesize = UINT64_MAX;
      o->chapters_input_file = INT_MAX;
  
  }
  
  
 -static double parse_frame_aspect_ratio(const char *arg)
 +static int opt_frame_crop(const char *opt, const char *arg)
  {
 -    int x = 0, y = 0;
 -    double ar = 0;
 -    const char *p;
 -    char *end;
 -
 -    p = strchr(arg, ':');
 -    if (p) {
 -        x = strtol(arg, &end, 10);
 -        if (end == p)
 -            y = strtol(end + 1, &end, 10);
 -        if (x > 0 && y > 0)
 -            ar = (double)x / (double)y;
 -    } else
 -        ar = strtod(arg, NULL);
 +    av_log(NULL, AV_LOG_FATAL, "Option '%s' has been removed, use the crop filter instead\n", opt);
 +    return AVERROR(EINVAL);
 +}
  
 -    if (!ar) {
 -        av_log(NULL, AV_LOG_FATAL, "Incorrect aspect ratio specification.\n");
 -        exit_program(1);
 +static int opt_pad(const char *opt, const char *arg)
 +{
 +    av_log(NULL, AV_LOG_FATAL, "Option '%s' has been removed, use the pad filter instead\n", opt);
 +    return -1;
 +}
 +
 +static int opt_video_channel(const char *opt, const char *arg)
 +{
 +    av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -channel.\n");
 +    return opt_default("channel", arg);
      }
 -    return ar;
 +
 +static int opt_video_standard(const char *opt, const char *arg)
 +{
 +    av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -standard.\n");
 +    return opt_default("standard", arg);
  }
  
  static int opt_audio_codec(void *optctx, const char *opt, const char *arg)
  {
      OptionsContext *o = optctx;
 +    audio_codec_name = arg;
      return parse_option(o, "codec:a", arg, options);
  }
  
  static int opt_video_codec(void *optctx, const char *opt, const char *arg)
  {
      OptionsContext *o = optctx;
 +    video_codec_name = arg;
      return parse_option(o, "codec:v", arg, options);
  }
  
  static int opt_subtitle_codec(void *optctx, const char *opt, const char *arg)
  {
      OptionsContext *o = optctx;
 +    subtitle_codec_name = arg;
      return parse_option(o, "codec:s", arg, options);
  }
  
@@@ -199,7 -177,7 +199,7 @@@ static int opt_map(void *optctx, const 
      OptionsContext *o = optctx;
      StreamMap *m = NULL;
      int i, negative = 0, file_idx;
 -    int sync_file_idx = -1, sync_stream_idx;
 +    int sync_file_idx = -1, sync_stream_idx = 0;
      char *p, *sync;
      char *map;
  
@@@ -300,67 -278,6 +300,67 @@@ static int opt_attach(void *optctx, con
      return 0;
  }
  
 +static int opt_map_channel(void *optctx, const char *opt, const char *arg)
 +{
 +    OptionsContext *o = optctx;
 +    int n;
 +    AVStream *st;
 +    AudioChannelMap *m;
 +
 +    o->audio_channel_maps =
 +        grow_array(o->audio_channel_maps, sizeof(*o->audio_channel_maps),
 +                   &o->nb_audio_channel_maps, o->nb_audio_channel_maps + 1);
 +    m = &o->audio_channel_maps[o->nb_audio_channel_maps - 1];
 +
 +    /* muted channel syntax */
 +    n = sscanf(arg, "%d:%d.%d", &m->channel_idx, &m->ofile_idx, &m->ostream_idx);
 +    if ((n == 1 || n == 3) && m->channel_idx == -1) {
 +        m->file_idx = m->stream_idx = -1;
 +        if (n == 1)
 +            m->ofile_idx = m->ostream_idx = -1;
 +        return 0;
 +    }
 +
 +    /* normal syntax */
 +    n = sscanf(arg, "%d.%d.%d:%d.%d",
 +               &m->file_idx,  &m->stream_idx, &m->channel_idx,
 +               &m->ofile_idx, &m->ostream_idx);
 +
 +    if (n != 3 && n != 5) {
 +        av_log(NULL, AV_LOG_FATAL, "Syntax error, mapchan usage: "
 +               "[file.stream.channel|-1][:syncfile:syncstream]\n");
 +        exit_program(1);
 +    }
 +
 +    if (n != 5) // only file.stream.channel specified
 +        m->ofile_idx = m->ostream_idx = -1;
 +
 +    /* check input */
 +    if (m->file_idx < 0 || m->file_idx >= nb_input_files) {
 +        av_log(NULL, AV_LOG_FATAL, "mapchan: invalid input file index: %d\n",
 +               m->file_idx);
 +        exit_program(1);
 +    }
 +    if (m->stream_idx < 0 ||
 +        m->stream_idx >= input_files[m->file_idx]->nb_streams) {
 +        av_log(NULL, AV_LOG_FATAL, "mapchan: invalid input file stream index #%d.%d\n",
 +               m->file_idx, m->stream_idx);
 +        exit_program(1);
 +    }
 +    st = input_files[m->file_idx]->ctx->streams[m->stream_idx];
 +    if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO) {
 +        av_log(NULL, AV_LOG_FATAL, "mapchan: stream #%d.%d is not an audio stream.\n",
 +               m->file_idx, m->stream_idx);
 +        exit_program(1);
 +    }
 +    if (m->channel_idx < 0 || m->channel_idx >= st->codec->channels) {
 +        av_log(NULL, AV_LOG_FATAL, "mapchan: invalid audio channel #%d.%d.%d\n",
 +               m->file_idx, m->stream_idx, m->channel_idx);
 +        exit_program(1);
 +    }
 +    return 0;
 +}
 +
  /**
   * Parse a metadata specifier in arg.
   * @param type metadata type is written here -- g(lobal)/s(tream)/c(hapter)/p(rogram)
@@@ -397,7 -314,7 +397,7 @@@ static void parse_meta_type(char *arg, 
  static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFormatContext *ic, OptionsContext *o)
  {
      AVDictionary **meta_in = NULL;
 -    AVDictionary **meta_out;
 +    AVDictionary **meta_out = NULL;
      int i, ret = 0;
      char type_in, type_out;
      const char *istream_spec = NULL, *ostream_spec = NULL;
      parse_meta_type(inspec,  &type_in,  &idx_in,  &istream_spec);
      parse_meta_type(outspec, &type_out, &idx_out, &ostream_spec);
  
 +    if (!ic) {
 +        if (type_out == 'g' || !*outspec)
 +            o->metadata_global_manual = 1;
 +        if (type_out == 's' || !*outspec)
 +            o->metadata_streams_manual = 1;
 +        if (type_out == 'c' || !*outspec)
 +            o->metadata_chapters_manual = 1;
 +        return 0;
 +    }
 +
      if (type_in == 'g' || type_out == 'g')
          o->metadata_global_manual = 1;
      if (type_in == 's' || type_out == 's')
      return 0;
  }
  
 +static int opt_recording_timestamp(void *optctx, const char *opt, const char *arg)
 +{
 +    OptionsContext *o = optctx;
 +    char buf[128];
 +    int64_t recording_timestamp = parse_time_or_die(opt, arg, 0) / 1E6;
 +    struct tm time = *gmtime((time_t*)&recording_timestamp);
 +    strftime(buf, sizeof(buf), "creation_time=%FT%T%z", &time);
 +    parse_option(o, "metadata", buf, options);
 +
 +    av_log(NULL, AV_LOG_WARNING, "%s is deprecated, set the 'creation_time' metadata "
 +                                 "tag instead.\n", opt);
 +    return 0;
 +}
 +
  static AVCodec *find_codec_or_die(const char *name, enum AVMediaType type, int encoder)
  {
      const AVCodecDescriptor *desc;
@@@ -541,7 -434,6 +541,7 @@@ static AVCodec *choose_decoder(OptionsC
  static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
  {
      int i;
 +    char *next, *codec_tag = NULL;
  
      for (i = 0; i < ic->nb_streams; i++) {
          AVStream *st = ic->streams[i];
          ist->file_index = nb_input_files;
          ist->discard = 1;
          st->discard  = AVDISCARD_ALL;
 -        ist->opts = filter_codec_opts(codec_opts, ist->st->codec->codec_id, ic, st, NULL);
 +        ist->opts = filter_codec_opts(codec_opts, ist->st->codec->codec_id, ic, st, choose_decoder(o, ic, st));
  
          ist->ts_scale = 1.0;
          MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st);
  
 +        MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, ic, st);
 +        if (codec_tag) {
 +            uint32_t tag = strtol(codec_tag, &next, 0);
 +            if (*next)
 +                tag = AV_RL32(codec_tag);
 +            st->codec->codec_tag = tag;
 +        }
 +
          ist->dec = choose_decoder(o, ic, st);
  
          switch (dec->codec_type) {
          case AVMEDIA_TYPE_VIDEO:
 +            if(!ist->dec)
 +                ist->dec = avcodec_find_decoder(dec->codec_id);
 +            if (dec->lowres) {
 +                dec->flags |= CODEC_FLAG_EMU_EDGE;
 +            }
 +
              ist->resample_height  = dec->height;
              ist->resample_width   = dec->width;
              ist->resample_pix_fmt = dec->pix_fmt;
                  exit_program(1);
              }
  
 +            ist->top_field_first = -1;
 +            MATCH_PER_STREAM_OPT(top_field_first, i, ist->top_field_first, ic, st);
 +
              break;
          case AVMEDIA_TYPE_AUDIO:
              guess_input_channel_layout(ist);
              break;
          case AVMEDIA_TYPE_DATA:
          case AVMEDIA_TYPE_SUBTITLE:
 +            if(!ist->dec)
 +                ist->dec = avcodec_find_decoder(dec->codec_id);
 +            MATCH_PER_STREAM_OPT(fix_sub_duration, i, ist->fix_sub_duration, ic, st);
 +            break;
          case AVMEDIA_TYPE_ATTACHMENT:
          case AVMEDIA_TYPE_UNKNOWN:
              break;
  
  static void assert_file_overwrite(const char *filename)
  {
 -    if (!file_overwrite &&
 +    if ((!file_overwrite || no_file_overwrite) &&
          (strchr(filename, ':') == NULL || filename[1] == ':' ||
           av_strstart(filename, "file:", NULL))) {
          if (avio_check(filename, 0) == 0) {
 -            if (!using_stdin) {
 +            if (stdin_interaction && (!no_file_overwrite || file_overwrite)) {
                  fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename);
                  fflush(stderr);
 +                term_exit();
 +                signal(SIGINT, SIG_DFL);
                  if (!read_yesno()) {
 -                    fprintf(stderr, "Not overwriting - exiting\n");
 +                    av_log(NULL, AV_LOG_FATAL, "Not overwriting - exiting\n");
                      exit_program(1);
                  }
 +                term_init();
              }
              else {
 -                fprintf(stderr,"File '%s' already exists. Exiting.\n", filename);
 +                av_log(NULL, AV_LOG_FATAL, "File '%s' already exists. Exiting.\n", filename);
                  exit_program(1);
              }
          }
@@@ -700,8 -568,8 +700,8 @@@ static int opt_input_file(void *optctx
      if (!strcmp(filename, "-"))
          filename = "pipe:";
  
 -    using_stdin |= !strncmp(filename, "pipe:", 5) ||
 -                    !strcmp(filename, "/dev/stdin");
 +    stdin_interaction &= strncmp(filename, "pipe:", 5) &&
 +                         strcmp(filename, "/dev/stdin");
  
      /* get default parameters from command line */
      ic = avformat_alloc_context();
      if (o->nb_frame_pix_fmts)
          av_dict_set(&format_opts, "pixel_format", o->frame_pix_fmts[o->nb_frame_pix_fmts - 1].u.str, 0);
  
 +    ic->video_codec_id   = video_codec_name ?
 +        find_codec_or_die(video_codec_name   , AVMEDIA_TYPE_VIDEO   , 0)->id : AV_CODEC_ID_NONE;
 +    ic->audio_codec_id   = audio_codec_name ?
 +        find_codec_or_die(audio_codec_name   , AVMEDIA_TYPE_AUDIO   , 0)->id : AV_CODEC_ID_NONE;
 +    ic->subtitle_codec_id= subtitle_codec_name ?
 +        find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0)->id : AV_CODEC_ID_NONE;
      ic->flags |= AVFMT_FLAG_NONBLOCK;
      ic->interrupt_callback = int_cb;
  
 -    /* open the input file with generic libav function */
 +    /* open the input file with generic avformat function */
      err = avformat_open_input(&ic, filename, file_iformat, &format_opts);
      if (err < 0) {
          print_error(filename, err);
          av_dict_free(&opts[i]);
      av_freep(&opts);
  
 -    reset_options(o);
 +    reset_options(o, 1);
      return 0;
  }
  
@@@ -886,7 -748,7 +886,7 @@@ static void choose_encoder(OptionsConte
      }
  }
  
 -static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type)
 +static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type, int source_index)
  {
      OutputStream *ost;
      AVStream *st = avformat_new_stream(oc, NULL);
          st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
  
      av_opt_get_int(sws_opts, "sws_flags", 0, &ost->sws_flags);
 -
 -    ost->pix_fmts[0] = ost->pix_fmts[1] = PIX_FMT_NONE;
 +    av_opt_get_int   (swr_opts, "dither_method", 0, &ost->swr_dither_method);
 +    av_opt_get_double(swr_opts, "dither_scale" , 0, &ost->swr_dither_scale);
 +
 +    ost->source_index = source_index;
 +    if (source_index >= 0) {
 +        ost->sync_ist = input_streams[source_index];
 +        input_streams[source_index]->discard = 0;
 +        input_streams[source_index]->st->discard = AVDISCARD_NONE;
 +    }
  
      return ost;
  }
@@@ -1016,31 -871,30 +1016,31 @@@ static void parse_matrix_coeffs(uint16_
      }
  }
  
 -static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc)
 +static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
  {
      AVStream *st;
      OutputStream *ost;
      AVCodecContext *video_enc;
 +    char *frame_rate = NULL;
  
 -    ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO);
 +    ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO, source_index);
      st  = ost->st;
      video_enc = st->codec;
  
 +    MATCH_PER_STREAM_OPT(frame_rates, str, frame_rate, oc, st);
 +    if (frame_rate && av_parse_video_rate(&ost->frame_rate, frame_rate) < 0) {
 +        av_log(NULL, AV_LOG_FATAL, "Invalid framerate value: %s\n", frame_rate);
 +        exit_program(1);
 +    }
 +
      if (!ost->stream_copy) {
          const char *p = NULL;
 -        char *frame_rate = NULL, *frame_size = NULL;
 +        char *frame_size = NULL;
          char *frame_aspect_ratio = NULL, *frame_pix_fmt = NULL;
          char *intra_matrix = NULL, *inter_matrix = NULL;
          const char *filters = "null";
          int i;
  
 -        MATCH_PER_STREAM_OPT(frame_rates, str, frame_rate, oc, st);
 -        if (frame_rate && av_parse_video_rate(&ost->frame_rate, frame_rate) < 0) {
 -            av_log(NULL, AV_LOG_FATAL, "Invalid framerate value: %s\n", frame_rate);
 -            exit_program(1);
 -        }
 -
          MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
          if (frame_size && av_parse_video_size(&video_enc->width, &video_enc->height, frame_size) < 0) {
              av_log(NULL, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size);
          }
  
          MATCH_PER_STREAM_OPT(frame_aspect_ratios, str, frame_aspect_ratio, oc, st);
 -        if (frame_aspect_ratio)
 -            ost->frame_aspect_ratio = parse_frame_aspect_ratio(frame_aspect_ratio);
 +        if (frame_aspect_ratio) {
 +            AVRational q;
 +            if (av_parse_ratio(&q, frame_aspect_ratio, 255, 0, NULL) < 0 ||
 +                q.num <= 0 || q.den <= 0) {
 +                av_log(NULL, AV_LOG_FATAL, "Invalid aspect ratio: %s\n", frame_aspect_ratio);
 +                exit_program(1);
 +            }
 +            ost->frame_aspect_ratio = av_q2d(q);
 +        }
  
 +        video_enc->bits_per_raw_sample = frame_bits_per_raw_sample;
          MATCH_PER_STREAM_OPT(frame_pix_fmts, str, frame_pix_fmt, oc, st);
 +        if (frame_pix_fmt && *frame_pix_fmt == '+') {
 +            ost->keep_pix_fmt = 1;
 +            if (!*++frame_pix_fmt)
 +                frame_pix_fmt = NULL;
 +        }
          if (frame_pix_fmt && (video_enc->pix_fmt = av_get_pix_fmt(frame_pix_fmt)) == PIX_FMT_NONE) {
              av_log(NULL, AV_LOG_FATAL, "Unknown pixel format requested: %s.\n", frame_pix_fmt);
              exit_program(1);
          }
          st->sample_aspect_ratio = video_enc->sample_aspect_ratio;
  
 +        if (intra_only)
 +            video_enc->gop_size = 0;
          MATCH_PER_STREAM_OPT(intra_matrices, str, intra_matrix, oc, st);
          if (intra_matrix) {
              if (!(video_enc->intra_matrix = av_mallocz(sizeof(*video_enc->intra_matrix) * 64))) {
                  av_log(NULL, AV_LOG_FATAL, "error parsing rc_override\n");
                  exit_program(1);
              }
 +            /* FIXME realloc failure */
              video_enc->rc_override =
                  av_realloc(video_enc->rc_override,
                             sizeof(RcOverride) * (i + 1));
              video_enc->rc_initial_buffer_occupancy = video_enc->rc_buffer_size * 3 / 4;
          video_enc->intra_dc_precision = intra_dc_precision - 8;
  
 +        if (do_psnr)
 +            video_enc->flags|= CODEC_FLAG_PSNR;
 +
          /* two pass mode */
          if (do_pass) {
 -            if (do_pass == 1) {
 +            if (do_pass & 1) {
                  video_enc->flags |= CODEC_FLAG_PASS1;
 -            } else {
 +            }
 +            if (do_pass & 2) {
                  video_enc->flags |= CODEC_FLAG_PASS2;
              }
          }
      return ost;
  }
  
 -static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc)
 +static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
  {
 +    int n;
      AVStream *st;
      OutputStream *ost;
      AVCodecContext *audio_enc;
  
 -    ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO);
 +    ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO, source_index);
      st  = ost->st;
  
      audio_enc = st->codec;
          MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st);
  
          MATCH_PER_STREAM_OPT(filters, str, filters, oc, st);
 +
 +        av_assert1(filters);
          ost->avfilter = av_strdup(filters);
 +
 +        /* check for channel mapping for this audio stream */
 +        for (n = 0; n < o->nb_audio_channel_maps; n++) {
 +            AudioChannelMap *map = &o->audio_channel_maps[n];
 +            InputStream *ist = input_streams[ost->source_index];
 +            if ((map->channel_idx == -1 || (ist->file_index == map->file_idx && ist->st->index == map->stream_idx)) &&
 +                (map->ofile_idx   == -1 || ost->file_index == map->ofile_idx) &&
 +                (map->ostream_idx == -1 || ost->st->index  == map->ostream_idx)) {
 +                if (ost->audio_channels_mapped < FF_ARRAY_ELEMS(ost->audio_channels_map))
 +                    ost->audio_channels_map[ost->audio_channels_mapped++] = map->channel_idx;
 +                else
 +                    av_log(NULL, AV_LOG_FATAL, "Max channel mapping for output %d.%d reached\n",
 +                           ost->file_index, ost->st->index);
 +            }
 +        }
      }
  
      return ost;
  }
  
 -static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc)
 +static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
  {
      OutputStream *ost;
  
 -    ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA);
 +    ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA, source_index);
      if (!ost->stream_copy) {
          av_log(NULL, AV_LOG_FATAL, "Data stream encoding not supported yet (only streamcopy)\n");
          exit_program(1);
      return ost;
  }
  
 -static OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *oc)
 +static OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
  {
 -    OutputStream *ost = new_output_stream(o, oc, AVMEDIA_TYPE_ATTACHMENT);
 +    OutputStream *ost = new_output_stream(o, oc, AVMEDIA_TYPE_ATTACHMENT, source_index);
      ost->stream_copy = 1;
      return ost;
  }
  
 -static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc)
 +static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
  {
      AVStream *st;
      OutputStream *ost;
      AVCodecContext *subtitle_enc;
  
 -    ost = new_output_stream(o, oc, AVMEDIA_TYPE_SUBTITLE);
 +    ost = new_output_stream(o, oc, AVMEDIA_TYPE_SUBTITLE, source_index);
      st  = ost->st;
      subtitle_enc = st->codec;
  
      subtitle_enc->codec_type = AVMEDIA_TYPE_SUBTITLE;
  
 +    MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc, st);
 +
 +    if (!ost->stream_copy) {
 +        char *frame_size = NULL;
 +
 +        MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
 +        if (frame_size && av_parse_video_size(&subtitle_enc->width, &subtitle_enc->height, frame_size) < 0) {
 +            av_log(NULL, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size);
 +            exit_program(1);
 +        }
 +    }
 +
      return ost;
  }
  
@@@ -1267,7 -1071,7 +1267,7 @@@ static int opt_streamid(void *optctx, c
          exit_program(1);
      }
      *p++ = '\0';
 -    idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, INT_MAX);
 +    idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, MAX_STREAMS-1);
      o->streamid_map = grow_array(o->streamid_map, sizeof(*o->streamid_map), &o->nb_streamid_map, idx+1);
      o->streamid_map[idx] = parse_number_or_die(opt, p, OPT_INT, 0, INT_MAX);
      return 0;
@@@ -1305,7 -1109,7 +1305,7 @@@ static int copy_chapters(InputFile *ifi
              av_dict_copy(&out_ch->metadata, in_ch->metadata, 0);
  
          os->nb_chapters++;
 -        os->chapters = av_realloc(os->chapters, sizeof(AVChapter) * os->nb_chapters);
 +        os->chapters = av_realloc_f(os->chapters, os->nb_chapters, sizeof(AVChapter));
          if (!os->chapters)
              return AVERROR(ENOMEM);
          os->chapters[os->nb_chapters - 1] = out_ch;
      return 0;
  }
  
 +static int read_ffserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename)
 +{
 +    int i, err;
 +    AVFormatContext *ic = avformat_alloc_context();
 +
 +    ic->interrupt_callback = int_cb;
 +    err = avformat_open_input(&ic, filename, NULL, NULL);
 +    if (err < 0)
 +        return err;
 +    /* copy stream format */
 +    for(i=0;i<ic->nb_streams;i++) {
 +        AVStream *st;
 +        OutputStream *ost;
 +        AVCodec *codec;
 +        AVCodecContext *avctx;
 +
 +        codec = avcodec_find_encoder(ic->streams[i]->codec->codec_id);
 +        ost   = new_output_stream(o, s, codec->type, -1);
 +        st    = ost->st;
 +        avctx = st->codec;
 +        ost->enc = codec;
 +
 +        // FIXME: a more elegant solution is needed
 +        memcpy(st, ic->streams[i], sizeof(AVStream));
 +        st->cur_dts = 0;
 +        st->info = av_malloc(sizeof(*st->info));
 +        memcpy(st->info, ic->streams[i]->info, sizeof(*st->info));
 +        st->codec= avctx;
 +        avcodec_copy_context(st->codec, ic->streams[i]->codec);
 +
 +        if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && !ost->stream_copy)
 +            choose_sample_fmt(st, codec);
 +        else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && !ost->stream_copy)
 +            choose_pixel_fmt(st, codec, st->codec->pix_fmt);
 +    }
 +
 +    avformat_close_input(&ic);
 +    return 0;
 +}
 +
  static void init_output_filter(OutputFilter *ofilter, OptionsContext *o,
                                 AVFormatContext *oc)
  {
  
      switch (avfilter_pad_get_type(ofilter->out_tmp->filter_ctx->output_pads,
                                    ofilter->out_tmp->pad_idx)) {
 -    case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc); break;
 -    case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc); break;
 +    case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc, -1); break;
 +    case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc, -1); break;
      default:
          av_log(NULL, AV_LOG_FATAL, "Only video and audio filters are supported "
                 "currently.\n");
                 "cannot be used together.\n", ost->file_index, ost->index);
          exit_program(1);
      }
 +    if (o->recording_time != INT64_MAX)
 +        av_log(NULL, AV_LOG_WARNING,
 +               "-t does not work with -filter_complex (yet).\n");
  
      if (configure_output_filter(ofilter->graph, ofilter, ofilter->out_tmp) < 0) {
          av_log(NULL, AV_LOG_FATAL, "Error configuring filter.\n");
@@@ -1418,13 -1179,30 +1418,13 @@@ void opt_output_file(void *optctx, cons
      if (!strcmp(filename, "-"))
          filename = "pipe:";
  
 -    oc = avformat_alloc_context();
 +    err = avformat_alloc_output_context2(&oc, NULL, o->format, filename);
      if (!oc) {
 -        print_error(filename, AVERROR(ENOMEM));
 +        print_error(filename, err);
          exit_program(1);
      }
 -
 -    if (o->format) {
 -        file_oformat = av_guess_format(o->format, NULL, NULL);
 -        if (!file_oformat) {
 -            av_log(NULL, AV_LOG_FATAL, "Requested output format '%s' is not a suitable output format\n", o->format);
 -            exit_program(1);
 -        }
 -    } else {
 -        file_oformat = av_guess_format(NULL, filename, NULL);
 -        if (!file_oformat) {
 -            av_log(NULL, AV_LOG_FATAL, "Unable to find a suitable output format for '%s'\n",
 -                   filename);
 -            exit_program(1);
 -        }
 -    }
 -
 -    oc->oformat = file_oformat;
 +    file_oformat= oc->oformat;
      oc->interrupt_callback = int_cb;
 -    av_strlcpy(oc->filename, filename, sizeof(oc->filename));
  
      /* create streams for all unlabeled output pads */
      for (i = 0; i < nb_filtergraphs; i++) {
          }
      }
  
 -    if (!o->nb_stream_maps) {
 -        /* pick the "best" stream of each type */
 -#define NEW_STREAM(type, index)\
 -        if (index >= 0) {\
 -            ost = new_ ## type ## _stream(o, oc);\
 -            ost->source_index = index;\
 -            ost->sync_ist     = input_streams[index];\
 -            input_streams[index]->discard = 0;\
 -            input_streams[index]->st->discard = AVDISCARD_NONE;\
 +    if (!strcmp(file_oformat->name, "ffm") &&
 +        av_strstart(filename, "http:", NULL)) {
 +        int j;
 +        /* special case for files sent to ffserver: we get the stream
 +           parameters from ffserver */
 +        int err = read_ffserver_streams(o, oc, filename);
 +        if (err < 0) {
 +            print_error(filename, err);
 +            exit_program(1);
 +        }
 +        for(j = nb_output_streams - oc->nb_streams; j < nb_output_streams; j++) {
 +            ost = output_streams[j];
 +            for (i = 0; i < nb_input_streams; i++) {
 +                ist = input_streams[i];
 +                if(ist->st->codec->codec_type == ost->st->codec->codec_type){
 +                    ost->sync_ist= ist;
 +                    ost->source_index= i;
 +                    if(ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO) ost->avfilter = av_strdup("anull");
 +                    if(ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) ost->avfilter = av_strdup("null");
 +                    ist->discard = 0;
 +                    ist->st->discard = AVDISCARD_NONE;
 +                    break;
 +                }
 +            }
 +            if(!ost->sync_ist){
 +                av_log(NULL, AV_LOG_FATAL, "Missing %s stream which is required by this ffm\n", av_get_media_type_string(ost->st->codec->codec_type));
 +                exit_program(1);
 +            }
          }
 +    } else if (!o->nb_stream_maps) {
 +        /* pick the "best" stream of each type */
  
          /* video: highest resolution */
          if (!o->video_disable && oc->oformat->video_codec != AV_CODEC_ID_NONE) {
              int area = 0, idx = -1;
 +            int qcr = avformat_query_codec(oc->oformat, oc->oformat->video_codec, 0);
              for (i = 0; i < nb_input_streams; i++) {
                  ist = input_streams[i];
                  if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
                      ist->st->codec->width * ist->st->codec->height > area) {
 +                    if((qcr==MKTAG('A', 'P', 'I', 'C')) && !(ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
 +                        continue;
                      area = ist->st->codec->width * ist->st->codec->height;
                      idx = i;
                  }
              }
 -            NEW_STREAM(video, idx);
 +            if (idx >= 0)
 +                new_video_stream(o, oc, idx);
          }
  
          /* audio: most channels */
                      idx = i;
                  }
              }
 -            NEW_STREAM(audio, idx);
 +            if (idx >= 0)
 +                new_audio_stream(o, oc, idx);
          }
  
          /* subtitles: pick first */
 -        if (!o->subtitle_disable && oc->oformat->subtitle_codec != AV_CODEC_ID_NONE) {
 +        if (!o->subtitle_disable && (oc->oformat->subtitle_codec != AV_CODEC_ID_NONE || subtitle_codec_name)) {
              for (i = 0; i < nb_input_streams; i++)
                  if (input_streams[i]->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
 -                    NEW_STREAM(subtitle, i);
 +                    new_subtitle_stream(o, oc, i);
                      break;
                  }
          }
      } else {
          for (i = 0; i < o->nb_stream_maps; i++) {
              StreamMap *map = &o->stream_maps[i];
 +            int src_idx = input_files[map->file_index]->ist_index + map->stream_index;
  
              if (map->disabled)
                  continue;
@@@ -1551,42 -1302,27 +1551,42 @@@ loop_end
                  init_output_filter(ofilter, o, oc);
              } else {
                  ist = input_streams[input_files[map->file_index]->ist_index + map->stream_index];
 +                if(o->subtitle_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE)
 +                    continue;
 +                if(o->   audio_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
 +                    continue;
 +                if(o->   video_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
 +                    continue;
 +                if(o->    data_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_DATA)
 +                    continue;
 +
                  switch (ist->st->codec->codec_type) {
 -                case AVMEDIA_TYPE_VIDEO:    ost = new_video_stream(o, oc);    break;
 -                case AVMEDIA_TYPE_AUDIO:    ost = new_audio_stream(o, oc);    break;
 -                case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream(o, oc); break;
 -                case AVMEDIA_TYPE_DATA:     ost = new_data_stream(o, oc);     break;
 -                case AVMEDIA_TYPE_ATTACHMENT: ost = new_attachment_stream(o, oc); break;
 +                case AVMEDIA_TYPE_VIDEO:      ost = new_video_stream     (o, oc, src_idx); break;
 +                case AVMEDIA_TYPE_AUDIO:      ost = new_audio_stream     (o, oc, src_idx); break;
 +                case AVMEDIA_TYPE_SUBTITLE:   ost = new_subtitle_stream  (o, oc, src_idx); break;
 +                case AVMEDIA_TYPE_DATA:       ost = new_data_stream      (o, oc, src_idx); break;
 +                case AVMEDIA_TYPE_ATTACHMENT: ost = new_attachment_stream(o, oc, src_idx); break;
                  default:
                      av_log(NULL, AV_LOG_FATAL, "Cannot map stream #%d:%d - unsupported type.\n",
                             map->file_index, map->stream_index);
                      exit_program(1);
                  }
 -
 -                ost->source_index = input_files[map->file_index]->ist_index + map->stream_index;
 -                ost->sync_ist     = input_streams[input_files[map->sync_file_index]->ist_index +
 -                                               map->sync_stream_index];
 -                ist->discard = 0;
 -                ist->st->discard = AVDISCARD_NONE;
              }
          }
      }
  
 +
 +    for (i = nb_output_streams - oc->nb_streams; i < nb_output_streams; i++) { //for all streams of this output file
 +        AVDictionaryEntry *e;
 +        ost = output_streams[i];
 +
 +        if (   ost->stream_copy
 +            && (e = av_dict_get(codec_opts, "flags", NULL, AV_DICT_IGNORE_SUFFIX))
 +            && (!e->key[5] || check_stream_specifier(oc, ost->st, e->key+6)))
 +            if (av_opt_set(ost->st->codec, "flags", e->value, 0) < 0)
 +                exit_program(1);
 +    }
 +
      /* handle attached files */
      for (i = 0; i < o->nb_attachments; i++) {
          AVIOContext *pb;
          }
          avio_read(pb, attachment, len);
  
 -        ost = new_attachment_stream(o, oc);
 +        ost = new_attachment_stream(o, oc, -1);
          ost->stream_copy               = 0;
 -        ost->source_index              = -1;
          ost->attachment_filename       = o->attachments[i];
          ost->st->codec->extradata      = attachment;
          ost->st->codec->extradata_size = len;
          av_dict_set(&output_files[nb_output_files - 1]->opts, "preload", buf, 0);
      }
      oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE);
 -    oc->flags |= AVFMT_FLAG_NONBLOCK;
  
      /* copy metadata */
      for (i = 0; i < o->nb_metadata_map; i++) {
          char *p;
          int in_file_index = strtol(o->metadata_map[i].u.str, &p, 0);
  
 -        if (in_file_index < 0)
 -            continue;
          if (in_file_index >= nb_input_files) {
              av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d while processing metadata maps\n", in_file_index);
              exit_program(1);
          }
 -        copy_metadata(o->metadata_map[i].specifier, *p ? p + 1 : p, oc, input_files[in_file_index]->ctx, o);
 +        copy_metadata(o->metadata_map[i].specifier, *p ? p + 1 : p, oc, in_file_index >= 0 ? input_files[in_file_index]->ctx : NULL, o);
      }
  
      /* copy chapters */
                        !o->metadata_chapters_manual);
  
      /* copy global metadata by default */
 -    if (!o->metadata_global_manual && nb_input_files)
 +    if (!o->metadata_global_manual && nb_input_files){
          av_dict_copy(&oc->metadata, input_files[0]->ctx->metadata,
                       AV_DICT_DONT_OVERWRITE);
 +        if(o->recording_time != INT64_MAX)
 +            av_dict_set(&oc->metadata, "duration", NULL, 0);
 +        av_dict_set(&oc->metadata, "creation_time", NULL, 0);
 +    }
      if (!o->metadata_streams_manual)
          for (i = output_files[nb_output_files - 1]->ost_index; i < nb_output_streams; i++) {
              InputStream *ist;
          AVDictionary **m;
          char type, *val;
          const char *stream_spec;
 -        int index = 0, j, ret;
 +        int index = 0, j, ret = 0;
  
          val = strchr(o->metadata[i].u.str, '=');
          if (!val) {
          }
      }
  
 -    reset_options(o);
 +    reset_options(o, 0);
  }
  
  /* same option as mencoder */
  static int opt_pass(const char *opt, const char *arg)
  {
 -    do_pass = parse_number_or_die(opt, arg, OPT_INT, 1, 2);
 +    do_pass = parse_number_or_die(opt, arg, OPT_INT, 1, 3);
      return 0;
  }
  
@@@ -1825,7 -1561,7 +1825,7 @@@ static int opt_target(void *optctx, con
          parse_option(o, "r", frame_rates[norm], options);
          opt_default("g", norm == PAL ? "15" : "18");
  
 -        opt_default("b", "1150000");
 +        opt_default("b:v", "1150000");
          opt_default("maxrate", "1150000");
          opt_default("minrate", "1150000");
          opt_default("bufsize", "327680"); // 40*1024*8;
  
          parse_option(o, "s", norm == PAL ? "480x576" : "480x480", options);
          parse_option(o, "r", frame_rates[norm], options);
 +        parse_option(o, "pix_fmt", "yuv420p", options);
          opt_default("g", norm == PAL ? "15" : "18");
  
 -        opt_default("b", "2040000");
 +        opt_default("b:v", "2040000");
          opt_default("maxrate", "2516000");
          opt_default("minrate", "0"); // 1145000;
          opt_default("bufsize", "1835008"); // 224*1024*8;
 -        opt_default("flags", "+scan_offset");
 +        opt_default("scan_offset", "1");
  
  
          opt_default("b:a", "224000");
  
          parse_option(o, "s", norm == PAL ? "720x576" : "720x480", options);
          parse_option(o, "r", frame_rates[norm], options);
 +        parse_option(o, "pix_fmt", "yuv420p", options);
          opt_default("g", norm == PAL ? "15" : "18");
  
 -        opt_default("b", "6000000");
 +        opt_default("b:v", "6000000");
          opt_default("maxrate", "9000000");
          opt_default("minrate", "0"); // 1500000;
          opt_default("bufsize", "1835008"); // 224*1024*8;
@@@ -1943,105 -1677,22 +1943,105 @@@ static int opt_data_frames(void *optctx
      return parse_option(o, "frames:d", arg, options);
  }
  
 -static int opt_video_tag(void *optctx, const char *opt, const char *arg)
 +static int opt_preset(void *optctx, const char *opt, const char *arg)
 +{
 +    OptionsContext *o = optctx;
 +    FILE *f=NULL;
 +    char filename[1000], line[1000], tmp_line[1000];
 +    const char *codec_name = *opt == 'v' ? video_codec_name :
 +                             *opt == 'a' ? audio_codec_name :
 +                                           subtitle_codec_name;
 +
 +    if (!(f = get_preset_file(filename, sizeof(filename), arg, *opt == 'f', codec_name))) {
 +        if(!strncmp(arg, "libx264-lossless", strlen("libx264-lossless"))){
 +            av_log(NULL, AV_LOG_FATAL, "Please use -preset <speed> -qp 0\n");
 +        }else
 +            av_log(NULL, AV_LOG_FATAL, "File for preset '%s' not found\n", arg);
 +        exit_program(1);
 +}
 +
 +    while (fgets(line, sizeof(line), f)) {
 +        char *key = tmp_line, *value, *endptr;
 +
 +        if (strcspn(line, "#\n\r") == 0)
 +            continue;
 +        strcpy(tmp_line, line);
 +        if (!av_strtok(key,   "=",    &value) ||
 +            !av_strtok(value, "\r\n", &endptr)) {
 +            av_log(NULL, AV_LOG_FATAL, "%s: Invalid syntax: '%s'\n", filename, line);
 +            exit_program(1);
 +        }
 +        av_log(NULL, AV_LOG_DEBUG, "ffpreset[%s]: set '%s' = '%s'\n", filename, key, value);
 +
 +        if      (!strcmp(key, "acodec")) opt_audio_codec   (o, key, value);
 +        else if (!strcmp(key, "vcodec")) opt_video_codec   (o, key, value);
 +        else if (!strcmp(key, "scodec")) opt_subtitle_codec(o, key, value);
 +        else if (!strcmp(key, "dcodec")) opt_data_codec    (o, key, value);
 +        else if (opt_default(key, value) < 0) {
 +            av_log(NULL, AV_LOG_FATAL, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n",
 +                   filename, line, key, value);
 +            exit_program(1);
 +        }
 +    }
 +
 +    fclose(f);
 +
 +    return 0;
 +}
 +
 +static int opt_passlogfile(const char *opt, const char *arg)
 +{
 +    pass_logfilename_prefix = arg;
 +#if CONFIG_LIBX264_ENCODER
 +    return opt_default(opt, arg);
 +#else
 +    return 0;
 +#endif
 +}
 +
 +static int opt_old2new(void *optctx, const char *opt, const char *arg)
  {
      OptionsContext *o = optctx;
 -    return parse_option(o, "tag:v", arg, options);
 +    char *s = av_asprintf("%s:%c", opt + 1, *opt);
 +    int ret = parse_option(o, s, arg, options);
 +    av_free(s);
 +    return ret;
  }
  
 -static int opt_audio_tag(void *optctx, const char *opt, const char *arg)
 +static int opt_bitrate(void *optctx, const char *opt, const char *arg)
  {
      OptionsContext *o = optctx;
 -    return parse_option(o, "tag:a", arg, options);
 +    if(!strcmp(opt, "b")){
 +        av_log(NULL, AV_LOG_WARNING, "Please use -b:a or -b:v, -b is ambiguous\n");
 +        return parse_option(o, "b:v", arg, options);
 +    }
 +    return opt_default(opt, arg);
  }
  
 -static int opt_subtitle_tag(void *optctx, const char *opt, const char *arg)
 +static int opt_qscale(void *optctx, const char *opt, const char *arg)
  {
      OptionsContext *o = optctx;
 -    return parse_option(o, "tag:s", arg, options);
 +    char *s;
 +    int ret;
 +    if(!strcmp(opt, "qscale")){
 +        av_log(NULL, AV_LOG_WARNING, "Please use -q:a or -q:v, -qscale is ambiguous\n");
 +        return parse_option(o, "q:v", arg, options);
 +    }
 +    s = av_asprintf("q%s", opt + 6);
 +    ret = parse_option(o, s, arg, options);
 +    av_free(s);
 +    return ret;
 +}
 +
 +static int opt_profile(void *optctx, const char *opt, const char *arg)
 +{
 +    OptionsContext *o = optctx;
 +    if(!strcmp(opt, "profile")){
 +        av_log(NULL, AV_LOG_WARNING, "Please use -profile:a or -profile:v, -profile is ambiguous\n");
 +        return parse_option(o, "profile:v", arg, options);
 +    }
 +    return opt_default(opt, arg);
 +
  }
  
  static int opt_video_filters(void *optctx, const char *opt, const char *arg)
@@@ -2061,7 -1712,6 +2061,7 @@@ static int opt_vsync(const char *opt, c
      if      (!av_strcasecmp(arg, "cfr"))         video_sync_method = VSYNC_CFR;
      else if (!av_strcasecmp(arg, "vfr"))         video_sync_method = VSYNC_VFR;
      else if (!av_strcasecmp(arg, "passthrough")) video_sync_method = VSYNC_PASSTHROUGH;
 +    else if (!av_strcasecmp(arg, "drop"))        video_sync_method = VSYNC_DROP;
  
      if (video_sync_method == VSYNC_AUTO)
          video_sync_method = parse_number_or_die("vsync", arg, OPT_INT, VSYNC_AUTO, VSYNC_VFR);
@@@ -2075,15 -1725,15 +2075,15 @@@ static int opt_deinterlace(const char *
      return 0;
  }
  
 -int opt_cpuflags(const char *opt, const char *arg)
 +static int opt_timecode(void *optctx, const char *opt, const char *arg)
  {
 -    int flags = av_parse_cpu_flags(arg);
 -
 -    if (flags < 0)
 -        return flags;
 -
 -    av_set_cpu_flags_mask(flags);
 -    return 0;
 +    OptionsContext *o = optctx;
 +    char *tcr = av_asprintf("timecode=%s", arg);
 +    int ret = parse_option(o, "metadata:g", tcr, options);
 +    if (ret >= 0)
 +        ret = opt_default("gop_timecode", arg);
 +    av_free(tcr);
 +    return ret;
  }
  
  static int opt_channel_layout(void *optctx, const char *opt, const char *arg)
@@@ -2144,63 -1794,35 +2144,54 @@@ static int show_help(const char *opt, c
      int flags = AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM;
      av_log_set_callback(log_callback_help);
      show_usage();
-     show_help_options(options, "Main options:\n",
-                       OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE | OPT_GRAB, 0);
-     show_help_options(options, "\nAdvanced options:\n",
-                       OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE | OPT_GRAB,
-                       OPT_EXPERT);
-     show_help_options(options, "\nVideo options:\n",
-                       OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_GRAB,
-                       OPT_VIDEO);
-     show_help_options(options, "\nAdvanced Video options:\n",
-                       OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_GRAB,
-                       OPT_VIDEO | OPT_EXPERT);
-     show_help_options(options, "\nAudio options:\n",
-                       OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_GRAB,
-                       OPT_AUDIO);
-     show_help_options(options, "\nAdvanced Audio options:\n",
-                       OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_GRAB,
-                       OPT_AUDIO | OPT_EXPERT);
-     show_help_options(options, "\nSubtitle options:\n",
-                       OPT_SUBTITLE | OPT_GRAB,
-                       OPT_SUBTITLE);
-     show_help_options(options, "\nAudio/Video grab options:\n",
-                       OPT_GRAB,
-                       OPT_GRAB);
+     show_help_options(options, "Main options:",
+                       0, OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE);
+     show_help_options(options, "Advanced options:",
+                       OPT_EXPERT, OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE);
+     show_help_options(options, "Video options:",
+                       OPT_VIDEO, OPT_EXPERT | OPT_AUDIO);
+     show_help_options(options, "Advanced Video options:",
+                       OPT_EXPERT | OPT_VIDEO, OPT_AUDIO);
+     show_help_options(options, "Audio options:",
+                       OPT_AUDIO, OPT_EXPERT | OPT_VIDEO);
+     show_help_options(options, "Advanced Audio options:",
+                       OPT_EXPERT | OPT_AUDIO, OPT_VIDEO);
+     show_help_options(options, "Subtitle options:",
+                       OPT_SUBTITLE, 0);
      printf("\n");
      show_help_children(avcodec_get_class(), flags);
      show_help_children(avformat_get_class(), flags);
      show_help_children(sws_get_class(), flags);
 +    show_help_children(swr_get_class(), AV_OPT_FLAG_AUDIO_PARAM);
 +    show_help_children(avfilter_get_class(), AV_OPT_FLAG_FILTERING_PARAM);
      return 0;
  }
  
  void show_usage(void)
  {
 -    printf("Hyper fast Audio and Video encoder\n");
 -    printf("usage: %s [options] [[infile options] -i infile]... {[outfile options] outfile}...\n", program_name);
 -    printf("\n");
 +    av_log(NULL, AV_LOG_INFO, "Hyper fast Audio and Video encoder\n");
 +    av_log(NULL, AV_LOG_INFO, "usage: %s [options] [[infile options] -i infile]... {[outfile options] outfile}...\n", program_name);
 +    av_log(NULL, AV_LOG_INFO, "\n");
  }
  
  
 +static int opt_progress(const char *opt, const char *arg)
 +{
 +    AVIOContext *avio = NULL;
 +    int ret;
 +
 +    if (!strcmp(arg, "-"))
 +        arg = "pipe:";
 +    ret = avio_open2(&avio, arg, AVIO_FLAG_WRITE, &int_cb, NULL);
 +    if (ret < 0) {
 +        av_log(0, AV_LOG_ERROR, "Failed to open progress URL \"%s\": %s\n",
 +               arg, av_err2str(ret));
 +        return ret;
 +    }
 +    progress_avio = avio;
 +    return 0;
 +}
 +
  #define OFFSET(x) offsetof(OptionsContext, x)
  const OptionDef options[] = {
      /* main options */
          "input file name", "filename" },
      { "y",              OPT_BOOL,                                    {              &file_overwrite },
          "overwrite output files" },
 +    { "n",              OPT_BOOL,                                    {              &no_file_overwrite },
 +        "do not overwrite output files" },
      { "c",              HAS_ARG | OPT_STRING | OPT_SPEC,             { .off       = OFFSET(codec_names) },
          "codec name", "codec" },
      { "codec",          HAS_ARG | OPT_STRING | OPT_SPEC,             { .off       = OFFSET(codec_names) },
      { "map",            HAS_ARG | OPT_EXPERT | OPT_FUNC2,            { .func2_arg = opt_map },
          "set input stream mapping",
          "[-]input_file_id[:stream_specifier][,sync_file_id[:stream_specifier]]" },
 +    { "map_channel",    HAS_ARG | OPT_EXPERT | OPT_FUNC2,            { .func2_arg = opt_map_channel },
 +        "map an audio channel from one stream to another", "file.stream.channel[:syncfile.syncstream]" },
      { "map_metadata",   HAS_ARG | OPT_STRING | OPT_SPEC,             { .off       = OFFSET(metadata_map) },
          "set metadata information of outfile from infile",
          "outfile[,metadata]:infile[,metadata]" },
          "set the input ts offset", "time_off" },
      { "itsscale",       HAS_ARG | OPT_DOUBLE | OPT_SPEC,             { .off = OFFSET(ts_scale) },
          "set the input ts scale", "scale" },
 +    { "timestamp",      HAS_ARG | OPT_FUNC2,                         { .func2_arg = opt_recording_timestamp },
 +        "set the recording timestamp ('now' to set the current time)", "time" },
      { "metadata",       HAS_ARG | OPT_STRING | OPT_SPEC,             { .off = OFFSET(metadata) },
          "add metadata", "string=string" },
      { "dframes",        HAS_ARG | OPT_FUNC2,                         { .func2_arg = opt_data_frames },
          "set the number of data frames to record", "number" },
      { "benchmark",      OPT_BOOL | OPT_EXPERT,                       { &do_benchmark },
          "add timings for benchmarking" },
 +    { "benchmark_all",  OPT_BOOL | OPT_EXPERT,                       { &do_benchmark_all },
 +      "add timings for each task" },
 +    { "progress",       HAS_ARG | OPT_EXPERT,                        { .func_arg = opt_progress },
 +      "write program-readable progress information", "url" },
 +    { "stdin",          OPT_BOOL | OPT_EXPERT,                       { &stdin_interaction },
 +      "enable or disable interaction on standard input" },
      { "timelimit",      HAS_ARG,                                     { .func_arg = opt_timelimit },
          "set max runtime in seconds", "limit" },
      { "dump",           OPT_BOOL | OPT_EXPERT,                       { &do_pkt_dump },
          "audio drift threshold", "threshold" },
      { "copyts",         OPT_BOOL | OPT_EXPERT,                       { &copy_ts },
          "copy timestamps" },
 -    { "copytb",         OPT_BOOL | OPT_EXPERT,                       { &copy_tb },
 -        "copy input stream time base when stream copying" },
 +    { "copytb",         HAS_ARG | OPT_INT | OPT_EXPERT,              { &copy_tb },
 +        "copy input stream time base when stream copying", "mode" },
      { "shortest",       OPT_BOOL | OPT_EXPERT | OPT_OFFSET,          { .off = OFFSET(shortest) },
          "finish encoding within shortest input" },
      { "dts_delta_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT,       { &dts_delta_threshold },
          "timestamp discontinuity delta threshold", "threshold" },
 +    { "dts_error_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT,       { &dts_error_threshold },
 +        "timestamp error delta threshold", "threshold" },
      { "xerror",         OPT_BOOL,                                    { &exit_on_error },
          "exit on error", "error" },
      { "copyinkf",       OPT_BOOL | OPT_EXPERT | OPT_SPEC,            { .off = OFFSET(copy_initial_nonkeyframes) },
          "force codec tag/fourcc", "fourcc/tag" },
      { "q",              HAS_ARG | OPT_EXPERT | OPT_DOUBLE | OPT_SPEC,{ .off = OFFSET(qscale) },
          "use fixed quality scale (VBR)", "q" },
 -    { "qscale",         HAS_ARG | OPT_EXPERT | OPT_DOUBLE | OPT_SPEC,{ .off = OFFSET(qscale) },
 +    { "qscale",         HAS_ARG | OPT_EXPERT | OPT_FUNC2,            { .func2_arg = opt_qscale },
          "use fixed quality scale (VBR)", "q" },
 +    { "profile",        HAS_ARG | OPT_EXPERT | OPT_FUNC2,            { .func2_arg = opt_profile },
 +        "set profile", "profile" },
      { "filter",         HAS_ARG | OPT_STRING | OPT_SPEC,             { .off = OFFSET(filters) },
          "set stream filterchain", "filter_list" },
      { "filter_complex", HAS_ARG | OPT_EXPERT,                        { .func_arg = opt_filter_complex },
          "add an attachment to the output file", "filename" },
      { "dump_attachment", HAS_ARG | OPT_STRING | OPT_SPEC,            { .off = OFFSET(dump_attachment) },
          "extract an attachment into a file", "filename" },
 -    { "cpuflags",       HAS_ARG | OPT_EXPERT,                        { .func_arg = opt_cpuflags },
 -        "set CPU flags mask", "mask" },
 +    { "debug_ts",       OPT_BOOL | OPT_EXPERT,                       { &debug_ts },
 +        "print timestamp debugging info" },
  
      /* video options */
      { "vframes",      OPT_VIDEO | HAS_ARG  | OPT_FUNC2,                          { .func2_arg = opt_video_frames },
          "set the number of video frames to record", "number" },
      { "r",            OPT_VIDEO | HAS_ARG  | OPT_STRING | OPT_SPEC,              { .off = OFFSET(frame_rates) },
          "set frame rate (Hz value, fraction or abbreviation)", "rate" },
 -    { "s",            OPT_VIDEO | HAS_ARG  | OPT_STRING | OPT_SPEC,              { .off = OFFSET(frame_sizes) },
 +    { "s",            OPT_VIDEO | HAS_ARG | OPT_SUBTITLE | OPT_STRING | OPT_SPEC,{ .off = OFFSET(frame_sizes) },
          "set frame size (WxH or abbreviation)", "size" },
      { "aspect",       OPT_VIDEO | HAS_ARG  | OPT_STRING | OPT_SPEC,              { .off = OFFSET(frame_aspect_ratios) },
          "set aspect ratio (4:3, 16:9 or 1.3333, 1.7777)", "aspect" },
      { "pix_fmt",      OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_STRING | OPT_SPEC, { .off = OFFSET(frame_pix_fmts) },
          "set pixel format", "format" },
 +    { "bits_per_raw_sample", OPT_VIDEO | OPT_INT | HAS_ARG,                      { &frame_bits_per_raw_sample },
 +        "set the number of bits per raw sample", "number" },
 +    { "croptop",      OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_frame_crop },
 +        "Removed, use the crop filter instead", "size" },
 +    { "cropbottom",   OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_frame_crop },
 +        "Removed, use the crop filter instead", "size" },
 +    { "cropleft",     OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_frame_crop },
 +        "Removed, use the crop filter instead", "size" },
 +    { "cropright",    OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_frame_crop },
 +        "Removed, use the crop filter instead", "size" },
 +    { "padtop",       OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_pad },
 +        "Removed, use the pad filter instead", "size" },
 +    { "padbottom",    OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_pad },
 +        "Removed, use the pad filter instead", "size" },
 +    { "padleft",      OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_pad },
 +        "Removed, use the pad filter instead", "size" },
 +    { "padright",     OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_pad },
 +        "Removed, use the pad filter instead", "size" },
 +    { "padcolor",     OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_pad },
 +        "Removed, use the pad filter instead", "color" },
 +    { "intra",        OPT_VIDEO | OPT_BOOL | OPT_EXPERT,                         { &intra_only },
 +        "deprecated use -g 1" },
      { "vn",           OPT_VIDEO | OPT_BOOL  | OPT_OFFSET,                        { .off = OFFSET(video_disable) },
          "disable video" },
      { "vdt",          OPT_VIDEO | OPT_INT | HAS_ARG | OPT_EXPERT ,               { &video_discard },
          "rate control override for specific intervals", "override" },
      { "vcodec",       OPT_VIDEO | HAS_ARG  | OPT_FUNC2,                          { .func2_arg = opt_video_codec },
          "force video codec ('copy' to copy stream)", "codec" },
 +    { "sameq",        OPT_VIDEO | OPT_BOOL,                                      { &same_quant },
 +        "use same quantizer as source (implies VBR)" },
      { "same_quant",   OPT_VIDEO | OPT_BOOL ,                                     { &same_quant },
          "use same quantizer as source (implies VBR)" },
 +    { "timecode",     OPT_VIDEO | HAS_ARG | OPT_FUNC2,                           { .func2_arg = opt_timecode },
 +        "set initial TimeCode value.", "hh:mm:ss[:;.]ff" },
      { "pass",         OPT_VIDEO | HAS_ARG ,                                      { opt_pass },
          "select the pass number (1 or 2)", "n" },
 -    { "passlogfile",  OPT_VIDEO | HAS_ARG | OPT_STRING ,                         { &pass_logfilename_prefix },
 +    { "passlogfile",  OPT_VIDEO | HAS_ARG,                                       { .func_arg = &opt_passlogfile },
          "select two pass log file name prefix", "prefix" },
      { "deinterlace",  OPT_VIDEO | OPT_EXPERT ,                                   { .func_arg = opt_deinterlace },
          "this option is deprecated, use the yadif filter instead" },
 +    { "psnr",         OPT_VIDEO | OPT_BOOL | OPT_EXPERT,                         { &do_psnr },
 +        "calculate PSNR of compressed frames" },
      { "vstats",       OPT_VIDEO | OPT_EXPERT ,                                   { &opt_vstats },
          "dump video coding statistics to file" },
      { "vstats_file",  OPT_VIDEO | HAS_ARG | OPT_EXPERT ,                         { opt_vstats_file },
          "top=1/bottom=0/auto=-1 field first", "" },
      { "dc",           OPT_VIDEO | OPT_INT | HAS_ARG | OPT_EXPERT ,               { &intra_dc_precision },
          "intra_dc_precision", "precision" },
 -    { "vtag",         OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_FUNC2,             { .func2_arg = opt_video_tag },
 +    { "vtag",         OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_FUNC2,             { .func2_arg = opt_old2new },
          "force video tag/fourcc", "fourcc/tag" },
      { "qphist",       OPT_VIDEO | OPT_BOOL | OPT_EXPERT ,                        { &qp_hist },
          "show QP histogram" },
      { "streamid",     OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_FUNC2,              { .func2_arg = opt_streamid },
          "set the value of an outfile streamid", "streamIndex:value" },
      { "force_key_frames", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT  | OPT_SPEC,
 -        { .off = OFFSET(forced_key_frames) }, "force key frames at specified timestamps", "timestamps" },
 +        { .off = OFFSET(forced_key_frames) },
 +        "force key frames at specified timestamps", "timestamps" },
 +    { "b",            OPT_VIDEO | HAS_ARG | OPT_FUNC2,                           { .func2_arg = opt_bitrate },
 +        "video bitrate (please use -b:v)", "bitrate" },
  
      /* audio options */
      { "aframes",        OPT_AUDIO | HAS_ARG  | OPT_FUNC2,                          { .func2_arg = opt_audio_frames },
          "disable audio" },
      { "acodec",         OPT_AUDIO | HAS_ARG  | OPT_FUNC2,                          { .func2_arg = opt_audio_codec },
          "force audio codec ('copy' to copy stream)", "codec" },
 -    { "atag",           OPT_AUDIO | HAS_ARG  | OPT_EXPERT | OPT_FUNC2,             { .func2_arg = opt_audio_tag },
 +    { "atag",           OPT_AUDIO | HAS_ARG  | OPT_EXPERT | OPT_FUNC2,             { .func2_arg = opt_old2new },
          "force audio tag/fourcc", "fourcc/tag" },
      { "vol",            OPT_AUDIO | HAS_ARG  | OPT_INT,                            { &audio_volume },
          "change audio volume (256=normal)" , "volume" },
          "disable subtitle" },
      { "scodec", OPT_SUBTITLE | HAS_ARG  | OPT_FUNC2,  { .func2_arg = opt_subtitle_codec },
          "force subtitle codec ('copy' to copy stream)", "codec" },
 -    { "stag",   OPT_SUBTITLE | HAS_ARG  | OPT_EXPERT  | OPT_FUNC2, { .func2_arg = opt_subtitle_tag }
 -        , "force subtitle tag/fourcc", "fourcc/tag" },
 +    { "stag", HAS_ARG | OPT_EXPERT | OPT_SUBTITLE | OPT_FUNC2, { .func2_arg = opt_old2new },
 +        "force subtitle tag/fourcc", "fourcc/tag" },
 +    { "fix_sub_duration", OPT_BOOL | OPT_EXPERT | OPT_SUBTITLE | OPT_SPEC, { .off = OFFSET(fix_sub_duration) },
 +        "fix subtitles duration" },
  
      /* grab options */
-     { "vc", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_GRAB, { .func_arg = opt_video_channel },
++    { "vc", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_video_channel },
 +        "deprecated, use -channel", "channel" },
-     { "tvstd", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_GRAB, { .func_arg = opt_video_standard },
++    { "tvstd", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_video_standard },
 +        "deprecated, use -standard", "standard" },
-     { "isync", OPT_BOOL | OPT_EXPERT | OPT_GRAB, { &input_sync },
-         "sync read on input", "" },
+     { "isync", OPT_BOOL | OPT_EXPERT, { &input_sync }, "this option is deprecated and does nothing", "" },
  
      /* muxer options */
      { "muxdelay",   OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET, { .off = OFFSET(mux_max_delay) },
  
      { "bsf", HAS_ARG | OPT_STRING | OPT_SPEC, { .off = OFFSET(bitstream_filters) },
          "A comma-separated list of bitstream filters", "bitstream_filters" },
 -
 +    { "absf", HAS_ARG | OPT_AUDIO | OPT_EXPERT| OPT_FUNC2, { .func2_arg = opt_old2new },
 +        "deprecated", "audio bitstream_filters" },
 +    { "vbsf", OPT_VIDEO | HAS_ARG | OPT_EXPERT| OPT_FUNC2, { .func2_arg = opt_old2new },
 +        "deprecated", "video bitstream_filters" },
 +
 +    { "apre", HAS_ARG | OPT_AUDIO | OPT_EXPERT| OPT_FUNC2, { .func2_arg = opt_preset },
 +        "set the audio options to the indicated preset", "preset" },
 +    { "vpre", OPT_VIDEO | HAS_ARG | OPT_EXPERT| OPT_FUNC2, { .func2_arg = opt_preset },
 +        "set the video options to the indicated preset", "preset" },
 +    { "spre", HAS_ARG | OPT_SUBTITLE | OPT_EXPERT| OPT_FUNC2, { .func2_arg = opt_preset },
 +        "set the subtitle options to the indicated preset", "preset" },
 +    { "fpre", HAS_ARG | OPT_EXPERT| OPT_FUNC2, { .func2_arg = opt_preset },
 +        "set options from indicated preset file", "filename" },
      /* data codec support */
      { "dcodec", HAS_ARG | OPT_DATA | OPT_FUNC2, { .func2_arg = opt_data_codec },
          "force data codec ('copy' to copy stream)", "codec" },
 +    { "dn", OPT_BOOL | OPT_VIDEO | OPT_OFFSET, { .off = OFFSET(data_disable) },
 +        "disable data" },
  
      { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { .func_arg = opt_default },
          "generic catch all option", "" },
diff --combined ffplay.c
+++ b/ffplay.c
@@@ -1,33 -1,28 +1,33 @@@
  /*
 - * avplay : Simple Media Player based on the Libav libraries
   * Copyright (c) 2003 Fabrice Bellard
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * FFmpeg is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * FFmpeg is distributed in the hope that it will be useful,
   * 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
 - * License along with Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
 +/**
 + * @file
 + * simple media player based on the FFmpeg libraries
 + */
 +
  #include "config.h"
  #include <inttypes.h>
  #include <math.h>
  #include <limits.h>
 +#include <signal.h>
  #include "libavutil/avstring.h"
  #include "libavutil/colorspace.h"
  #include "libavutil/mathematics.h"
  #include "libavutil/dict.h"
  #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 "libavresample/avresample.h"
  #include "libavutil/opt.h"
  #include "libavcodec/avfft.h"
 +#include "libswresample/swresample.h"
  
  #if CONFIG_AVFILTER
 +# include "libavfilter/avcodec.h"
  # include "libavfilter/avfilter.h"
  # include "libavfilter/avfiltergraph.h"
  # include "libavfilter/buffersink.h"
  # include "libavfilter/buffersrc.h"
  #endif
  
 -#include "cmdutils.h"
 -
  #include <SDL.h>
  #include <SDL_thread.h>
  
 -#ifdef __MINGW32__
 -#undef main /* We don't want SDL to override our main() */
 -#endif
 +#include "cmdutils.h"
  
  #include <assert.h>
  
 -const char program_name[] = "avplay";
 +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
@@@ -75,6 -73,8 +75,6 @@@
  /* no AV correction is done if too big error */
  #define AV_NOSYNC_THRESHOLD 10.0
  
 -#define FRAME_SKIP_FACTOR 0.05
 -
  /* maximum audio speed change to get correct sync */
  #define SAMPLE_CORRECTION_PERCENT_MAX 10
  
@@@ -100,13 -100,13 +100,13 @@@ typedef struct PacketQueue 
  
  typedef struct VideoPicture {
      double pts;                                  ///< presentation time stamp for this picture
 -    double target_clock;                         ///< av_gettime() time at which this should be displayed ideally
      int64_t pos;                                 ///< byte position in file
 +    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;
@@@ -118,13 -118,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,
  };
  
  typedef struct VideoState {
 -    SDL_Thread *parse_tid;
 +    SDL_Thread *read_tid;
      SDL_Thread *video_tid;
      SDL_Thread *refresh_tid;
      AVInputFormat *iformat;
      int no_background;
      int abort_request;
 +    int force_refresh;
      int paused;
      int last_paused;
 +    int que_attachments_req;
      int seek_req;
      int seek_flags;
      int64_t seek_pos;
      AVStream *audio_st;
      PacketQueue audioq;
      int audio_hw_buf_size;
 +    DECLARE_ALIGNED(16,uint8_t,audio_buf2)[AVCODEC_MAX_AUDIO_FRAME_SIZE * 4];
      uint8_t silence_buf[SDL_AUDIO_BUFFER_SIZE];
      uint8_t *audio_buf;
      uint8_t *audio_buf1;
      unsigned int audio_buf_size; /* in bytes */
      int audio_buf_index; /* in bytes */
 +    int audio_write_buf_size;
      AVPacket audio_pkt_temp;
      AVPacket audio_pkt;
 -    enum AVSampleFormat sdl_sample_fmt;
 -    uint64_t sdl_channel_layout;
 -    int sdl_channels;
 -    enum AVSampleFormat resample_sample_fmt;
 -    uint64_t resample_channel_layout;
 -    AVAudioResampleContext *avr;
 +    struct AudioParams audio_src;
 +    struct AudioParams audio_tgt;
 +    struct SwrContext *swr_ctx;
 +    double audio_current_pts;
 +    double audio_current_pts_drift;
 +    int frame_drops_early;
 +    int frame_drops_late;
      AVFrame *frame;
  
 -    int show_audio; /* if true, display audio samples */
 +    enum ShowMode {
 +        SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB
 +    } show_mode;
      int16_t sample_array[SAMPLE_ARRAY_SIZE];
      int sample_array_index;
      int last_i_start;
  
      double frame_timer;
      double frame_last_pts;
 -    double frame_last_delay;
 +    double frame_last_duration;
 +    double frame_last_dropped_pts;
 +    double frame_last_returned_time;
 +    double frame_last_filter_delay;
 +    int64_t frame_last_dropped_pos;
      double video_clock;                          ///< pts of last decoded frame / predicted pts of next decoded frame
      int video_stream;
      AVStream *video_st;
      struct SwsContext *img_convert_ctx;
  #endif
  
 -    //    QETimer *video_timer;
      char filename[1024];
      int width, height, xleft, ytop;
 -
 -    PtsCorrectionContext pts_ctx;
 +    int step;
  
  #if CONFIG_AVFILTER
      AVFilterContext *in_video_filter;           ///< the first filter in the video chain
      FrameBuffer *buffer_pool;
  #endif
  
 -    float skip_frames;
 -    float skip_frames_index;
      int refresh;
 +    int last_video_stream, last_audio_stream, last_subtitle_stream;
  } VideoState;
  
 +typedef struct AllocEventProps {
 +    VideoState *is;
 +    AVFrame *frame;
 +} AllocEventProps;
 +
  static int show_help(const char *opt, const char *arg);
  
  /* options specified by the user */
@@@ -267,10 -247,12 +267,10 @@@ static int show_status = 1
  static int av_sync_type = AV_SYNC_AUDIO_MASTER;
  static int64_t start_time = AV_NOPTS_VALUE;
  static int64_t duration = AV_NOPTS_VALUE;
 -static int debug = 0;
 -static int debug_mv = 0;
 -static int step = 0;
  static int workaround_bugs = 1;
  static int fast = 0;
  static int genpts = 0;
 +static int lowres = 0;
  static int idct = FF_IDCT_AUTO;
  static enum AVDiscard skip_frame       = AVDISCARD_DEFAULT;
  static enum AVDiscard skip_idct        = AVDISCARD_DEFAULT;
@@@ -281,12 -263,9 +281,12 @@@ static int autoexit
  static int exit_on_keydown;
  static int exit_on_mousedown;
  static int loop = 1;
 -static int framedrop = 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;
 +static const char *video_codec_name;
  static int rdftspeed = 20;
  #if CONFIG_AVFILTER
  static char *vfilters = NULL;
  
  /* current context */
  static int is_full_screen;
 -static VideoState *cur_stream;
  static int64_t audio_callback_time;
  
  static AVPacket flush_pkt;
  
  static SDL_Surface *screen;
  
 -void exit_program(int ret)
 +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;
 +
 +    if (q->abort_request)
 +       return -1;
 +
 +    pkt1 = av_malloc(sizeof(AVPacketList));
 +    if (!pkt1)
 +        return -1;
 +    pkt1->pkt = *pkt;
 +    pkt1->next = NULL;
 +
 +    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);
 +    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);
 +
 +    if (pkt != &flush_pkt && ret < 0)
 +        av_free_packet(pkt);
 +
 +    return ret;
 +}
  
  /* packet queue handling */
  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)
      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);
      SDL_DestroyCond(q->cond);
  }
  
 -static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
 +static void packet_queue_abort(PacketQueue *q)
  {
 -    AVPacketList *pkt1;
 -
 -    /* duplicate the packet */
 -    if (pkt != &flush_pkt && av_dup_packet(pkt) < 0)
 -        return -1;
 -
 -    pkt1 = av_malloc(sizeof(AVPacketList));
 -    if (!pkt1)
 -        return -1;
 -    pkt1->pkt = *pkt;
 -    pkt1->next = NULL;
 -
 -
      SDL_LockMutex(q->mutex);
  
 -    if (!q->last_pkt)
 +    q->abort_request = 1;
  
 -        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);
  
      SDL_UnlockMutex(q->mutex);
 -    return 0;
  }
  
 -static void packet_queue_abort(PacketQueue *q)
 +static void packet_queue_start(PacketQueue *q)
  {
      SDL_LockMutex(q->mutex);
 -
 -    q->abort_request = 1;
 -
 -    SDL_CondSignal(q->cond);
 -
 +    q->abort_request = 0;
 +    packet_queue_put_private(q, &flush_pkt);
      SDL_UnlockMutex(q->mutex);
  }
  
@@@ -697,20 -660,33 +697,20 @@@ static void video_image_display(VideoSt
  
      vp = &is->pictq[is->pictq_rindex];
      if (vp->bmp) {
 -#if CONFIG_AVFILTER
 -         if (vp->picref->video->pixel_aspect.num == 0)
 -             aspect_ratio = 0;
 -         else
 -             aspect_ratio = av_q2d(vp->picref->video->pixel_aspect);
 -#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;
  
 -        if (is->subtitle_st)
 -        {
 -            if (is->subpq_size > 0)
 -            {
 +        if (is->subtitle_st) {
 +            if (is->subpq_size > 0) {
                  sp = &is->subpq[is->subpq_rindex];
  
 -                if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000))
 -                {
 +                if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) {
                      SDL_LockYUVOverlay (vp->bmp);
  
                      pict.data[0] = vp->bmp->pixels[0];
          is->no_background = 0;
          rect.x = is->xleft + x;
          rect.y = is->ytop  + y;
 -        rect.w = width;
 -        rect.h = height;
 +        rect.w = FFMAX(width,  1);
 +        rect.h = FFMAX(height, 1);
          SDL_DisplayYUVOverlay(vp->bmp, &rect);
      }
  }
  
 -/* get the current audio output buffer size, in samples. With SDL, we
 -   cannot have a precise information */
 -static int audio_write_get_buf_size(VideoState *is)
 -{
 -    return is->audio_buf_size - is->audio_buf_index;
 -}
 -
  static inline int compute_mod(int a, int b)
  {
 -    a = a % b;
 -    if (a >= 0)
 -        return a;
 -    else
 -        return a + b;
 +    return a < 0 ? a%b + b : a%b;
  }
  
  static void video_audio_display(VideoState *s)
      nb_freq = 1 << (rdft_bits - 1);
  
      /* compute display index : center on currently output samples */
 -    channels = s->sdl_channels;
 +    channels = s->audio_tgt.channels;
      nb_display_channels = channels;
      if (!s->paused) {
 -        int data_used = s->show_audio == 1 ? s->width : (2 * nb_freq);
 +        int data_used= s->show_mode == SHOW_MODE_WAVES ? s->width : (2*nb_freq);
          n = 2 * channels;
 -        delay = audio_write_get_buf_size(s);
 +        delay = s->audio_write_buf_size;
          delay /= n;
  
          /* to be more precise, we take into account the time spent since
             the last buffer computation */
          if (audio_callback_time) {
              time_diff = av_gettime() - audio_callback_time;
 -            delay -= (time_diff * s->audio_st->codec->sample_rate) / 1000000;
 +            delay -= (time_diff * s->audio_tgt.freq) / 1000000;
          }
  
          delay += 2 * data_used;
              delay = data_used;
  
          i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
 -        if (s->show_audio == 1) {
 +        if (s->show_mode == SHOW_MODE_WAVES) {
              h = INT_MIN;
              for (i = 0; i < 1000; i += channels) {
                  int idx = (SAMPLE_ARRAY_SIZE + x - i) % SAMPLE_ARRAY_SIZE;
      }
  
      bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
 -    if (s->show_audio == 1) {
 +    if (s->show_mode == SHOW_MODE_WAVES) {
          fill_rectangle(screen,
                         s->xleft, s->ytop, s->width, s->height,
                         bgcolor);
              }
          }
          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;
      }
  }
  
 -static int video_open(VideoState *is)
 +static void stream_close(VideoState *is)
 +{
 +    VideoPicture *vp;
 +    int i;
 +    /* XXX: use a special url_shutdown call to abort parse cleanly */
 +    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
 +        avfilter_unref_bufferp(&vp->picref);
 +#endif
 +        if (vp->bmp) {
 +            SDL_FreeYUVOverlay(vp->bmp);
 +            vp->bmp = NULL;
 +        }
 +    }
 +    SDL_DestroyMutex(is->pictq_mutex);
 +    SDL_DestroyCond(is->pictq_cond);
 +    SDL_DestroyMutex(is->subpq_mutex);
 +    SDL_DestroyCond(is->subpq_cond);
 +#if !CONFIG_AVFILTER
 +    if (is->img_convert_ctx)
 +        sws_freeContext(is->img_convert_ctx);
 +#endif
 +    av_free(is);
 +}
 +
 +static void do_exit(VideoState *is)
 +{
 +    if (is) {
 +        stream_close(is);
 +    }
 +    av_lockmgr_register(NULL);
 +    uninit_opts();
 +#if CONFIG_AVFILTER
 +    avfilter_uninit();
 +#endif
 +    avformat_network_deinit();
 +    if (show_status)
 +        printf("\n");
 +    SDL_Quit();
 +    av_log(NULL, AV_LOG_QUIET, "%s", "");
 +    exit(0);
 +}
 +
 +static void sigterm_handler(int sig)
 +{
 +    exit(123);
 +}
 +
 +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;
      } 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;
      }
      if (screen && is->width == screen->w && screen->w == w
 -       && is->height== screen->h && screen->h == h)
 +       && is->height== screen->h && screen->h == h && !force_set_video_mode)
          return 0;
 -
 -#if defined(__APPLE__) && !SDL_VERSION_ATLEAST(1, 2, 14)
 -    /* setting bits_per_pixel = 0 or 32 causes blank video on OS X and older SDL */
 -    screen = SDL_SetVideoMode(w, h, 24, flags);
 -#else
      screen = SDL_SetVideoMode(w, h, 0, flags);
 -#endif
      if (!screen) {
          fprintf(stderr, "SDL: could not set video mode - exiting\n");
 -        return -1;
 +        do_exit(is);
      }
      if (!window_title)
          window_title = input_filename;
  static void video_display(VideoState *is)
  {
      if (!screen)
 -        video_open(cur_stream);
 -    if (is->audio_st && is->show_audio)
 +        video_open(is, 0);
 +    if (is->audio_st && is->show_mode != SHOW_MODE_VIDEO)
          video_audio_display(is);
      else if (is->video_st)
          video_image_display(is);
@@@ -1009,12 -949,11 +1009,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);
          }
 -        av_usleep(is->audio_st && is->show_audio ? rdftspeed * 1000 : 5000); // FIXME ideally we should wait the correct time but SDLs event passing is so slow it would be silly
 +        //FIXME ideally we should wait the correct time but SDLs event passing is so slow it would be silly
 +        av_usleep(is->audio_st && is->show_mode != SHOW_MODE_VIDEO ? rdftspeed*1000 : 5000);
      }
      return 0;
  }
  /* get the current audio clock value */
  static double get_audio_clock(VideoState *is)
  {
 -    double pts;
 -    int hw_buf_size, bytes_per_sec;
 -    pts = is->audio_clock;
 -    hw_buf_size = audio_write_get_buf_size(is);
 -    bytes_per_sec = 0;
 -    if (is->audio_st) {
 -        bytes_per_sec = is->audio_st->codec->sample_rate * is->sdl_channels *
 -                        av_get_bytes_per_sample(is->sdl_sample_fmt);
 +    if (is->paused) {
 +        return is->audio_current_pts;
 +    } else {
 +        return is->audio_current_pts_drift + av_gettime() / 1000000.0;
      }
 -    if (bytes_per_sec)
 -        pts -= (double)hw_buf_size / bytes_per_sec;
 -    return pts;
  }
  
  /* get the current video clock value */
@@@ -1082,7 -1028,7 +1082,7 @@@ static void stream_seek(VideoState *is
  }
  
  /* pause or resume the video */
 -static void stream_pause(VideoState *is)
 +static void stream_toggle_pause(VideoState *is)
  {
      if (is->paused) {
          is->frame_timer += av_gettime() / 1000000.0 + is->video_current_pts_drift - is->video_current_pts;
      is->paused = !is->paused;
  }
  
 -static double compute_target_time(double frame_current_pts, VideoState *is)
 +static double compute_target_delay(double delay, VideoState *is)
  {
 -    double delay, sync_threshold, diff;
 -
 -    /* compute nominal delay */
 -    delay = frame_current_pts - is->frame_last_pts;
 -    if (delay <= 0 || delay >= 10.0) {
 -        /* if incorrect delay, use previous one */
 -        delay = is->frame_last_delay;
 -    } else {
 -        is->frame_last_delay = delay;
 -    }
 -    is->frame_last_pts = frame_current_pts;
 +    double sync_threshold, diff;
  
      /* update delay to follow master synchronisation source */
      if (((is->av_sync_type == AV_SYNC_AUDIO_MASTER && is->audio_st) ||
                  delay = 2 * delay;
          }
      }
 -    is->frame_timer += delay;
  
 -    av_dlog(NULL, "video: delay=%0.3f pts=%0.3f A-V=%f\n",
 -            delay, frame_current_pts, -diff);
 +    av_dlog(NULL, "video: delay=%0.3f A-V=%f\n",
 +            delay, -diff);
 +
 +    return delay;
 +}
 +
 +static void pictq_next_picture(VideoState *is) {
 +    /* update queue size and signal for next picture */
 +    if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
 +        is->pictq_rindex = 0;
 +
 +    SDL_LockMutex(is->pictq_mutex);
 +    is->pictq_size--;
 +    SDL_CondSignal(is->pictq_cond);
 +    SDL_UnlockMutex(is->pictq_mutex);
 +}
  
 -    return is->frame_timer;
 +static void update_video_pts(VideoState *is, double pts, int64_t pos) {
 +    double time = av_gettime() / 1000000.0;
 +    /* update current video pts */
 +    is->video_current_pts = pts;
 +    is->video_current_pts_drift = is->video_current_pts - time;
 +    is->video_current_pos = pos;
 +    is->frame_last_pts = pts;
  }
  
  /* called to display each frame */
 -static void video_refresh_timer(void *opaque)
 +static void video_refresh(void *opaque)
  {
      VideoState *is = opaque;
      VideoPicture *vp;
 +    double time;
  
      SubPicture *sp, *sp2;
  
      if (is->video_st) {
  retry:
          if (is->pictq_size == 0) {
 +            SDL_LockMutex(is->pictq_mutex);
 +            if (is->frame_last_dropped_pts != AV_NOPTS_VALUE && is->frame_last_dropped_pts > is->frame_last_pts) {
 +                update_video_pts(is, is->frame_last_dropped_pts, is->frame_last_dropped_pos);
 +                is->frame_last_dropped_pts = AV_NOPTS_VALUE;
 +            }
 +            SDL_UnlockMutex(is->pictq_mutex);
              // nothing to do, no picture to display in the que
          } else {
 -            double time = av_gettime() / 1000000.0;
 -            double next_target;
 +            double last_duration, duration, delay;
              /* dequeue the picture */
              vp = &is->pictq[is->pictq_rindex];
  
 -            if (time < vp->target_clock)
 +            if (vp->skip) {
 +                pictq_next_picture(is);
 +                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) {
 +                /* if duration of the last frame was sane, update last_duration in video state */
 +                is->frame_last_duration = last_duration;
 +            }
 +            delay = compute_target_delay(is->frame_last_duration, is);
 +
 +            time= av_gettime()/1000000.0;
 +            if (time < is->frame_timer + delay)
                  return;
 -            /* update current video pts */
 -            is->video_current_pts = vp->pts;
 -            is->video_current_pts_drift = is->video_current_pts - time;
 -            is->video_current_pos = vp->pos;
 +
 +            if (delay > 0)
 +                is->frame_timer += delay * FFMAX(1, floor((time-is->frame_timer) / delay));
 +
 +            SDL_LockMutex(is->pictq_mutex);
 +            update_video_pts(is, vp->pts, vp->pos);
 +            SDL_UnlockMutex(is->pictq_mutex);
 +
              if (is->pictq_size > 1) {
                  VideoPicture *nextvp = &is->pictq[(is->pictq_rindex + 1) % VIDEO_PICTURE_QUEUE_SIZE];
 -                assert(nextvp->target_clock >= vp->target_clock);
 -                next_target= nextvp->target_clock;
 -            } else {
 -                next_target = vp->target_clock + is->video_clock - vp->pts; // FIXME pass durations cleanly
 -            }
 -            if (framedrop && time > next_target) {
 -                is->skip_frames *= 1.0 + FRAME_SKIP_FACTOR;
 -                if (is->pictq_size > 1 || time > next_target + 0.5) {
 -                    /* update queue size and signal for next picture */
 -                    if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
 -                        is->pictq_rindex = 0;
 -
 -                    SDL_LockMutex(is->pictq_mutex);
 -                    is->pictq_size--;
 -                    SDL_CondSignal(is->pictq_cond);
 -                    SDL_UnlockMutex(is->pictq_mutex);
 +                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;
                  }
              }
                  }
              }
  
 +display:
              /* display picture */
              if (!display_disable)
                  video_display(is);
  
 -            /* update queue size and signal for next picture */
 -            if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
 -                is->pictq_rindex = 0;
 -
 -            SDL_LockMutex(is->pictq_mutex);
 -            is->pictq_size--;
 -            SDL_CondSignal(is->pictq_cond);
 -            SDL_UnlockMutex(is->pictq_mutex);
 +            if (!is->paused)
 +                pictq_next_picture(is);
          }
      } else if (is->audio_st) {
          /* draw the next audio frame */
          if (!display_disable)
              video_display(is);
      }
 +    is->force_refresh = 0;
      if (show_status) {
          static int64_t last_time;
          int64_t cur_time;
              av_diff = 0;
              if (is->audio_st && is->video_st)
                  av_diff = get_audio_clock(is) - get_video_clock(is);
 -            printf("%7.2f A-V:%7.3f s:%3.1f aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64"   \r",
 -                   get_master_clock(is), av_diff, FFMAX(is->skip_frames - 1, 0), aqsize / 1024,
 -                   vqsize / 1024, sqsize, is->pts_ctx.num_faulty_dts, is->pts_ctx.num_faulty_pts);
 +            printf("%7.2f A-V:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64"   \r",
 +                   get_master_clock(is),
 +                   av_diff,
 +                   is->frame_drops_early + is->frame_drops_late,
 +                   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);
              fflush(stdout);
              last_time = cur_time;
          }
      }
  }
  
 -static void stream_close(VideoState *is)
 -{
 -    VideoPicture *vp;
 -    int i;
 -    /* XXX: use a special url_shutdown call to abort parse cleanly */
 -    is->abort_request = 1;
 -    SDL_WaitThread(is->parse_tid, NULL);
 -    SDL_WaitThread(is->refresh_tid, NULL);
 -
 -    /* free all pictures */
 -    for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
 -        vp = &is->pictq[i];
 -#if CONFIG_AVFILTER
 -        avfilter_unref_bufferp(&vp->picref);
 -#endif
 -        if (vp->bmp) {
 -            SDL_FreeYUVOverlay(vp->bmp);
 -            vp->bmp = NULL;
 -        }
 -    }
 -    SDL_DestroyMutex(is->pictq_mutex);
 -    SDL_DestroyCond(is->pictq_cond);
 -    SDL_DestroyMutex(is->subpq_mutex);
 -    SDL_DestroyCond(is->subpq_cond);
 -#if !CONFIG_AVFILTER
 -    if (is->img_convert_ctx)
 -        sws_freeContext(is->img_convert_ctx);
 -#endif
 -    av_free(is);
 -}
 -
 -static void do_exit(void)
 -{
 -    if (cur_stream) {
 -        stream_close(cur_stream);
 -        cur_stream = NULL;
 -    }
 -    uninit_opts();
 -#if CONFIG_AVFILTER
 -    avfilter_uninit();
 -#endif
 -    avformat_network_deinit();
 -    if (show_status)
 -        printf("\n");
 -    SDL_Quit();
 -    av_log(NULL, AV_LOG_QUIET, "");
 -    exit(0);
 -}
 -
  /* 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];
  
  #if CONFIG_AVFILTER
      avfilter_unref_bufferp(&vp->picref);
 -
 -    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;
  #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);
          /* SDL allocates a buffer smaller than requested if the video
           * overlay hardware is unable to support the requested size. */
          fprintf(stderr, "Error: the video system does not support an image\n"
 -                        "size of %dx%d pixels. Try using -vf \"scale=w:h\"\n"
 +                        "size of %dx%d pixels. Try using -lowres or -vf \"scale=w:h\"\n"
                          "to reduce the image size.\n", vp->width, vp->height );
 -        do_exit();
 +        do_exit(is);
      }
  
      SDL_LockMutex(is->pictq_mutex);
      SDL_UnlockMutex(is->pictq_mutex);
  }
  
 -/**
 - *
 - * @param pts the dts of the pkt / pts of the frame and guessed if not known
 - */
 -static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t pos)
 +static int queue_picture(VideoState *is, AVFrame *src_frame, double pts1, int64_t pos)
  {
      VideoPicture *vp;
 -#if CONFIG_AVFILTER
 -    AVPicture pict_src;
 -#else
 -    int dst_pix_fmt = PIX_FMT_YUV420P;
 +    double frame_delay, pts = pts1;
 +
 +    /* compute the exact PTS for the picture if it is omitted in the stream
 +     * pts1 is the dts of the pkt / pts of the frame */
 +    if (pts != 0) {
 +        /* update video clock with pts, if present */
 +        is->video_clock = pts;
 +    } else {
 +        pts = is->video_clock;
 +    }
 +    /* update video clock for next frame */
 +    frame_delay = av_q2d(is->video_st->codec->time_base);
 +    /* for MPEG2, the frame can be repeated, so we update the
 +       clock accordingly */
 +    frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);
 +    is->video_clock += frame_delay;
 +
 +#if defined(DEBUG_SYNC) && 0
 +    printf("frame_type=%c clock=%0.3f pts=%0.3f\n",
 +           av_get_picture_type_char(src_frame->pict_type), pts, pts1);
  #endif
 +
      /* wait until we have space to put a new picture */
      SDL_LockMutex(is->pictq_mutex);
  
 -    if (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && !is->refresh)
 -        is->skip_frames = FFMAX(1.0 - FRAME_SKIP_FACTOR, is->skip_frames * (1.0 - FRAME_SKIP_FACTOR));
 -
      while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE &&
             !is->videoq.abort_request) {
          SDL_CondWait(is->pictq_cond, is->pictq_mutex);
  
      /* 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 */
          while (!vp->allocated && !is->videoq.abort_request) {
              SDL_CondWait(is->pictq_cond, is->pictq_mutex);
          }
 +        /* 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) {
 +            while (!vp->allocated) {
 +                SDL_CondWait(is->pictq_cond, is->pictq_mutex);
 +            }
 +        }
          SDL_UnlockMutex(is->pictq_mutex);
  
          if (is->videoq.abort_request)
          pict.linesize[2] = vp->bmp->pitches[1];
  
  #if CONFIG_AVFILTER
 -        pict_src.data[0] = src_frame->data[0];
 -        pict_src.data[1] = src_frame->data[1];
 -        pict_src.data[2] = src_frame->data[2];
 -
 -        pict_src.linesize[0] = src_frame->linesize[0];
 -        pict_src.linesize[1] = src_frame->linesize[1];
 -        pict_src.linesize[2] = src_frame->linesize[2];
 -
          // FIXME use direct rendering
 -        av_picture_copy(&pict, &pict_src,
 -                        vp->pix_fmt, vp->width, vp->height);
 +        av_picture_copy(&pict, (AVPicture *)src_frame,
 +                        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,
 -            dst_pix_fmt, sws_flags, NULL, NULL, NULL);
 +            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");
              exit(1);
          }
          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);
  
          vp->pts = pts;
          vp->pos = pos;
 +        vp->skip = 0;
  
          /* now we can update the picture count */
          if (++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE)
              is->pictq_windex = 0;
          SDL_LockMutex(is->pictq_mutex);
 -        vp->target_clock = compute_target_time(vp->pts, is);
 -
          is->pictq_size++;
          SDL_UnlockMutex(is->pictq_mutex);
      }
      return 0;
  }
  
 -/**
 - * compute the exact PTS for the picture if it is omitted in the stream
 - * @param pts1 the dts of the pkt / pts of the frame
 - */
 -static int output_picture2(VideoState *is, AVFrame *src_frame, double pts1, int64_t pos)
 -{
 -    double frame_delay, pts;
 -
 -    pts = pts1;
 -
 -    if (pts != 0) {
 -        /* update video clock with pts, if present */
 -        is->video_clock = pts;
 -    } else {
 -        pts = is->video_clock;
 -    }
 -    /* update video clock for next frame */
 -    frame_delay = av_q2d(is->video_st->codec->time_base);
 -    /* for MPEG2, the frame can be repeated, so we update the
 -       clock accordingly */
 -    frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);
 -    is->video_clock += frame_delay;
 -
 -    return queue_picture(is, src_frame, pts, pos);
 -}
 -
  static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacket *pkt)
  {
      int got_picture, i;
          SDL_LockMutex(is->pictq_mutex);
          // Make sure there are no long delay timers (ideally we should just flush the que but thats harder)
          for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
 -            is->pictq[i].target_clock= 0;
 +            is->pictq[i].skip = 1;
          }
          while (is->pictq_size && !is->videoq.abort_request) {
              SDL_CondWait(is->pictq_cond, is->pictq_mutex);
          }
          is->video_current_pos = -1;
 -        SDL_UnlockMutex(is->pictq_mutex);
 -
 -        init_pts_correction(&is->pts_ctx);
          is->frame_last_pts = AV_NOPTS_VALUE;
 -        is->frame_last_delay = 0;
 +        is->frame_last_duration = 0;
          is->frame_timer = (double)av_gettime() / 1000000.0;
 -        is->skip_frames = 1;
 -        is->skip_frames_index = 0;
 +        is->frame_last_dropped_pts = AV_NOPTS_VALUE;
 +        SDL_UnlockMutex(is->pictq_mutex);
 +
          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 = guess_correct_pts(&is->pts_ctx, frame->pkt_pts, frame->pkt_dts);
 +            *pts = av_frame_get_best_effort_timestamp(frame);
          } else if (decoder_reorder_pts) {
              *pts = frame->pkt_pts;
          } else {
              *pts = 0;
          }
  
 -        is->skip_frames_index += 1;
 -        if (is->skip_frames_index >= is->skip_frames) {
 -            is->skip_frames_index -= FFMAX(is->skip_frames, 1.0);
 -            return 1;
 +        if (((is->av_sync_type == AV_SYNC_AUDIO_MASTER && is->audio_st) || is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK) &&
 +             (framedrop>0 || (framedrop && is->audio_st))) {
 +            SDL_LockMutex(is->pictq_mutex);
 +            if (is->frame_last_pts != AV_NOPTS_VALUE && *pts) {
 +                double clockdiff = get_video_clock(is) - get_master_clock(is);
 +                double dpts = av_q2d(is->video_st->time_base) * *pts;
 +                double ptsdiff = dpts - is->frame_last_pts;
 +                if (fabs(clockdiff) < AV_NOSYNC_THRESHOLD &&
 +                     ptsdiff > 0 && ptsdiff < AV_NOSYNC_THRESHOLD &&
 +                     clockdiff + ptsdiff - is->frame_last_filter_delay < 0) {
 +                    is->frame_last_dropped_pos = pkt->pos;
 +                    is->frame_last_dropped_pts = dpts;
 +                    is->frame_drops_early++;
 +                    ret = 0;
 +                }
 +            }
 +            SDL_UnlockMutex(is->pictq_mutex);
          }
  
 +        return ret;
      }
      return 0;
  }
  
  #if CONFIG_AVFILTER
 +static int configure_filtergraph(AVFilterGraph *graph, const char *filtergraph,
 +                                 AVFilterContext *source_ctx, AVFilterContext *sink_ctx)
 +{
 +    int ret;
 +    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;
 +
 +        if ((ret = avfilter_graph_parse(graph, filtergraph, &inputs, &outputs, NULL)) < 0)
 +            goto fail;
 +    } else {
 +        if ((ret = avfilter_link(source_ctx, 0, sink_ctx, 0)) < 0)
 +            goto fail;
 +    }
 +
 +    return avfilter_graph_config(graph, NULL);
 +fail:
 +    avfilter_inout_free(&outputs);
 +    avfilter_inout_free(&inputs);
 +    return ret;
 +}
 +
  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;
 +    AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc();
      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);
  
 -    snprintf(buffersrc_args, sizeof(buffersrc_args), "%d:%d:%d:%d:%d:%d:%d",
 +    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"),
 -                                            "src", buffersrc_args, NULL,
 +                                            "ffplay_buffer", buffersrc_args, NULL,
                                              graph)) < 0)
          return ret;
 -    if ((ret = avfilter_graph_create_filter(&filt_out,
 -                                            avfilter_get_by_name("buffersink"),
 -                                            "out", NULL, NULL, graph)) < 0)
 +
 +    buffersink_params->pixel_fmts = pix_fmts;
 +    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 ((ret = avfilter_graph_create_filter(&filt_format,
      if ((ret = avfilter_link(filt_format, 0, filt_out, 0)) < 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_format;
 -        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_format, 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;
  
 -    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;
 -    }
 -
      return ret;
  }
  
@@@ -1637,24 -1595,21 +1637,24 @@@ static int video_thread(void *arg
      AVPacket pkt = { 0 };
      VideoState *is = arg;
      AVFrame *frame = avcodec_alloc_frame();
 -    int64_t pts_int;
 +    int64_t pts_int = AV_NOPTS_VALUE, pos = -1;
      double pts;
      int ret;
  
  #if CONFIG_AVFILTER
 +    AVCodecContext *codec = is->video_st->codec;
      AVFilterGraph *graph = avfilter_graph_alloc();
      AVFilterContext *filt_out = NULL, *filt_in = NULL;
 -    int64_t pos;
 -    int last_w = is->video_st->codec->width;
 -    int last_h = is->video_st->codec->height;
 -
 -    if ((ret = configure_video_filters(graph, is, vfilters)) < 0)
 -        goto the_end;
 -    filt_in  = is->in_video_filter;
 -    filt_out = is->out_video_filter;
 +    int last_w = 0;
 +    int last_h = 0;
 +    enum PixelFormat last_format = -2;
 +
 +    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 (;;) {
          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 CONFIG_AVFILTER
          if (   last_w != is->video_st->codec->width
 -            || last_h != is->video_st->codec->height) {
 -            av_dlog(NULL, "Changing size %dx%d -> %dx%d\n", last_w, last_h,
 -                    is->video_st->codec->width, 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;
 +            last_format = is->video_st->codec->pix_fmt;
          }
  
          frame->pts = pts_int;
 -        if (is->use_dr1) {
 +        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,
              fb->buf->free           = filter_release_buffer;
  
              buf->refcount++;
 -            av_buffersrc_buffer(filt_in, fb);
 +            av_buffersrc_add_ref(filt_in, fb, AV_BUFFERSRC_FLAG_NO_COPY);
  
          } else
              av_buffersrc_write_frame(filt_in, frame);
  
 +        av_free_packet(&pkt);
 +
          while (ret >= 0) {
 -            ret = av_buffersink_read(filt_out, &picref);
 +            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;
 +
              avfilter_copy_buf_props(frame, picref);
  
              pts_int = picref->pts;
                          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 = output_picture2(is, frame, pts, pos);
 +            ret = queue_picture(is, frame, pts, pos);
          }
  #else
          pts = pts_int * av_q2d(is->video_st->time_base);
 -        ret = output_picture2(is, frame, pts,  pkt.pos);
 +        ret = queue_picture(is, frame, pts, pkt.pos);
  #endif
  
          if (ret < 0)
              goto the_end;
  
 -        if (step)
 -            if (cur_stream)
 -                stream_pause(cur_stream);
 +        if (is->step)
 +            stream_toggle_pause(is);
      }
   the_end:
 +    avcodec_flush_buffers(is->video_st->codec);
  #if CONFIG_AVFILTER
      av_freep(&vfilters);
      avfilter_graph_free(&graph);
@@@ -1861,19 -1798,25 +1861,19 @@@ static void update_sample_display(Video
      }
  }
  
 -/* return the new audio buffer size (samples can be added or deleted
 -   to get better sync if video or external master clock) */
 -static int synchronize_audio(VideoState *is, short *samples,
 -                             int samples_size1, double pts)
 +/* 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)
  {
 -    int n, samples_size;
 -    double ref_clock;
 -
 -    n = is->sdl_channels * av_get_bytes_per_sample(is->sdl_sample_fmt);
 -    samples_size = samples_size1;
 +    int wanted_nb_samples = nb_samples;
  
      /* if not master, then we try to remove or add samples to correct the clock */
      if (((is->av_sync_type == AV_SYNC_VIDEO_MASTER && is->video_st) ||
           is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {
          double diff, avg_diff;
 -        int wanted_size, min_size, max_size, nb_samples;
 +        int min_nb_samples, max_nb_samples;
  
 -        ref_clock = get_master_clock(is);
 -        diff = get_audio_clock(is) - ref_clock;
 +        diff = get_audio_clock(is) - get_master_clock(is);
  
          if (diff < AV_NOSYNC_THRESHOLD) {
              is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum;
                  avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef);
  
                  if (fabs(avg_diff) >= is->audio_diff_threshold) {
 -                    wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n);
 -                    nb_samples = samples_size / n;
 -
 -                    min_size = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n;
 -                    max_size = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n;
 -                    if (wanted_size < min_size)
 -                        wanted_size = min_size;
 -                    else if (wanted_size > max_size)
 -                        wanted_size = max_size;
 -
 -                    /* add or remove samples to correction the synchro */
 -                    if (wanted_size < samples_size) {
 -                        /* remove samples */
 -                        samples_size = wanted_size;
 -                    } else if (wanted_size > samples_size) {
 -                        uint8_t *samples_end, *q;
 -                        int nb;
 -
 -                        /* add samples */
 -                        nb = (samples_size - wanted_size);
 -                        samples_end = (uint8_t *)samples + samples_size - n;
 -                        q = samples_end + n;
 -                        while (nb > 0) {
 -                            memcpy(q, samples_end, n);
 -                            q += n;
 -                            nb -= n;
 -                        }
 -                        samples_size = wanted_size;
 -                    }
 +                    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);
                  }
                  av_dlog(NULL, "diff=%f adiff=%f sample_diff=%d apts=%0.3f vpts=%0.3f %f\n",
 -                        diff, avg_diff, samples_size - samples_size1,
 +                        diff, avg_diff, wanted_nb_samples - nb_samples,
                          is->audio_clock, is->video_clock, is->audio_diff_threshold);
              }
          } else {
          }
      }
  
 -    return samples_size;
 +    return wanted_nb_samples;
  }
  
  /* decode one audio frame and returns its uncompressed size */
@@@ -1911,26 -1879,22 +1911,26 @@@ static int audio_decode_frame(VideoStat
      AVPacket *pkt_temp = &is->audio_pkt_temp;
      AVPacket *pkt = &is->audio_pkt;
      AVCodecContext *dec = is->audio_st->codec;
 -    int n, len1, data_size, got_frame;
 +    int len1, len2, data_size, resampled_data_size;
 +    int64_t dec_channel_layout;
 +    int got_frame;
      double pts;
      int new_packet = 0;
      int flush_complete = 0;
 +    int wanted_nb_samples;
  
      for (;;) {
          /* NOTE: the audio packet can contain several frames */
          while (pkt_temp->size > 0 || (!pkt_temp->data && new_packet)) {
 -            int resample_changed, audio_resample;
 -
              if (!is->frame) {
                  if (!(is->frame = avcodec_alloc_frame()))
                      return AVERROR(ENOMEM);
              } else
                  avcodec_get_frame_defaults(is->frame);
  
 +            if (is->paused)
 +                return -1;
 +
              if (flush_complete)
                  break;
              new_packet = 0;
                                                     is->frame->nb_samples,
                                                     dec->sample_fmt, 1);
  
 -            audio_resample = dec->sample_fmt     != is->sdl_sample_fmt ||
 -                             dec->channel_layout != is->sdl_channel_layout;
 -
 -            resample_changed = dec->sample_fmt     != is->resample_sample_fmt ||
 -                               dec->channel_layout != is->resample_channel_layout;
 -
 -            if ((!is->avr && audio_resample) || resample_changed) {
 -                int ret;
 -                if (is->avr)
 -                    avresample_close(is->avr);
 -                else if (audio_resample) {
 -                    is->avr = avresample_alloc_context();
 -                    if (!is->avr) {
 -                        fprintf(stderr, "error allocating AVAudioResampleContext\n");
 -                        break;
 -                    }
 +            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           ||
 +                (wanted_nb_samples != is->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,           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);
 +                    break;
                  }
 -                if (audio_resample) {
 -                    av_opt_set_int(is->avr, "in_channel_layout",  dec->channel_layout,    0);
 -                    av_opt_set_int(is->avr, "in_sample_fmt",      dec->sample_fmt,        0);
 -                    av_opt_set_int(is->avr, "in_sample_rate",     dec->sample_rate,       0);
 -                    av_opt_set_int(is->avr, "out_channel_layout", is->sdl_channel_layout, 0);
 -                    av_opt_set_int(is->avr, "out_sample_fmt",     is->sdl_sample_fmt,     0);
 -                    av_opt_set_int(is->avr, "out_sample_rate",    dec->sample_rate,       0);
 -
 -                    if ((ret = avresample_open(is->avr)) < 0) {
 -                        fprintf(stderr, "error initializing libavresample\n");
 +                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;
 +            }
 +
 +            if (is->swr_ctx) {
 +                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) {
 +                        fprintf(stderr, "swr_set_compensation() failed\n");
                          break;
                      }
                  }
 -                is->resample_sample_fmt     = dec->sample_fmt;
 -                is->resample_channel_layout = dec->channel_layout;
 -            }
 -
 -            if (audio_resample) {
 -                void *tmp_out;
 -                int out_samples, out_size, out_linesize;
 -                int osize      = av_get_bytes_per_sample(is->sdl_sample_fmt);
 -                int nb_samples = is->frame->nb_samples;
 -
 -                out_size = av_samples_get_buffer_size(&out_linesize,
 -                                                      is->sdl_channels,
 -                                                      nb_samples,
 -                                                      is->sdl_sample_fmt, 0);
 -                tmp_out = av_realloc(is->audio_buf1, out_size);
 -                if (!tmp_out)
 -                    return AVERROR(ENOMEM);
 -                is->audio_buf1 = tmp_out;
 -
 -                out_samples = avresample_convert(is->avr,
 -                                                 (void **)&is->audio_buf1,
 -                                                 out_linesize, nb_samples,
 -                                                 (void **)is->frame->data,
 -                                                 is->frame->linesize[0],
 -                                                 is->frame->nb_samples);
 -                if (out_samples < 0) {
 -                    fprintf(stderr, "avresample_convert() failed\n");
 +                len2 = swr_convert(is->swr_ctx, out, out_count, in, is->frame->nb_samples);
 +                if (len2 < 0) {
 +                    fprintf(stderr, "swr_convert() failed\n");
                      break;
                  }
 -                is->audio_buf = is->audio_buf1;
 -                data_size = out_samples * osize * is->sdl_channels;
 +                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);
              } 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;
 -            n = is->sdl_channels * av_get_bytes_per_sample(is->sdl_sample_fmt);
              is->audio_clock += (double)data_size /
 -                (double)(n * dec->sample_rate);
 +                (dec->channels * dec->sample_rate * av_get_bytes_per_sample(dec->sample_fmt));
  #ifdef DEBUG
              {
                  static double last_clock;
                  last_clock = is->audio_clock;
              }
  #endif
 -            return data_size;
 +            return resampled_data_size;
          }
  
          /* free the current packet */
@@@ -2056,8 -2033,6 +2056,8 @@@ static void sdl_audio_callback(void *op
  {
      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);
      double pts;
  
      audio_callback_time = av_gettime();
             if (audio_size < 0) {
                  /* if error, just output silence */
                 is->audio_buf      = is->silence_buf;
 -               is->audio_buf_size = sizeof(is->silence_buf);
 +               is->audio_buf_size = sizeof(is->silence_buf) / frame_size * frame_size;
             } else {
 -               if (is->show_audio)
 +               if (is->show_mode != SHOW_MODE_VIDEO)
                     update_sample_display(is, (int16_t *)is->audio_buf, audio_size);
 -               audio_size = synchronize_audio(is, (int16_t *)is->audio_buf, audio_size,
 -                                              pts);
                 is->audio_buf_size = audio_size;
             }
             is->audio_buf_index = 0;
          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);
 +    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 = 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 */
@@@ -2151,6 -2069,7 +2151,6 @@@ static int stream_component_open(VideoS
      AVFormatContext *ic = is->ic;
      AVCodecContext *avctx;
      AVCodec *codec;
 -    SDL_AudioSpec wanted_spec, spec;
      AVDictionary *opts;
      AVDictionaryEntry *t = NULL;
  
          return -1;
      avctx = ic->streams[stream_index]->codec;
  
 -    opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], NULL);
 -
      codec = avcodec_find_decoder(avctx->codec_id);
 -    avctx->debug_mv          = debug_mv;
 -    avctx->debug             = debug;
 +    opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], codec);
 +
 +    switch(avctx->codec_type){
 +        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;
 +
      avctx->workaround_bugs   = workaround_bugs;
 +    avctx->lowres            = lowres;
 +    if(avctx->lowres > codec->max_lowres){
 +        av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n",
 +                codec->max_lowres);
 +        avctx->lowres= codec->max_lowres;
 +    }
      avctx->idct_algo         = idct;
      avctx->skip_frame        = skip_frame;
      avctx->skip_idct         = skip_idct;
      avctx->skip_loop_filter  = skip_loop_filter;
      avctx->error_concealment = error_concealment;
  
 +    if(avctx->lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE;
      if (fast)   avctx->flags2 |= CODEC_FLAG2_FAST;
 +    if(codec->capabilities & CODEC_CAP_DR1)
 +        avctx->flags |= CODEC_FLAG_EMU_EDGE;
  
      if (!av_dict_get(opts, "threads", NULL, 0))
          av_dict_set(&opts, "threads", "auto", 0);
  
      /* prepare audio output */
      if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
 -        wanted_spec.freq = avctx->sample_rate;
 -        wanted_spec.format = AUDIO_S16SYS;
 -
 -        if (!avctx->channel_layout)
 -            avctx->channel_layout = av_get_default_channel_layout(avctx->channels);
 -        if (!avctx->channel_layout) {
 -            fprintf(stderr, "unable to guess channel layout\n");
 +        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 (avctx->channels == 1)
 -            is->sdl_channel_layout = AV_CH_LAYOUT_MONO;
 -        else
 -            is->sdl_channel_layout = AV_CH_LAYOUT_STEREO;
 -        is->sdl_channels = av_get_channel_layout_nb_channels(is->sdl_channel_layout);
 -
 -        wanted_spec.channels = is->sdl_channels;
 -        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;
 -        is->sdl_sample_fmt          = AV_SAMPLE_FMT_S16;
 -        is->resample_sample_fmt     = is->sdl_sample_fmt;
 -        is->resample_channel_layout = is->sdl_channel_layout;
 +        is->audio_hw_buf_size = audio_hw_buf_size;
 +        is->audio_tgt = is->audio_src;
      }
  
      ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
          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 / avctx->sample_rate;
 +        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;
@@@ -2261,9 -2187,10 +2261,9 @@@ static void stream_component_close(Vide
  
          SDL_CloseAudio();
  
 -        packet_queue_end(&is->audioq);
 +        packet_queue_flush(&is->audioq);
          av_free_packet(&is->audio_pkt);
 -        if (is->avr)
 -            avresample_free(&is->avr);
 +        swr_free(&is->swr_ctx);
          av_freep(&is->audio_buf1);
          is->audio_buf = NULL;
          av_freep(&is->frame);
  
          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);
  
          SDL_WaitThread(is->subtitle_tid, NULL);
  
 -        packet_queue_end(&is->subtitleq);
 +        packet_queue_flush(&is->subtitleq);
          break;
      default:
          break;
      }
  }
  
 -/* since we have only one decoding thread, we can use a global
 -   variable instead of a thread local variable */
 -static VideoState *global_video_state;
 -
  static int decode_interrupt_cb(void *ctx)
  {
 -    return global_video_state && global_video_state->abort_request;
 +    VideoState *is = ctx;
 +    return is->abort_request;
  }
  
  /* this thread gets the stream from the disk or the network */
 -static int decode_thread(void *arg)
 +static int read_thread(void *arg)
  {
      VideoState *is = arg;
      AVFormatContext *ic = NULL;
      int orig_nb_streams;
  
      memset(st_index, -1, sizeof(st_index));
 -    is->video_stream = -1;
 -    is->audio_stream = -1;
 -    is->subtitle_stream = -1;
 -
 -    global_video_state = is;
 +    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;
 +    ic->interrupt_callback.opaque = is;
      err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts);
      if (err < 0) {
          print_error(is->filename, err);
      av_freep(&opts);
  
      if (ic->pb)
 -        ic->pb->eof_reached = 0; // FIXME hack, avplay maybe should not use url_feof() to test for the end
 +        ic->pb->eof_reached = 0; // FIXME hack, ffplay maybe should not use url_feof() to test for the end
  
      if (seek_by_bytes < 0)
          seek_by_bytes = !!(ic->iformat->flags & AVFMT_TS_DISCONT);
          av_dump_format(ic, 0, is->filename, 0);
      }
  
 +    is->show_mode = show_mode;
 +
      /* open the streams */
      if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {
          stream_component_open(is, st_index[AVMEDIA_TYPE_AUDIO]);
          ret = stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO]);
      }
      is->refresh_tid = SDL_CreateThread(refresh_thread, is);
 -    if (ret < 0) {
 -        if (!display_disable)
 -            is->show_audio = 2;
 -    }
 +    if (is->show_mode == SHOW_MODE_NONE)
 +        is->show_mode = ret >= 0 ? SHOW_MODE_VIDEO : SHOW_MODE_RDFT;
  
      if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) {
          stream_component_open(is, st_index[AVMEDIA_TYPE_SUBTITLE]);
              else
                  av_read_play(ic);
          }
 -#if CONFIG_RTSP_DEMUXER
 -        if (is->paused && !strcmp(ic->iformat->name, "rtsp")) {
 +#if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL
 +        if (is->paused &&
 +                (!strcmp(ic->iformat->name, "rtsp") ||
 +                 (ic->pb && !strncmp(input_filename, "mmsh:", 5)))) {
              /* wait 10 ms to avoid trying to get another packet */
              /* XXX: horrible */
              SDL_Delay(10);
              is->seek_req = 0;
              eof = 0;
          }
 +        if (is->que_attachments_req) {
 +            avformat_queue_attached_pictures(ic);
 +            is->que_attachments_req = 0;
 +        }
  
          /* if the queue are full, no need to read more */
          if (!infinite_buffer &&
                (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)))) {
 +            || (   (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;
              SDL_Delay(10);
              if (is->audioq.size + is->videoq.size + is->subtitleq.size == 0) {
                  if (loop != 1 && (!loop || --loop)) {
 -                    stream_seek(cur_stream, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0);
 +                    stream_seek(is, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0);
                  } else if (autoexit) {
                      ret = AVERROR_EOF;
                      goto fail;
                  }
              }
 +            eof=0;
              continue;
          }
          ret = av_read_frame(ic, pkt);
          if (ret < 0) {
 -            if (ret == AVERROR_EOF || (ic->pb && ic->pb->eof_reached))
 +            if (ret == AVERROR_EOF || url_feof(ic->pb))
                  eof = 1;
              if (ic->pb && ic->pb->error)
                  break;
  
      ret = 0;
   fail:
 -    /* disable interrupting */
 -    global_video_state = NULL;
 -
      /* close each stream */
      if (is->audio_stream >= 0)
          stream_component_close(is, is->audio_stream);
@@@ -2619,13 -2546,9 +2619,13 @@@ static VideoState *stream_open(const ch
      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->parse_tid    = SDL_CreateThread(decode_thread, is);
 -    if (!is->parse_tid) {
 +    is->read_tid     = SDL_CreateThread(read_thread, is);
 +    if (!is->read_tid) {
          av_free(is);
          return NULL;
      }
@@@ -2636,19 -2559,16 +2636,19 @@@ static void stream_cycle_channel(VideoS
  {
      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)
              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;
          }
      }
   the_end:
 -    stream_component_close(is, start_index);
 +    stream_component_close(is, old_index);
      stream_component_open(is, stream_index);
 +    if (codec_type == AVMEDIA_TYPE_VIDEO)
 +        is->que_attachments_req = 1;
  }
  
  
 -static void toggle_full_screen(void)
 +static void toggle_full_screen(VideoState *is)
  {
  #if defined(__APPLE__) && SDL_VERSION_ATLEAST(1, 2, 14)
 -    /* OS X needs to empty the picture_queue */
 +    /* OS X needs to reallocate the SDL overlays */
      int i;
      for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++)
 -        cur_stream->pictq[i].reallocate = 1;
 +        is->pictq[i].reallocate = 1;
  #endif
      is_full_screen = !is_full_screen;
 -    video_open(cur_stream);
 +    video_open(is, 1);
  }
  
 -static void toggle_pause(void)
 +static void toggle_pause(VideoState *is)
  {
 -    if (cur_stream)
 -        stream_pause(cur_stream);
 -    step = 0;
 +    stream_toggle_pause(is);
 +    is->step = 0;
  }
  
 -static void step_to_next_frame(void)
 +static void step_to_next_frame(VideoState *is)
  {
 -    if (cur_stream) {
 -        /* if the stream is paused unpause it, then step */
 -        if (cur_stream->paused)
 -            stream_pause(cur_stream);
 -    }
 -    step = 1;
 +    /* if the stream is paused unpause it, then step */
 +    if (is->paused)
 +        stream_toggle_pause(is);
 +    is->step = 1;
  }
  
 -static void toggle_audio_display(void)
 +static void toggle_audio_display(VideoState *is)
  {
 -    if (cur_stream) {
 -        int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
 -        cur_stream->show_audio = (cur_stream->show_audio + 1) % 3;
 -        fill_rectangle(screen,
 -                       cur_stream->xleft, cur_stream->ytop, cur_stream->width, cur_stream->height,
 -                       bgcolor);
 -        SDL_UpdateRect(screen, cur_stream->xleft, cur_stream->ytop, cur_stream->width, cur_stream->height);
 -    }
 +    int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
 +    is->show_mode = (is->show_mode + 1) % SHOW_MODE_NB;
 +    fill_rectangle(screen,
 +                is->xleft, is->ytop, is->width, is->height,
 +                bgcolor);
 +    SDL_UpdateRect(screen, is->xleft, is->ytop, is->width, is->height);
  }
  
  /* handle an event sent by the GUI */
 -static void event_loop(void)
 +static void event_loop(VideoState *cur_stream)
  {
      SDL_Event event;
      double incr, pos, frac;
          switch (event.type) {
          case SDL_KEYDOWN:
              if (exit_on_keydown) {
 -                do_exit();
 +                do_exit(cur_stream);
                  break;
              }
              switch (event.key.keysym.sym) {
              case SDLK_ESCAPE:
              case SDLK_q:
 -                do_exit();
 +                do_exit(cur_stream);
                  break;
              case SDLK_f:
 -                toggle_full_screen();
 +                toggle_full_screen(cur_stream);
 +                cur_stream->force_refresh = 1;
                  break;
              case SDLK_p:
              case SDLK_SPACE:
 -                toggle_pause();
 +                toggle_pause(cur_stream);
                  break;
              case SDLK_s: // S: Step to next frame
 -                step_to_next_frame();
 +                step_to_next_frame(cur_stream);
                  break;
              case SDLK_a:
 -                if (cur_stream)
 -                    stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
 +                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
                  break;
              case SDLK_v:
 -                if (cur_stream)
 -                    stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
 +                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
                  break;
              case SDLK_t:
 -                if (cur_stream)
 -                    stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
 +                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
                  break;
              case SDLK_w:
 -                toggle_audio_display();
 +                toggle_audio_display(cur_stream);
 +                cur_stream->force_refresh = 1;
                  break;
 +            case SDLK_PAGEUP:
 +                incr = 600.0;
 +                goto do_seek;
 +            case SDLK_PAGEDOWN:
 +                incr = -600.0;
 +                goto do_seek;
              case SDLK_LEFT:
                  incr = -10.0;
                  goto do_seek;
              case SDLK_DOWN:
                  incr = -60.0;
              do_seek:
 -                if (cur_stream) {
                      if (seek_by_bytes) {
                          if (cur_stream->video_stream >= 0 && cur_stream->video_current_pos >= 0) {
                              pos = cur_stream->video_current_pos;
                          pos += incr;
                          stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0);
                      }
 -                }
                  break;
              default:
                  break;
              }
              break;
 +        case SDL_VIDEOEXPOSE:
 +            cur_stream->force_refresh = 1;
 +            break;
          case SDL_MOUSEBUTTONDOWN:
              if (exit_on_mousedown) {
 -                do_exit();
 +                do_exit(cur_stream);
                  break;
              }
          case SDL_MOUSEMOTION:
                      break;
                  x = event.motion.x;
              }
 -            if (cur_stream) {
                  if (seek_by_bytes || cur_stream->ic->duration <= 0) {
                      uint64_t size =  avio_size(cur_stream->ic->pb);
                      stream_seek(cur_stream, size*x/cur_stream->width, 0, 1);
                          ts += cur_stream->ic->start_time;
                      stream_seek(cur_stream, ts, 0, 0);
                  }
 -            }
              break;
          case SDL_VIDEORESIZE:
 -            if (cur_stream) {
                  screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 0,
                                            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();
 +            do_exit(cur_stream);
              break;
          case FF_ALLOC_EVENT:
 -            video_open(event.user.data1);
              alloc_picture(event.user.data1);
              break;
          case FF_REFRESH_EVENT:
 -            video_refresh_timer(event.user.data1);
 +            video_refresh(event.user.data1);
              cur_stream->refresh = 0;
              break;
          default:
  
  static int opt_frame_size(const char *opt, const char *arg)
  {
 -    av_log(NULL, AV_LOG_ERROR,
 -           "Option '%s' has been removed, use private format options instead\n", opt);
 -    return AVERROR(EINVAL);
 +    av_log(NULL, AV_LOG_WARNING, "Option -s is deprecated, use -video_size.\n");
 +    return opt_default("video_size", arg);
  }
  
  static int opt_width(const char *opt, const char *arg)
@@@ -2905,8 -2824,9 +2905,8 @@@ static int opt_format(const char *opt, 
  
  static int opt_frame_pix_fmt(const char *opt, const char *arg)
  {
 -    av_log(NULL, AV_LOG_ERROR,
 -           "Option '%s' has been removed, use private format options instead\n", opt);
 -    return AVERROR(EINVAL);
 +    av_log(NULL, AV_LOG_WARNING, "Option -pix_fmt is deprecated, use -pixel_format.\n");
 +    return opt_default("pixel_format", arg);
  }
  
  static int opt_sync(const char *opt, const char *arg)
@@@ -2936,39 -2856,19 +2936,39 @@@ static int opt_duration(const char *opt
      return 0;
  }
  
 -static int opt_debug(const char *opt, const char *arg)
 +static int opt_show_mode(const char *opt, const char *arg)
  {
 -    av_log_set_level(99);
 -    debug = parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX);
 +    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;
  }
  
 -static int opt_vismv(const char *opt, const char *arg)
 +static void opt_input_file(void *optctx, const char *filename)
 +{
 +    if (input_filename) {
 +        fprintf(stderr, "Argument '%s' provided as input filename, but '%s' was already specified.\n",
 +                filename, input_filename);
 +        exit_program(1);
 +    }
 +    if (!strcmp(filename, "-"))
 +        filename = "pipe:";
 +    input_filename = filename;
 +}
 +
 +static int opt_codec(void *o, const char *opt, const char *arg)
  {
 -    debug_mv = parse_number_or_die(opt, arg, OPT_INT64, INT_MIN, INT_MAX);
 +    switch(opt[strlen(opt)-1]){
 +    case 'a' :    audio_codec_name = arg; break;
 +    case 's' : subtitle_codec_name = arg; break;
 +    case 'v' :    video_codec_name = arg; break;
 +    }
      return 0;
  }
  
 +static int dummy;
 +
  static const OptionDef options[] = {
  #include "cmdutils_common_opts.h"
      { "x", HAS_ARG, { (void*)opt_width }, "force displayed width", "width" },
      { "f", HAS_ARG, { (void*)opt_format }, "force format", "fmt" },
      { "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { (void*)opt_frame_pix_fmt }, "set pixel format", "format" },
      { "stats", OPT_BOOL | OPT_EXPERT, { (void*)&show_status }, "show status", "" },
 -    { "debug", HAS_ARG | OPT_EXPERT, { (void*)opt_debug }, "print specific debug info", "" },
      { "bug", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&workaround_bugs }, "workaround bugs", "" },
 -    { "vismv", HAS_ARG | OPT_EXPERT, { (void*)opt_vismv }, "visualize motion vectors", "" },
      { "fast", OPT_BOOL | OPT_EXPERT, { (void*)&fast }, "non spec compliant optimizations", "" },
      { "genpts", OPT_BOOL | OPT_EXPERT, { (void*)&genpts }, "generate pts", "" },
      { "drp", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&decoder_reorder_pts }, "let decoder reorder pts 0=off 1=on -1=auto", ""},
 +    { "lowres", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&lowres }, "", "" },
      { "skiploop", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&skip_loop_filter }, "", "" },
      { "skipframe", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&skip_frame }, "", "" },
      { "skipidct", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&skip_idct }, "", "" },
      { "vf", OPT_STRING | HAS_ARG, { (void*)&vfilters }, "video filters", "filter list" },
  #endif
      { "rdftspeed", OPT_INT | HAS_ARG| OPT_AUDIO | OPT_EXPERT, { (void*)&rdftspeed }, "rdft speed", "msecs" },
 +    { "showmode", HAS_ARG, {(void*)opt_show_mode}, "select show mode (0 = video, 1 = waves, 2 = RDFT)", "mode" },
      { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { (void*)opt_default }, "generic catch all option", "" },
 -    { "i", 0, { NULL }, "avconv compatibility dummy option", ""},
 +    { "i", OPT_BOOL, {(void *)&dummy}, "read specified file", "input_file"},
 +    { "codec", HAS_ARG | OPT_FUNC2, {(void*)opt_codec}, "force decoder", "decoder" },
      { NULL, },
  };
  
  static void show_usage(void)
  {
 -    printf("Simple media player\n");
 -    printf("usage: %s [options] input_file\n", program_name);
 -    printf("\n");
 +    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");
  }
  
  static int show_help(const char *opt, const char *arg)
  {
      av_log_set_callback(log_callback_help);
      show_usage();
-     show_help_options(options, "Main options:\n",
-                       OPT_EXPERT, 0);
-     show_help_options(options, "\nAdvanced options:\n",
-                       OPT_EXPERT, OPT_EXPERT);
+     show_help_options(options, "Main options:", 0, OPT_EXPERT);
+     show_help_options(options, "Advanced options:", OPT_EXPERT, 0);
      printf("\n");
      show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM);
      show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
  #if !CONFIG_AVFILTER
      show_help_children(sws_get_class(), AV_OPT_FLAG_ENCODING_PARAM);
 +#else
 +    show_help_children(avfilter_get_class(), AV_OPT_FLAG_FILTERING_PARAM);
  #endif
      printf("\nWhile playing:\n"
             "q, ESC              quit\n"
             "s                   activate frame-step mode\n"
             "left/right          seek backward/forward 10 seconds\n"
             "down/up             seek backward/forward 1 minute\n"
 +           "page down/page up   seek backward/forward 10 minutes\n"
             "mouse click         seek to percentage in file corresponding to fraction of width\n"
             );
 -
      return 0;
  }
  
 -static void opt_input_file(void *optctx, const char *filename)
 +static int lockmgr(void **mtx, enum AVLockOp op)
  {
 -    if (input_filename) {
 -        fprintf(stderr, "Argument '%s' provided as input filename, but '%s' was already specified.\n",
 -                filename, input_filename);
 -        exit(1);
 -    }
 -    if (!strcmp(filename, "-"))
 -        filename = "pipe:";
 -    input_filename = filename;
 +   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;
  }
  
  /* Called from the main */
  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);
  
      init_opts();
  
 -    show_banner();
 +    signal(SIGINT , sigterm_handler); /* Interrupt (ANSI).    */
 +    signal(SIGTERM, sigterm_handler); /* Termination (ANSI).  */
 +
 +    show_banner(argc, argv, options);
  
      parse_options(NULL, argc, argv, options, opt_input_file);
  
          video_disable = 1;
      }
      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
      if (SDL_Init (flags)) {
          fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
 +        fprintf(stderr, "(Did you set the DISPLAY variable?)\n");
          exit(1);
      }
  
      SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
      SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
  
 +    if (av_lockmgr_register(lockmgr)) {
 +        fprintf(stderr, "Could not initialize lock manager!\n");
 +        do_exit(NULL);
 +    }
 +
      av_init_packet(&flush_pkt);
 -    flush_pkt.data = "FLUSH";
 +    flush_pkt.data = (char *)(intptr_t)"FLUSH";
  
 -    cur_stream = stream_open(input_filename, file_iformat);
 +    is = stream_open(input_filename, file_iformat);
 +    if (!is) {
 +        fprintf(stderr, "Failed to initialize VideoState!\n");
 +        do_exit(NULL);
 +    }
  
 -    event_loop();
 +    event_loop(is);
  
      /* never returns */
  
diff --combined ffprobe.c
index 0038956,0000000..2046ec0
mode 100644,000000..100644
--- /dev/null
+++ b/ffprobe.c
@@@ -1,2205 -1,0 +1,2205 @@@
-     show_help_options(options, "Main options:\n", 0, 0);
 +/*
 + * Copyright (c) 2007-2010 Stefano Sabatini
 + *
 + * This file is part of FFmpeg.
 + *
 + * FFmpeg is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2.1 of the License, or (at your option) any later version.
 + *
 + * FFmpeg is distributed in the hope that it will be useful,
 + * 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
 + * License along with FFmpeg; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 + */
 +
 +/**
 + * @file
 + * simple media prober based on the FFmpeg libraries
 + */
 +
 +#include "config.h"
 +#include "version.h"
 +
 +#include "libavformat/avformat.h"
 +#include "libavcodec/avcodec.h"
 +#include "libavutil/avstring.h"
 +#include "libavutil/bprint.h"
 +#include "libavutil/opt.h"
 +#include "libavutil/pixdesc.h"
 +#include "libavutil/dict.h"
 +#include "libavutil/libm.h"
 +#include "libavutil/timecode.h"
 +#include "libavdevice/avdevice.h"
 +#include "libswscale/swscale.h"
 +#include "libswresample/swresample.h"
 +#include "libpostproc/postprocess.h"
 +#include "cmdutils.h"
 +
 +const char program_name[] = "ffprobe";
 +const int program_birth_year = 2007;
 +
 +static int do_count_frames = 0;
 +static int do_count_packets = 0;
 +static int do_read_frames  = 0;
 +static int do_read_packets = 0;
 +static int do_show_error   = 0;
 +static int do_show_format  = 0;
 +static int do_show_frames  = 0;
 +static AVDictionary *fmt_entries_to_show = NULL;
 +static int do_show_packets = 0;
 +static int do_show_streams = 0;
 +static int do_show_data    = 0;
 +static int do_show_program_version  = 0;
 +static int do_show_library_versions = 0;
 +
 +static int show_value_unit              = 0;
 +static int use_value_prefix             = 0;
 +static int use_byte_value_binary_prefix = 0;
 +static int use_value_sexagesimal_format = 0;
 +static int show_private_data            = 1;
 +
 +static char *print_format;
 +
 +static const OptionDef *options;
 +
 +/* FFprobe context */
 +static const char *input_filename;
 +static AVInputFormat *iformat = NULL;
 +
 +static const char *const binary_unit_prefixes [] = { "", "Ki", "Mi", "Gi", "Ti", "Pi" };
 +static const char *const decimal_unit_prefixes[] = { "", "K" , "M" , "G" , "T" , "P"  };
 +
 +static const char unit_second_str[]         = "s"    ;
 +static const char unit_hertz_str[]          = "Hz"   ;
 +static const char unit_byte_str[]           = "byte" ;
 +static const char unit_bit_per_second_str[] = "bit/s";
 +static uint64_t *nb_streams_packets;
 +static uint64_t *nb_streams_frames;
 +
 +void av_noreturn exit_program(int ret)
 +{
 +    av_dict_free(&fmt_entries_to_show);
 +    exit(ret);
 +}
 +
 +struct unit_value {
 +    union { double d; long long int i; } val;
 +    const char *unit;
 +};
 +
 +static char *value_string(char *buf, int buf_size, struct unit_value uv)
 +{
 +    double vald;
 +    int show_float = 0;
 +
 +    if (uv.unit == unit_second_str) {
 +        vald = uv.val.d;
 +        show_float = 1;
 +    } else {
 +        vald = uv.val.i;
 +    }
 +
 +    if (uv.unit == unit_second_str && use_value_sexagesimal_format) {
 +        double secs;
 +        int hours, mins;
 +        secs  = vald;
 +        mins  = (int)secs / 60;
 +        secs  = secs - mins * 60;
 +        hours = mins / 60;
 +        mins %= 60;
 +        snprintf(buf, buf_size, "%d:%02d:%09.6f", hours, mins, secs);
 +    } else {
 +        const char *prefix_string = "";
 +        int l;
 +
 +        if (use_value_prefix && vald > 1) {
 +            long long int index;
 +
 +            if (uv.unit == unit_byte_str && use_byte_value_binary_prefix) {
 +                index = (long long int) (log2(vald)) / 10;
 +                index = av_clip(index, 0, FF_ARRAY_ELEMS(binary_unit_prefixes) - 1);
 +                vald /= pow(2, index * 10);
 +                prefix_string = binary_unit_prefixes[index];
 +            } else {
 +                index = (long long int) (log10(vald)) / 3;
 +                index = av_clip(index, 0, FF_ARRAY_ELEMS(decimal_unit_prefixes) - 1);
 +                vald /= pow(10, index * 3);
 +                prefix_string = decimal_unit_prefixes[index];
 +            }
 +        }
 +
 +        if (show_float || (use_value_prefix && vald != (long long int)vald))
 +            l = snprintf(buf, buf_size, "%f", vald);
 +        else
 +            l = snprintf(buf, buf_size, "%lld", (long long int)vald);
 +        snprintf(buf+l, buf_size-l, "%s%s%s", *prefix_string || show_value_unit ? " " : "",
 +                 prefix_string, show_value_unit ? uv.unit : "");
 +    }
 +
 +    return buf;
 +}
 +
 +/* WRITERS API */
 +
 +typedef struct WriterContext WriterContext;
 +
 +#define WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS 1
 +#define WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER 2
 +
 +typedef struct Writer {
 +    int priv_size;                  ///< private size for the writer context
 +    const char *name;
 +
 +    int  (*init)  (WriterContext *wctx, const char *args, void *opaque);
 +    void (*uninit)(WriterContext *wctx);
 +
 +    void (*print_header)(WriterContext *ctx);
 +    void (*print_footer)(WriterContext *ctx);
 +
 +    void (*print_chapter_header)(WriterContext *wctx, const char *);
 +    void (*print_chapter_footer)(WriterContext *wctx, const char *);
 +    void (*print_section_header)(WriterContext *wctx, const char *);
 +    void (*print_section_footer)(WriterContext *wctx, const char *);
 +    void (*print_integer)       (WriterContext *wctx, const char *, long long int);
 +    void (*print_rational)      (WriterContext *wctx, AVRational *q, char *sep);
 +    void (*print_string)        (WriterContext *wctx, const char *, const char *);
 +    void (*show_tags)           (WriterContext *wctx, AVDictionary *dict);
 +    int flags;                  ///< a combination or WRITER_FLAG_*
 +} Writer;
 +
 +struct WriterContext {
 +    const AVClass *class;           ///< class of the writer
 +    const Writer *writer;           ///< the Writer of which this is an instance
 +    char *name;                     ///< name of this writer instance
 +    void *priv;                     ///< private data for use by the filter
 +    unsigned int nb_item;           ///< number of the item printed in the given section, starting at 0
 +    unsigned int nb_section;        ///< number of the section printed in the given section sequence, starting at 0
 +    unsigned int nb_section_packet; ///< number of the packet section in case we are in "packets_and_frames" section
 +    unsigned int nb_section_frame;  ///< number of the frame  section in case we are in "packets_and_frames" section
 +    unsigned int nb_section_packet_frame; ///< nb_section_packet or nb_section_frame according if is_packets_and_frames
 +    unsigned int nb_chapter;        ///< number of the chapter, starting at 0
 +
 +    int multiple_sections;          ///< tells if the current chapter can contain multiple sections
 +    int is_fmt_chapter;             ///< tells if the current chapter is "format", required by the print_format_entry option
 +    int is_packets_and_frames;      ///< tells if the current section is "packets_and_frames"
 +};
 +
 +static const char *writer_get_name(void *p)
 +{
 +    WriterContext *wctx = p;
 +    return wctx->writer->name;
 +}
 +
 +static const AVClass writer_class = {
 +    "Writer",
 +    writer_get_name,
 +    NULL,
 +    LIBAVUTIL_VERSION_INT,
 +};
 +
 +static void writer_close(WriterContext **wctx)
 +{
 +    if (!*wctx)
 +        return;
 +
 +    if ((*wctx)->writer->uninit)
 +        (*wctx)->writer->uninit(*wctx);
 +    av_freep(&((*wctx)->priv));
 +    av_freep(wctx);
 +}
 +
 +static int writer_open(WriterContext **wctx, const Writer *writer,
 +                       const char *args, void *opaque)
 +{
 +    int ret = 0;
 +
 +    if (!(*wctx = av_malloc(sizeof(WriterContext)))) {
 +        ret = AVERROR(ENOMEM);
 +        goto fail;
 +    }
 +
 +    if (!((*wctx)->priv = av_mallocz(writer->priv_size))) {
 +        ret = AVERROR(ENOMEM);
 +        goto fail;
 +    }
 +
 +    (*wctx)->class = &writer_class;
 +    (*wctx)->writer = writer;
 +    if ((*wctx)->writer->init)
 +        ret = (*wctx)->writer->init(*wctx, args, opaque);
 +    if (ret < 0)
 +        goto fail;
 +
 +    return 0;
 +
 +fail:
 +    writer_close(wctx);
 +    return ret;
 +}
 +
 +static inline void writer_print_header(WriterContext *wctx)
 +{
 +    if (wctx->writer->print_header)
 +        wctx->writer->print_header(wctx);
 +    wctx->nb_chapter = 0;
 +}
 +
 +static inline void writer_print_footer(WriterContext *wctx)
 +{
 +    if (wctx->writer->print_footer)
 +        wctx->writer->print_footer(wctx);
 +}
 +
 +static inline void writer_print_chapter_header(WriterContext *wctx,
 +                                               const char *chapter)
 +{
 +    wctx->nb_section =
 +    wctx->nb_section_packet = wctx->nb_section_frame =
 +    wctx->nb_section_packet_frame = 0;
 +    wctx->is_packets_and_frames = !strcmp(chapter, "packets_and_frames");
 +    wctx->multiple_sections = !strcmp(chapter, "packets") || !strcmp(chapter, "frames" ) ||
 +                              wctx->is_packets_and_frames ||
 +                              !strcmp(chapter, "streams") || !strcmp(chapter, "library_versions");
 +    wctx->is_fmt_chapter = !strcmp(chapter, "format");
 +
 +    if (wctx->writer->print_chapter_header)
 +        wctx->writer->print_chapter_header(wctx, chapter);
 +}
 +
 +static inline void writer_print_chapter_footer(WriterContext *wctx,
 +                                               const char *chapter)
 +{
 +    if (wctx->writer->print_chapter_footer)
 +        wctx->writer->print_chapter_footer(wctx, chapter);
 +    wctx->nb_chapter++;
 +}
 +
 +static inline void writer_print_section_header(WriterContext *wctx,
 +                                               const char *section)
 +{
 +    if (wctx->is_packets_and_frames)
 +        wctx->nb_section_packet_frame = !strcmp(section, "packet") ? wctx->nb_section_packet
 +                                                                   : wctx->nb_section_frame;
 +    if (wctx->writer->print_section_header)
 +        wctx->writer->print_section_header(wctx, section);
 +    wctx->nb_item = 0;
 +}
 +
 +static inline void writer_print_section_footer(WriterContext *wctx,
 +                                               const char *section)
 +{
 +    if (wctx->writer->print_section_footer)
 +        wctx->writer->print_section_footer(wctx, section);
 +    if (wctx->is_packets_and_frames) {
 +        if (!strcmp(section, "packet")) wctx->nb_section_packet++;
 +        else                            wctx->nb_section_frame++;
 +    }
 +    wctx->nb_section++;
 +}
 +
 +static inline void writer_print_integer(WriterContext *wctx,
 +                                        const char *key, long long int val)
 +{
 +    if (!wctx->is_fmt_chapter || !fmt_entries_to_show || av_dict_get(fmt_entries_to_show, key, NULL, 0)) {
 +        wctx->writer->print_integer(wctx, key, val);
 +        wctx->nb_item++;
 +    }
 +}
 +
 +static inline void writer_print_rational(WriterContext *wctx,
 +                                         const char *key, AVRational q, char sep)
 +{
 +    AVBPrint buf;
 +    av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
 +    av_bprintf(&buf, "%d%c%d", q.num, sep, q.den);
 +    wctx->writer->print_string(wctx, key, buf.str);
 +    wctx->nb_item++;
 +}
 +
 +static inline void writer_print_string(WriterContext *wctx,
 +                                       const char *key, const char *val, int opt)
 +{
 +    if (opt && !(wctx->writer->flags & WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS))
 +        return;
 +    if (!wctx->is_fmt_chapter || !fmt_entries_to_show || av_dict_get(fmt_entries_to_show, key, NULL, 0)) {
 +        wctx->writer->print_string(wctx, key, val);
 +        wctx->nb_item++;
 +    }
 +}
 +
 +static void writer_print_time(WriterContext *wctx, const char *key,
 +                              int64_t ts, const AVRational *time_base, int is_duration)
 +{
 +    char buf[128];
 +
 +    if (!wctx->is_fmt_chapter || !fmt_entries_to_show || av_dict_get(fmt_entries_to_show, key, NULL, 0)) {
 +        if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
 +            writer_print_string(wctx, key, "N/A", 1);
 +        } else {
 +            double d = ts * av_q2d(*time_base);
 +            value_string(buf, sizeof(buf), (struct unit_value){.val.d=d, .unit=unit_second_str});
 +            writer_print_string(wctx, key, buf, 0);
 +        }
 +    }
 +}
 +
 +static void writer_print_ts(WriterContext *wctx, const char *key, int64_t ts, int is_duration)
 +{
 +    if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
 +        writer_print_string(wctx, key, "N/A", 1);
 +    } else {
 +        writer_print_integer(wctx, key, ts);
 +    }
 +}
 +
 +static inline void writer_show_tags(WriterContext *wctx, AVDictionary *dict)
 +{
 +    wctx->writer->show_tags(wctx, dict);
 +}
 +
 +static void writer_print_data(WriterContext *wctx, const char *name,
 +                              uint8_t *data, int size)
 +{
 +    AVBPrint bp;
 +    int offset = 0, l, i;
 +
 +    av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
 +    av_bprintf(&bp, "\n");
 +    while (size) {
 +        av_bprintf(&bp, "%08x: ", offset);
 +        l = FFMIN(size, 16);
 +        for (i = 0; i < l; i++) {
 +            av_bprintf(&bp, "%02x", data[i]);
 +            if (i & 1)
 +                av_bprintf(&bp, " ");
 +        }
 +        av_bprint_chars(&bp, ' ', 41 - 2 * i - i / 2);
 +        for (i = 0; i < l; i++)
 +            av_bprint_chars(&bp, data[i] - 32U < 95 ? data[i] : '.', 1);
 +        av_bprintf(&bp, "\n");
 +        offset += l;
 +        data   += l;
 +        size   -= l;
 +    }
 +    writer_print_string(wctx, name, bp.str, 0);
 +    av_bprint_finalize(&bp, NULL);
 +}
 +
 +#define MAX_REGISTERED_WRITERS_NB 64
 +
 +static const Writer *registered_writers[MAX_REGISTERED_WRITERS_NB + 1];
 +
 +static int writer_register(const Writer *writer)
 +{
 +    static int next_registered_writer_idx = 0;
 +
 +    if (next_registered_writer_idx == MAX_REGISTERED_WRITERS_NB)
 +        return AVERROR(ENOMEM);
 +
 +    registered_writers[next_registered_writer_idx++] = writer;
 +    return 0;
 +}
 +
 +static const Writer *writer_get_by_name(const char *name)
 +{
 +    int i;
 +
 +    for (i = 0; registered_writers[i]; i++)
 +        if (!strcmp(registered_writers[i]->name, name))
 +            return registered_writers[i];
 +
 +    return NULL;
 +}
 +
 +
 +/* WRITERS */
 +
 +/* Default output */
 +
 +typedef struct DefaultContext {
 +    const AVClass *class;
 +    int nokey;
 +    int noprint_wrappers;
 +} DefaultContext;
 +
 +#define OFFSET(x) offsetof(DefaultContext, x)
 +
 +static const AVOption default_options[] = {
 +    { "noprint_wrappers", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_INT, {.dbl=0}, 0, 1 },
 +    { "nw",               "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_INT, {.dbl=0}, 0, 1 },
 +    { "nokey",          "force no key printing",     OFFSET(nokey),          AV_OPT_TYPE_INT, {.dbl=0}, 0, 1 },
 +    { "nk",             "force no key printing",     OFFSET(nokey),          AV_OPT_TYPE_INT, {.dbl=0}, 0, 1 },
 +    {NULL},
 +};
 +
 +static const char *default_get_name(void *ctx)
 +{
 +    return "default";
 +}
 +
 +static const AVClass default_class = {
 +    "DefaultContext",
 +    default_get_name,
 +    default_options
 +};
 +
 +static av_cold int default_init(WriterContext *wctx, const char *args, void *opaque)
 +{
 +    DefaultContext *def = wctx->priv;
 +    int err;
 +
 +    def->class = &default_class;
 +    av_opt_set_defaults(def);
 +
 +    if (args &&
 +        (err = (av_set_options_string(def, args, "=", ":"))) < 0)
 +        return err;
 +
 +    return 0;
 +}
 +
 +static void default_print_footer(WriterContext *wctx)
 +{
 +    DefaultContext *def = wctx->priv;
 +
 +    if (!def->noprint_wrappers)
 +        printf("\n");
 +}
 +
 +static void default_print_chapter_header(WriterContext *wctx, const char *chapter)
 +{
 +    DefaultContext *def = wctx->priv;
 +
 +    if (!def->noprint_wrappers && wctx->nb_chapter)
 +        printf("\n");
 +}
 +
 +/* lame uppercasing routine, assumes the string is lower case ASCII */
 +static inline char *upcase_string(char *dst, size_t dst_size, const char *src)
 +{
 +    int i;
 +    for (i = 0; src[i] && i < dst_size-1; i++)
 +        dst[i] = av_toupper(src[i]);
 +    dst[i] = 0;
 +    return dst;
 +}
 +
 +static void default_print_section_header(WriterContext *wctx, const char *section)
 +{
 +    DefaultContext *def = wctx->priv;
 +    char buf[32];
 +
 +    if (wctx->nb_section)
 +        printf("\n");
 +    if (!def->noprint_wrappers)
 +        printf("[%s]\n", upcase_string(buf, sizeof(buf), section));
 +}
 +
 +static void default_print_section_footer(WriterContext *wctx, const char *section)
 +{
 +    DefaultContext *def = wctx->priv;
 +    char buf[32];
 +
 +    if (!def->noprint_wrappers)
 +        printf("[/%s]", upcase_string(buf, sizeof(buf), section));
 +}
 +
 +static void default_print_str(WriterContext *wctx, const char *key, const char *value)
 +{
 +    DefaultContext *def = wctx->priv;
 +    if (!def->nokey)
 +        printf("%s=", key);
 +    printf("%s\n", value);
 +}
 +
 +static void default_print_int(WriterContext *wctx, const char *key, long long int value)
 +{
 +    DefaultContext *def = wctx->priv;
 +
 +    if (!def->nokey)
 +        printf("%s=", key);
 +    printf("%lld\n", value);
 +}
 +
 +static void default_show_tags(WriterContext *wctx, AVDictionary *dict)
 +{
 +    AVDictionaryEntry *tag = NULL;
 +    while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
 +        if (!fmt_entries_to_show || (tag->key && av_dict_get(fmt_entries_to_show, tag->key, NULL, 0)))
 +            printf("TAG:");
 +        writer_print_string(wctx, tag->key, tag->value, 0);
 +    }
 +}
 +
 +static const Writer default_writer = {
 +    .name                  = "default",
 +    .priv_size             = sizeof(DefaultContext),
 +    .init                  = default_init,
 +    .print_footer          = default_print_footer,
 +    .print_chapter_header  = default_print_chapter_header,
 +    .print_section_header  = default_print_section_header,
 +    .print_section_footer  = default_print_section_footer,
 +    .print_integer         = default_print_int,
 +    .print_string          = default_print_str,
 +    .show_tags             = default_show_tags,
 +    .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
 +};
 +
 +/* Compact output */
 +
 +/**
 + * Apply C-language-like string escaping.
 + */
 +static const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
 +{
 +    const char *p;
 +
 +    for (p = src; *p; p++) {
 +        switch (*p) {
 +        case '\b': av_bprintf(dst, "%s", "\\b");  break;
 +        case '\f': av_bprintf(dst, "%s", "\\f");  break;
 +        case '\n': av_bprintf(dst, "%s", "\\n");  break;
 +        case '\r': av_bprintf(dst, "%s", "\\r");  break;
 +        case '\\': av_bprintf(dst, "%s", "\\\\"); break;
 +        default:
 +            if (*p == sep)
 +                av_bprint_chars(dst, '\\', 1);
 +            av_bprint_chars(dst, *p, 1);
 +        }
 +    }
 +    return dst->str;
 +}
 +
 +/**
 + * Quote fields containing special characters, check RFC4180.
 + */
 +static const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
 +{
 +    const char *p;
 +    int quote = 0;
 +
 +    /* check if input needs quoting */
 +    for (p = src; *p; p++)
 +        if (*p == '"' || *p == sep || *p == '\n' || *p == '\r')
 +            quote = 1;
 +
 +    if (quote)
 +        av_bprint_chars(dst, '\"', 1);
 +
 +    for (p = src; *p; p++) {
 +        if (*p == '"')
 +            av_bprint_chars(dst, '\"', 1);
 +        av_bprint_chars(dst, *p, 1);
 +    }
 +    if (quote)
 +        av_bprint_chars(dst, '\"', 1);
 +    return dst->str;
 +}
 +
 +static const char *none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
 +{
 +    return src;
 +}
 +
 +typedef struct CompactContext {
 +    const AVClass *class;
 +    char *item_sep_str;
 +    char item_sep;
 +    int nokey;
 +    char *escape_mode_str;
 +    const char * (*escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx);
 +} CompactContext;
 +
 +#undef OFFSET
 +#define OFFSET(x) offsetof(CompactContext, x)
 +
 +static const AVOption compact_options[]= {
 +    {"item_sep", "set item separator",    OFFSET(item_sep_str),    AV_OPT_TYPE_STRING, {.str="|"},  CHAR_MIN, CHAR_MAX },
 +    {"s",        "set item separator",    OFFSET(item_sep_str),    AV_OPT_TYPE_STRING, {.str="|"},  CHAR_MIN, CHAR_MAX },
 +    {"nokey",    "force no key printing", OFFSET(nokey),           AV_OPT_TYPE_INT,    {.dbl=0},    0,        1        },
 +    {"nk",       "force no key printing", OFFSET(nokey),           AV_OPT_TYPE_INT,    {.dbl=0},    0,        1        },
 +    {"escape",   "set escape mode",       OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"},  CHAR_MIN, CHAR_MAX },
 +    {"e",        "set escape mode",       OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"},  CHAR_MIN, CHAR_MAX },
 +    {NULL},
 +};
 +
 +static const char *compact_get_name(void *ctx)
 +{
 +    return "compact";
 +}
 +
 +static const AVClass compact_class = {
 +    "CompactContext",
 +    compact_get_name,
 +    compact_options
 +};
 +
 +static av_cold int compact_init(WriterContext *wctx, const char *args, void *opaque)
 +{
 +    CompactContext *compact = wctx->priv;
 +    int err;
 +
 +    compact->class = &compact_class;
 +    av_opt_set_defaults(compact);
 +
 +    if (args &&
 +        (err = (av_set_options_string(compact, args, "=", ":"))) < 0)
 +        return err;
 +    if (strlen(compact->item_sep_str) != 1) {
 +        av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
 +               compact->item_sep_str);
 +        return AVERROR(EINVAL);
 +    }
 +    compact->item_sep = compact->item_sep_str[0];
 +
 +    if      (!strcmp(compact->escape_mode_str, "none")) compact->escape_str = none_escape_str;
 +    else if (!strcmp(compact->escape_mode_str, "c"   )) compact->escape_str = c_escape_str;
 +    else if (!strcmp(compact->escape_mode_str, "csv" )) compact->escape_str = csv_escape_str;
 +    else {
 +        av_log(wctx, AV_LOG_ERROR, "Unknown escape mode '%s'\n", compact->escape_mode_str);
 +        return AVERROR(EINVAL);
 +    }
 +
 +    return 0;
 +}
 +
 +static av_cold void compact_uninit(WriterContext *wctx)
 +{
 +    CompactContext *compact = wctx->priv;
 +
 +    av_freep(&compact->item_sep_str);
 +    av_freep(&compact->escape_mode_str);
 +}
 +
 +static void compact_print_section_header(WriterContext *wctx, const char *section)
 +{
 +    CompactContext *compact = wctx->priv;
 +
 +    printf("%s%c", section, compact->item_sep);
 +}
 +
 +static void compact_print_section_footer(WriterContext *wctx, const char *section)
 +{
 +    printf("\n");
 +}
 +
 +static void compact_print_str(WriterContext *wctx, const char *key, const char *value)
 +{
 +    CompactContext *compact = wctx->priv;
 +    AVBPrint buf;
 +
 +    if (wctx->nb_item) printf("%c", compact->item_sep);
 +    if (!compact->nokey)
 +        printf("%s=", key);
 +    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
 +    printf("%s", compact->escape_str(&buf, value, compact->item_sep, wctx));
 +    av_bprint_finalize(&buf, NULL);
 +}
 +
 +static void compact_print_int(WriterContext *wctx, const char *key, long long int value)
 +{
 +    CompactContext *compact = wctx->priv;
 +
 +    if (wctx->nb_item) printf("%c", compact->item_sep);
 +    if (!compact->nokey)
 +        printf("%s=", key);
 +    printf("%lld", value);
 +}
 +
 +static void compact_show_tags(WriterContext *wctx, AVDictionary *dict)
 +{
 +    CompactContext *compact = wctx->priv;
 +    AVDictionaryEntry *tag = NULL;
 +    AVBPrint buf;
 +
 +    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
 +    while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
 +        if (wctx->nb_item) printf("%c", compact->item_sep);
 +        if (!compact->nokey) {
 +            av_bprint_clear(&buf);
 +            printf("tag:%s=", compact->escape_str(&buf, tag->key, compact->item_sep, wctx));
 +        }
 +        av_bprint_clear(&buf);
 +        printf("%s", compact->escape_str(&buf, tag->value, compact->item_sep, wctx));
 +    }
 +    av_bprint_finalize(&buf, NULL);
 +}
 +
 +static const Writer compact_writer = {
 +    .name                 = "compact",
 +    .priv_size            = sizeof(CompactContext),
 +    .init                 = compact_init,
 +    .uninit               = compact_uninit,
 +    .print_section_header = compact_print_section_header,
 +    .print_section_footer = compact_print_section_footer,
 +    .print_integer        = compact_print_int,
 +    .print_string         = compact_print_str,
 +    .show_tags            = compact_show_tags,
 +    .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
 +};
 +
 +/* CSV output */
 +
 +static av_cold int csv_init(WriterContext *wctx, const char *args, void *opaque)
 +{
 +    return compact_init(wctx, "item_sep=,:nokey=1:escape=csv", opaque);
 +}
 +
 +static const Writer csv_writer = {
 +    .name                 = "csv",
 +    .priv_size            = sizeof(CompactContext),
 +    .init                 = csv_init,
 +    .uninit               = compact_uninit,
 +    .print_section_header = compact_print_section_header,
 +    .print_section_footer = compact_print_section_footer,
 +    .print_integer        = compact_print_int,
 +    .print_string         = compact_print_str,
 +    .show_tags            = compact_show_tags,
 +    .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
 +};
 +
 +/* Flat output */
 +
 +typedef struct FlatContext {
 +    const AVClass *class;
 +    const char *section, *chapter;
 +    const char *sep_str;
 +    char sep;
 +    int hierarchical;
 +} FlatContext;
 +
 +#undef OFFSET
 +#define OFFSET(x) offsetof(FlatContext, x)
 +
 +static const AVOption flat_options[]= {
 +    {"sep_char", "set separator",    OFFSET(sep_str),    AV_OPT_TYPE_STRING, {.str="."},  CHAR_MIN, CHAR_MAX },
 +    {"s",        "set separator",    OFFSET(sep_str),    AV_OPT_TYPE_STRING, {.str="."},  CHAR_MIN, CHAR_MAX },
 +    {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.dbl=1}, 0, 1 },
 +    {"h",           "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.dbl=1}, 0, 1 },
 +    {NULL},
 +};
 +
 +static const char *flat_get_name(void *ctx)
 +{
 +    return "flat";
 +}
 +
 +static const AVClass flat_class = {
 +    "FlatContext",
 +    flat_get_name,
 +    flat_options
 +};
 +
 +static av_cold int flat_init(WriterContext *wctx, const char *args, void *opaque)
 +{
 +    FlatContext *flat = wctx->priv;
 +    int err;
 +
 +    flat->class = &flat_class;
 +    av_opt_set_defaults(flat);
 +
 +    if (args &&
 +        (err = (av_set_options_string(flat, args, "=", ":"))) < 0)
 +        return err;
 +    if (strlen(flat->sep_str) != 1) {
 +        av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
 +               flat->sep_str);
 +        return AVERROR(EINVAL);
 +    }
 +    flat->sep = flat->sep_str[0];
 +    return 0;
 +}
 +
 +static const char *flat_escape_key_str(AVBPrint *dst, const char *src, const char sep)
 +{
 +    const char *p;
 +
 +    for (p = src; *p; p++) {
 +        if (!((*p >= '0' && *p <= '9') ||
 +              (*p >= 'a' && *p <= 'z') ||
 +              (*p >= 'A' && *p <= 'Z')))
 +            av_bprint_chars(dst, '_', 1);
 +        else
 +            av_bprint_chars(dst, *p, 1);
 +    }
 +    return dst->str;
 +}
 +
 +static const char *flat_escape_value_str(AVBPrint *dst, const char *src)
 +{
 +    const char *p;
 +
 +    for (p = src; *p; p++) {
 +        switch (*p) {
 +        case '\n': av_bprintf(dst, "%s", "\\n");  break;
 +        case '\r': av_bprintf(dst, "%s", "\\r");  break;
 +        case '\\': av_bprintf(dst, "%s", "\\\\"); break;
 +        case '"':  av_bprintf(dst, "%s", "\\\""); break;
 +        case '`':  av_bprintf(dst, "%s", "\\`");  break;
 +        case '$':  av_bprintf(dst, "%s", "\\$");  break;
 +        default:   av_bprint_chars(dst, *p, 1);   break;
 +        }
 +    }
 +    return dst->str;
 +}
 +
 +static void flat_print_chapter_header(WriterContext *wctx, const char *chapter)
 +{
 +    FlatContext *flat = wctx->priv;
 +    flat->chapter = chapter;
 +}
 +
 +static void flat_print_section_header(WriterContext *wctx, const char *section)
 +{
 +    FlatContext *flat = wctx->priv;
 +    flat->section = section;
 +}
 +
 +static void flat_print_section(WriterContext *wctx)
 +{
 +    FlatContext *flat = wctx->priv;
 +    int n = wctx->is_packets_and_frames ? wctx->nb_section_packet_frame
 +                                        : wctx->nb_section;
 +
 +    if (flat->hierarchical && wctx->multiple_sections)
 +        printf("%s%c", flat->chapter, flat->sep);
 +    printf("%s%c", flat->section, flat->sep);
 +    if (wctx->multiple_sections)
 +        printf("%d%c", n, flat->sep);
 +}
 +
 +static void flat_print_int(WriterContext *wctx, const char *key, long long int value)
 +{
 +    flat_print_section(wctx);
 +    printf("%s=%lld\n", key, value);
 +}
 +
 +static void flat_print_str(WriterContext *wctx, const char *key, const char *value)
 +{
 +    FlatContext *flat = wctx->priv;
 +    AVBPrint buf;
 +
 +    flat_print_section(wctx);
 +    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
 +    printf("%s=", flat_escape_key_str(&buf, key, flat->sep));
 +    av_bprint_clear(&buf);
 +    printf("\"%s\"\n", flat_escape_value_str(&buf, value));
 +    av_bprint_finalize(&buf, NULL);
 +}
 +
 +static void flat_show_tags(WriterContext *wctx, AVDictionary *dict)
 +{
 +    FlatContext *flat = wctx->priv;
 +    AVBPrint buf;
 +    AVDictionaryEntry *tag = NULL;
 +
 +    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
 +    while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
 +        flat_print_section(wctx);
 +        av_bprint_clear(&buf);
 +        printf("tags%c%s=", flat->sep, flat_escape_key_str(&buf, tag->key, flat->sep));
 +        av_bprint_clear(&buf);
 +        printf("\"%s\"\n", flat_escape_value_str(&buf, tag->value));
 +    }
 +    av_bprint_finalize(&buf, NULL);
 +}
 +
 +static const Writer flat_writer = {
 +    .name                  = "flat",
 +    .priv_size             = sizeof(FlatContext),
 +    .init                  = flat_init,
 +    .print_chapter_header  = flat_print_chapter_header,
 +    .print_section_header  = flat_print_section_header,
 +    .print_integer         = flat_print_int,
 +    .print_string          = flat_print_str,
 +    .show_tags             = flat_show_tags,
 +    .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
 +};
 +
 +/* INI format output */
 +
 +typedef struct {
 +    const AVClass *class;
 +    AVBPrint chapter_name, section_name;
 +    int hierarchical;
 +} INIContext;
 +
 +#undef OFFSET
 +#define OFFSET(x) offsetof(INIContext, x)
 +
 +static const AVOption ini_options[] = {
 +    {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.dbl=1}, 0, 1 },
 +    {"h",           "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.dbl=1}, 0, 1 },
 +    {NULL},
 +};
 +
 +static const char *ini_get_name(void *ctx)
 +{
 +    return "ini";
 +}
 +
 +static const AVClass ini_class = {
 +    "INIContext",
 +    ini_get_name,
 +    ini_options
 +};
 +
 +static av_cold int ini_init(WriterContext *wctx, const char *args, void *opaque)
 +{
 +    INIContext *ini = wctx->priv;
 +    int err;
 +
 +    av_bprint_init(&ini->chapter_name, 1, AV_BPRINT_SIZE_UNLIMITED);
 +    av_bprint_init(&ini->section_name, 1, AV_BPRINT_SIZE_UNLIMITED);
 +
 +    ini->class = &ini_class;
 +    av_opt_set_defaults(ini);
 +
 +    if (args && (err = av_set_options_string(ini, args, "=", ":")) < 0)
 +        return err;
 +
 +    return 0;
 +}
 +
 +static av_cold void ini_uninit(WriterContext *wctx)
 +{
 +    INIContext *ini = wctx->priv;
 +    av_bprint_finalize(&ini->chapter_name, NULL);
 +    av_bprint_finalize(&ini->section_name, NULL);
 +}
 +
 +static void ini_print_header(WriterContext *wctx)
 +{
 +    printf("# ffprobe output\n\n");
 +}
 +
 +static char *ini_escape_str(AVBPrint *dst, const char *src)
 +{
 +    int i = 0;
 +    char c = 0;
 +
 +    while (c = src[i++]) {
 +        switch (c) {
 +        case '\b': av_bprintf(dst, "%s", "\\b"); break;
 +        case '\f': av_bprintf(dst, "%s", "\\f"); break;
 +        case '\n': av_bprintf(dst, "%s", "\\n"); break;
 +        case '\r': av_bprintf(dst, "%s", "\\r"); break;
 +        case '\t': av_bprintf(dst, "%s", "\\t"); break;
 +        case '\\':
 +        case '#' :
 +        case '=' :
 +        case ':' : av_bprint_chars(dst, '\\', 1);
 +        default:
 +            if ((unsigned char)c < 32)
 +                av_bprintf(dst, "\\x00%02x", c & 0xff);
 +            else
 +                av_bprint_chars(dst, c, 1);
 +            break;
 +        }
 +    }
 +    return dst->str;
 +}
 +
 +static void ini_print_chapter_header(WriterContext *wctx, const char *chapter)
 +{
 +    INIContext *ini = wctx->priv;
 +
 +    av_bprint_clear(&ini->chapter_name);
 +    av_bprintf(&ini->chapter_name, "%s", chapter);
 +
 +    if (wctx->nb_chapter)
 +        printf("\n");
 +}
 +
 +static void ini_print_section_header(WriterContext *wctx, const char *section)
 +{
 +    INIContext *ini = wctx->priv;
 +    int n = wctx->is_packets_and_frames ? wctx->nb_section_packet_frame
 +                                        : wctx->nb_section;
 +    if (wctx->nb_section)
 +        printf("\n");
 +    av_bprint_clear(&ini->section_name);
 +
 +    if (ini->hierarchical && wctx->multiple_sections)
 +        av_bprintf(&ini->section_name, "%s.", ini->chapter_name.str);
 +    av_bprintf(&ini->section_name, "%s", section);
 +
 +    if (wctx->multiple_sections)
 +        av_bprintf(&ini->section_name, ".%d", n);
 +    printf("[%s]\n", ini->section_name.str);
 +}
 +
 +static void ini_print_str(WriterContext *wctx, const char *key, const char *value)
 +{
 +    AVBPrint buf;
 +
 +    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
 +    printf("%s=", ini_escape_str(&buf, key));
 +    av_bprint_clear(&buf);
 +    printf("%s\n", ini_escape_str(&buf, value));
 +    av_bprint_finalize(&buf, NULL);
 +}
 +
 +static void ini_print_int(WriterContext *wctx, const char *key, long long int value)
 +{
 +    printf("%s=%lld\n", key, value);
 +}
 +
 +static void ini_show_tags(WriterContext *wctx, AVDictionary *dict)
 +{
 +    INIContext *ini = wctx->priv;
 +    AVDictionaryEntry *tag = NULL;
 +    int is_first = 1;
 +
 +    while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
 +        if (is_first) {
 +            printf("\n[%s.tags]\n", ini->section_name.str);
 +            is_first = 0;
 +        }
 +        writer_print_string(wctx, tag->key, tag->value, 0);
 +    }
 +}
 +
 +static const Writer ini_writer = {
 +    .name                  = "ini",
 +    .priv_size             = sizeof(INIContext),
 +    .init                  = ini_init,
 +    .uninit                = ini_uninit,
 +    .print_header          = ini_print_header,
 +    .print_chapter_header  = ini_print_chapter_header,
 +    .print_section_header  = ini_print_section_header,
 +    .print_integer         = ini_print_int,
 +    .print_string          = ini_print_str,
 +    .show_tags             = ini_show_tags,
 +    .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
 +};
 +
 +/* JSON output */
 +
 +typedef struct {
 +    const AVClass *class;
 +    int indent_level;
 +    int compact;
 +    const char *item_sep, *item_start_end;
 +} JSONContext;
 +
 +#undef OFFSET
 +#define OFFSET(x) offsetof(JSONContext, x)
 +
 +static const AVOption json_options[]= {
 +    { "compact", "enable compact output", OFFSET(compact), AV_OPT_TYPE_INT, {.dbl=0}, 0, 1 },
 +    { "c",       "enable compact output", OFFSET(compact), AV_OPT_TYPE_INT, {.dbl=0}, 0, 1 },
 +    { NULL }
 +};
 +
 +static const char *json_get_name(void *ctx)
 +{
 +    return "json";
 +}
 +
 +static const AVClass json_class = {
 +    "JSONContext",
 +    json_get_name,
 +    json_options
 +};
 +
 +static av_cold int json_init(WriterContext *wctx, const char *args, void *opaque)
 +{
 +    JSONContext *json = wctx->priv;
 +    int err;
 +
 +    json->class = &json_class;
 +    av_opt_set_defaults(json);
 +
 +    if (args &&
 +        (err = (av_set_options_string(json, args, "=", ":"))) < 0)
 +        return err;
 +
 +    json->item_sep       = json->compact ? ", " : ",\n";
 +    json->item_start_end = json->compact ? " "  : "\n";
 +
 +    return 0;
 +}
 +
 +static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
 +{
 +    static const char json_escape[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0};
 +    static const char json_subst[]  = {'"', '\\',  'b',  'f',  'n',  'r',  't', 0};
 +    const char *p;
 +
 +    for (p = src; *p; p++) {
 +        char *s = strchr(json_escape, *p);
 +        if (s) {
 +            av_bprint_chars(dst, '\\', 1);
 +            av_bprint_chars(dst, json_subst[s - json_escape], 1);
 +        } else if ((unsigned char)*p < 32) {
 +            av_bprintf(dst, "\\u00%02x", *p & 0xff);
 +        } else {
 +            av_bprint_chars(dst, *p, 1);
 +        }
 +    }
 +    return dst->str;
 +}
 +
 +static void json_print_header(WriterContext *wctx)
 +{
 +    JSONContext *json = wctx->priv;
 +    printf("{");
 +    json->indent_level++;
 +}
 +
 +static void json_print_footer(WriterContext *wctx)
 +{
 +    JSONContext *json = wctx->priv;
 +    json->indent_level--;
 +    printf("\n}\n");
 +}
 +
 +#define JSON_INDENT() printf("%*c", json->indent_level * 4, ' ')
 +
 +static void json_print_chapter_header(WriterContext *wctx, const char *chapter)
 +{
 +    JSONContext *json = wctx->priv;
 +    AVBPrint buf;
 +
 +    if (wctx->nb_chapter)
 +        printf(",");
 +    printf("\n");
 +    if (wctx->multiple_sections) {
 +        JSON_INDENT();
 +        av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
 +        printf("\"%s\": [\n", json_escape_str(&buf, chapter, wctx));
 +        av_bprint_finalize(&buf, NULL);
 +        json->indent_level++;
 +    }
 +}
 +
 +static void json_print_chapter_footer(WriterContext *wctx, const char *chapter)
 +{
 +    JSONContext *json = wctx->priv;
 +
 +    if (wctx->multiple_sections) {
 +        printf("\n");
 +        json->indent_level--;
 +        JSON_INDENT();
 +        printf("]");
 +    }
 +}
 +
 +static void json_print_section_header(WriterContext *wctx, const char *section)
 +{
 +    JSONContext *json = wctx->priv;
 +
 +    if (wctx->nb_section)
 +        printf(",\n");
 +    JSON_INDENT();
 +    if (!wctx->multiple_sections)
 +        printf("\"%s\": ", section);
 +    printf("{%s", json->item_start_end);
 +    json->indent_level++;
 +    /* this is required so the parser can distinguish between packets and frames */
 +    if (wctx->is_packets_and_frames) {
 +        if (!json->compact)
 +            JSON_INDENT();
 +        printf("\"type\": \"%s\"%s", section, json->item_sep);
 +    }
 +}
 +
 +static void json_print_section_footer(WriterContext *wctx, const char *section)
 +{
 +    JSONContext *json = wctx->priv;
 +
 +    printf("%s", json->item_start_end);
 +    json->indent_level--;
 +    if (!json->compact)
 +        JSON_INDENT();
 +    printf("}");
 +}
 +
 +static inline void json_print_item_str(WriterContext *wctx,
 +                                       const char *key, const char *value)
 +{
 +    AVBPrint buf;
 +
 +    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
 +    printf("\"%s\":", json_escape_str(&buf, key,   wctx));
 +    av_bprint_clear(&buf);
 +    printf(" \"%s\"", json_escape_str(&buf, value, wctx));
 +    av_bprint_finalize(&buf, NULL);
 +}
 +
 +static void json_print_str(WriterContext *wctx, const char *key, const char *value)
 +{
 +    JSONContext *json = wctx->priv;
 +
 +    if (wctx->nb_item) printf("%s", json->item_sep);
 +    if (!json->compact)
 +        JSON_INDENT();
 +    json_print_item_str(wctx, key, value);
 +}
 +
 +static void json_print_int(WriterContext *wctx, const char *key, long long int value)
 +{
 +    JSONContext *json = wctx->priv;
 +    AVBPrint buf;
 +
 +    if (wctx->nb_item) printf("%s", json->item_sep);
 +    if (!json->compact)
 +        JSON_INDENT();
 +
 +    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
 +    printf("\"%s\": %lld", json_escape_str(&buf, key, wctx), value);
 +    av_bprint_finalize(&buf, NULL);
 +}
 +
 +static void json_show_tags(WriterContext *wctx, AVDictionary *dict)
 +{
 +    JSONContext *json = wctx->priv;
 +    AVDictionaryEntry *tag = NULL;
 +    int is_first = 1;
 +    if (!dict)
 +        return;
 +    printf("%s", json->item_sep);
 +    if (!json->compact)
 +        JSON_INDENT();
 +    printf("\"tags\": {%s", json->item_start_end);
 +    json->indent_level++;
 +    while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
 +        if (is_first) is_first = 0;
 +        else          printf("%s", json->item_sep);
 +        if (!json->compact)
 +            JSON_INDENT();
 +        json_print_item_str(wctx, tag->key, tag->value);
 +    }
 +    json->indent_level--;
 +    printf("%s", json->item_start_end);
 +    if (!json->compact)
 +        JSON_INDENT();
 +    printf("}");
 +}
 +
 +static const Writer json_writer = {
 +    .name                 = "json",
 +    .priv_size            = sizeof(JSONContext),
 +    .init                 = json_init,
 +    .print_header         = json_print_header,
 +    .print_footer         = json_print_footer,
 +    .print_chapter_header = json_print_chapter_header,
 +    .print_chapter_footer = json_print_chapter_footer,
 +    .print_section_header = json_print_section_header,
 +    .print_section_footer = json_print_section_footer,
 +    .print_integer        = json_print_int,
 +    .print_string         = json_print_str,
 +    .show_tags            = json_show_tags,
 +    .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
 +};
 +
 +/* XML output */
 +
 +typedef struct {
 +    const AVClass *class;
 +    int within_tag;
 +    int indent_level;
 +    int fully_qualified;
 +    int xsd_strict;
 +} XMLContext;
 +
 +#undef OFFSET
 +#define OFFSET(x) offsetof(XMLContext, x)
 +
 +static const AVOption xml_options[] = {
 +    {"fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_INT, {.dbl=0},  0, 1 },
 +    {"q",               "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_INT, {.dbl=0},  0, 1 },
 +    {"xsd_strict",      "ensure that the output is XSD compliant",         OFFSET(xsd_strict),      AV_OPT_TYPE_INT, {.dbl=0},  0, 1 },
 +    {"x",               "ensure that the output is XSD compliant",         OFFSET(xsd_strict),      AV_OPT_TYPE_INT, {.dbl=0},  0, 1 },
 +    {NULL},
 +};
 +
 +static const char *xml_get_name(void *ctx)
 +{
 +    return "xml";
 +}
 +
 +static const AVClass xml_class = {
 +    "XMLContext",
 +    xml_get_name,
 +    xml_options
 +};
 +
 +static av_cold int xml_init(WriterContext *wctx, const char *args, void *opaque)
 +{
 +    XMLContext *xml = wctx->priv;
 +    int err;
 +
 +    xml->class = &xml_class;
 +    av_opt_set_defaults(xml);
 +
 +    if (args &&
 +        (err = (av_set_options_string(xml, args, "=", ":"))) < 0)
 +        return err;
 +
 +    if (xml->xsd_strict) {
 +        xml->fully_qualified = 1;
 +#define CHECK_COMPLIANCE(opt, opt_name)                                 \
 +        if (opt) {                                                      \
 +            av_log(wctx, AV_LOG_ERROR,                                  \
 +                   "XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \
 +                   "You need to disable such option with '-no%s'\n", opt_name, opt_name); \
 +            return AVERROR(EINVAL);                                     \
 +        }
 +        CHECK_COMPLIANCE(show_private_data, "private");
 +        CHECK_COMPLIANCE(show_value_unit,   "unit");
 +        CHECK_COMPLIANCE(use_value_prefix,  "prefix");
 +
 +        if (do_show_frames && do_show_packets) {
 +            av_log(wctx, AV_LOG_ERROR,
 +                   "Interleaved frames and packets are not allowed in XSD. "
 +                   "Select only one between the -show_frames and the -show_packets options.\n");
 +            return AVERROR(EINVAL);
 +        }
 +    }
 +
 +    return 0;
 +}
 +
 +static const char *xml_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
 +{
 +    const char *p;
 +
 +    for (p = src; *p; p++) {
 +        switch (*p) {
 +        case '&' : av_bprintf(dst, "%s", "&amp;");  break;
 +        case '<' : av_bprintf(dst, "%s", "&lt;");   break;
 +        case '>' : av_bprintf(dst, "%s", "&gt;");   break;
 +        case '\"': av_bprintf(dst, "%s", "&quot;"); break;
 +        case '\'': av_bprintf(dst, "%s", "&apos;"); break;
 +        default: av_bprint_chars(dst, *p, 1);
 +        }
 +    }
 +
 +    return dst->str;
 +}
 +
 +static void xml_print_header(WriterContext *wctx)
 +{
 +    XMLContext *xml = wctx->priv;
 +    const char *qual = " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' "
 +        "xmlns:ffprobe='http://www.ffmpeg.org/schema/ffprobe' "
 +        "xsi:schemaLocation='http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd'";
 +
 +    printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
 +    printf("<%sffprobe%s>\n",
 +           xml->fully_qualified ? "ffprobe:" : "",
 +           xml->fully_qualified ? qual : "");
 +
 +    xml->indent_level++;
 +}
 +
 +static void xml_print_footer(WriterContext *wctx)
 +{
 +    XMLContext *xml = wctx->priv;
 +
 +    xml->indent_level--;
 +    printf("</%sffprobe>\n", xml->fully_qualified ? "ffprobe:" : "");
 +}
 +
 +#define XML_INDENT() printf("%*c", xml->indent_level * 4, ' ')
 +
 +static void xml_print_chapter_header(WriterContext *wctx, const char *chapter)
 +{
 +    XMLContext *xml = wctx->priv;
 +
 +    if (wctx->nb_chapter)
 +        printf("\n");
 +    if (wctx->multiple_sections) {
 +        XML_INDENT(); printf("<%s>\n", chapter);
 +        xml->indent_level++;
 +    }
 +}
 +
 +static void xml_print_chapter_footer(WriterContext *wctx, const char *chapter)
 +{
 +    XMLContext *xml = wctx->priv;
 +
 +    if (wctx->multiple_sections) {
 +        xml->indent_level--;
 +        XML_INDENT(); printf("</%s>\n", chapter);
 +    }
 +}
 +
 +static void xml_print_section_header(WriterContext *wctx, const char *section)
 +{
 +    XMLContext *xml = wctx->priv;
 +
 +    XML_INDENT(); printf("<%s ", section);
 +    xml->within_tag = 1;
 +}
 +
 +static void xml_print_section_footer(WriterContext *wctx, const char *section)
 +{
 +    XMLContext *xml = wctx->priv;
 +
 +    if (xml->within_tag)
 +        printf("/>\n");
 +    else {
 +        XML_INDENT(); printf("</%s>\n", section);
 +    }
 +}
 +
 +static void xml_print_str(WriterContext *wctx, const char *key, const char *value)
 +{
 +    AVBPrint buf;
 +
 +    if (wctx->nb_item)
 +        printf(" ");
 +    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
 +    printf("%s=\"%s\"", key, xml_escape_str(&buf, value, wctx));
 +    av_bprint_finalize(&buf, NULL);
 +}
 +
 +static void xml_print_int(WriterContext *wctx, const char *key, long long int value)
 +{
 +    if (wctx->nb_item)
 +        printf(" ");
 +    printf("%s=\"%lld\"", key, value);
 +}
 +
 +static void xml_show_tags(WriterContext *wctx, AVDictionary *dict)
 +{
 +    XMLContext *xml = wctx->priv;
 +    AVDictionaryEntry *tag = NULL;
 +    int is_first = 1;
 +    AVBPrint buf;
 +
 +    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
 +    xml->indent_level++;
 +    while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
 +        if (is_first) {
 +            /* close section tag */
 +            printf(">\n");
 +            xml->within_tag = 0;
 +            is_first = 0;
 +        }
 +        XML_INDENT();
 +
 +        av_bprint_clear(&buf);
 +        printf("<tag key=\"%s\"", xml_escape_str(&buf, tag->key, wctx));
 +        av_bprint_clear(&buf);
 +        printf(" value=\"%s\"/>\n", xml_escape_str(&buf, tag->value, wctx));
 +    }
 +    av_bprint_finalize(&buf, NULL);
 +    xml->indent_level--;
 +}
 +
 +static Writer xml_writer = {
 +    .name                 = "xml",
 +    .priv_size            = sizeof(XMLContext),
 +    .init                 = xml_init,
 +    .print_header         = xml_print_header,
 +    .print_footer         = xml_print_footer,
 +    .print_chapter_header = xml_print_chapter_header,
 +    .print_chapter_footer = xml_print_chapter_footer,
 +    .print_section_header = xml_print_section_header,
 +    .print_section_footer = xml_print_section_footer,
 +    .print_integer        = xml_print_int,
 +    .print_string         = xml_print_str,
 +    .show_tags            = xml_show_tags,
 +    .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
 +};
 +
 +static void writer_register_all(void)
 +{
 +    static int initialized;
 +
 +    if (initialized)
 +        return;
 +    initialized = 1;
 +
 +    writer_register(&default_writer);
 +    writer_register(&compact_writer);
 +    writer_register(&csv_writer);
 +    writer_register(&flat_writer);
 +    writer_register(&ini_writer);
 +    writer_register(&json_writer);
 +    writer_register(&xml_writer);
 +}
 +
 +#define print_fmt(k, f, ...) do {              \
 +    av_bprint_clear(&pbuf);                    \
 +    av_bprintf(&pbuf, f, __VA_ARGS__);         \
 +    writer_print_string(w, k, pbuf.str, 0);    \
 +} while (0)
 +
 +#define print_int(k, v)         writer_print_integer(w, k, v)
 +#define print_q(k, v, s)        writer_print_rational(w, k, v, s)
 +#define print_str(k, v)         writer_print_string(w, k, v, 0)
 +#define print_str_opt(k, v)     writer_print_string(w, k, v, 1)
 +#define print_time(k, v, tb)    writer_print_time(w, k, v, tb, 0)
 +#define print_ts(k, v)          writer_print_ts(w, k, v, 0)
 +#define print_duration_time(k, v, tb) writer_print_time(w, k, v, tb, 1)
 +#define print_duration_ts(k, v)       writer_print_ts(w, k, v, 1)
 +#define print_val(k, v, u)      writer_print_string(w, k, \
 +    value_string(val_str, sizeof(val_str), (struct unit_value){.val.i = v, .unit=u}), 0)
 +#define print_section_header(s) writer_print_section_header(w, s)
 +#define print_section_footer(s) writer_print_section_footer(w, s)
 +#define show_tags(metadata)     writer_show_tags(w, metadata)
 +
 +static void show_packet(WriterContext *w, AVFormatContext *fmt_ctx, AVPacket *pkt, int packet_idx)
 +{
 +    char val_str[128];
 +    AVStream *st = fmt_ctx->streams[pkt->stream_index];
 +    AVBPrint pbuf;
 +    const char *s;
 +
 +    av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
 +
 +    print_section_header("packet");
 +    s = av_get_media_type_string(st->codec->codec_type);
 +    if (s) print_str    ("codec_type", s);
 +    else   print_str_opt("codec_type", "unknown");
 +    print_int("stream_index",     pkt->stream_index);
 +    print_ts  ("pts",             pkt->pts);
 +    print_time("pts_time",        pkt->pts, &st->time_base);
 +    print_ts  ("dts",             pkt->dts);
 +    print_time("dts_time",        pkt->dts, &st->time_base);
 +    print_duration_ts("duration",        pkt->duration);
 +    print_duration_time("duration_time", pkt->duration, &st->time_base);
 +    print_duration_ts("convergence_duration", pkt->convergence_duration);
 +    print_duration_time("convergence_duration_time", pkt->convergence_duration, &st->time_base);
 +    print_val("size",             pkt->size, unit_byte_str);
 +    if (pkt->pos != -1) print_fmt    ("pos", "%"PRId64, pkt->pos);
 +    else                print_str_opt("pos", "N/A");
 +    print_fmt("flags", "%c",      pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_');
 +    if (do_show_data)
 +        writer_print_data(w, "data", pkt->data, pkt->size);
 +    print_section_footer("packet");
 +
 +    av_bprint_finalize(&pbuf, NULL);
 +    fflush(stdout);
 +}
 +
 +static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream,
 +                       AVFormatContext *fmt_ctx)
 +{
 +    AVBPrint pbuf;
 +    const char *s;
 +
 +    av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
 +
 +    print_section_header("frame");
 +
 +    s = av_get_media_type_string(stream->codec->codec_type);
 +    if (s) print_str    ("media_type", s);
 +    else   print_str_opt("media_type", "unknown");
 +    print_int("key_frame",              frame->key_frame);
 +    print_ts  ("pkt_pts",               frame->pkt_pts);
 +    print_time("pkt_pts_time",          frame->pkt_pts, &stream->time_base);
 +    print_ts  ("pkt_dts",               frame->pkt_dts);
 +    print_time("pkt_dts_time",          frame->pkt_dts, &stream->time_base);
 +    print_duration_ts  ("pkt_duration",      frame->pkt_duration);
 +    print_duration_time("pkt_duration_time", frame->pkt_duration, &stream->time_base);
 +    if (frame->pkt_pos != -1) print_fmt    ("pkt_pos", "%"PRId64, frame->pkt_pos);
 +    else                      print_str_opt("pkt_pos", "N/A");
 +
 +    switch (stream->codec->codec_type) {
 +        AVRational sar;
 +
 +    case AVMEDIA_TYPE_VIDEO:
 +        print_int("width",                  frame->width);
 +        print_int("height",                 frame->height);
 +        s = av_get_pix_fmt_name(frame->format);
 +        if (s) print_str    ("pix_fmt", s);
 +        else   print_str_opt("pix_fmt", "unknown");
 +        sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, frame);
 +        if (sar.num) {
 +            print_q("sample_aspect_ratio", sar, ':');
 +        } else {
 +            print_str_opt("sample_aspect_ratio", "N/A");
 +        }
 +        print_fmt("pict_type",              "%c", av_get_picture_type_char(frame->pict_type));
 +        print_int("coded_picture_number",   frame->coded_picture_number);
 +        print_int("display_picture_number", frame->display_picture_number);
 +        print_int("interlaced_frame",       frame->interlaced_frame);
 +        print_int("top_field_first",        frame->top_field_first);
 +        print_int("repeat_pict",            frame->repeat_pict);
 +        print_int("reference",              frame->reference);
 +        break;
 +
 +    case AVMEDIA_TYPE_AUDIO:
 +        s = av_get_sample_fmt_name(frame->format);
 +        if (s) print_str    ("sample_fmt", s);
 +        else   print_str_opt("sample_fmt", "unknown");
 +        print_int("nb_samples",         frame->nb_samples);
 +        print_int("channels", av_frame_get_channels(frame));
 +        if (av_frame_get_channel_layout(frame)) {
 +            av_bprint_clear(&pbuf);
 +            av_bprint_channel_layout(&pbuf, av_frame_get_channels(frame),
 +                                     av_frame_get_channel_layout(frame));
 +            print_str    ("channel_layout", pbuf.str);
 +        } else
 +            print_str_opt("channel_layout", "unknown");
 +        break;
 +    }
 +    show_tags(av_frame_get_metadata(frame));
 +
 +    print_section_footer("frame");
 +
 +    av_bprint_finalize(&pbuf, NULL);
 +    fflush(stdout);
 +}
 +
 +static av_always_inline int process_frame(WriterContext *w,
 +                                          AVFormatContext *fmt_ctx,
 +                                          AVFrame *frame, AVPacket *pkt)
 +{
 +    AVCodecContext *dec_ctx = fmt_ctx->streams[pkt->stream_index]->codec;
 +    int ret = 0, got_frame = 0;
 +
 +    avcodec_get_frame_defaults(frame);
 +    if (dec_ctx->codec) {
 +        switch (dec_ctx->codec_type) {
 +        case AVMEDIA_TYPE_VIDEO:
 +            ret = avcodec_decode_video2(dec_ctx, frame, &got_frame, pkt);
 +            break;
 +
 +        case AVMEDIA_TYPE_AUDIO:
 +            ret = avcodec_decode_audio4(dec_ctx, frame, &got_frame, pkt);
 +            break;
 +        }
 +    }
 +
 +    if (ret < 0)
 +        return ret;
 +    ret = FFMIN(ret, pkt->size); /* guard against bogus return values */
 +    pkt->data += ret;
 +    pkt->size -= ret;
 +    if (got_frame) {
 +        nb_streams_frames[pkt->stream_index]++;
 +        if (do_show_frames)
 +            show_frame(w, frame, fmt_ctx->streams[pkt->stream_index], fmt_ctx);
 +    }
 +    return got_frame;
 +}
 +
 +static void read_packets(WriterContext *w, AVFormatContext *fmt_ctx)
 +{
 +    AVPacket pkt, pkt1;
 +    AVFrame frame;
 +    int i = 0;
 +
 +    av_init_packet(&pkt);
 +
 +    while (!av_read_frame(fmt_ctx, &pkt)) {
 +        if (do_read_packets) {
 +            if (do_show_packets)
 +                show_packet(w, fmt_ctx, &pkt, i++);
 +            nb_streams_packets[pkt.stream_index]++;
 +        }
 +        if (do_read_frames) {
 +            pkt1 = pkt;
 +            while (pkt1.size && process_frame(w, fmt_ctx, &frame, &pkt1) > 0);
 +        }
 +        av_free_packet(&pkt);
 +    }
 +    av_init_packet(&pkt);
 +    pkt.data = NULL;
 +    pkt.size = 0;
 +    //Flush remaining frames that are cached in the decoder
 +    for (i = 0; i < fmt_ctx->nb_streams; i++) {
 +        pkt.stream_index = i;
 +        if (do_read_frames)
 +            while (process_frame(w, fmt_ctx, &frame, &pkt) > 0);
 +    }
 +}
 +
 +static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx)
 +{
 +    AVStream *stream = fmt_ctx->streams[stream_idx];
 +    AVCodecContext *dec_ctx;
 +    const AVCodec *dec;
 +    char val_str[128];
 +    const char *s;
 +    AVRational sar, dar;
 +    AVBPrint pbuf;
 +
 +    av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
 +
 +    print_section_header("stream");
 +
 +    print_int("index", stream->index);
 +
 +    if ((dec_ctx = stream->codec)) {
 +        const char *profile = NULL;
 +        if ((dec = dec_ctx->codec)) {
 +            print_str("codec_name",      dec->name);
 +            print_str("codec_long_name", dec->long_name);
 +        } else {
 +            print_str_opt("codec_name",      "unknown");
 +            print_str_opt("codec_long_name", "unknown");
 +        }
 +
 +        if (dec && (profile = av_get_profile_name(dec, dec_ctx->profile)))
 +            print_str("profile", profile);
 +        else
 +            print_str_opt("profile", "unknown");
 +
 +        s = av_get_media_type_string(dec_ctx->codec_type);
 +        if (s) print_str    ("codec_type", s);
 +        else   print_str_opt("codec_type", "unknown");
 +        print_q("codec_time_base", dec_ctx->time_base, '/');
 +
 +        /* print AVI/FourCC tag */
 +        av_get_codec_tag_string(val_str, sizeof(val_str), dec_ctx->codec_tag);
 +        print_str("codec_tag_string",    val_str);
 +        print_fmt("codec_tag", "0x%04x", dec_ctx->codec_tag);
 +
 +        switch (dec_ctx->codec_type) {
 +        case AVMEDIA_TYPE_VIDEO:
 +            print_int("width",        dec_ctx->width);
 +            print_int("height",       dec_ctx->height);
 +            print_int("has_b_frames", dec_ctx->has_b_frames);
 +            sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL);
 +            if (sar.den) {
 +                print_q("sample_aspect_ratio", sar, ':');
 +                av_reduce(&dar.num, &dar.den,
 +                          dec_ctx->width  * sar.num,
 +                          dec_ctx->height * sar.den,
 +                          1024*1024);
 +                print_q("display_aspect_ratio", dar, ':');
 +            } else {
 +                print_str_opt("sample_aspect_ratio", "N/A");
 +                print_str_opt("display_aspect_ratio", "N/A");
 +            }
 +            s = av_get_pix_fmt_name(dec_ctx->pix_fmt);
 +            if (s) print_str    ("pix_fmt", s);
 +            else   print_str_opt("pix_fmt", "unknown");
 +            print_int("level",   dec_ctx->level);
 +            if (dec_ctx->timecode_frame_start >= 0) {
 +                char tcbuf[AV_TIMECODE_STR_SIZE];
 +                av_timecode_make_mpeg_tc_string(tcbuf, dec_ctx->timecode_frame_start);
 +                print_str("timecode", tcbuf);
 +            } else {
 +                print_str_opt("timecode", "N/A");
 +            }
 +            break;
 +
 +        case AVMEDIA_TYPE_AUDIO:
 +            s = av_get_sample_fmt_name(dec_ctx->sample_fmt);
 +            if (s) print_str    ("sample_fmt", s);
 +            else   print_str_opt("sample_fmt", "unknown");
 +            print_val("sample_rate",     dec_ctx->sample_rate, unit_hertz_str);
 +            print_int("channels",        dec_ctx->channels);
 +            print_int("bits_per_sample", av_get_bits_per_sample(dec_ctx->codec_id));
 +            break;
 +        }
 +    } else {
 +        print_str_opt("codec_type", "unknown");
 +    }
 +    if (dec_ctx->codec && dec_ctx->codec->priv_class && show_private_data) {
 +        const AVOption *opt = NULL;
 +        while (opt = av_opt_next(dec_ctx->priv_data,opt)) {
 +            uint8_t *str;
 +            if (opt->flags) continue;
 +            if (av_opt_get(dec_ctx->priv_data, opt->name, 0, &str) >= 0) {
 +                print_str(opt->name, str);
 +                av_free(str);
 +            }
 +        }
 +    }
 +
 +    if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt    ("id", "0x%x", stream->id);
 +    else                                          print_str_opt("id", "N/A");
 +    print_q("r_frame_rate",   stream->r_frame_rate,   '/');
 +    print_q("avg_frame_rate", stream->avg_frame_rate, '/');
 +    print_q("time_base",      stream->time_base,      '/');
 +    print_time("start_time",    stream->start_time, &stream->time_base);
 +    print_time("duration",      stream->duration,   &stream->time_base);
 +    if (dec_ctx->bit_rate > 0) print_val    ("bit_rate", dec_ctx->bit_rate, unit_bit_per