Merge commit '67351924fa91dea4339109100a4c0689f006581f'
authorClément Bœsch <cboesch@gopro.com>
Thu, 30 Mar 2017 08:26:29 +0000 (10:26 +0200)
committerClément Bœsch <cboesch@gopro.com>
Thu, 30 Mar 2017 08:26:29 +0000 (10:26 +0200)
* commit '67351924fa91dea4339109100a4c0689f006581f':
  Drop unreachable break and return statements

Merged-by: Clément Bœsch <cboesch@gopro.com>
1  2 
libavcodec/bmvvideo.c
libavcodec/hevc_sei.c
libavcodec/sanm.c
libavformat/rtpproto.c
libavformat/rtspdec.c
libavformat/smush.c
libavutil/opt.c

diff --combined libavcodec/bmvvideo.c
@@@ -2,24 -2,23 +2,24 @@@
   * Discworld II BMV video decoder
   * Copyright (c) 2011 Konstantin Shishkov
   *
 - * 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 "libavutil/avassert.h"
  #include "libavutil/common.h"
  
  #include "avcodec.h"
@@@ -51,7 -50,7 +51,7 @@@ typedef struct BMVDecContext 
      const uint8_t *stream;
  } BMVDecContext;
  
 -#define NEXT_BYTE(v) v = forward ? v + 1 : v - 1;
 +#define NEXT_BYTE(v) (v) = forward ? (v) + 1 : (v) - 1;
  
  static int decode_bmv_frame(const uint8_t *source, int src_len, uint8_t *frame, int frame_off)
  {
          }
          if (!(val & 0xC)) {
              for (;;) {
 +                if(shift>22)
 +                    return -1;
                  if (!read_two_nibbles) {
                      if (src < source || src >= source_end)
                          return AVERROR_INVALIDDATA;
          }
          advance_mode = val & 1;
          len = (val >> 1) - 1;
 +        av_assert0(len>0);
          mode += 1 + advance_mode;
          if (mode >= 4)
              mode -= 3;
                  memset(dst, val, len);
              }
              break;
 -        default:
 -            break;
          }
          if (dst == dst_end)
              return 0;
      }
-     return 0;
  }
  
  static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
              return AVERROR_INVALIDDATA;
          }
          for (i = 0; i < 256; i++)
 -            c->pal[i] = bytestream_get_be24(&c->stream);
 +            c->pal[i] = 0xFFU << 24 | bytestream_get_be24(&c->stream);
      }
      if (type & BMV_SCROLL) {
          if (c->stream - pkt->data > pkt->size - 2) {
          scr_off = 0;
      }
  
 -    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
 -        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
 +    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
          return ret;
 -    }
  
      if (decode_bmv_frame(c->stream, pkt->size - (c->stream - pkt->data), c->frame, scr_off)) {
          av_log(avctx, AV_LOG_ERROR, "Error decoding frame data\n");
@@@ -276,11 -275,6 +275,11 @@@ static av_cold int decode_init(AVCodecC
      c->avctx = avctx;
      avctx->pix_fmt = AV_PIX_FMT_PAL8;
  
 +    if (avctx->width != SCREEN_WIDE || avctx->height != SCREEN_HIGH) {
 +        av_log(avctx, AV_LOG_ERROR, "Invalid dimension %dx%d\n", avctx->width, avctx->height);
 +        return AVERROR_INVALIDDATA;
 +    }
 +
      c->frame = c->frame_base + 640;
  
      return 0;
@@@ -295,5 -289,4 +294,5 @@@ AVCodec ff_bmv_video_decoder = 
      .init           = decode_init,
      .decode         = decode_frame,
      .capabilities   = AV_CODEC_CAP_DR1,
 +    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
  };
diff --combined libavcodec/hevc_sei.c
@@@ -5,20 -5,20 +5,20 @@@
   * Copyright (C) 2012 - 2013 Gildas Cocherel
   * Copyright (C) 2013 Vittorio Giovara
   *
 - * 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
   */
  
@@@ -56,13 -56,10 +56,13 @@@ enum HEVC_SEI_TYPE 
  static int decode_nal_sei_decoded_picture_hash(HEVCContext *s)
  {
      int cIdx, i;
 -    GetBitContext *gb = &s->HEVClc.gb;
 -    uint8_t hash_type = get_bits(gb, 8);
 +    uint8_t hash_type;
 +    //uint16_t picture_crc;
 +    //uint32_t picture_checksum;
 +    GetBitContext *gb = &s->HEVClc->gb;
 +    hash_type = get_bits(gb, 8);
  
 -    for (cIdx = 0; cIdx < 3; cIdx++) {
 +    for (cIdx = 0; cIdx < 3/*((s->sps->chroma_format_idc == 0) ? 1 : 3)*/; cIdx++) {
          if (hash_type == 0) {
              s->is_md5 = 1;
              for (i = 0; i < 16; i++)
              // picture_crc = get_bits(gb, 16);
              skip_bits(gb, 16);
          } else if (hash_type == 2) {
 -            // picture_checksum = get_bits(gb, 32);
 +            // picture_checksum = get_bits_long(gb, 32);
              skip_bits(gb, 32);
          }
      }
      return 0;
  }
  
 +static int decode_nal_sei_mastering_display_info(HEVCContext *s)
 +{
 +    GetBitContext *gb = &s->HEVClc->gb;
 +    int i;
 +    // Mastering primaries
 +    for (i = 0; i < 3; i++) {
 +        s->display_primaries[i][0] = get_bits(gb, 16);
 +        s->display_primaries[i][1] = get_bits(gb, 16);
 +    }
 +    // White point (x, y)
 +    s->white_point[0] = get_bits(gb, 16);
 +    s->white_point[1] = get_bits(gb, 16);
 +
 +    // Max and min luminance of mastering display
 +    s->max_mastering_luminance = get_bits_long(gb, 32);
 +    s->min_mastering_luminance = get_bits_long(gb, 32);
 +
 +    // As this SEI message comes before the first frame that references it,
 +    // initialize the flag to 2 and decrement on IRAP access unit so it
 +    // persists for the coded video sequence (e.g., between two IRAPs)
 +    s->sei_mastering_display_info_present = 2;
 +    return 0;
 +}
 +
  static int decode_nal_sei_frame_packing_arrangement(HEVCContext *s)
  {
 -    GetBitContext *gb = &s->HEVClc.gb;
 +    GetBitContext *gb = &s->HEVClc->gb;
  
 -    get_ue_golomb(gb);                  // frame_packing_arrangement_id
 +    get_ue_golomb_long(gb);             // frame_packing_arrangement_id
      s->sei_frame_packing_present = !get_bits1(gb);
  
      if (s->sei_frame_packing_present) {
  
  static int decode_nal_sei_display_orientation(HEVCContext *s)
  {
 -    GetBitContext *gb = &s->HEVClc.gb;
 +    GetBitContext *gb = &s->HEVClc->gb;
  
      s->sei_display_orientation_present = !get_bits1(gb);
  
      return 0;
  }
  
 +static int decode_pic_timing(HEVCContext *s)
 +{
 +    GetBitContext *gb = &s->HEVClc->gb;
 +    HEVCSPS *sps;
 +
 +    if (!s->ps.sps_list[s->active_seq_parameter_set_id])
 +        return(AVERROR(ENOMEM));
 +    sps = (HEVCSPS*)s->ps.sps_list[s->active_seq_parameter_set_id]->data;
 +
 +    if (sps->vui.frame_field_info_present_flag) {
 +        int pic_struct = get_bits(gb, 4);
 +        s->picture_struct = AV_PICTURE_STRUCTURE_UNKNOWN;
 +        if (pic_struct == 2) {
 +            av_log(s->avctx, AV_LOG_DEBUG, "BOTTOM Field\n");
 +            s->picture_struct = AV_PICTURE_STRUCTURE_BOTTOM_FIELD;
 +        } else if (pic_struct == 1) {
 +            av_log(s->avctx, AV_LOG_DEBUG, "TOP Field\n");
 +            s->picture_struct = AV_PICTURE_STRUCTURE_TOP_FIELD;
 +        }
 +        get_bits(gb, 2);                   // source_scan_type
 +        get_bits(gb, 1);                   // duplicate_flag
 +    }
 +    return 1;
 +}
 +
 +static int decode_registered_user_data_closed_caption(HEVCContext *s, int size)
 +{
 +    int flag;
 +    int user_data_type_code;
 +    int cc_count;
 +
 +    GetBitContext *gb = &s->HEVClc->gb;
 +
 +    if (size < 3)
 +       return AVERROR(EINVAL);
 +
 +    user_data_type_code = get_bits(gb, 8);
 +    if (user_data_type_code == 0x3) {
 +        skip_bits(gb, 1); // reserved
 +
 +        flag = get_bits(gb, 1); // process_cc_data_flag
 +        if (flag) {
 +            skip_bits(gb, 1);
 +            cc_count = get_bits(gb, 5);
 +            skip_bits(gb, 8); // reserved
 +            size -= 2;
 +
 +            if (cc_count && size >= cc_count * 3) {
 +                const uint64_t new_size = (s->a53_caption_size + cc_count
 +                                           * UINT64_C(3));
 +                int i, ret;
 +
 +                if (new_size > INT_MAX)
 +                    return AVERROR(EINVAL);
 +
 +                /* Allow merging of the cc data from two fields. */
 +                ret = av_reallocp(&s->a53_caption, new_size);
 +                if (ret < 0)
 +                    return ret;
 +
 +                for (i = 0; i < cc_count; i++) {
 +                    s->a53_caption[s->a53_caption_size++] = get_bits(gb, 8);
 +                    s->a53_caption[s->a53_caption_size++] = get_bits(gb, 8);
 +                    s->a53_caption[s->a53_caption_size++] = get_bits(gb, 8);
 +                }
 +                skip_bits(gb, 8); // marker_bits
 +            }
 +        }
 +    } else {
 +        int i;
 +        for (i = 0; i < size - 1; i++)
 +            skip_bits(gb, 8);
 +    }
 +
 +    return 0;
 +}
 +
 +static int decode_nal_sei_user_data_registered_itu_t_t35(HEVCContext *s, int size)
 +{
 +    uint32_t country_code;
 +    uint32_t user_identifier;
 +
 +    GetBitContext *gb = &s->HEVClc->gb;
 +
 +    if (size < 7)
 +        return AVERROR(EINVAL);
 +    size -= 7;
 +
 +    country_code = get_bits(gb, 8);
 +    if (country_code == 0xFF) {
 +        skip_bits(gb, 8);
 +        size--;
 +    }
 +
 +    skip_bits(gb, 8);
 +    skip_bits(gb, 8);
 +
 +    user_identifier = get_bits_long(gb, 32);
 +
 +    switch (user_identifier) {
 +        case MKBETAG('G', 'A', '9', '4'):
 +            return decode_registered_user_data_closed_caption(s, size);
 +        default:
 +            skip_bits_long(gb, size * 8);
 +            break;
 +    }
 +    return 0;
 +}
 +
 +static int active_parameter_sets(HEVCContext *s)
 +{
 +    GetBitContext *gb = &s->HEVClc->gb;
 +    int num_sps_ids_minus1;
 +    int i;
 +    unsigned active_seq_parameter_set_id;
 +
 +    get_bits(gb, 4); // active_video_parameter_set_id
 +    get_bits(gb, 1); // self_contained_cvs_flag
 +    get_bits(gb, 1); // num_sps_ids_minus1
 +    num_sps_ids_minus1 = get_ue_golomb_long(gb); // num_sps_ids_minus1
 +
 +    if (num_sps_ids_minus1 < 0 || num_sps_ids_minus1 > 15) {
 +        av_log(s->avctx, AV_LOG_ERROR, "num_sps_ids_minus1 %d invalid\n", num_sps_ids_minus1);
 +        return AVERROR_INVALIDDATA;
 +    }
 +
 +    active_seq_parameter_set_id = get_ue_golomb_long(gb);
 +    if (active_seq_parameter_set_id >= HEVC_MAX_SPS_COUNT) {
 +        av_log(s->avctx, AV_LOG_ERROR, "active_parameter_set_id %d invalid\n", active_seq_parameter_set_id);
 +        return AVERROR_INVALIDDATA;
 +    }
 +    s->active_seq_parameter_set_id = active_seq_parameter_set_id;
 +
 +    for (i = 1; i <= num_sps_ids_minus1; i++)
 +        get_ue_golomb_long(gb); // active_seq_parameter_set_id[i]
 +
 +    return 0;
 +}
 +
  static int decode_nal_sei_prefix(HEVCContext *s, int type, int size)
  {
 -    GetBitContext *gb = &s->HEVClc.gb;
 +    GetBitContext *gb = &s->HEVClc->gb;
  
      switch (type) {
      case 256:  // Mismatched value from HM 8.1
          return decode_nal_sei_frame_packing_arrangement(s);
      case SEI_TYPE_DISPLAY_ORIENTATION:
          return decode_nal_sei_display_orientation(s);
 +    case SEI_TYPE_PICTURE_TIMING:
 +        {
 +            int ret = decode_pic_timing(s);
 +            av_log(s->avctx, AV_LOG_DEBUG, "Skipped PREFIX SEI %d\n", type);
 +            skip_bits(gb, 8 * size);
 +            return ret;
 +        }
 +    case SEI_TYPE_MASTERING_DISPLAY_INFO:
 +        return decode_nal_sei_mastering_display_info(s);
 +    case SEI_TYPE_ACTIVE_PARAMETER_SETS:
 +        active_parameter_sets(s);
 +        av_log(s->avctx, AV_LOG_DEBUG, "Skipped PREFIX SEI %d\n", type);
 +        return 0;
 +    case SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35:
 +        return decode_nal_sei_user_data_registered_itu_t_t35(s, size);
      default:
          av_log(s->avctx, AV_LOG_DEBUG, "Skipped PREFIX SEI %d\n", type);
          skip_bits_long(gb, 8 * size);
  
  static int decode_nal_sei_suffix(HEVCContext *s, int type, int size)
  {
 -    GetBitContext *gb = &s->HEVClc.gb;
 +    GetBitContext *gb = &s->HEVClc->gb;
  
      switch (type) {
      case SEI_TYPE_DECODED_PICTURE_HASH:
  
  static int decode_nal_sei_message(HEVCContext *s)
  {
 -    GetBitContext *gb = &s->HEVClc.gb;
 +    GetBitContext *gb = &s->HEVClc->gb;
  
      int payload_type = 0;
      int payload_size = 0;
      } else { /* nal_unit_type == NAL_SEI_SUFFIX */
          return decode_nal_sei_suffix(s, payload_type, payload_size);
      }
-     return 1;
  }
  
  static int more_rbsp_data(GetBitContext *gb)
  
  int ff_hevc_decode_nal_sei(HEVCContext *s)
  {
 +    int ret;
 +
      do {
 -        decode_nal_sei_message(s);
 -    } while (more_rbsp_data(&s->HEVClc.gb));
 -    return 0;
 +        ret = decode_nal_sei_message(s);
 +        if (ret < 0)
 +            return(AVERROR(ENOMEM));
 +    } while (more_rbsp_data(&s->HEVClc->gb));
 +    return 1;
 +}
 +
 +void ff_hevc_reset_sei(HEVCContext *s)
 +{
 +    s->a53_caption_size = 0;
 +    av_freep(&s->a53_caption);
  }
diff --combined libavcodec/sanm.c
@@@ -3,20 -3,20 +3,20 @@@
   * Copyright (c) 2006 Cyril Zorin
   * Copyright (c) 2011 Konstantin Shishkov
   *
 - * 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
   */
  
@@@ -105,159 -105,108 +105,159 @@@ static const int8_t motion_vectors[256]
  };
  
  static const int8_t c37_mv[] = {
 -    0,   0,   1,   0,   2,   0,   3,   0,   5,   0,   8,   0,  13,   0,  21,
 -    0,  -1,   0,  -2,   0,  -3,   0,  -5,   0,  -8,   0, -13,   0, -17,   0,
 -  -21,   0,   0,   1,   1,   1,   2,   1,   3,   1,   5,   1,   8,   1,  13,
 -    1,  21,   1,  -1,   1,  -2,   1,  -3,   1,  -5,   1,  -8,   1, -13,   1,
 -  -17,   1, -21,   1,   0,   2,   1,   2,   2,   2,   3,   2,   5,   2,   8,
 -    2,  13,   2,  21,   2,  -1,   2,  -2,   2,  -3,   2,  -5,   2,  -8,   2,
 -  -13,   2, -17,   2, -21,   2,   0,   3,   1,   3,   2,   3,   3,   3,   5,
 -    3,   8,   3,  13,   3,  21,   3,  -1,   3,  -2,   3,  -3,   3,  -5,   3,
 -   -8,   3, -13,   3, -17,   3, -21,   3,   0,   5,   1,   5,   2,   5,   3,
 -    5,   5,   5,   8,   5,  13,   5,  21,   5,  -1,   5,  -2,   5,  -3,   5,
 -   -5,   5,  -8,   5, -13,   5, -17,   5, -21,   5,   0,   8,   1,   8,   2,
 -    8,   3,   8,   5,   8,   8,   8,  13,   8,  21,   8,  -1,   8,  -2,   8,
 -   -3,   8,  -5,   8,  -8,   8, -13,   8, -17,   8, -21,   8,   0,  13,   1,
 -   13,   2,  13,   3,  13,   5,  13,   8,  13,  13,  13,  21,  13,  -1,  13,
 -   -2,  13,  -3,  13,  -5,  13,  -8,  13, -13,  13, -17,  13, -21,  13,   0,
 -   21,   1,  21,   2,  21,   3,  21,   5,  21,   8,  21,  13,  21,  21,  21,
 -   -1,  21,  -2,  21,  -3,  21,  -5,  21,  -8,  21, -13,  21, -17,  21, -21,
 -   21,   0,  -1,   1,  -1,   2,  -1,   3,  -1,   5,  -1,   8,  -1,  13,  -1,
 -   21,  -1,  -1,  -1,  -2,  -1,  -3,  -1,  -5,  -1,  -8,  -1, -13,  -1, -17,
 -   -1, -21,  -1,   0,  -2,   1,  -2,   2,  -2,   3,  -2,   5,  -2,   8,  -2,
 -   13,  -2,  21,  -2,  -1,  -2,  -2,  -2,  -3,  -2,  -5,  -2,  -8,  -2, -13,
 -   -2, -17,  -2, -21,  -2,   0,  -3,   1,  -3,   2,  -3,   3,  -3,   5,  -3,
 -    8,  -3,  13,  -3,  21,  -3,  -1,  -3,  -2,  -3,  -3,  -3,  -5,  -3,  -8,
 -   -3, -13,  -3, -17,  -3, -21,  -3,   0,  -5,   1,  -5,   2,  -5,   3,  -5,
 -    5,  -5,   8,  -5,  13,  -5,  21,  -5,  -1,  -5,  -2,  -5,  -3,  -5,  -5,
 -   -5,  -8,  -5, -13,  -5, -17,  -5, -21,  -5,   0,  -8,   1,  -8,   2,  -8,
 -    3,  -8,   5,  -8,   8,  -8,  13,  -8,  21,  -8,  -1,  -8,  -2,  -8,  -3,
 -   -8,  -5,  -8,  -8,  -8, -13,  -8, -17,  -8, -21,  -8,   0, -13,   1, -13,
 -    2, -13,   3, -13,   5, -13,   8, -13,  13, -13,  21, -13,  -1, -13,  -2,
 -  -13,  -3, -13,  -5, -13,  -8, -13, -13, -13, -17, -13, -21, -13,   0, -17,
 -    1, -17,   2, -17,   3, -17,   5, -17,   8, -17,  13, -17,  21, -17,  -1,
 -  -17,  -2, -17,  -3, -17,  -5, -17,  -8, -17, -13, -17, -17, -17, -21, -17,
 -    0, -21,   1, -21,   2, -21,   3, -21,   5, -21,   8, -21,  13, -21,  21,
 -  -21,  -1, -21,  -2, -21,  -3, -21,  -5, -21,  -8, -21, -13, -21, -17, -21,
 -    0,   0,  -8, -29,   8, -29, -18, -25,  17, -25,   0, -23,  -6, -22,   6,
 -  -22, -13, -19,  12, -19,   0, -18,  25, -18, -25, -17,  -5, -17,   5, -17,
 -  -10, -15,  10, -15,   0, -14,  -4, -13,   4, -13,  19, -13, -19, -12,  -8,
 -  -11,  -2, -11,   0, -11,   2, -11,   8, -11, -15, -10,  -4, -10,   4, -10,
 -   15, -10,  -6,  -9,  -1,  -9,   1,  -9,   6,  -9, -29,  -8, -11,  -8,  -8,
 -   -8,  -3,  -8,   3,  -8,   8,  -8,  11,  -8,  29,  -8,  -5,  -7,  -2,  -7,
 -    0,  -7,   2,  -7,   5,  -7, -22,  -6,  -9,  -6,  -6,  -6,  -3,  -6,  -1,
 -   -6,   1,  -6,   3,  -6,   6,  -6,   9,  -6,  22,  -6, -17,  -5,  -7,  -5,
 -   -4,  -5,  -2,  -5,   0,  -5,   2,  -5,   4,  -5,   7,  -5,  17,  -5, -13,
 -   -4, -10,  -4,  -5,  -4,  -3,  -4,  -1,  -4,   0,  -4,   1,  -4,   3,  -4,
 -    5,  -4,  10,  -4,  13,  -4,  -8,  -3,  -6,  -3,  -4,  -3,  -3,  -3,  -2,
 -   -3,  -1,  -3,   0,  -3,   1,  -3,   2,  -3,   4,  -3,   6,  -3,   8,  -3,
 -  -11,  -2,  -7,  -2,  -5,  -2,  -3,  -2,  -2,  -2,  -1,  -2,   0,  -2,   1,
 -   -2,   2,  -2,   3,  -2,   5,  -2,   7,  -2,  11,  -2,  -9,  -1,  -6,  -1,
 -   -4,  -1,  -3,  -1,  -2,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,
 -   -1,   4,  -1,   6,  -1,   9,  -1, -31,   0, -23,   0, -18,   0, -14,   0,
 -  -11,   0,  -7,   0,  -5,   0,  -4,   0,  -3,   0,  -2,   0,  -1,   0,   0,
 -  -31,   1,   0,   2,   0,   3,   0,   4,   0,   5,   0,   7,   0,  11,   0,
 -   14,   0,  18,   0,  23,   0,  31,   0,  -9,   1,  -6,   1,  -4,   1,  -3,
 -    1,  -2,   1,  -1,   1,   0,   1,   1,   1,   2,   1,   3,   1,   4,   1,
 -    6,   1,   9,   1, -11,   2,  -7,   2,  -5,   2,  -3,   2,  -2,   2,  -1,
 -    2,   0,   2,   1,   2,   2,   2,   3,   2,   5,   2,   7,   2,  11,   2,
 -   -8,   3,  -6,   3,  -4,   3,  -2,   3,  -1,   3,   0,   3,   1,   3,   2,
 -    3,   3,   3,   4,   3,   6,   3,   8,   3, -13,   4, -10,   4,  -5,   4,
 -   -3,   4,  -1,   4,   0,   4,   1,   4,   3,   4,   5,   4,  10,   4,  13,
 -    4, -17,   5,  -7,   5,  -4,   5,  -2,   5,   0,   5,   2,   5,   4,   5,
 -    7,   5,  17,   5, -22,   6,  -9,   6,  -6,   6,  -3,   6,  -1,   6,   1,
 -    6,   3,   6,   6,   6,   9,   6,  22,   6,  -5,   7,  -2,   7,   0,   7,
 -    2,   7,   5,   7, -29,   8, -11,   8,  -8,   8,  -3,   8,   3,   8,   8,
 -    8,  11,   8,  29,   8,  -6,   9,  -1,   9,   1,   9,   6,   9, -15,  10,
 -   -4,  10,   4,  10,  15,  10,  -8,  11,  -2,  11,   0,  11,   2,  11,   8,
 -   11,  19,  12, -19,  13,  -4,  13,   4,  13,   0,  14, -10,  15,  10,  15,
 -   -5,  17,   5,  17,  25,  17, -25,  18,   0,  18, -12,  19,  13,  19,  -6,
 -   22,   6,  22,   0,  23, -17,  25,  18,  25,  -8,  29,   8,  29,   0,  31,
 -    0,   0,  -6, -22,   6, -22, -13, -19,  12, -19,   0, -18,  -5, -17,   5,
 -  -17, -10, -15,  10, -15,   0, -14,  -4, -13,   4, -13,  19, -13, -19, -12,
 -   -8, -11,  -2, -11,   0, -11,   2, -11,   8, -11, -15, -10,  -4, -10,   4,
 -  -10,  15, -10,  -6,  -9,  -1,  -9,   1,  -9,   6,  -9, -11,  -8,  -8,  -8,
 -   -3,  -8,   0,  -8,   3,  -8,   8,  -8,  11,  -8,  -5,  -7,  -2,  -7,   0,
 -   -7,   2,  -7,   5,  -7, -22,  -6,  -9,  -6,  -6,  -6,  -3,  -6,  -1,  -6,
 -    1,  -6,   3,  -6,   6,  -6,   9,  -6,  22,  -6, -17,  -5,  -7,  -5,  -4,
 -   -5,  -2,  -5,  -1,  -5,   0,  -5,   1,  -5,   2,  -5,   4,  -5,   7,  -5,
 -   17,  -5, -13,  -4, -10,  -4,  -5,  -4,  -3,  -4,  -2,  -4,  -1,  -4,   0,
 -   -4,   1,  -4,   2,  -4,   3,  -4,   5,  -4,  10,  -4,  13,  -4,  -8,  -3,
 -   -6,  -3,  -4,  -3,  -3,  -3,  -2,  -3,  -1,  -3,   0,  -3,   1,  -3,   2,
 -   -3,   3,  -3,   4,  -3,   6,  -3,   8,  -3, -11,  -2,  -7,  -2,  -5,  -2,
 -   -4,  -2,  -3,  -2,  -2,  -2,  -1,  -2,   0,  -2,   1,  -2,   2,  -2,   3,
 -   -2,   4,  -2,   5,  -2,   7,  -2,  11,  -2,  -9,  -1,  -6,  -1,  -5,  -1,
 -   -4,  -1,  -3,  -1,  -2,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,
 -   -1,   4,  -1,   5,  -1,   6,  -1,   9,  -1, -23,   0, -18,   0, -14,   0,
 -  -11,   0,  -7,   0,  -5,   0,  -4,   0,  -3,   0,  -2,   0,  -1,   0,   0,
 -  -23,   1,   0,   2,   0,   3,   0,   4,   0,   5,   0,   7,   0,  11,   0,
 -   14,   0,  18,   0,  23,   0,  -9,   1,  -6,   1,  -5,   1,  -4,   1,  -3,
 -    1,  -2,   1,  -1,   1,   0,   1,   1,   1,   2,   1,   3,   1,   4,   1,
 -    5,   1,   6,   1,   9,   1, -11,   2,  -7,   2,  -5,   2,  -4,   2,  -3,
 -    2,  -2,   2,  -1,   2,   0,   2,   1,   2,   2,   2,   3,   2,   4,   2,
 -    5,   2,   7,   2,  11,   2,  -8,   3,  -6,   3,  -4,   3,  -3,   3,  -2,
 -    3,  -1,   3,   0,   3,   1,   3,   2,   3,   3,   3,   4,   3,   6,   3,
 -    8,   3, -13,   4, -10,   4,  -5,   4,  -3,   4,  -2,   4,  -1,   4,   0,
 -    4,   1,   4,   2,   4,   3,   4,   5,   4,  10,   4,  13,   4, -17,   5,
 -   -7,   5,  -4,   5,  -2,   5,  -1,   5,   0,   5,   1,   5,   2,   5,   4,
 -    5,   7,   5,  17,   5, -22,   6,  -9,   6,  -6,   6,  -3,   6,  -1,   6,
 -    1,   6,   3,   6,   6,   6,   9,   6,  22,   6,  -5,   7,  -2,   7,   0,
 -    7,   2,   7,   5,   7, -11,   8,  -8,   8,  -3,   8,   0,   8,   3,   8,
 -    8,   8,  11,   8,  -6,   9,  -1,   9,   1,   9,   6,   9, -15,  10,  -4,
 -   10,   4,  10,  15,  10,  -8,  11,  -2,  11,   0,  11,   2,  11,   8,  11,
 -   19,  12, -19,  13,  -4,  13,   4,  13,   0,  14, -10,  15,  10,  15,  -5,
 -   17,   5,  17,   0,  18, -12,  19,  13,  19,  -6,  22,   6,  22,   0,  23,
 +    0,   0,   1,   0,   2,   0,   3,   0,   5,   0,
 +    8,   0,  13,   0,  21,   0,  -1,   0,  -2,   0,
 +   -3,   0,  -5,   0,  -8,   0, -13,   0, -17,   0,
 +  -21,   0,   0,   1,   1,   1,   2,   1,   3,   1,
 +    5,   1,   8,   1,  13,   1,  21,   1,  -1,   1,
 +   -2,   1,  -3,   1,  -5,   1,  -8,   1, -13,   1,
 +  -17,   1, -21,   1,   0,   2,   1,   2,   2,   2,
 +    3,   2,   5,   2,   8,   2,  13,   2,  21,   2,
 +   -1,   2,  -2,   2,  -3,   2,  -5,   2,  -8,   2,
 +  -13,   2, -17,   2, -21,   2,   0,   3,   1,   3,
 +    2,   3,   3,   3,   5,   3,   8,   3,  13,   3,
 +   21,   3,  -1,   3,  -2,   3,  -3,   3,  -5,   3,
 +   -8,   3, -13,   3, -17,   3, -21,   3,   0,   5,
 +    1,   5,   2,   5,   3,   5,   5,   5,   8,   5,
 +   13,   5,  21,   5,  -1,   5,  -2,   5,  -3,   5,
 +   -5,   5,  -8,   5, -13,   5, -17,   5, -21,   5,
 +    0,   8,   1,   8,   2,   8,   3,   8,   5,   8,
 +    8,   8,  13,   8,  21,   8,  -1,   8,  -2,   8,
 +   -3,   8,  -5,   8,  -8,   8, -13,   8, -17,   8,
 +  -21,   8,   0,  13,   1,  13,   2,  13,   3,  13,
 +    5,  13,   8,  13,  13,  13,  21,  13,  -1,  13,
 +   -2,  13,  -3,  13,  -5,  13,  -8,  13, -13,  13,
 +  -17,  13, -21,  13,   0,  21,   1,  21,   2,  21,
 +    3,  21,   5,  21,   8,  21,  13,  21,  21,  21,
 +   -1,  21,  -2,  21,  -3,  21,  -5,  21,  -8,  21,
 +  -13,  21, -17,  21, -21,  21,   0,  -1,   1,  -1,
 +    2,  -1,   3,  -1,   5,  -1,   8,  -1,  13,  -1,
 +   21,  -1,  -1,  -1,  -2,  -1,  -3,  -1,  -5,  -1,
 +   -8,  -1, -13,  -1, -17,  -1, -21,  -1,   0,  -2,
 +    1,  -2,   2,  -2,   3,  -2,   5,  -2,   8,  -2,
 +   13,  -2,  21,  -2,  -1,  -2,  -2,  -2,  -3,  -2,
 +   -5,  -2,  -8,  -2, -13,  -2, -17,  -2, -21,  -2,
 +    0,  -3,   1,  -3,   2,  -3,   3,  -3,   5,  -3,
 +    8,  -3,  13,  -3,  21,  -3,  -1,  -3,  -2,  -3,
 +   -3,  -3,  -5,  -3,  -8,  -3, -13,  -3, -17,  -3,
 +  -21,  -3,   0,  -5,   1,  -5,   2,  -5,   3,  -5,
 +    5,  -5,   8,  -5,  13,  -5,  21,  -5,  -1,  -5,
 +   -2,  -5,  -3,  -5,  -5,  -5,  -8,  -5, -13,  -5,
 +  -17,  -5, -21,  -5,   0,  -8,   1,  -8,   2,  -8,
 +    3,  -8,   5,  -8,   8,  -8,  13,  -8,  21,  -8,
 +   -1,  -8,  -2,  -8,  -3,  -8,  -5,  -8,  -8,  -8,
 +  -13,  -8, -17,  -8, -21,  -8,   0, -13,   1, -13,
 +    2, -13,   3, -13,   5, -13,   8, -13,  13, -13,
 +   21, -13,  -1, -13,  -2, -13,  -3, -13,  -5, -13,
 +   -8, -13, -13, -13, -17, -13, -21, -13,   0, -17,
 +    1, -17,   2, -17,   3, -17,   5, -17,   8, -17,
 +   13, -17,  21, -17,  -1, -17,  -2, -17,  -3, -17,
 +   -5, -17,  -8, -17, -13, -17, -17, -17, -21, -17,
 +    0, -21,   1, -21,   2, -21,   3, -21,   5, -21,
 +    8, -21,  13, -21,  21, -21,  -1, -21,  -2, -21,
 +   -3, -21,  -5, -21,  -8, -21, -13, -21, -17, -21,
 +    0,   0,  -8, -29,   8, -29, -18, -25,  17, -25,
 +    0, -23,  -6, -22,   6, -22, -13, -19,  12, -19,
 +    0, -18,  25, -18, -25, -17,  -5, -17,   5, -17,
 +  -10, -15,  10, -15,   0, -14,  -4, -13,   4, -13,
 +   19, -13, -19, -12,  -8, -11,  -2, -11,   0, -11,
 +    2, -11,   8, -11, -15, -10,  -4, -10,   4, -10,
 +   15, -10,  -6,  -9,  -1,  -9,   1,  -9,   6,  -9,
 +  -29,  -8, -11,  -8,  -8,  -8,  -3,  -8,   3,  -8,
 +    8,  -8,  11,  -8,  29,  -8,  -5,  -7,  -2,  -7,
 +    0,  -7,   2,  -7,   5,  -7, -22,  -6,  -9,  -6,
 +   -6,  -6,  -3,  -6,  -1,  -6,   1,  -6,   3,  -6,
 +    6,  -6,   9,  -6,  22,  -6, -17,  -5,  -7,  -5,
 +   -4,  -5,  -2,  -5,   0,  -5,   2,  -5,   4,  -5,
 +    7,  -5,  17,  -5, -13,  -4, -10,  -4,  -5,  -4,
 +   -3,  -4,  -1,  -4,   0,  -4,   1,  -4,   3,  -4,
 +    5,  -4,  10,  -4,  13,  -4,  -8,  -3,  -6,  -3,
 +   -4,  -3,  -3,  -3,  -2,  -3,  -1,  -3,   0,  -3,
 +    1,  -3,   2,  -3,   4,  -3,   6,  -3,   8,  -3,
 +  -11,  -2,  -7,  -2,  -5,  -2,  -3,  -2,  -2,  -2,
 +   -1,  -2,   0,  -2,   1,  -2,   2,  -2,   3,  -2,
 +    5,  -2,   7,  -2,  11,  -2,  -9,  -1,  -6,  -1,
 +   -4,  -1,  -3,  -1,  -2,  -1,  -1,  -1,   0,  -1,
 +    1,  -1,   2,  -1,   3,  -1,   4,  -1,   6,  -1,
 +    9,  -1, -31,   0, -23,   0, -18,   0, -14,   0,
 +  -11,   0,  -7,   0,  -5,   0,  -4,   0,  -3,   0,
 +   -2,   0,  -1,   0,   0, -31,   1,   0,   2,   0,
 +    3,   0,   4,   0,   5,   0,   7,   0,  11,   0,
 +   14,   0,  18,   0,  23,   0,  31,   0,  -9,   1,
 +   -6,   1,  -4,   1,  -3,   1,  -2,   1,  -1,   1,
 +    0,   1,   1,   1,   2,   1,   3,   1,   4,   1,
 +    6,   1,   9,   1, -11,   2,  -7,   2,  -5,   2,
 +   -3,   2,  -2,   2,  -1,   2,   0,   2,   1,   2,
 +    2,   2,   3,   2,   5,   2,   7,   2,  11,   2,
 +   -8,   3,  -6,   3,  -4,   3,  -2,   3,  -1,   3,
 +    0,   3,   1,   3,   2,   3,   3,   3,   4,   3,
 +    6,   3,   8,   3, -13,   4, -10,   4,  -5,   4,
 +   -3,   4,  -1,   4,   0,   4,   1,   4,   3,   4,
 +    5,   4,  10,   4,  13,   4, -17,   5,  -7,   5,
 +   -4,   5,  -2,   5,   0,   5,   2,   5,   4,   5,
 +    7,   5,  17,   5, -22,   6,  -9,   6,  -6,   6,
 +   -3,   6,  -1,   6,   1,   6,   3,   6,   6,   6,
 +    9,   6,  22,   6,  -5,   7,  -2,   7,   0,   7,
 +    2,   7,   5,   7, -29,   8, -11,   8,  -8,   8,
 +   -3,   8,   3,   8,   8,   8,  11,   8,  29,   8,
 +   -6,   9,  -1,   9,   1,   9,   6,   9, -15,  10,
 +   -4,  10,   4,  10,  15,  10,  -8,  11,  -2,  11,
 +    0,  11,   2,  11,   8,  11,  19,  12, -19,  13,
 +   -4,  13,   4,  13,   0,  14, -10,  15,  10,  15,
 +   -5,  17,   5,  17,  25,  17, -25,  18,   0,  18,
 +  -12,  19,  13,  19,  -6,  22,   6,  22,   0,  23,
 +  -17,  25,  18,  25,  -8,  29,   8,  29,   0,  31,
 +    0,   0,  -6, -22,   6, -22, -13, -19,  12, -19,
 +    0, -18,  -5, -17,   5, -17, -10, -15,  10, -15,
 +    0, -14,  -4, -13,   4, -13,  19, -13, -19, -12,
 +   -8, -11,  -2, -11,   0, -11,   2, -11,   8, -11,
 +  -15, -10,  -4, -10,   4, -10,  15, -10,  -6,  -9,
 +   -1,  -9,   1,  -9,   6,  -9, -11,  -8,  -8,  -8,
 +   -3,  -8,   0,  -8,   3,  -8,   8,  -8,  11,  -8,
 +   -5,  -7,  -2,  -7,   0,  -7,   2,  -7,   5,  -7,
 +  -22,  -6,  -9,  -6,  -6,  -6,  -3,  -6,  -1,  -6,
 +    1,  -6,   3,  -6,   6,  -6,   9,  -6,  22,  -6,
 +  -17,  -5,  -7,  -5,  -4,  -5,  -2,  -5,  -1,  -5,
 +    0,  -5,   1,  -5,   2,  -5,   4,  -5,   7,  -5,
 +   17,  -5, -13,  -4, -10,  -4,  -5,  -4,  -3,  -4,
 +   -2,  -4,  -1,  -4,   0,  -4,   1,  -4,   2,  -4,
 +    3,  -4,   5,  -4,  10,  -4,  13,  -4,  -8,  -3,
 +   -6,  -3,  -4,  -3,  -3,  -3,  -2,  -3,  -1,  -3,
 +    0,  -3,   1,  -3,   2,  -3,   3,  -3,   4,  -3,
 +    6,  -3,   8,  -3, -11,  -2,  -7,  -2,  -5,  -2,
 +   -4,  -2,  -3,  -2,  -2,  -2,  -1,  -2,   0,  -2,
 +    1,  -2,   2,  -2,   3,  -2,   4,  -2,   5,  -2,
 +    7,  -2,  11,  -2,  -9,  -1,  -6,  -1,  -5,  -1,
 +   -4,  -1,  -3,  -1,  -2,  -1,  -1,  -1,   0,  -1,
 +    1,  -1,   2,  -1,   3,  -1,   4,  -1,   5,  -1,
 +    6,  -1,   9,  -1, -23,   0, -18,   0, -14,   0,
 +  -11,   0,  -7,   0,  -5,   0,  -4,   0,  -3,   0,
 +   -2,   0,  -1,   0,   0, -23,   1,   0,   2,   0,
 +    3,   0,   4,   0,   5,   0,   7,   0,  11,   0,
 +   14,   0,  18,   0,  23,   0,  -9,   1,  -6,   1,
 +   -5,   1,  -4,   1,  -3,   1,  -2,   1,  -1,   1,
 +    0,   1,   1,   1,   2,   1,   3,   1,   4,   1,
 +    5,   1,   6,   1,   9,   1, -11,   2,  -7,   2,
 +   -5,   2,  -4,   2,  -3,   2,  -2,   2,  -1,   2,
 +    0,   2,   1,   2,   2,   2,   3,   2,   4,   2,
 +    5,   2,   7,   2,  11,   2,  -8,   3,  -6,   3,
 +   -4,   3,  -3,   3,  -2,   3,  -1,   3,   0,   3,
 +    1,   3,   2,   3,   3,   3,   4,   3,   6,   3,
 +    8,   3, -13,   4, -10,   4,  -5,   4,  -3,   4,
 +   -2,   4,  -1,   4,   0,   4,   1,   4,   2,   4,
 +    3,   4,   5,   4,  10,   4,  13,   4, -17,   5,
 +   -7,   5,  -4,   5,  -2,   5,  -1,   5,   0,   5,
 +    1,   5,   2,   5,   4,   5,   7,   5,  17,   5,
 +  -22,   6,  -9,   6,  -6,   6,  -3,   6,  -1,   6,
 +    1,   6,   3,   6,   6,   6,   9,   6,  22,   6,
 +   -5,   7,  -2,   7,   0,   7,   2,   7,   5,   7,
 +  -11,   8,  -8,   8,  -3,   8,   0,   8,   3,   8,
 +    8,   8,  11,   8,  -6,   9,  -1,   9,   1,   9,
 +    6,   9, -15,  10,  -4,  10,   4,  10,  15,  10,
 +   -8,  11,  -2,  11,   0,  11,   2,  11,   8,  11,
 +   19,  12, -19,  13,  -4,  13,   4,  13,   0,  14,
 +  -10,  15,  10,  15,  -5,  17,   5,  17,   0,  18,
 +  -12,  19,  13,  19,  -6,  22,   6,  22,   0,  23,
  };
  
  typedef struct SANMVideoContext {
@@@ -457,7 -406,6 +457,7 @@@ static void destroy_buffers(SANMVideoCo
      ctx->frm0_size =
      ctx->frm1_size =
      ctx->frm2_size = 0;
 +    init_sizes(ctx, 0, 0);
  }
  
  static av_cold int init_buffers(SANMVideoContext *ctx)
@@@ -512,7 -460,7 +512,7 @@@ static av_cold int decode_init(AVCodecC
          }
  
          ctx->subversion = AV_RL16(avctx->extradata);
 -        for (i = 0; i < 256; i++)
 +        for (i = 0; i < PALETTE_SIZE; i++)
              ctx->pal[i] = 0xFFU << 24 | AV_RL32(avctx->extradata + 2 + i * 4);
      }
  
@@@ -978,13 -926,10 +978,10 @@@ static int process_frame_obj(SANMVideoC
      case 1:
      case 3:
          return old_codec1(ctx, top, left, w, h);
-         break;
      case 37:
          return old_codec37(ctx, top, left, w, h);
-         break;
      case 47:
          return old_codec47(ctx, top, left, w, h);
-         break;
      default:
          avpriv_request_sample(ctx->avctx, "Subcodec %d", codec);
          return AVERROR_PATCHWELCOME;
@@@ -1518,7 -1463,7 +1515,7 @@@ static int decode_frame(AVCodecContext 
  
  AVCodec ff_sanm_decoder = {
      .name           = "sanm",
 -    .long_name      = NULL_IF_CONFIG_SMALL("LucasArts SANM video"),
 +    .long_name      = NULL_IF_CONFIG_SMALL("LucasArts SANM/Smush video"),
      .type           = AVMEDIA_TYPE_VIDEO,
      .id             = AV_CODEC_ID_SANM,
      .priv_data_size = sizeof(SANMVideoContext),
diff --combined libavformat/rtpproto.c
@@@ -2,20 -2,20 +2,20 @@@
   * RTP network protocol
   * Copyright (c) 2002 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
   */
  
@@@ -44,7 -44,7 +44,7 @@@
  
  typedef struct RTPContext {
      const AVClass *class;
 -    URLContext *rtp_hd, *rtcp_hd;
 +    URLContext *rtp_hd, *rtcp_hd, *fec_hd;
      int rtp_fd, rtcp_fd, nb_ssm_include_addrs, nb_ssm_exclude_addrs;
      struct sockaddr_storage **ssm_include_addrs, **ssm_exclude_addrs;
      int write_to_source;
      int rtcp_port, local_rtpport, local_rtcpport;
      int connect;
      int pkt_size;
 +    int dscp;
      char *sources;
      char *block;
 +    char *fec_options_str;
  } RTPContext;
  
  #define OFFSET(x) offsetof(RTPContext, x)
@@@ -70,13 -68,11 +70,13 @@@ static const AVOption options[] = 
      { "rtcp_port",          "Custom rtcp port",                                                 OFFSET(rtcp_port),       AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
      { "local_rtpport",      "Local rtp port",                                                   OFFSET(local_rtpport),   AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
      { "local_rtcpport",     "Local rtcp port",                                                  OFFSET(local_rtcpport),  AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
 -    { "connect",            "Connect socket",                                                   OFFSET(connect),         AV_OPT_TYPE_INT,    { .i64 =  0 },     0, 1,       .flags = D|E },
 -    { "write_to_source",    "Send packets to the source address of the latest received packet", OFFSET(write_to_source), AV_OPT_TYPE_INT,    { .i64 =  0 },     0, 1,       .flags = D|E },
 +    { "connect",            "Connect socket",                                                   OFFSET(connect),         AV_OPT_TYPE_BOOL,   { .i64 =  0 },     0, 1,       .flags = D|E },
 +    { "write_to_source",    "Send packets to the source address of the latest received packet", OFFSET(write_to_source), AV_OPT_TYPE_BOOL,   { .i64 =  0 },     0, 1,       .flags = D|E },
      { "pkt_size",           "Maximum packet size",                                              OFFSET(pkt_size),        AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
 +    { "dscp",               "DSCP class",                                                       OFFSET(dscp),            AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
      { "sources",            "Source list",                                                      OFFSET(sources),         AV_OPT_TYPE_STRING, { .str = NULL },               .flags = D|E },
      { "block",              "Block list",                                                       OFFSET(block),           AV_OPT_TYPE_STRING, { .str = NULL },               .flags = D|E },
 +    { "fec",                "FEC",                                                              OFFSET(fec_options_str), AV_OPT_TYPE_STRING, { .str = NULL },               .flags = E },
      { NULL }
  };
  
@@@ -243,9 -239,6 +243,9 @@@ static void build_udp_url(RTPContext *s
          url_add_option(buf, buf_size, "pkt_size=%d", s->pkt_size);
      if (s->connect)
          url_add_option(buf, buf_size, "connect=1");
 +    if (s->dscp >= 0)
 +        url_add_option(buf, buf_size, "dscp=%d", s->dscp);
 +    url_add_option(buf, buf_size, "fifo_size=0");
      if (include_sources && include_sources[0])
          url_add_option(buf, buf_size, "sources=%s", include_sources);
      if (exclude_sources && exclude_sources[0])
@@@ -305,7 -298,6 +305,7 @@@ static void rtp_parse_addr_list(URLCont
   *         'sources=ip[,ip]'  : list allowed source IP addresses
   *         'block=ip[,ip]'    : list disallowed source IP addresses
   *         'write_to_source=0/1' : send packets to the source address of the latest received packet
 + *         'dscp=n'           : set DSCP value to n (QoS)
   * deprecated option:
   *         'localport=n'      : set the local port to n
   *
  static int rtp_open(URLContext *h, const char *uri, int flags)
  {
      RTPContext *s = h->priv_data;
 +    AVDictionary *fec_opts = NULL;
      int rtp_port;
      char hostname[256], include_sources[1024] = "", exclude_sources[1024] = "";
      char *sources = include_sources, *block = exclude_sources;
 +    char *fec_protocol = NULL;
      char buf[1024];
      char path[1024];
      const char *p;
 +    int i, max_retry_count = 3;
 +    int rtcpflags;
  
      av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port,
                   path, sizeof(path), uri);
          if (av_find_info_tag(buf, sizeof(buf), "write_to_source", p)) {
              s->write_to_source = strtol(buf, NULL, 10);
          }
 +        if (av_find_info_tag(buf, sizeof(buf), "dscp", p)) {
 +            s->dscp = strtol(buf, NULL, 10);
 +        }
          if (av_find_info_tag(buf, sizeof(buf), "sources", p)) {
              av_strlcpy(include_sources, buf, sizeof(include_sources));
  
          }
      }
  
 -    build_udp_url(s, buf, sizeof(buf),
 -                  hostname, rtp_port, s->local_rtpport, sources, block);
 -    if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL,
 -                   h->protocols, h) < 0)
 -        goto fail;
 -    if (s->local_rtpport >= 0 && s->local_rtcpport < 0)
 -        s->local_rtcpport = ff_udp_get_local_port(s->rtp_hd) + 1;
 +    if (s->fec_options_str) {
 +        p = s->fec_options_str;
 +
 +        if (!(fec_protocol = av_get_token(&p, "="))) {
 +            av_log(h, AV_LOG_ERROR, "Failed to parse the FEC protocol value\n");
 +            goto fail;
 +        }
 +        if (strcmp(fec_protocol, "prompeg")) {
 +            av_log(h, AV_LOG_ERROR, "Unsupported FEC protocol %s\n", fec_protocol);
 +            goto fail;
 +        }
 +
 +        p = s->fec_options_str + strlen(fec_protocol);
 +        while (*p && *p == '=') p++;
  
 -    build_udp_url(s, buf, sizeof(buf),
 -                  hostname, s->rtcp_port, s->local_rtcpport, sources, block);
 -    if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL,
 -                   h->protocols, h) < 0)
 -        goto fail;
 +        if (av_dict_parse_string(&fec_opts, p, "=", ":", 0) < 0) {
 +            av_log(h, AV_LOG_ERROR, "Failed to parse the FEC options\n");
 +            goto fail;
 +        }
 +        if (s->ttl > 0) {
 +            snprintf(buf, sizeof (buf), "%d", s->ttl);
 +            av_dict_set(&fec_opts, "ttl", buf, 0);
 +        }
 +    }
 +
 +    for (i = 0; i < max_retry_count; i++) {
 +        build_udp_url(s, buf, sizeof(buf),
 +                      hostname, rtp_port, s->local_rtpport,
 +                      sources, block);
 +        if (ffurl_open_whitelist(&s->rtp_hd, buf, flags, &h->interrupt_callback,
 +                                 NULL, h->protocol_whitelist, h->protocol_blacklist, h) < 0)
 +            goto fail;
 +        s->local_rtpport = ff_udp_get_local_port(s->rtp_hd);
 +        if(s->local_rtpport == 65535) {
 +            s->local_rtpport = -1;
 +            continue;
 +        }
 +        rtcpflags = flags | AVIO_FLAG_WRITE;
 +        if (s->local_rtcpport < 0) {
 +            s->local_rtcpport = s->local_rtpport + 1;
 +            build_udp_url(s, buf, sizeof(buf),
 +                          hostname, s->rtcp_port, s->local_rtcpport,
 +                          sources, block);
 +            if (ffurl_open_whitelist(&s->rtcp_hd, buf, rtcpflags,
 +                                     &h->interrupt_callback, NULL,
 +                                     h->protocol_whitelist, h->protocol_blacklist, h) < 0) {
 +                s->local_rtpport = s->local_rtcpport = -1;
 +                continue;
 +            }
 +            break;
 +        }
 +        build_udp_url(s, buf, sizeof(buf),
 +                      hostname, s->rtcp_port, s->local_rtcpport,
 +                      sources, block);
 +        if (ffurl_open_whitelist(&s->rtcp_hd, buf, rtcpflags, &h->interrupt_callback,
 +                                 NULL, h->protocol_whitelist, h->protocol_blacklist, h) < 0)
 +            goto fail;
 +        break;
 +    }
 +
 +    s->fec_hd = NULL;
 +    if (fec_protocol) {
 +        ff_url_join(buf, sizeof(buf), fec_protocol, NULL, hostname, rtp_port, NULL);
 +        if (ffurl_open_whitelist(&s->fec_hd, buf, flags, &h->interrupt_callback,
 +                             &fec_opts, h->protocol_whitelist, h->protocol_blacklist, h) < 0)
 +            goto fail;
 +    }
  
      /* just to ease handle access. XXX: need to suppress direct handle
         access */
  
      h->max_packet_size = s->rtp_hd->max_packet_size;
      h->is_streamed = 1;
 +
 +    av_free(fec_protocol);
 +    av_dict_free(&fec_opts);
 +
      return 0;
  
   fail:
          ffurl_close(s->rtp_hd);
      if (s->rtcp_hd)
          ffurl_close(s->rtcp_hd);
 +    ffurl_closep(&s->fec_hd);
 +    av_free(fec_protocol);
 +    av_dict_free(&fec_opts);
      return AVERROR(EIO);
  }
  
@@@ -512,13 -436,12 +512,12 @@@ static int rtp_read(URLContext *h, uint
          if (h->flags & AVIO_FLAG_NONBLOCK)
              return AVERROR(EAGAIN);
      }
-     return len;
  }
  
  static int rtp_write(URLContext *h, const uint8_t *buf, int size)
  {
      RTPContext *s = h->priv_data;
 -    int ret;
 +    int ret, ret_fec;
      URLContext *hd;
  
      if (size < 2)
          hd = s->rtp_hd;
      }
  
 -    ret = ffurl_write(hd, buf, size);
 +    if ((ret = ffurl_write(hd, buf, size)) < 0) {
 +        return ret;
 +    }
 +
 +    if (s->fec_hd && !RTP_PT_IS_RTCP(buf[1])) {
 +        if ((ret_fec = ffurl_write(s->fec_hd, buf, size)) < 0) {
 +            av_log(h, AV_LOG_ERROR, "Failed to send FEC\n");
 +            return ret_fec;
 +        }
 +    }
 +
      return ret;
  }
  
@@@ -607,15 -520,14 +606,15 @@@ static int rtp_close(URLContext *h
      int i;
  
      for (i = 0; i < s->nb_ssm_include_addrs; i++)
 -        av_free(s->ssm_include_addrs[i]);
 +        av_freep(&s->ssm_include_addrs[i]);
      av_freep(&s->ssm_include_addrs);
      for (i = 0; i < s->nb_ssm_exclude_addrs; i++)
 -        av_free(s->ssm_exclude_addrs[i]);
 +        av_freep(&s->ssm_exclude_addrs[i]);
      av_freep(&s->ssm_exclude_addrs);
  
      ffurl_close(s->rtp_hd);
      ffurl_close(s->rtcp_hd);
 +    ffurl_closep(&s->fec_hd);
      return 0;
  }
  
diff --combined libavformat/rtspdec.c
@@@ -2,20 -2,20 +2,20 @@@
   * RTSP demuxer
   * Copyright (c) 2002 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
   */
  
@@@ -294,9 -294,8 +294,9 @@@ static int rtsp_read_setup(AVFormatCont
              av_dict_set(&opts, "buffer_size", buf, 0);
              ff_url_join(url, sizeof(url), "rtp", NULL, host, localport, NULL);
              av_log(s, AV_LOG_TRACE, "Opening: %s", url);
 -            ret = ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE,
 -                             &s->interrupt_callback, &opts, rt->protocols, NULL);
 +            ret = ffurl_open_whitelist(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE,
 +                                       &s->interrupt_callback, &opts,
 +                                       s->protocol_whitelist, s->protocol_blacklist, NULL);
              av_dict_free(&opts);
              if (ret)
                  localport += 2;
@@@ -368,10 -367,8 +368,10 @@@ static inline int parse_command_line(AV
      const char *linept, *searchlinept;
      linept = strchr(line, ' ');
  
 -    if (!linept)
 +    if (!linept) {
 +        av_log(s, AV_LOG_ERROR, "Error parsing method string\n");
          return AVERROR_INVALIDDATA;
 +    }
  
      if (linept - line > methodsize - 1) {
          av_log(s, AV_LOG_ERROR, "Method string too long\n");
@@@ -551,7 -548,7 +551,7 @@@ static int rtsp_read_play(AVFormatConte
          }
          ff_rtsp_send_cmd(s, "PLAY", rt->control_uri, cmd, reply, NULL);
          if (reply->status_code != RTSP_STATUS_OK) {
 -            return -1;
 +            return ff_rtsp_averror(reply->status_code, -1);
          }
          if (rt->transport == RTSP_TRANSPORT_RTP &&
              reply->range_start != AV_NOPTS_VALUE) {
                  AVStream *st = NULL;
                  if (!rtpctx || rtsp_st->stream_index < 0)
                      continue;
 +
                  st = s->streams[rtsp_st->stream_index];
                  rtpctx->range_start_offset =
                      av_rescale_q(reply->range_start, AV_TIME_BASE_Q,
@@@ -584,7 -580,7 +584,7 @@@ static int rtsp_read_pause(AVFormatCont
      else if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) {
          ff_rtsp_send_cmd(s, "PAUSE", rt->control_uri, NULL, reply, NULL);
          if (reply->status_code != RTSP_STATUS_OK) {
 -            return -1;
 +            return ff_rtsp_averror(reply->status_code, -1);
          }
      }
      rt->state = RTSP_STATE_PAUSED;
@@@ -611,12 -607,12 +611,12 @@@ int ff_rtsp_setup_input_streams(AVForma
                     sizeof(cmd));
      }
      ff_rtsp_send_cmd(s, "DESCRIBE", rt->control_uri, cmd, reply, &content);
 -    if (!content)
 -        return AVERROR_INVALIDDATA;
      if (reply->status_code != RTSP_STATUS_OK) {
          av_freep(&content);
 -        return AVERROR_INVALIDDATA;
 +        return ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA);
      }
 +    if (!content)
 +        return AVERROR_INVALIDDATA;
  
      av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", content);
      /* now we got the SDP description, we parse it */
@@@ -643,6 -639,13 +643,6 @@@ static int rtsp_listen(AVFormatContext 
      int ret;
      enum RTSPMethod methodcode;
  
 -    if (!rt->protocols) {
 -        rt->protocols = ffurl_get_protocols(s->protocol_whitelist,
 -                                            s->protocol_blacklist);
 -        if (!rt->protocols)
 -            return AVERROR(ENOMEM);
 -    }
 -
      /* extract hostname and port */
      av_url_split(proto, sizeof(proto), auth, sizeof(auth), host, sizeof(host),
                   &port, path, sizeof(path), s->filename);
      ff_url_join(tcpname, sizeof(tcpname), lower_proto, NULL, host, port,
                  "?listen&listen_timeout=%d", rt->initial_timeout * 1000);
  
 -    if (ret = ffurl_open(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE,
 -                         &s->interrupt_callback, NULL, rt->protocols, NULL)) {
 +    if (ret = ffurl_open_whitelist(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE,
 +                                   &s->interrupt_callback, NULL,
 +                                   s->protocol_whitelist, s->protocol_blacklist, NULL)) {
          av_log(s, AV_LOG_ERROR, "Unable to open RTSP for listening\n");
          return ret;
      }
              return AVERROR_INVALIDDATA;
          }
      }
-     return 0;
  }
  
  static int rtsp_probe(AVProbeData *p)
@@@ -730,7 -731,7 +729,7 @@@ static int rtsp_read_header(AVFormatCon
              return ret;
  
          rt->real_setup_cache = !s->nb_streams ? NULL :
 -            av_mallocz(2 * s->nb_streams * sizeof(*rt->real_setup_cache));
 +            av_mallocz_array(s->nb_streams, 2 * sizeof(*rt->real_setup_cache));
          if (!rt->real_setup_cache && s->nb_streams)
              return AVERROR(ENOMEM);
          rt->real_setup = rt->real_setup_cache + s->nb_streams;
          if (rt->initial_pause) {
              /* do not start immediately */
          } else {
 -            if (rtsp_read_play(s) < 0) {
 +            if ((ret = rtsp_read_play(s)) < 0) {
                  ff_rtsp_close_streams(s);
                  ff_rtsp_close_connections(s);
 -                return AVERROR_INVALIDDATA;
 +                return ret;
              }
          }
      }
@@@ -776,7 -777,7 +775,7 @@@ redo
      id  = buf[0];
      len = AV_RB16(buf + 1);
      av_log(s, AV_LOG_TRACE, "id=%d len=%d\n", id, len);
 -    if (len > buf_size || len < 12)
 +    if (len > buf_size || len < 8)
          goto redo;
      /* get the data */
      ret = ffurl_read_complete(rt->rtsp_hd, buf, len);
@@@ -835,7 -836,7 +834,7 @@@ retry
                  ff_rtsp_send_cmd(s, "SET_PARAMETER", rt->control_uri,
                                   cmd, reply, NULL);
                  if (reply->status_code != RTSP_STATUS_OK)
 -                    return AVERROR_INVALIDDATA;
 +                    return ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA);
                  rt->need_subscription = 1;
              }
          }
              ff_rtsp_send_cmd(s, "SET_PARAMETER", rt->control_uri,
                               cmd, reply, NULL);
              if (reply->status_code != RTSP_STATUS_OK)
 -                return AVERROR_INVALIDDATA;
 +                return ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA);
              rt->need_subscription = 0;
  
              if (rt->state == RTSP_STATE_STREAMING)
@@@ -931,7 -932,6 +930,7 @@@ static int rtsp_read_seek(AVFormatConte
                            int64_t timestamp, int flags)
  {
      RTSPState *rt = s->priv_data;
 +    int ret;
  
      rt->seek_timestamp = av_rescale_q(timestamp,
                                        s->streams[stream_index]->time_base,
      case RTSP_STATE_IDLE:
          break;
      case RTSP_STATE_STREAMING:
 -        if (rtsp_read_pause(s) != 0)
 -            return -1;
 +        if ((ret = rtsp_read_pause(s)) != 0)
 +            return ret;
          rt->state = RTSP_STATE_SEEKING;
 -        if (rtsp_read_play(s) != 0)
 -            return -1;
 +        if ((ret = rtsp_read_play(s)) != 0)
 +            return ret;
          break;
      case RTSP_STATE_PAUSED:
          rt->state = RTSP_STATE_IDLE;
diff --combined libavformat/smush.c
@@@ -2,20 -2,20 +2,20 @@@
   * LucasArts Smush demuxer
   * Copyright (c) 2006 Cyril Zorin
   *
 - * 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
   */
  
@@@ -102,7 -102,7 +102,7 @@@ static int smush_read_header(AVFormatCo
          while (!got_audio && ((read + 8) < size)) {
              uint32_t sig, chunk_size;
  
 -            if (pb->eof_reached)
 +            if (avio_feof(pb))
                  return AVERROR_EOF;
  
              sig        = avio_rb32(pb);
                  break;
              default:
                  return AVERROR_INVALIDDATA;
-                 break;
              }
          }
  
      vst->codecpar->height     = height;
  
      if (!smush->version) {
 -        av_free(vst->codecpar->extradata);
 -        vst->codecpar->extradata_size = 1024 + 2;
 -        vst->codecpar->extradata = av_malloc(vst->codecpar->extradata_size +
 -                                             AV_INPUT_BUFFER_PADDING_SIZE);
 -        if (!vst->codecpar->extradata)
 +        if (ff_alloc_extradata(vst->codecpar, 1024 + 2))
              return AVERROR(ENOMEM);
  
          AV_WL16(vst->codecpar->extradata, subversion);
@@@ -196,7 -199,7 +195,7 @@@ static int smush_read_packet(AVFormatCo
      while (!done) {
          uint32_t sig, size;
  
 -        if (pb->eof_reached)
 +        if (avio_feof(pb))
              return AVERROR_EOF;
  
          sig  = avio_rb32(pb);
diff --combined libavutil/opt.c
@@@ -2,20 -2,20 +2,20 @@@
   * AVOptions
   * Copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
   *
 - * 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
   */
  
   * @author Michael Niedermayer <michaelni@gmx.at>
   */
  
 -#include "avstring.h"
  #include "avutil.h"
 +#include "avassert.h"
 +#include "avstring.h"
 +#include "channel_layout.h"
  #include "common.h"
  #include "dict.h"
  #include "eval.h"
  #include "log.h"
 +#include "parseutils.h"
 +#include "pixdesc.h"
  #include "mathematics.h"
  #include "opt.h"
 +#include "samplefmt.h"
 +#include "bprint.h"
 +
 +#include <float.h>
  
  const AVOption *av_opt_next(const void *obj, const AVOption *last)
  {
 -    AVClass *class = *(AVClass **)obj;
 -    if (!last && class->option && class->option[0].name)
 +    const AVClass *class;
 +    if (!obj)
 +        return NULL;
 +    class = *(const AVClass**)obj;
 +    if (!last && class && class->option && class->option[0].name)
          return class->option;
      if (last && last[1].name)
          return ++last;
@@@ -59,22 -48,12 +59,22 @@@ static int read_number(const AVOption *
  {
      switch (o->type) {
      case AV_OPT_TYPE_FLAGS:
 -        *intnum = *(unsigned int *)dst;
 +        *intnum = *(unsigned int*)dst;
 +        return 0;
 +    case AV_OPT_TYPE_PIXEL_FMT:
 +        *intnum = *(enum AVPixelFormat *)dst;
          return 0;
 +    case AV_OPT_TYPE_SAMPLE_FMT:
 +        *intnum = *(enum AVSampleFormat *)dst;
 +        return 0;
 +    case AV_OPT_TYPE_BOOL:
      case AV_OPT_TYPE_INT:
          *intnum = *(int *)dst;
          return 0;
 +    case AV_OPT_TYPE_CHANNEL_LAYOUT:
 +    case AV_OPT_TYPE_DURATION:
      case AV_OPT_TYPE_INT64:
 +    case AV_OPT_TYPE_UINT64:
          *intnum = *(int64_t *)dst;
          return 0;
      case AV_OPT_TYPE_FLOAT:
@@@ -87,9 -66,6 +87,9 @@@
          *intnum = ((AVRational *)dst)->num;
          *den    = ((AVRational *)dst)->den;
          return 0;
 +    case AV_OPT_TYPE_CONST:
 +        *num = o->default_val.dbl;
 +        return 0;
      }
      return AVERROR(EINVAL);
  }
  static int write_number(void *obj, const AVOption *o, void *dst, double num, int den, int64_t intnum)
  {
      if (o->type != AV_OPT_TYPE_FLAGS &&
 -        (o->max * den < num * intnum || o->min * den > num * intnum)) {
 -        av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range\n",
 -               num * intnum / den, o->name);
 +        (!den || o->max * den < num * intnum || o->min * den > num * intnum)) {
 +        num = den ? num * intnum / den : (num * intnum ? INFINITY : NAN);
 +        av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range [%g - %g]\n",
 +               num, o->name, o->min, o->max);
          return AVERROR(ERANGE);
      }
 +    if (o->type == AV_OPT_TYPE_FLAGS) {
 +        double d = num*intnum/den;
 +        if (d < -1.5 || d > 0xFFFFFFFF+0.5 || (llrint(d*256) & 255)) {
 +            av_log(obj, AV_LOG_ERROR,
 +                   "Value %f for parameter '%s' is not a valid set of 32bit integer flags\n",
 +                   num*intnum/den, o->name);
 +            return AVERROR(ERANGE);
 +        }
 +    }
  
      switch (o->type) {
 +    case AV_OPT_TYPE_PIXEL_FMT:
 +        *(enum AVPixelFormat *)dst = llrint(num / den) * intnum;
 +        break;
 +    case AV_OPT_TYPE_SAMPLE_FMT:
 +        *(enum AVSampleFormat *)dst = llrint(num / den) * intnum;
 +        break;
 +    case AV_OPT_TYPE_BOOL:
      case AV_OPT_TYPE_FLAGS:
      case AV_OPT_TYPE_INT:
          *(int *)dst = llrint(num / den) * intnum;
          break;
 -    case AV_OPT_TYPE_INT64:
 -        *(int64_t *)dst = llrint(num / den) * intnum;
 -        break;
 +    case AV_OPT_TYPE_DURATION:
 +    case AV_OPT_TYPE_CHANNEL_LAYOUT:
 +    case AV_OPT_TYPE_INT64:{
 +        double d = num / den;
 +        if (intnum == 1 && d == (double)INT64_MAX) {
 +            *(int64_t *)dst = INT64_MAX;
 +        } else
 +            *(int64_t *)dst = llrint(d) * intnum;
 +        break;}
 +    case AV_OPT_TYPE_UINT64:{
 +        double d = num / den;
 +        // We must special case uint64_t here as llrint() does not support values
 +        // outside the int64_t range and there is no portable function which does
 +        // "INT64_MAX + 1ULL" is used as it is representable exactly as IEEE double
 +        // while INT64_MAX is not
 +        if (intnum == 1 && d == (double)UINT64_MAX) {
 +            *(uint64_t *)dst = UINT64_MAX;
 +        } else if (d > INT64_MAX + 1ULL) {
 +            *(uint64_t *)dst = (llrint(d - (INT64_MAX + 1ULL)) + (INT64_MAX + 1ULL))*intnum;
 +        } else {
 +            *(uint64_t *)dst = llrint(d) * intnum;
 +        }
 +        break;}
      case AV_OPT_TYPE_FLOAT:
          *(float *)dst = num * intnum / den;
          break;
      case AV_OPT_TYPE_DOUBLE:
 -        *(double *)dst = num * intnum / den;
 +        *(double    *)dst = num * intnum / den;
          break;
      case AV_OPT_TYPE_RATIONAL:
 +    case AV_OPT_TYPE_VIDEO_RATE:
          if ((int) num == num)
              *(AVRational *)dst = (AVRational) { num *intnum, den };
          else
      return 0;
  }
  
 -static const double const_values[] = {
 -    M_PI,
 -    M_E,
 -    FF_QP2LAMBDA,
 -    0
 -};
 -
 -static const char *const const_names[] = {
 -    "PI",
 -    "E",
 -    "QP2LAMBDA",
 -    0
 -};
 -
 -static int hexchar2int(char c)
 -{
 +static int hexchar2int(char c) {
      if (c >= '0' && c <= '9')
          return c - '0';
      if (c >= 'a' && c <= 'f')
@@@ -181,14 -134,11 +181,14 @@@ static int set_string_binary(void *obj
  {
      int *lendst = (int *)(dst + 1);
      uint8_t *bin, *ptr;
 -    int len = strlen(val);
 +    int len;
  
      av_freep(dst);
      *lendst = 0;
  
 +    if (!val || !(len = strlen(val)))
 +        return 0;
 +
      if (len & 1)
          return AVERROR(EINVAL);
      len /= 2;
@@@ -219,7 -169,6 +219,7 @@@ static int set_string(void *obj, const 
  }
  
  #define DEFAULT_NUMVAL(opt) ((opt->type == AV_OPT_TYPE_INT64 || \
 +                              opt->type == AV_OPT_TYPE_UINT64 || \
                                opt->type == AV_OPT_TYPE_CONST || \
                                opt->type == AV_OPT_TYPE_FLAGS || \
                                opt->type == AV_OPT_TYPE_INT)     \
  
  static int set_string_number(void *obj, void *target_obj, const AVOption *o, const char *val, void *dst)
  {
 -    int ret = 0, notfirst = 0;
 +    int ret = 0;
 +    int num, den;
 +    char c;
 +
 +    if (sscanf(val, "%d%*1[:/]%d%c", &num, &den, &c) == 2) {
 +        if ((ret = write_number(obj, o, dst, 1, den, num)) >= 0)
 +            return ret;
 +        ret = 0;
 +    }
 +
      for (;;) {
 -        int i, den = 1;
 +        int i = 0;
          char buf[256];
          int cmd = 0;
 -        double d, num = 1;
 +        double d;
          int64_t intnum = 1;
  
 -        i = 0;
 -        if (*val == '+' || *val == '-') {
 -            if (o->type == AV_OPT_TYPE_FLAGS)
 +        if (o->type == AV_OPT_TYPE_FLAGS) {
 +            if (*val == '+' || *val == '-')
                  cmd = *(val++);
 -            else if (!notfirst)
 -                buf[i++] = *val;
 +            for (; i < sizeof(buf) - 1 && val[i] && val[i] != '+' && val[i] != '-'; i++)
 +                buf[i] = val[i];
 +            buf[i] = 0;
          }
  
 -        for (; i < sizeof(buf) - 1 && val[i] && val[i] != '+' && val[i] != '-'; i++)
 -            buf[i] = val[i];
 -        buf[i] = 0;
 -
          {
 -            const AVOption *o_named = av_opt_find(target_obj, buf, o->unit, 0, 0);
 +            const AVOption *o_named = av_opt_find(target_obj, i ? buf : val, o->unit, 0, 0);
 +            int res;
 +            int ci = 0;
 +            double const_values[64];
 +            const char * const_names[64];
              if (o_named && o_named->type == AV_OPT_TYPE_CONST)
                  d = DEFAULT_NUMVAL(o_named);
 -            else if (!strcmp(buf, "default"))
 -                d = DEFAULT_NUMVAL(o);
 -            else if (!strcmp(buf, "max"))
 -                d = o->max;
 -            else if (!strcmp(buf, "min"))
 -                d = o->min;
 -            else if (!strcmp(buf, "none"))
 -                d = 0;
 -            else if (!strcmp(buf, "all"))
 -                d = ~0;
              else {
 -                int res = av_expr_parse_and_eval(&d, buf, const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, obj);
 +                if (o->unit) {
 +                    for (o_named = NULL; o_named = av_opt_next(target_obj, o_named); ) {
 +                        if (o_named->type == AV_OPT_TYPE_CONST &&
 +                            o_named->unit &&
 +                            !strcmp(o_named->unit, o->unit)) {
 +                            if (ci + 6 >= FF_ARRAY_ELEMS(const_values)) {
 +                                av_log(obj, AV_LOG_ERROR, "const_values array too small for %s\n", o->unit);
 +                                return AVERROR_PATCHWELCOME;
 +                            }
 +                            const_names [ci  ] = o_named->name;
 +                            const_values[ci++] = DEFAULT_NUMVAL(o_named);
 +                        }
 +                    }
 +                }
 +                const_names [ci  ] = "default";
 +                const_values[ci++] = DEFAULT_NUMVAL(o);
 +                const_names [ci  ] = "max";
 +                const_values[ci++] = o->max;
 +                const_names [ci  ] = "min";
 +                const_values[ci++] = o->min;
 +                const_names [ci  ] = "none";
 +                const_values[ci++] = 0;
 +                const_names [ci  ] = "all";
 +                const_values[ci++] = ~0;
 +                const_names [ci] = NULL;
 +                const_values[ci] = 0;
 +
 +                res = av_expr_parse_and_eval(&d, i ? buf : val, const_names,
 +                                            const_values, NULL, NULL, NULL, NULL, NULL, 0, obj);
                  if (res < 0) {
                      av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\"\n", val);
                      return res;
              if (cmd == '+')
                  d = intnum | (int64_t)d;
              else if (cmd == '-')
 -                d = intnum & ~(int64_t)d;
 -        } else {
 -            read_number(o, dst, &num, &den, &intnum);
 -            if (cmd == '+')
 -                d = notfirst * num * intnum / den + d;
 -            else if (cmd == '-')
 -                d = notfirst * num * intnum / den - d;
 +                d = intnum &~(int64_t)d;
          }
  
          if ((ret = write_number(obj, o, dst, d, 1, 1)) < 0)
              return ret;
          val += i;
 -        if (!*val)
 +        if (!i || !*val)
              return 0;
 -        notfirst = 1;
      }
-     return 0;
  }
  
 +static int set_string_image_size(void *obj, const AVOption *o, const char *val, int *dst)
 +{
 +    int ret;
 +
 +    if (!val || !strcmp(val, "none")) {
 +        dst[0] =
 +        dst[1] = 0;
 +        return 0;
 +    }
 +    ret = av_parse_video_size(dst, dst + 1, val);
 +    if (ret < 0)
 +        av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as image size\n", val);
 +    return ret;
 +}
 +
 +static int set_string_video_rate(void *obj, const AVOption *o, const char *val, AVRational *dst)
 +{
 +    int ret;
 +    if (!val) {
 +        ret = AVERROR(EINVAL);
 +    } else {
 +        ret = av_parse_video_rate(dst, val);
 +    }
 +    if (ret < 0)
 +        av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as video rate\n", val);
 +    return ret;
 +}
 +
 +static int set_string_color(void *obj, const AVOption *o, const char *val, uint8_t *dst)
 +{
 +    int ret;
 +
 +    if (!val) {
 +        return 0;
 +    } else {
 +        ret = av_parse_color(dst, val, -1, obj);
 +        if (ret < 0)
 +            av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as color\n", val);
 +        return ret;
 +    }
 +    return 0;
 +}
 +
 +static const char *get_bool_name(int val)
 +{
 +    if (val < 0)
 +        return "auto";
 +    return val ? "true" : "false";
 +}
 +
 +static int set_string_bool(void *obj, const AVOption *o, const char *val, int *dst)
 +{
 +    int n;
 +
 +    if (!val)
 +        return 0;
 +
 +    if (!strcmp(val, "auto")) {
 +        n = -1;
 +    } else if (av_match_name(val, "true,y,yes,enable,enabled,on")) {
 +        n = 1;
 +    } else if (av_match_name(val, "false,n,no,disable,disabled,off")) {
 +        n = 0;
 +    } else {
 +        char *end = NULL;
 +        n = strtol(val, &end, 10);
 +        if (val + strlen(val) != end)
 +            goto fail;
 +    }
 +
 +    if (n < o->min || n > o->max)
 +        goto fail;
 +
 +    *dst = n;
 +    return 0;
 +
 +fail:
 +    av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as boolean\n", val);
 +    return AVERROR(EINVAL);
 +}
 +
 +static int set_string_fmt(void *obj, const AVOption *o, const char *val, uint8_t *dst,
 +                          int fmt_nb, int ((*get_fmt)(const char *)), const char *desc)
 +{
 +    int fmt, min, max;
 +
 +    if (!val || !strcmp(val, "none")) {
 +        fmt = -1;
 +    } else {
 +        fmt = get_fmt(val);
 +        if (fmt == -1) {
 +            char *tail;
 +            fmt = strtol(val, &tail, 0);
 +            if (*tail || (unsigned)fmt >= fmt_nb) {
 +                av_log(obj, AV_LOG_ERROR,
 +                       "Unable to parse option value \"%s\" as %s\n", val, desc);
 +                return AVERROR(EINVAL);
 +            }
 +        }
 +    }
 +
 +    min = FFMAX(o->min, -1);
 +    max = FFMIN(o->max, fmt_nb-1);
 +
 +    // hack for compatibility with old ffmpeg
 +    if(min == 0 && max == 0) {
 +        min = -1;
 +        max = fmt_nb-1;
 +    }
 +
 +    if (fmt < min || fmt > max) {
 +        av_log(obj, AV_LOG_ERROR,
 +               "Value %d for parameter '%s' out of %s format range [%d - %d]\n",
 +               fmt, o->name, desc, min, max);
 +        return AVERROR(ERANGE);
 +    }
 +
 +    *(int *)dst = fmt;
 +    return 0;
 +}
 +
 +static int set_string_pixel_fmt(void *obj, const AVOption *o, const char *val, uint8_t *dst)
 +{
 +    return set_string_fmt(obj, o, val, dst,
 +                          AV_PIX_FMT_NB, av_get_pix_fmt, "pixel format");
 +}
 +
 +static int set_string_sample_fmt(void *obj, const AVOption *o, const char *val, uint8_t *dst)
 +{
 +    return set_string_fmt(obj, o, val, dst,
 +                          AV_SAMPLE_FMT_NB, av_get_sample_fmt, "sample format");
 +}
 +
  int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
  {
 +    int ret = 0;
      void *dst, *target_obj;
      const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
      if (!o || !target_obj)
          return AVERROR_OPTION_NOT_FOUND;
 -    if (!val || o->flags & AV_OPT_FLAG_READONLY)
 +    if (!val && (o->type != AV_OPT_TYPE_STRING &&
 +                 o->type != AV_OPT_TYPE_PIXEL_FMT && o->type != AV_OPT_TYPE_SAMPLE_FMT &&
 +                 o->type != AV_OPT_TYPE_IMAGE_SIZE && o->type != AV_OPT_TYPE_VIDEO_RATE &&
 +                 o->type != AV_OPT_TYPE_DURATION && o->type != AV_OPT_TYPE_COLOR &&
 +                 o->type != AV_OPT_TYPE_CHANNEL_LAYOUT && o->type != AV_OPT_TYPE_BOOL))
 +        return AVERROR(EINVAL);
 +
 +    if (o->flags & AV_OPT_FLAG_READONLY)
          return AVERROR(EINVAL);
  
      dst = ((uint8_t *)target_obj) + o->offset;
      switch (o->type) {
 +    case AV_OPT_TYPE_BOOL:
 +        return set_string_bool(obj, o, val, dst);
      case AV_OPT_TYPE_STRING:
          return set_string(obj, o, val, dst);
      case AV_OPT_TYPE_BINARY:
      case AV_OPT_TYPE_FLAGS:
      case AV_OPT_TYPE_INT:
      case AV_OPT_TYPE_INT64:
 +    case AV_OPT_TYPE_UINT64:
      case AV_OPT_TYPE_FLOAT:
      case AV_OPT_TYPE_DOUBLE:
      case AV_OPT_TYPE_RATIONAL:
          return set_string_number(obj, target_obj, o, val, dst);
 +    case AV_OPT_TYPE_IMAGE_SIZE:
 +        return set_string_image_size(obj, o, val, dst);
 +    case AV_OPT_TYPE_VIDEO_RATE: {
 +        AVRational tmp;
 +        ret = set_string_video_rate(obj, o, val, &tmp);
 +        if (ret < 0)
 +            return ret;
 +        return write_number(obj, o, dst, 1, tmp.den, tmp.num);
 +    }
 +    case AV_OPT_TYPE_PIXEL_FMT:
 +        return set_string_pixel_fmt(obj, o, val, dst);
 +    case AV_OPT_TYPE_SAMPLE_FMT:
 +        return set_string_sample_fmt(obj, o, val, dst);
 +    case AV_OPT_TYPE_DURATION:
 +        if (!val) {
 +            *(int64_t *)dst = 0;
 +            return 0;
 +        } else {
 +            if ((ret = av_parse_time(dst, val, 1)) < 0)
 +                av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as duration\n", val);
 +            return ret;
 +        }
 +        break;
 +    case AV_OPT_TYPE_COLOR:
 +        return set_string_color(obj, o, val, dst);
 +    case AV_OPT_TYPE_CHANNEL_LAYOUT:
 +        if (!val || !strcmp(val, "none")) {
 +            *(int64_t *)dst = 0;
 +        } else {
 +            int64_t cl = av_get_channel_layout(val);
 +            if (!cl) {
 +                av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as channel layout\n", val);
 +                ret = AVERROR(EINVAL);
 +            }
 +            *(int64_t *)dst = cl;
 +            return ret;
 +        }
 +        break;
      }
  
      av_log(obj, AV_LOG_ERROR, "Invalid option type.\n");
@@@ -586,8 -331,8 +584,8 @@@ int av_opt_set_bin(void *obj, const cha
      if (o->type != AV_OPT_TYPE_BINARY || o->flags & AV_OPT_FLAG_READONLY)
          return AVERROR(EINVAL);
  
 -    ptr = av_malloc(len);
 -    if (!ptr)
 +    ptr = len ? av_malloc(len) : NULL;
 +    if (len && !ptr)
          return AVERROR(ENOMEM);
  
      dst    = (uint8_t **)(((uint8_t *)target_obj) + o->offset);
      av_free(*dst);
      *dst    = ptr;
      *lendst = len;
 -    memcpy(ptr, val, len);
 +    if (len)
 +        memcpy(ptr, val, len);
  
      return 0;
  }
  
 +int av_opt_set_image_size(void *obj, const char *name, int w, int h, int search_flags)
 +{
 +    void *target_obj;
 +    const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
 +
 +    if (!o || !target_obj)
 +        return AVERROR_OPTION_NOT_FOUND;
 +    if (o->type != AV_OPT_TYPE_IMAGE_SIZE) {
 +        av_log(obj, AV_LOG_ERROR,
 +               "The value set by option '%s' is not an image size.\n", o->name);
 +        return AVERROR(EINVAL);
 +    }
 +    if (w<0 || h<0) {
 +        av_log(obj, AV_LOG_ERROR,
 +               "Invalid negative size value %dx%d for size '%s'\n", w, h, o->name);
 +        return AVERROR(EINVAL);
 +    }
 +    *(int *)(((uint8_t *)target_obj)             + o->offset) = w;
 +    *(int *)(((uint8_t *)target_obj+sizeof(int)) + o->offset) = h;
 +    return 0;
 +}
 +
 +int av_opt_set_video_rate(void *obj, const char *name, AVRational val, int search_flags)
 +{
 +    void *target_obj;
 +    const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
 +
 +    if (!o || !target_obj)
 +        return AVERROR_OPTION_NOT_FOUND;
 +    if (o->type != AV_OPT_TYPE_VIDEO_RATE) {
 +        av_log(obj, AV_LOG_ERROR,
 +               "The value set by option '%s' is not a video rate.\n", o->name);
 +        return AVERROR(EINVAL);
 +    }
 +    if (val.num <= 0 || val.den <= 0)
 +        return AVERROR(EINVAL);
 +    return set_number(obj, name, val.num, val.den, 1, search_flags);
 +}
 +
 +static int set_format(void *obj, const char *name, int fmt, int search_flags,
 +                      enum AVOptionType type, const char *desc, int nb_fmts)
 +{
 +    void *target_obj;
 +    const AVOption *o = av_opt_find2(obj, name, NULL, 0,
 +                                     search_flags, &target_obj);
 +    int min, max;
 +
 +    if (!o || !target_obj)
 +        return AVERROR_OPTION_NOT_FOUND;
 +    if (o->type != type) {
 +        av_log(obj, AV_LOG_ERROR,
 +               "The value set by option '%s' is not a %s format", name, desc);
 +        return AVERROR(EINVAL);
 +    }
 +
 +    min = FFMAX(o->min, -1);
 +    max = FFMIN(o->max, nb_fmts-1);
 +
 +    if (fmt < min || fmt > max) {
 +        av_log(obj, AV_LOG_ERROR,
 +               "Value %d for parameter '%s' out of %s format range [%d - %d]\n",
 +               fmt, name, desc, min, max);
 +        return AVERROR(ERANGE);
 +    }
 +    *(int *)(((uint8_t *)target_obj) + o->offset) = fmt;
 +    return 0;
 +}
 +
 +int av_opt_set_pixel_fmt(void *obj, const char *name, enum AVPixelFormat fmt, int search_flags)
 +{
 +    return set_format(obj, name, fmt, search_flags, AV_OPT_TYPE_PIXEL_FMT, "pixel", AV_PIX_FMT_NB);
 +}
 +
 +int av_opt_set_sample_fmt(void *obj, const char *name, enum AVSampleFormat fmt, int search_flags)
 +{
 +    return set_format(obj, name, fmt, search_flags, AV_OPT_TYPE_SAMPLE_FMT, "sample", AV_SAMPLE_FMT_NB);
 +}
 +
 +int av_opt_set_channel_layout(void *obj, const char *name, int64_t cl, int search_flags)
 +{
 +    void *target_obj;
 +    const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
 +
 +    if (!o || !target_obj)
 +        return AVERROR_OPTION_NOT_FOUND;
 +    if (o->type != AV_OPT_TYPE_CHANNEL_LAYOUT) {
 +        av_log(obj, AV_LOG_ERROR,
 +               "The value set by option '%s' is not a channel layout.\n", o->name);
 +        return AVERROR(EINVAL);
 +    }
 +    *(int64_t *)(((uint8_t *)target_obj) + o->offset) = cl;
 +    return 0;
 +}
 +
  int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val,
                          int search_flags)
  {
      return 0;
  }
  
 +static void format_duration(char *buf, size_t size, int64_t d)
 +{
 +    char *e;
 +
 +    av_assert0(size >= 25);
 +    if (d < 0 && d != INT64_MIN) {
 +        *(buf++) = '-';
 +        size--;
 +        d = -d;
 +    }
 +    if (d == INT64_MAX)
 +        snprintf(buf, size, "INT64_MAX");
 +    else if (d == INT64_MIN)
 +        snprintf(buf, size, "INT64_MIN");
 +    else if (d > (int64_t)3600*1000000)
 +        snprintf(buf, size, "%"PRId64":%02d:%02d.%06d", d / 3600000000,
 +                 (int)((d / 60000000) % 60),
 +                 (int)((d / 1000000) % 60),
 +                 (int)(d % 1000000));
 +    else if (d > 60*1000000)
 +        snprintf(buf, size, "%d:%02d.%06d",
 +                 (int)(d / 60000000),
 +                 (int)((d / 1000000) % 60),
 +                 (int)(d % 1000000));
 +    else
 +        snprintf(buf, size, "%d.%06d",
 +                 (int)(d / 1000000),
 +                 (int)(d % 1000000));
 +    e = buf + strlen(buf);
 +    while (e > buf && e[-1] == '0')
 +        *(--e) = 0;
 +    if (e > buf && e[-1] == '.')
 +        *(--e) = 0;
 +}
 +
  int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
  {
      void *dst, *target_obj;
      const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
      uint8_t *bin, buf[128];
      int len, i, ret;
 +    int64_t i64;
  
 -    if (!o || !target_obj)
 +    if (!o || !target_obj || (o->offset<=0 && o->type != AV_OPT_TYPE_CONST))
          return AVERROR_OPTION_NOT_FOUND;
  
      dst = (uint8_t *)target_obj + o->offset;
  
      buf[0] = 0;
      switch (o->type) {
 +    case AV_OPT_TYPE_BOOL:
 +        ret = snprintf(buf, sizeof(buf), "%s", (char *)av_x_if_null(get_bool_name(*(int *)dst), "invalid"));
 +        break;
      case AV_OPT_TYPE_FLAGS:
          ret = snprintf(buf, sizeof(buf), "0x%08X", *(int *)dst);
          break;
          ret = snprintf(buf, sizeof(buf), "%d", *(int *)dst);
          break;
      case AV_OPT_TYPE_INT64:
 -        ret = snprintf(buf, sizeof(buf), "%" PRId64, *(int64_t *)dst);
 +        ret = snprintf(buf, sizeof(buf), "%"PRId64, *(int64_t *)dst);
 +        break;
 +    case AV_OPT_TYPE_UINT64:
 +        ret = snprintf(buf, sizeof(buf), "%"PRIu64, *(uint64_t *)dst);
          break;
      case AV_OPT_TYPE_FLOAT:
          ret = snprintf(buf, sizeof(buf), "%f", *(float *)dst);
      case AV_OPT_TYPE_DOUBLE:
          ret = snprintf(buf, sizeof(buf), "%f", *(double *)dst);
          break;
 +    case AV_OPT_TYPE_VIDEO_RATE:
      case AV_OPT_TYPE_RATIONAL:
 -        ret = snprintf(buf, sizeof(buf), "%d/%d", ((AVRational *)dst)->num,
 -                       ((AVRational *)dst)->den);
 +        ret = snprintf(buf, sizeof(buf), "%d/%d", ((AVRational *)dst)->num, ((AVRational *)dst)->den);
 +        break;
 +    case AV_OPT_TYPE_CONST:
 +        ret = snprintf(buf, sizeof(buf), "%f", o->default_val.dbl);
          break;
      case AV_OPT_TYPE_STRING:
 -        if (*(uint8_t **)dst)
 +        if (*(uint8_t **)dst) {
              *out_val = av_strdup(*(uint8_t **)dst);
 -        else
 +        } else if (search_flags & AV_OPT_ALLOW_NULL) {
 +            *out_val = NULL;
 +            return 0;
 +        } else {
              *out_val = av_strdup("");
 +        }
          return *out_val ? 0 : AVERROR(ENOMEM);
      case AV_OPT_TYPE_BINARY:
 +        if (!*(uint8_t **)dst && (search_flags & AV_OPT_ALLOW_NULL)) {
 +            *out_val = NULL;
 +            return 0;
 +        }
          len = *(int *)(((uint8_t *)dst) + sizeof(uint8_t *));
          if ((uint64_t)len * 2 + 1 > INT_MAX)
              return AVERROR(EINVAL);
          if (!(*out_val = av_malloc(len * 2 + 1)))
              return AVERROR(ENOMEM);
 +        if (!len) {
 +            *out_val[0] = '\0';
 +            return 0;
 +        }
          bin = *(uint8_t **)dst;
          for (i = 0; i < len; i++)
              snprintf(*out_val + i * 2, 3, "%02X", bin[i]);
          return 0;
 +    case AV_OPT_TYPE_IMAGE_SIZE:
 +        ret = snprintf(buf, sizeof(buf), "%dx%d", ((int *)dst)[0], ((int *)dst)[1]);
 +        break;
 +    case AV_OPT_TYPE_PIXEL_FMT:
 +        ret = snprintf(buf, sizeof(buf), "%s", (char *)av_x_if_null(av_get_pix_fmt_name(*(enum AVPixelFormat *)dst), "none"));
 +        break;
 +    case AV_OPT_TYPE_SAMPLE_FMT:
 +        ret = snprintf(buf, sizeof(buf), "%s", (char *)av_x_if_null(av_get_sample_fmt_name(*(enum AVSampleFormat *)dst), "none"));
 +        break;
 +    case AV_OPT_TYPE_DURATION:
 +        i64 = *(int64_t *)dst;
 +        format_duration(buf, sizeof(buf), i64);
 +        ret = strlen(buf); // no overflow possible, checked by an assert
 +        break;
 +    case AV_OPT_TYPE_COLOR:
 +        ret = snprintf(buf, sizeof(buf), "0x%02x%02x%02x%02x",
 +                       (int)((uint8_t *)dst)[0], (int)((uint8_t *)dst)[1],
 +                       (int)((uint8_t *)dst)[2], (int)((uint8_t *)dst)[3]);
 +        break;
 +    case AV_OPT_TYPE_CHANNEL_LAYOUT:
 +        i64 = *(int64_t *)dst;
 +        ret = snprintf(buf, sizeof(buf), "0x%"PRIx64, i64);
 +        break;
      default:
          return AVERROR(EINVAL);
      }
      return *out_val ? 0 : AVERROR(ENOMEM);
  }
  
 -static int get_number(void *obj, const char *name, double *num, int *den, int64_t *intnum,
 +static int get_number(void *obj, const char *name, const AVOption **o_out, double *num, int *den, int64_t *intnum,
                        int search_flags)
  {
      void *dst, *target_obj;
  
      dst = ((uint8_t *)target_obj) + o->offset;
  
 +    if (o_out) *o_out= o;
 +
      return read_number(o, dst, num, den, intnum);
  
  error:
@@@ -880,7 -448,7 +878,7 @@@ int av_opt_get_int(void *obj, const cha
      double num = 1;
      int ret, den = 1;
  
 -    if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0)
 +    if ((ret = get_number(obj, name, NULL, &num, &den, &intnum, search_flags)) < 0)
          return ret;
      *out_val = num * intnum / den;
      return 0;
@@@ -892,7 -460,7 +890,7 @@@ int av_opt_get_double(void *obj, const 
      double num = 1;
      int ret, den = 1;
  
 -    if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0)
 +    if ((ret = get_number(obj, name, NULL, &num, &den, &intnum, search_flags)) < 0)
          return ret;
      *out_val = num * intnum / den;
      return 0;
@@@ -904,41 -472,7 +902,41 @@@ int av_opt_get_q(void *obj, const char 
      double num = 1;
      int ret, den = 1;
  
 -    if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0)
 +    if ((ret = get_number(obj, name, NULL, &num, &den, &intnum, search_flags)) < 0)
 +        return ret;
 +
 +    if (num == 1.0 && (int)intnum == intnum)
 +        *out_val = (AVRational){intnum, den};
 +    else
 +        *out_val = av_d2q(num*intnum/den, 1<<24);
 +    return 0;
 +}
 +
 +int av_opt_get_image_size(void *obj, const char *name, int search_flags, int *w_out, int *h_out)
 +{
 +    void *dst, *target_obj;
 +    const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
 +    if (!o || !target_obj)
 +        return AVERROR_OPTION_NOT_FOUND;
 +    if (o->type != AV_OPT_TYPE_IMAGE_SIZE) {
 +        av_log(obj, AV_LOG_ERROR,
 +               "The value for option '%s' is not an image size.\n", name);
 +        return AVERROR(EINVAL);
 +    }
 +
 +    dst = ((uint8_t*)target_obj) + o->offset;
 +    if (w_out) *w_out = *(int *)dst;
 +    if (h_out) *h_out = *((int *)dst+1);
 +    return 0;
 +}
 +
 +int av_opt_get_video_rate(void *obj, const char *name, int search_flags, AVRational *out_val)
 +{
 +    int64_t intnum = 1;
 +    double     num = 1;
 +    int   ret, den = 1;
 +
 +    if ((ret = get_number(obj, name, NULL, &num, &den, &intnum, search_flags)) < 0)
          return ret;
  
      if (num == 1.0 && (int)intnum == intnum)
      return 0;
  }
  
 +static int get_format(void *obj, const char *name, int search_flags, int *out_fmt,
 +                      enum AVOptionType type, const char *desc)
 +{
 +    void *dst, *target_obj;
 +    const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
 +    if (!o || !target_obj)
 +        return AVERROR_OPTION_NOT_FOUND;
 +    if (o->type != type) {
 +        av_log(obj, AV_LOG_ERROR,
 +               "The value for option '%s' is not a %s format.\n", desc, name);
 +        return AVERROR(EINVAL);
 +    }
 +
 +    dst = ((uint8_t*)target_obj) + o->offset;
 +    *out_fmt = *(int *)dst;
 +    return 0;
 +}
 +
 +int av_opt_get_pixel_fmt(void *obj, const char *name, int search_flags, enum AVPixelFormat *out_fmt)
 +{
 +    return get_format(obj, name, search_flags, out_fmt, AV_OPT_TYPE_PIXEL_FMT, "pixel");
 +}
 +
 +int av_opt_get_sample_fmt(void *obj, const char *name, int search_flags, enum AVSampleFormat *out_fmt)
 +{
 +    return get_format(obj, name, search_flags, out_fmt, AV_OPT_TYPE_SAMPLE_FMT, "sample");
 +}
 +
 +int av_opt_get_channel_layout(void *obj, const char *name, int search_flags, int64_t *cl)
 +{
 +    void *dst, *target_obj;
 +    const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
 +    if (!o || !target_obj)
 +        return AVERROR_OPTION_NOT_FOUND;
 +    if (o->type != AV_OPT_TYPE_CHANNEL_LAYOUT) {
 +        av_log(obj, AV_LOG_ERROR,
 +               "The value for option '%s' is not a channel layout.\n", name);
 +        return AVERROR(EINVAL);
 +    }
 +
 +    dst = ((uint8_t*)target_obj) + o->offset;
 +    *cl = *(int64_t *)dst;
 +    return 0;
 +}
 +
  int av_opt_get_dict_val(void *obj, const char *name, int search_flags, AVDictionary **out_val)
  {
      void *target_obj;
@@@ -1023,79 -512,10 +1021,79 @@@ int av_opt_flag_is_set(void *obj, cons
      return res & flag->default_val.i64;
  }
  
 +static void log_value(void *av_log_obj, int level, double d)
 +{
 +    if      (d == INT_MAX) {
 +        av_log(av_log_obj, level, "INT_MAX");
 +    } else if (d == INT_MIN) {
 +        av_log(av_log_obj, level, "INT_MIN");
 +    } else if (d == UINT32_MAX) {
 +        av_log(av_log_obj, level, "UINT32_MAX");
 +    } else if (d == (double)INT64_MAX) {
 +        av_log(av_log_obj, level, "I64_MAX");
 +    } else if (d == INT64_MIN) {
 +        av_log(av_log_obj, level, "I64_MIN");
 +    } else if (d == FLT_MAX) {
 +        av_log(av_log_obj, level, "FLT_MAX");
 +    } else if (d == FLT_MIN) {
 +        av_log(av_log_obj, level, "FLT_MIN");
 +    } else if (d == -FLT_MAX) {
 +        av_log(av_log_obj, level, "-FLT_MAX");
 +    } else if (d == -FLT_MIN) {
 +        av_log(av_log_obj, level, "-FLT_MIN");
 +    } else if (d == DBL_MAX) {
 +        av_log(av_log_obj, level, "DBL_MAX");
 +    } else if (d == DBL_MIN) {
 +        av_log(av_log_obj, level, "DBL_MIN");
 +    } else if (d == -DBL_MAX) {
 +        av_log(av_log_obj, level, "-DBL_MAX");
 +    } else if (d == -DBL_MIN) {
 +        av_log(av_log_obj, level, "-DBL_MIN");
 +    } else {
 +        av_log(av_log_obj, level, "%g", d);
 +    }
 +}
 +
 +static const char *get_opt_const_name(void *obj, const char *unit, int64_t value)
 +{
 +    const AVOption *opt = NULL;
 +
 +    if (!unit)
 +        return NULL;
 +    while ((opt = av_opt_next(obj, opt)))
 +        if (opt->type == AV_OPT_TYPE_CONST && !strcmp(opt->unit, unit) &&
 +            opt->default_val.i64 == value)
 +            return opt->name;
 +    return NULL;
 +}
 +
 +static char *get_opt_flags_string(void *obj, const char *unit, int64_t value)
 +{
 +    const AVOption *opt = NULL;
 +    char flags[512];
 +
 +    flags[0] = 0;
 +    if (!unit)
 +        return NULL;
 +    while ((opt = av_opt_next(obj, opt))) {
 +        if (opt->type == AV_OPT_TYPE_CONST && !strcmp(opt->unit, unit) &&
 +            opt->default_val.i64 & value) {
 +            if (flags[0])
 +                av_strlcatf(flags, sizeof(flags), "+");
 +            av_strlcatf(flags, sizeof(flags), "%s", opt->name);
 +        }
 +    }
 +    if (flags[0])
 +        return av_strdup(flags);
 +    return NULL;
 +}
 +
  static void opt_list(void *obj, void *av_log_obj, const char *unit,
                       int req_flags, int rej_flags)
  {
      const AVOption *opt = NULL;
 +    AVOptionRanges *r;
 +    int i;
  
      while ((opt = av_opt_next(obj, opt))) {
          if (!(opt->flags & req_flags) || (opt->flags & rej_flags))
          else if (unit && opt->type == AV_OPT_TYPE_CONST && strcmp(unit, opt->unit))
              continue;
          else if (unit && opt->type == AV_OPT_TYPE_CONST)
 -            av_log(av_log_obj, AV_LOG_INFO, "   %-15s ", opt->name);
 +            av_log(av_log_obj, AV_LOG_INFO, "     %-15s ", opt->name);
          else
 -            av_log(av_log_obj, AV_LOG_INFO, "-%-17s ", opt->name);
 +            av_log(av_log_obj, AV_LOG_INFO, "  %s%-17s ",
 +                   (opt->flags & AV_OPT_FLAG_FILTERING_PARAM) ? "" : "-",
 +                   opt->name);
  
          switch (opt->type) {
 -        case AV_OPT_TYPE_FLAGS:
 -            av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<flags>");
 -            break;
 -        case AV_OPT_TYPE_INT:
 -            av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<int>");
 -            break;
 -        case AV_OPT_TYPE_INT64:
 -            av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<int64>");
 -            break;
 -        case AV_OPT_TYPE_DOUBLE:
 -            av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<double>");
 -            break;
 -        case AV_OPT_TYPE_FLOAT:
 -            av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<float>");
 -            break;
 -        case AV_OPT_TYPE_STRING:
 -            av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<string>");
 -            break;
 -        case AV_OPT_TYPE_RATIONAL:
 -            av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<rational>");
 -            break;
 -        case AV_OPT_TYPE_BINARY:
 -            av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<binary>");
 -            break;
 -        case AV_OPT_TYPE_CONST:
 -        default:
 -            av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "");
 -            break;
 +            case AV_OPT_TYPE_FLAGS:
 +                av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<flags>");
 +                break;
 +            case AV_OPT_TYPE_INT:
 +                av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<int>");
 +                break;
 +            case AV_OPT_TYPE_INT64:
 +                av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<int64>");
 +                break;
 +            case AV_OPT_TYPE_UINT64:
 +                av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<uint64>");
 +                break;
 +            case AV_OPT_TYPE_DOUBLE:
 +                av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<double>");
 +                break;
 +            case AV_OPT_TYPE_FLOAT:
 +                av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<float>");
 +                break;
 +            case AV_OPT_TYPE_STRING:
 +                av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<string>");
 +                break;
 +            case AV_OPT_TYPE_RATIONAL:
 +                av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<rational>");
 +                break;
 +            case AV_OPT_TYPE_BINARY:
 +                av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<binary>");
 +                break;
 +            case AV_OPT_TYPE_IMAGE_SIZE:
 +                av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<image_size>");
 +                break;
 +            case AV_OPT_TYPE_VIDEO_RATE:
 +                av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<video_rate>");
 +                break;
 +            case AV_OPT_TYPE_PIXEL_FMT:
 +                av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<pix_fmt>");
 +                break;
 +            case AV_OPT_TYPE_SAMPLE_FMT:
 +                av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<sample_fmt>");
 +                break;
 +            case AV_OPT_TYPE_DURATION:
 +                av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<duration>");
 +                break;
 +            case AV_OPT_TYPE_COLOR:
 +                av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<color>");
 +                break;
 +            case AV_OPT_TYPE_CHANNEL_LAYOUT:
 +                av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<channel_layout>");
 +                break;
 +            case AV_OPT_TYPE_BOOL:
 +                av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<boolean>");
 +                break;
 +            case AV_OPT_TYPE_CONST:
 +            default:
 +                av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "");
 +                break;
          }
          av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_ENCODING_PARAM) ? 'E' : '.');
          av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_DECODING_PARAM) ? 'D' : '.');
 -        av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_VIDEO_PARAM)    ? 'V' : '.');
 -        av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_AUDIO_PARAM)    ? 'A' : '.');
 +        av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_FILTERING_PARAM)? 'F' : '.');
 +        av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_VIDEO_PARAM   ) ? 'V' : '.');
 +        av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_AUDIO_PARAM   ) ? 'A' : '.');
          av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_SUBTITLE_PARAM) ? 'S' : '.');
          av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_EXPORT)         ? 'X' : '.');
          av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_READONLY)       ? 'R' : '.');
  
          if (opt->help)
              av_log(av_log_obj, AV_LOG_INFO, " %s", opt->help);
 +
 +        if (av_opt_query_ranges(&r, obj, opt->name, AV_OPT_SEARCH_FAKE_OBJ) >= 0) {
 +            switch (opt->type) {
 +            case AV_OPT_TYPE_INT:
 +            case AV_OPT_TYPE_INT64:
 +            case AV_OPT_TYPE_UINT64:
 +            case AV_OPT_TYPE_DOUBLE:
 +            case AV_OPT_TYPE_FLOAT:
 +            case AV_OPT_TYPE_RATIONAL:
 +                for (i = 0; i < r->nb_ranges; i++) {
 +                    av_log(av_log_obj, AV_LOG_INFO, " (from ");
 +                    log_value(av_log_obj, AV_LOG_INFO, r->range[i]->value_min);
 +                    av_log(av_log_obj, AV_LOG_INFO, " to ");
 +                    log_value(av_log_obj, AV_LOG_INFO, r->range[i]->value_max);
 +                    av_log(av_log_obj, AV_LOG_INFO, ")");
 +                }
 +                break;
 +            }
 +            av_opt_freep_ranges(&r);
 +        }
 +
 +        if (opt->type != AV_OPT_TYPE_CONST  &&
 +            opt->type != AV_OPT_TYPE_BINARY &&
 +                !((opt->type == AV_OPT_TYPE_COLOR      ||
 +                   opt->type == AV_OPT_TYPE_IMAGE_SIZE ||
 +                   opt->type == AV_OPT_TYPE_STRING     ||
 +                   opt->type == AV_OPT_TYPE_VIDEO_RATE) &&
 +                  !opt->default_val.str)) {
 +            av_log(av_log_obj, AV_LOG_INFO, " (default ");
 +            switch (opt->type) {
 +            case AV_OPT_TYPE_BOOL:
 +                av_log(av_log_obj, AV_LOG_INFO, "%s", (char *)av_x_if_null(get_bool_name(opt->default_val.i64), "invalid"));
 +                break;
 +            case AV_OPT_TYPE_FLAGS: {
 +                char *def_flags = get_opt_flags_string(obj, opt->unit, opt->default_val.i64);
 +                if (def_flags) {
 +                    av_log(av_log_obj, AV_LOG_INFO, "%s", def_flags);
 +                    av_freep(&def_flags);
 +                } else {
 +                    av_log(av_log_obj, AV_LOG_INFO, "%"PRIX64, opt->default_val.i64);
 +                }
 +                break;
 +            }
 +            case AV_OPT_TYPE_DURATION: {
 +                char buf[25];
 +                format_duration(buf, sizeof(buf), opt->default_val.i64);
 +                av_log(av_log_obj, AV_LOG_INFO, "%s", buf);
 +                break;
 +            }
 +            case AV_OPT_TYPE_INT:
 +            case AV_OPT_TYPE_UINT64:
 +            case AV_OPT_TYPE_INT64: {
 +                const char *def_const = get_opt_const_name(obj, opt->unit, opt->default_val.i64);
 +                if (def_const)
 +                    av_log(av_log_obj, AV_LOG_INFO, "%s", def_const);
 +                else
 +                    log_value(av_log_obj, AV_LOG_INFO, opt->default_val.i64);
 +                break;
 +            }
 +            case AV_OPT_TYPE_DOUBLE:
 +            case AV_OPT_TYPE_FLOAT:
 +                log_value(av_log_obj, AV_LOG_INFO, opt->default_val.dbl);
 +                break;
 +            case AV_OPT_TYPE_RATIONAL: {
 +                AVRational q = av_d2q(opt->default_val.dbl, INT_MAX);
 +                av_log(av_log_obj, AV_LOG_INFO, "%d/%d", q.num, q.den); }
 +                break;
 +            case AV_OPT_TYPE_PIXEL_FMT:
 +                av_log(av_log_obj, AV_LOG_INFO, "%s", (char *)av_x_if_null(av_get_pix_fmt_name(opt->default_val.i64), "none"));
 +                break;
 +            case AV_OPT_TYPE_SAMPLE_FMT:
 +                av_log(av_log_obj, AV_LOG_INFO, "%s", (char *)av_x_if_null(av_get_sample_fmt_name(opt->default_val.i64), "none"));
 +                break;
 +            case AV_OPT_TYPE_COLOR:
 +            case AV_OPT_TYPE_IMAGE_SIZE:
 +            case AV_OPT_TYPE_STRING:
 +            case AV_OPT_TYPE_VIDEO_RATE:
 +                av_log(av_log_obj, AV_LOG_INFO, "\"%s\"", opt->default_val.str);
 +                break;
 +            case AV_OPT_TYPE_CHANNEL_LAYOUT:
 +                av_log(av_log_obj, AV_LOG_INFO, "0x%"PRIx64, opt->default_val.i64);
 +                break;
 +            }
 +            av_log(av_log_obj, AV_LOG_INFO, ")");
 +        }
 +
          av_log(av_log_obj, AV_LOG_INFO, "\n");
          if (opt->unit && opt->type != AV_OPT_TYPE_CONST)
              opt_list(obj, av_log_obj, opt->unit, req_flags, rej_flags);
@@@ -1292,66 -596,41 +1290,66 @@@ int av_opt_show2(void *obj, void *av_lo
  
  void av_opt_set_defaults(void *s)
  {
 +    av_opt_set_defaults2(s, 0, 0);
 +}
 +
 +void av_opt_set_defaults2(void *s, int mask, int flags)
 +{
      const AVOption *opt = NULL;
      while ((opt = av_opt_next(s, opt))) {
 +        void *dst = ((uint8_t*)s) + opt->offset;
 +
 +        if ((opt->flags & mask) != flags)
 +            continue;
 +
          if (opt->flags & AV_OPT_FLAG_READONLY)
              continue;
  
          switch (opt->type) {
 -        case AV_OPT_TYPE_CONST:
 -            /* Nothing to be done here */
 -            break;
 -        case AV_OPT_TYPE_FLAGS:
 -        case AV_OPT_TYPE_INT:
 -        case AV_OPT_TYPE_INT64:
 -            av_opt_set_int(s, opt->name, opt->default_val.i64, 0);
 +            case AV_OPT_TYPE_CONST:
 +                /* Nothing to be done here */
 +                break;
 +            case AV_OPT_TYPE_BOOL:
 +            case AV_OPT_TYPE_FLAGS:
 +            case AV_OPT_TYPE_INT:
 +            case AV_OPT_TYPE_INT64:
 +            case AV_OPT_TYPE_UINT64:
 +            case AV_OPT_TYPE_DURATION:
 +            case AV_OPT_TYPE_CHANNEL_LAYOUT:
 +            case AV_OPT_TYPE_PIXEL_FMT:
 +            case AV_OPT_TYPE_SAMPLE_FMT:
 +                write_number(s, opt, dst, 1, 1, opt->default_val.i64);
 +                break;
 +            case AV_OPT_TYPE_DOUBLE:
 +            case AV_OPT_TYPE_FLOAT: {
 +                double val;
 +                val = opt->default_val.dbl;
 +                write_number(s, opt, dst, val, 1, 1);
 +            }
              break;
 -        case AV_OPT_TYPE_DOUBLE:
 -        case AV_OPT_TYPE_FLOAT:
 -        {
 -            double val;
 -            val = opt->default_val.dbl;
 -            av_opt_set_double(s, opt->name, val, 0);
 -        }
 -        break;
 -        case AV_OPT_TYPE_RATIONAL:
 -        {
 -            AVRational val;
 -            val = av_d2q(opt->default_val.dbl, INT_MAX);
 -            av_opt_set_q(s, opt->name, val, 0);
 -        }
 -        break;
 -        case AV_OPT_TYPE_STRING:
 -            av_opt_set(s, opt->name, opt->default_val.str, 0);
 +            case AV_OPT_TYPE_RATIONAL: {
 +                AVRational val;
 +                val = av_d2q(opt->default_val.dbl, INT_MAX);
 +                write_number(s, opt, dst, 1, val.den, val.num);
 +            }
              break;
 -        case AV_OPT_TYPE_BINARY:
 -        case AV_OPT_TYPE_DICT:
 -            /* Cannot set defaults for these types */
 +            case AV_OPT_TYPE_COLOR:
 +                set_string_color(s, opt, opt->default_val.str, dst);
 +                break;
 +            case AV_OPT_TYPE_STRING:
 +                set_string(s, opt, opt->default_val.str, dst);
 +                break;
 +            case AV_OPT_TYPE_IMAGE_SIZE:
 +                set_string_image_size(s, opt, opt->default_val.str, dst);
 +                break;
 +            case AV_OPT_TYPE_VIDEO_RATE:
 +                set_string_video_rate(s, opt, opt->default_val.str, dst);
 +                break;
 +            case AV_OPT_TYPE_BINARY:
 +                set_string_binary(s, opt, opt->default_val.str, dst);
 +                break;
 +            case AV_OPT_TYPE_DICT:
 +                /* Cannot set defaults for these types */
              break;
          default:
              av_log(s, AV_LOG_DEBUG, "AVOption type %d of option %s not implemented yet\n",
@@@ -1400,7 -679,7 +1398,7 @@@ static int parse_key_value_pair(void *c
          return AVERROR(EINVAL);
      }
  
 -    av_log(ctx, AV_LOG_DEBUG, "Setting value '%s' for key '%s'\n", val, key);
 +    av_log(ctx, AV_LOG_DEBUG, "Setting entry with key '%s' to value '%s'\n", key, val);
  
      ret = av_opt_set(ctx, key, val, AV_OPT_SEARCH_CHILDREN);
      if (ret == AVERROR_OPTION_NOT_FOUND)
@@@ -1431,118 -710,6 +1429,118 @@@ int av_set_options_string(void *ctx, co
      return count;
  }
  
 +#define WHITESPACES " \n\t\r"
 +
 +static int is_key_char(char c)
 +{
 +    return (unsigned)((c | 32) - 'a') < 26 ||
 +           (unsigned)(c - '0') < 10 ||
 +           c == '-' || c == '_' || c == '/' || c == '.';
 +}
 +
 +/**
 + * Read a key from a string.
 + *
 + * The key consists of is_key_char characters and must be terminated by a
 + * character from the delim string; spaces are ignored.
 + *
 + * @return  0 for success (even with ellipsis), <0 for failure
 + */
 +static int get_key(const char **ropts, const char *delim, char **rkey)
 +{
 +    const char *opts = *ropts;
 +    const char *key_start, *key_end;
 +
 +    key_start = opts += strspn(opts, WHITESPACES);
 +    while (is_key_char(*opts))
 +        opts++;
 +    key_end = opts;
 +    opts += strspn(opts, WHITESPACES);
 +    if (!*opts || !strchr(delim, *opts))
 +        return AVERROR(EINVAL);
 +    opts++;
 +    if (!(*rkey = av_malloc(key_end - key_start + 1)))
 +        return AVERROR(ENOMEM);
 +    memcpy(*rkey, key_start, key_end - key_start);
 +    (*rkey)[key_end - key_start] = 0;
 +    *ropts = opts;
 +    return 0;
 +}
 +
 +int av_opt_get_key_value(const char **ropts,
 +                         const char *key_val_sep, const char *pairs_sep,
 +                         unsigned flags,
 +                         char **rkey, char **rval)
 +{
 +    int ret;
 +    char *key = NULL, *val;
 +    const char *opts = *ropts;
 +
 +    if ((ret = get_key(&opts, key_val_sep, &key)) < 0 &&
 +        !(flags & AV_OPT_FLAG_IMPLICIT_KEY))
 +        return AVERROR(EINVAL);
 +    if (!(val = av_get_token(&opts, pairs_sep))) {
 +        av_free(key);
 +        return AVERROR(ENOMEM);
 +    }
 +    *ropts = opts;
 +    *rkey  = key;
 +    *rval  = val;
 +    return 0;
 +}
 +
 +int av_opt_set_from_string(void *ctx, const char *opts,
 +                           const char *const *shorthand,
 +                           const char *key_val_sep, const char *pairs_sep)
 +{
 +    int ret, count = 0;
 +    const char *dummy_shorthand = NULL;
 +    char *av_uninit(parsed_key), *av_uninit(value);
 +    const char *key;
 +
 +    if (!opts)
 +        return 0;
 +    if (!shorthand)
 +        shorthand = &dummy_shorthand;
 +
 +    while (*opts) {
 +        ret = av_opt_get_key_value(&opts, key_val_sep, pairs_sep,
 +                                   *shorthand ? AV_OPT_FLAG_IMPLICIT_KEY : 0,
 +                                   &parsed_key, &value);
 +        if (ret < 0) {
 +            if (ret == AVERROR(EINVAL))
 +                av_log(ctx, AV_LOG_ERROR, "No option name near '%s'\n", opts);
 +            else
 +                av_log(ctx, AV_LOG_ERROR, "Unable to parse '%s': %s\n", opts,
 +                       av_err2str(ret));
 +            return ret;
 +        }
 +        if (*opts)
 +            opts++;
 +        if (parsed_key) {
 +            key = parsed_key;
 +            while (*shorthand) /* discard all remaining shorthand */
 +                shorthand++;
 +        } else {
 +            key = *(shorthand++);
 +        }
 +
 +        av_log(ctx, AV_LOG_DEBUG, "Setting '%s' to value '%s'\n", key, value);
 +        if ((ret = av_opt_set(ctx, key, value, 0)) < 0) {
 +            if (ret == AVERROR_OPTION_NOT_FOUND)
 +                av_log(ctx, AV_LOG_ERROR, "Option '%s' not found\n", key);
 +            av_free(value);
 +            av_free(parsed_key);
 +            return ret;
 +        }
 +
 +        av_free(value);
 +        av_free(parsed_key);
 +        count++;
 +    }
 +    return count;
 +}
 +
  void av_opt_free(void *obj)
  {
      const AVOption *o = NULL;
      }
  }
  
 -int av_opt_set_dict(void *obj, AVDictionary **options)
 +int av_opt_set_dict2(void *obj, AVDictionary **options, int search_flags)
  {
      AVDictionaryEntry *t = NULL;
      AVDictionary    *tmp = NULL;
      int ret = 0;
  
 +    if (!options)
 +        return 0;
 +
      while ((t = av_dict_get(*options, "", t, AV_DICT_IGNORE_SUFFIX))) {
 -        ret = av_opt_set(obj, t->key, t->value, 0);
 +        ret = av_opt_set(obj, t->key, t->value, search_flags);
          if (ret == AVERROR_OPTION_NOT_FOUND)
 -            av_dict_set(&tmp, t->key, t->value, 0);
 -        else if (ret < 0) {
 +            ret = av_dict_set(&tmp, t->key, t->value, 0);
 +        if (ret < 0) {
              av_log(obj, AV_LOG_ERROR, "Error setting option %s to value %s.\n", t->key, t->value);
 -            break;
 +            av_dict_free(&tmp);
 +            return ret;
          }
          ret = 0;
      }
      return ret;
  }
  
 +int av_opt_set_dict(void *obj, AVDictionary **options)
 +{
 +    return av_opt_set_dict2(obj, options, 0);
 +}
 +
  const AVOption *av_opt_find(void *obj, const char *name, const char *unit,
                              int opt_flags, int search_flags)
  {
  const AVOption *av_opt_find2(void *obj, const char *name, const char *unit,
                               int opt_flags, int search_flags, void **target_obj)
  {
 -    const AVClass  *c = *(AVClass **)obj;
 +    const AVClass  *c;
      const AVOption *o = NULL;
  
 +    if(!obj)
 +        return NULL;
 +
 +    c= *(AVClass**)obj;
 +
      if (!c)
          return NULL;
  
      while (o = av_opt_next(obj, o)) {
          if (!strcmp(o->name, name) && (o->flags & opt_flags) == opt_flags &&
              ((!unit && o->type != AV_OPT_TYPE_CONST) ||
 -              (unit && o->unit && !strcmp(o->unit, unit)))) {
 +             (unit  && o->type == AV_OPT_TYPE_CONST && o->unit && !strcmp(o->unit, unit)))) {
              if (target_obj) {
                  if (!(search_flags & AV_OPT_SEARCH_FAKE_OBJ))
                      *target_obj = obj;
@@@ -1658,45 -811,24 +1656,45 @@@ const AVClass *av_opt_child_class_next(
      return NULL;
  }
  
 +void *av_opt_ptr(const AVClass *class, void *obj, const char *name)
 +{
 +    const AVOption *opt= av_opt_find2(&class, name, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ, NULL);
 +    if(!opt)
 +        return NULL;
 +    return (uint8_t*)obj + opt->offset;
 +}
 +
  static int opt_size(enum AVOptionType type)
  {
 -    switch (type) {
 +    switch(type) {
 +    case AV_OPT_TYPE_BOOL:
      case AV_OPT_TYPE_INT:
      case AV_OPT_TYPE_FLAGS:
          return sizeof(int);
 +    case AV_OPT_TYPE_DURATION:
 +    case AV_OPT_TYPE_CHANNEL_LAYOUT:
      case AV_OPT_TYPE_INT64:
 +    case AV_OPT_TYPE_UINT64:
          return sizeof(int64_t);
      case AV_OPT_TYPE_DOUBLE:
          return sizeof(double);
      case AV_OPT_TYPE_FLOAT:
          return sizeof(float);
      case AV_OPT_TYPE_STRING:
 -        return sizeof(uint8_t *);
 +        return sizeof(uint8_t*);
 +    case AV_OPT_TYPE_VIDEO_RATE:
      case AV_OPT_TYPE_RATIONAL:
          return sizeof(AVRational);
      case AV_OPT_TYPE_BINARY:
 -        return sizeof(uint8_t *) + sizeof(int);
 +        return sizeof(uint8_t*) + sizeof(int);
 +    case AV_OPT_TYPE_IMAGE_SIZE:
 +        return sizeof(int[2]);
 +    case AV_OPT_TYPE_PIXEL_FMT:
 +        return sizeof(enum AVPixelFormat);
 +    case AV_OPT_TYPE_SAMPLE_FMT:
 +        return sizeof(enum AVSampleFormat);
 +    case AV_OPT_TYPE_COLOR:
 +        return 4;
      }
      return AVERROR(EINVAL);
  }
@@@ -1721,32 -853,26 +1719,32 @@@ int av_opt_copy(void *dst, const void *
          uint8_t **field_src8 = (uint8_t **)field_src;
  
          if (o->type == AV_OPT_TYPE_STRING) {
 -            set_string(dst, o, *field_src8, field_dst8);
 +            if (*field_dst8 != *field_src8)
 +                av_freep(field_dst8);
 +            *field_dst8 = av_strdup(*field_src8);
              if (*field_src8 && !*field_dst8)
                  ret = AVERROR(ENOMEM);
          } else if (o->type == AV_OPT_TYPE_BINARY) {
              int len = *(int *)(field_src8 + 1);
              if (*field_dst8 != *field_src8)
                  av_freep(field_dst8);
 -            if (len) {
 -                *field_dst8 = av_malloc(len);
 -                if (!*field_dst8) {
 -                    ret = AVERROR(ENOMEM);
 -                    len = 0;
 -                }
 -                memcpy(*field_dst8, *field_src8, len);
 -            } else {
 -                *field_dst8 = NULL;
 +            *field_dst8 = av_memdup(*field_src8, len);
 +            if (len && !*field_dst8) {
 +                ret = AVERROR(ENOMEM);
 +                len = 0;
              }
              *(int *)(field_dst8 + 1) = len;
          } else if (o->type == AV_OPT_TYPE_CONST) {
              // do nothing
 +        } else if (o->type == AV_OPT_TYPE_DICT) {
 +            AVDictionary **sdict = (AVDictionary **) field_src;
 +            AVDictionary **ddict = (AVDictionary **) field_dst;
 +            if (*sdict != *ddict)
 +                av_dict_free(ddict);
 +            *ddict = NULL;
 +            av_dict_copy(ddict, *sdict, 0);
 +            if (av_dict_count(*sdict) != av_dict_count(*ddict))
 +                ret = AVERROR(ENOMEM);
          } else {
              int size = opt_size(o->type);
              if (size < 0)
      }
      return ret;
  }
 +
 +int av_opt_query_ranges(AVOptionRanges **ranges_arg, void *obj, const char *key, int flags)
 +{
 +    int ret;
 +    const AVClass *c = *(AVClass**)obj;
 +    int (*callback)(AVOptionRanges **, void *obj, const char *key, int flags) = NULL;
 +
 +    if (c->version > (52 << 16 | 11 << 8))
 +        callback = c->query_ranges;
 +
 +    if (!callback)
 +        callback = av_opt_query_ranges_default;
 +
 +    ret = callback(ranges_arg, obj, key, flags);
 +    if (ret >= 0) {
 +        if (!(flags & AV_OPT_MULTI_COMPONENT_RANGE))
 +            ret = 1;
 +        (*ranges_arg)->nb_components = ret;
 +    }
 +    return ret;
 +}
 +
 +int av_opt_query_ranges_default(AVOptionRanges **ranges_arg, void *obj, const char *key, int flags)
 +{
 +    AVOptionRanges *ranges = av_mallocz(sizeof(*ranges));
 +    AVOptionRange **range_array = av_mallocz(sizeof(void*));
 +    AVOptionRange *range = av_mallocz(sizeof(*range));
 +    const AVOption *field = av_opt_find(obj, key, NULL, 0, flags);
 +    int ret;
 +
 +    *ranges_arg = NULL;
 +
 +    if (!ranges || !range || !range_array || !field) {
 +        ret = AVERROR(ENOMEM);
 +        goto fail;
 +    }
 +
 +    ranges->range = range_array;
 +    ranges->range[0] = range;
 +    ranges->nb_ranges = 1;
 +    ranges->nb_components = 1;
 +    range->is_range = 1;
 +    range->value_min = field->min;
 +    range->value_max = field->max;
 +
 +    switch (field->type) {
 +    case AV_OPT_TYPE_BOOL:
 +    case AV_OPT_TYPE_INT:
 +    case AV_OPT_TYPE_INT64:
 +    case AV_OPT_TYPE_UINT64:
 +    case AV_OPT_TYPE_PIXEL_FMT:
 +    case AV_OPT_TYPE_SAMPLE_FMT:
 +    case AV_OPT_TYPE_FLOAT:
 +    case AV_OPT_TYPE_DOUBLE:
 +    case AV_OPT_TYPE_DURATION:
 +    case AV_OPT_TYPE_COLOR:
 +    case AV_OPT_TYPE_CHANNEL_LAYOUT:
 +        break;
 +    case AV_OPT_TYPE_STRING:
 +        range->component_min = 0;
 +        range->component_max = 0x10FFFF; // max unicode value
 +        range->value_min = -1;
 +        range->value_max = INT_MAX;
 +        break;
 +    case AV_OPT_TYPE_RATIONAL:
 +        range->component_min = INT_MIN;
 +        range->component_max = INT_MAX;
 +        break;
 +    case AV_OPT_TYPE_IMAGE_SIZE:
 +        range->component_min = 0;
 +        range->component_max = INT_MAX/128/8;
 +        range->value_min = 0;
 +        range->value_max = INT_MAX/8;
 +        break;
 +    case AV_OPT_TYPE_VIDEO_RATE:
 +        range->component_min = 1;
 +        range->component_max = INT_MAX;
 +        range->value_min = 1;
 +        range->value_max = INT_MAX;
 +        break;
 +    default:
 +        ret = AVERROR(ENOSYS);
 +        goto fail;
 +    }
 +
 +    *ranges_arg = ranges;
 +    return 1;
 +fail:
 +    av_free(ranges);
 +    av_free(range);
 +    av_free(range_array);
 +    return ret;
 +}
 +
 +void av_opt_freep_ranges(AVOptionRanges **rangesp)
 +{
 +    int i;
 +    AVOptionRanges *ranges = *rangesp;
 +
 +    if (!ranges)
 +        return;
 +
 +    for (i = 0; i < ranges->nb_ranges * ranges->nb_components; i++) {
 +        AVOptionRange *range = ranges->range[i];
 +        if (range) {
 +            av_freep(&range->str);
 +            av_freep(&ranges->range[i]);
 +        }
 +    }
 +    av_freep(&ranges->range);
 +    av_freep(rangesp);
 +}
 +
 +int av_opt_is_set_to_default(void *obj, const AVOption *o)
 +{
 +    int64_t i64;
 +    double d, d2;
 +    float f;
 +    AVRational q;
 +    int ret, w, h;
 +    char *str;
 +    void *dst;
 +
 +    if (!o || !obj)
 +        return AVERROR(EINVAL);
 +
 +    dst = ((uint8_t*)obj) + o->offset;
 +
 +    switch (o->type) {
 +    case AV_OPT_TYPE_CONST:
 +        return 1;
 +    case AV_OPT_TYPE_BOOL:
 +    case AV_OPT_TYPE_FLAGS:
 +    case AV_OPT_TYPE_PIXEL_FMT:
 +    case AV_OPT_TYPE_SAMPLE_FMT:
 +    case AV_OPT_TYPE_INT:
 +    case AV_OPT_TYPE_CHANNEL_LAYOUT:
 +    case AV_OPT_TYPE_DURATION:
 +    case AV_OPT_TYPE_INT64:
 +    case AV_OPT_TYPE_UINT64:
 +        read_number(o, dst, NULL, NULL, &i64);
 +        return o->default_val.i64 == i64;
 +    case AV_OPT_TYPE_STRING:
 +        str = *(char **)dst;
 +        if (str == o->default_val.str) //2 NULLs
 +            return 1;
 +        if (!str || !o->default_val.str) //1 NULL
 +            return 0;
 +        return !strcmp(str, o->default_val.str);
 +    case AV_OPT_TYPE_DOUBLE:
 +        read_number(o, dst, &d, NULL, NULL);
 +        return o->default_val.dbl == d;
 +    case AV_OPT_TYPE_FLOAT:
 +        read_number(o, dst, &d, NULL, NULL);
 +        f = o->default_val.dbl;
 +        d2 = f;
 +        return d2 == d;
 +    case AV_OPT_TYPE_RATIONAL:
 +        q = av_d2q(o->default_val.dbl, INT_MAX);
 +        return !av_cmp_q(*(AVRational*)dst, q);
 +    case AV_OPT_TYPE_BINARY: {
 +        struct {
 +            uint8_t *data;
 +            int size;
 +        } tmp = {0};
 +        int opt_size = *(int *)((void **)dst + 1);
 +        void *opt_ptr = *(void **)dst;
 +        if (!opt_size && (!o->default_val.str || !strlen(o->default_val.str)))
 +            return 1;
 +        if (!opt_size ||  !o->default_val.str || !strlen(o->default_val.str ))
 +            return 0;
 +        if (opt_size != strlen(o->default_val.str) / 2)
 +            return 0;
 +        ret = set_string_binary(NULL, NULL, o->default_val.str, &tmp.data);
 +        if (!ret)
 +            ret = !memcmp(opt_ptr, tmp.data, tmp.size);
 +        av_free(tmp.data);
 +        return ret;
 +    }
 +    case AV_OPT_TYPE_DICT:
 +        /* Binary and dict have not default support yet. Any pointer is not default. */
 +        return !!(*(void **)dst);
 +    case AV_OPT_TYPE_IMAGE_SIZE:
 +        if (!o->default_val.str || !strcmp(o->default_val.str, "none"))
 +            w = h = 0;
 +        else if ((ret = av_parse_video_size(&w, &h, o->default_val.str)) < 0)
 +            return ret;
 +        return (w == *(int *)dst) && (h == *((int *)dst+1));
 +    case AV_OPT_TYPE_VIDEO_RATE:
 +        q = (AVRational){0, 0};
 +        if (o->default_val.str) {
 +            if ((ret = av_parse_video_rate(&q, o->default_val.str)) < 0)
 +                return ret;
 +        }
 +        return !av_cmp_q(*(AVRational*)dst, q);
 +    case AV_OPT_TYPE_COLOR: {
 +        uint8_t color[4] = {0, 0, 0, 0};
 +        if (o->default_val.str) {
 +            if ((ret = av_parse_color(color, o->default_val.str, -1, NULL)) < 0)
 +                return ret;
 +        }
 +        return !memcmp(color, dst, sizeof(color));
 +    }
 +    default:
 +        av_log(obj, AV_LOG_WARNING, "Not supported option type: %d, option name: %s\n", o->type, o->name);
 +        break;
 +    }
 +    return AVERROR_PATCHWELCOME;
 +}
 +
 +int av_opt_is_set_to_default_by_name(void *obj, const char *name, int search_flags)
 +{
 +    const AVOption *o;
 +    void *target;
 +    if (!obj)
 +        return AVERROR(EINVAL);
 +    o = av_opt_find2(obj, name, NULL, 0, search_flags, &target);
 +    if (!o)
 +        return AVERROR_OPTION_NOT_FOUND;
 +    return av_opt_is_set_to_default(target, o);
 +}
 +
 +int av_opt_serialize(void *obj, int opt_flags, int flags, char **buffer,
 +                     const char key_val_sep, const char pairs_sep)
 +{
 +    const AVOption *o = NULL;
 +    uint8_t *buf;
 +    AVBPrint bprint;
 +    int ret, cnt = 0;
 +    const char special_chars[] = {pairs_sep, key_val_sep, '\0'};
 +
 +    if (pairs_sep == '\0' || key_val_sep == '\0' || pairs_sep == key_val_sep ||
 +        pairs_sep == '\\' || key_val_sep == '\\') {
 +        av_log(obj, AV_LOG_ERROR, "Invalid separator(s) found.");
 +        return AVERROR(EINVAL);
 +    }
 +
 +    if (!obj || !buffer)
 +        return AVERROR(EINVAL);
 +
 +    *buffer = NULL;
 +    av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED);
 +
 +    while (o = av_opt_next(obj, o)) {
 +        if (o->type == AV_OPT_TYPE_CONST)
 +            continue;
 +        if ((flags & AV_OPT_SERIALIZE_OPT_FLAGS_EXACT) && o->flags != opt_flags)
 +            continue;
 +        else if (((o->flags & opt_flags) != opt_flags))
 +            continue;
 +        if (flags & AV_OPT_SERIALIZE_SKIP_DEFAULTS && av_opt_is_set_to_default(obj, o) > 0)
 +            continue;
 +        if ((ret = av_opt_get(obj, o->name, 0, &buf)) < 0) {
 +            av_bprint_finalize(&bprint, NULL);
 +            return ret;
 +        }
 +        if (buf) {
 +            if (cnt++)
 +                av_bprint_append_data(&bprint, &pairs_sep, 1);
 +            av_bprint_escape(&bprint, o->name, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0);
 +            av_bprint_append_data(&bprint, &key_val_sep, 1);
 +            av_bprint_escape(&bprint, buf, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0);
 +            av_freep(&buf);
 +        }
 +    }
 +    av_bprint_finalize(&bprint, buffer);
 +    return 0;
 +}