Merge commit 'efcde917af407a6031ecff68edd51fce7b83d104'
authorMichael Niedermayer <michaelni@gmx.at>
Wed, 28 May 2014 11:08:50 +0000 (13:08 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Wed, 28 May 2014 11:08:50 +0000 (13:08 +0200)
* commit 'efcde917af407a6031ecff68edd51fce7b83d104':
  vorbiscomment: simplify API by using av_dict_count()

Conflicts:
libavformat/flacenc.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
libavformat/flacenc.c
libavformat/oggenc.c
libavformat/vorbiscomment.c
libavformat/vorbiscomment.h

diff --combined libavformat/flacenc.c
@@@ -2,20 -2,20 +2,20 @@@
   * raw FLAC muxer
   * Copyright (c) 2006-2009 Justin Ruggles
   *
 - * 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
   */
  
@@@ -23,7 -23,6 +23,7 @@@
  #include "libavutil/opt.h"
  #include "libavcodec/flac.h"
  #include "avformat.h"
 +#include "avio_internal.h"
  #include "flacenc.h"
  #include "vorbiscomment.h"
  #include "libavcodec/bytestream.h"
@@@ -39,20 -38,23 +39,20 @@@ static int flac_write_block_padding(AVI
  {
      avio_w8(pb, last_block ? 0x81 : 0x01);
      avio_wb24(pb, n_padding_bytes);
 -    while (n_padding_bytes > 0) {
 -        avio_w8(pb, 0);
 -        n_padding_bytes--;
 -    }
 +    ffio_fill(pb, 0, n_padding_bytes);
      return 0;
  }
  
  static int flac_write_block_comment(AVIOContext *pb, AVDictionary **m,
                                      int last_block, int bitexact)
  {
 -    const char *vendor = bitexact ? "Libav" : LIBAVFORMAT_IDENT;
 +    const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT;
-     unsigned int len, count;
+     unsigned int len;
      uint8_t *p, *p0;
  
      ff_metadata_conv(m, ff_vorbiscomment_metadata_conv, NULL);
  
-     len = ff_vorbiscomment_length(*m, vendor, &count);
+     len = ff_vorbiscomment_length(*m, vendor);
      p0 = av_malloc(len+4);
      if (!p0)
          return AVERROR(ENOMEM);
@@@ -60,7 -62,7 +60,7 @@@
  
      bytestream_put_byte(&p, last_block ? 0x84 : 0x04);
      bytestream_put_be24(&p, len);
-     ff_vorbiscomment_write(&p, m, vendor, count);
+     ff_vorbiscomment_write(&p, m, vendor);
  
      avio_write(pb, p0, len+4);
      av_freep(&p0);
  static int flac_write_header(struct AVFormatContext *s)
  {
      int ret;
 +    int padding = s->metadata_header_padding;
      AVCodecContext *codec = s->streams[0]->codec;
      FlacMuxerContext *c   = s->priv_data;
  
      if (!c->write_header)
          return 0;
  
 +    if (s->nb_streams > 1) {
 +        av_log(s, AV_LOG_ERROR, "only one stream is supported\n");
 +        return AVERROR(EINVAL);
 +    }
 +    if (codec->codec_id != AV_CODEC_ID_FLAC) {
 +        av_log(s, AV_LOG_ERROR, "unsupported codec\n");
 +        return AVERROR(EINVAL);
 +    }
 +
 +    if (padding < 0)
 +        padding = 8192;
 +    /* The FLAC specification states that 24 bits are used to represent the
 +     * size of a metadata block so we must clip this value to 2^24-1. */
 +    padding = av_clip_c(padding, 0, 16777215);
 +
      ret = ff_flac_write_header(s->pb, codec, 0);
      if (ret)
          return ret;
          }
      }
  
 -    ret = flac_write_block_comment(s->pb, &s->metadata, 0,
 +    ret = flac_write_block_comment(s->pb, &s->metadata, !padding,
                                     s->flags & AVFMT_FLAG_BITEXACT);
      if (ret)
          return ret;
      /* The command line flac encoder defaults to placing a seekpoint
       * every 10s.  So one might add padding to allow that later
       * but there seems to be no simple way to get the duration here.
 -     * So let's try the flac default of 8192 bytes */
 -    flac_write_block_padding(s->pb, 8192, 1);
 +     * So just add the amount requested by the user. */
 +    if (padding)
 +        flac_write_block_padding(s->pb, padding, 1);
  
      return ret;
  }
diff --combined libavformat/oggenc.c
@@@ -2,20 -2,20 +2,20 @@@
   * Ogg muxer
   * Copyright (c) 2007 Baptiste Coudurier <baptiste dot coudurier at free dot fr>
   *
 - * 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
   */
  
@@@ -77,15 -77,21 +77,15 @@@ typedef struct 
  #define PARAM AV_OPT_FLAG_ENCODING_PARAM
  
  static const AVOption options[] = {
 +    { "oggpagesize", "Set preferred Ogg page size.",
 +      offsetof(OGGContext, pref_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, MAX_PAGE_SIZE, AV_OPT_FLAG_ENCODING_PARAM},
      { "pagesize", "preferred page size in bytes (deprecated)",
          OFFSET(pref_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, MAX_PAGE_SIZE, PARAM },
      { "page_duration", "preferred page duration, in microseconds",
 -        OFFSET(pref_duration), AV_OPT_TYPE_INT, { .i64 = 1000000 }, 0, INT64_MAX, PARAM },
 +        OFFSET(pref_duration), AV_OPT_TYPE_INT64, { .i64 = 1000000 }, 0, INT64_MAX, PARAM },
      { NULL },
  };
  
 -static const AVClass ogg_muxer_class = {
 -    .class_name = "Ogg muxer",
 -    .item_name  = av_default_item_name,
 -    .option     = options,
 -    .version    = LIBAVUTIL_VERSION_INT,
 -};
 -
 -
  static void ogg_update_checksum(AVFormatContext *s, AVIOContext *pb, int64_t crc_offset)
  {
      int64_t pos = avio_tell(pb);
@@@ -133,11 -139,6 +133,11 @@@ static int ogg_write_page(AVFormatConte
      return 0;
  }
  
 +static int ogg_key_granule(OGGStreamContext *oggstream, int64_t granule)
 +{
 +    return oggstream->kfgshift && !(granule & ((1<<oggstream->kfgshift)-1));
 +}
 +
  static int64_t ogg_granule_to_timestamp(OGGStreamContext *oggstream, int64_t granule)
  {
      if (oggstream->kfgshift)
@@@ -208,14 -209,9 +208,14 @@@ static int ogg_buffer_data(AVFormatCont
      int i, segments, len, flush = 0;
  
      // Handles VFR by flushing page because this frame needs to have a timestamp
 +    // For theora, keyframes also need to have a timestamp to correctly mark
 +    // them as such, otherwise seeking will not work correctly at the very
 +    // least with old libogg versions.
 +    // Do not try to flush header packets though, that will create broken files.
      if (st->codec->codec_id == AV_CODEC_ID_THEORA && !header &&
 -        ogg_granule_to_timestamp(oggstream, granule) >
 -        ogg_granule_to_timestamp(oggstream, oggstream->last_granule) + 1) {
 +        (ogg_granule_to_timestamp(oggstream, granule) >
 +         ogg_granule_to_timestamp(oggstream, oggstream->last_granule) + 1 ||
 +         ogg_key_granule(oggstream, granule))) {
          if (oggstream->page.granule != -1)
              ogg_buffer_page(s, oggstream);
          flush = 1;
  static uint8_t *ogg_write_vorbiscomment(int offset, int bitexact,
                                          int *header_len, AVDictionary **m, int framing_bit)
  {
 -    const char *vendor = bitexact ? "Libav" : LIBAVFORMAT_IDENT;
 +    const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT;
      int size;
      uint8_t *p, *p0;
-     unsigned int count;
  
      ff_metadata_conv(m, ff_vorbiscomment_metadata_conv, NULL);
  
-     size = offset + ff_vorbiscomment_length(*m, vendor, &count) + framing_bit;
+     size = offset + ff_vorbiscomment_length(*m, vendor) + framing_bit;
      p = av_mallocz(size);
      if (!p)
          return NULL;
      p0 = p;
  
      p += offset;
-     ff_vorbiscomment_write(&p, m, vendor, count);
+     ff_vorbiscomment_write(&p, m, vendor);
      if (framing_bit)
          bytestream_put_byte(&p, 1);
  
@@@ -406,7 -401,7 +405,7 @@@ static void ogg_write_pages(AVFormatCon
          if (oggstream->page_count < 2 && !flush)
              break;
          ogg_write_page(s, &p->page,
 -                       flush && oggstream->page_count == 1 ? 4 : 0); // eos
 +                       flush == 1 && oggstream->page_count == 1 ? 4 : 0); // eos
          next = p->next;
          av_freep(&p);
          p = next;
  static int ogg_write_header(AVFormatContext *s)
  {
      OGGContext *ogg = s->priv_data;
 -    OGGStreamContext *oggstream;
 +    OGGStreamContext *oggstream = NULL;
      int i, j;
  
      if (ogg->pref_size)
          AVStream *st = s->streams[i];
          unsigned serial_num = i;
  
 -        if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
 +        if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
              if (st->codec->codec_id == AV_CODEC_ID_OPUS)
                  /* Opus requires a fixed 48kHz clock */
                  avpriv_set_pts_info(st, 64, 1, 48000);
              else
                  avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
 -        else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
 +        else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
              avpriv_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den);
          if (st->codec->codec_id != AV_CODEC_ID_VORBIS &&
              st->codec->codec_id != AV_CODEC_ID_THEORA &&
              return -1;
          }
          oggstream = av_mallocz(sizeof(*oggstream));
 +        if (!oggstream)
 +            return AVERROR(ENOMEM);
 +
          oggstream->page.stream_index = i;
  
          if (!(s->flags & AVFMT_FLAG_BITEXACT))
              } while (j < i);
          oggstream->serial_num = serial_num;
  
 +        av_dict_copy(&st->metadata, s->metadata, AV_DICT_DONT_OVERWRITE);
 +
          st->priv_data = oggstream;
          if (st->codec->codec_id == AV_CODEC_ID_FLAC) {
              int err = ogg_build_flac_headers(st->codec, oggstream,
                                               s->flags & AVFMT_FLAG_BITEXACT,
 -                                             &s->metadata);
 +                                             &st->metadata);
              if (err) {
                  av_log(s, AV_LOG_ERROR, "Error writing FLAC headers\n");
                  av_freep(&st->priv_data);
          } else if (st->codec->codec_id == AV_CODEC_ID_SPEEX) {
              int err = ogg_build_speex_headers(st->codec, oggstream,
                                                s->flags & AVFMT_FLAG_BITEXACT,
 -                                              &s->metadata);
 +                                              &st->metadata);
              if (err) {
                  av_log(s, AV_LOG_ERROR, "Error writing Speex headers\n");
                  av_freep(&st->priv_data);
          } else if (st->codec->codec_id == AV_CODEC_ID_OPUS) {
              int err = ogg_build_opus_headers(st->codec, oggstream,
                                               s->flags & AVFMT_FLAG_BITEXACT,
 -                                             &s->metadata);
 +                                             &st->metadata);
              if (err) {
                  av_log(s, AV_LOG_ERROR, "Error writing Opus headers\n");
                  av_freep(&st->priv_data);
              }
  
              p = ogg_write_vorbiscomment(7, s->flags & AVFMT_FLAG_BITEXACT,
 -                                        &oggstream->header_len[1], &s->metadata,
 +                                        &oggstream->header_len[1], &st->metadata,
                                          framing_bit);
              oggstream->header[1] = p;
              if (!p)
          AVStream *st = s->streams[j];
          OGGStreamContext *oggstream = st->priv_data;
          for (i = 1; i < 3; i++) {
 -            if (oggstream && oggstream->header_len[i])
 +            if (oggstream->header_len[i])
                  ogg_buffer_data(s, st, oggstream->header[i],
                                  oggstream->header_len[i], 0, 1);
          }
  
      oggstream->page.start_granule = AV_NOPTS_VALUE;
  
 -    ogg_write_pages(s, 1);
 +    ogg_write_pages(s, 2);
  
      return 0;
  }
@@@ -613,7 -603,7 +612,7 @@@ static int ogg_write_trailer(AVFormatCo
          if (st->codec->codec_id == AV_CODEC_ID_FLAC ||
              st->codec->codec_id == AV_CODEC_ID_SPEEX ||
              st->codec->codec_id == AV_CODEC_ID_OPUS) {
 -            av_free(oggstream->header[0]);
 +            av_freep(&oggstream->header[0]);
          }
          av_freep(&oggstream->header[1]);
          av_freep(&st->priv_data);
      return 0;
  }
  
 +#if CONFIG_OGG_MUXER
 +static const AVClass ogg_muxer_class = {
 +    .class_name = "Ogg muxer",
 +    .item_name  = av_default_item_name,
 +    .option     = options,
 +    .version    = LIBAVUTIL_VERSION_INT,
 +};
 +
  AVOutputFormat ff_ogg_muxer = {
      .name              = "ogg",
      .long_name         = NULL_IF_CONFIG_SMALL("Ogg"),
      .mime_type         = "application/ogg",
 -    .extensions        = "ogg,ogv,spx,opus",
 +    .extensions        = "ogg,ogv"
 +#if !CONFIG_SPEEX_MUXER
 +                         ",spx"
 +#endif
 +#if !CONFIG_OPUS_MUXER
 +                         ",opus"
 +#endif
 +                         ,
      .priv_data_size    = sizeof(OGGContext),
      .audio_codec       = CONFIG_LIBVORBIS_ENCODER ?
                           AV_CODEC_ID_VORBIS : AV_CODEC_ID_FLAC,
      .flags             = AVFMT_TS_NEGATIVE,
      .priv_class        = &ogg_muxer_class,
  };
 +#endif
 +
 +#if CONFIG_OGA_MUXER
 +static const AVClass oga_muxer_class = {
 +    .class_name = "Ogg audio muxer",
 +    .item_name  = av_default_item_name,
 +    .option     = options,
 +    .version    = LIBAVUTIL_VERSION_INT,
 +};
 +
 +AVOutputFormat ff_oga_muxer = {
 +    .name              = "oga",
 +    .long_name         = NULL_IF_CONFIG_SMALL("Ogg audio"),
 +    .mime_type         = "audio/ogg",
 +    .extensions        = "oga",
 +    .priv_data_size    = sizeof(OGGContext),
 +    .audio_codec       = AV_CODEC_ID_VORBIS,
 +    .video_codec       = AV_CODEC_ID_NONE,
 +    .write_header      = ogg_write_header,
 +    .write_packet      = ogg_write_packet,
 +    .write_trailer     = ogg_write_trailer,
 +    .flags             = AVFMT_TS_NEGATIVE,
 +    .priv_class        = &oga_muxer_class,
 +};
 +#endif
 +
 +#if CONFIG_SPEEX_MUXER
 +static const AVClass speex_muxer_class = {
 +    .class_name = "Speex muxer",
 +    .item_name  = av_default_item_name,
 +    .option     = options,
 +    .version    = LIBAVUTIL_VERSION_INT,
 +};
 +
 +AVOutputFormat ff_speex_muxer = {
 +    .name              = "speex",
 +    .long_name         = NULL_IF_CONFIG_SMALL("Speex"),
 +    .mime_type         = "audio/ogg",
 +    .extensions        = "spx",
 +    .priv_data_size    = sizeof(OGGContext),
 +    .audio_codec       = AV_CODEC_ID_SPEEX,
 +     .video_codec      = AV_CODEC_ID_NONE,
 +    .write_header      = ogg_write_header,
 +    .write_packet      = ogg_write_packet,
 +    .write_trailer     = ogg_write_trailer,
 +    .flags             = AVFMT_TS_NEGATIVE,
 +    .priv_class        = &speex_muxer_class,
 +};
 +#endif
 +
 +#if CONFIG_OPUS_MUXER
 +static const AVClass opus_muxer_class = {
 +    .class_name = "Opus muxer",
 +    .item_name  = av_default_item_name,
 +    .option     = options,
 +    .version    = LIBAVUTIL_VERSION_INT,
 +};
 +
 +AVOutputFormat ff_opus_muxer = {
 +    .name              = "opus",
 +    .long_name         = NULL_IF_CONFIG_SMALL("Opus"),
 +    .mime_type         = "audio/ogg",
 +    .extensions        = "opus",
 +    .priv_data_size    = sizeof(OGGContext),
 +    .audio_codec       = AV_CODEC_ID_OPUS,
 +    .video_codec       = AV_CODEC_ID_NONE,
 +    .write_header      = ogg_write_header,
 +    .write_packet      = ogg_write_packet,
 +    .write_trailer     = ogg_write_trailer,
 +    .flags             = AVFMT_TS_NEGATIVE,
 +    .priv_class        = &opus_muxer_class,
 +};
 +#endif
@@@ -2,20 -2,20 +2,20 @@@
   * VorbisComment writer
   * Copyright (c) 2009 James Darnley
   *
 - * 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
   */
  
@@@ -34,32 -34,29 +34,30 @@@ const AVMetadataConv ff_vorbiscomment_m
      { "ALBUMARTIST", "album_artist"},
      { "TRACKNUMBER", "track"  },
      { "DISCNUMBER",  "disc"   },
 +    { "DESCRIPTION", "comment" },
      { 0 }
  };
  
- int ff_vorbiscomment_length(AVDictionary *m, const char *vendor_string,
-                             unsigned *count)
+ int ff_vorbiscomment_length(AVDictionary *m, const char *vendor_string)
  {
      int len = 8;
      len += strlen(vendor_string);
-     *count = 0;
      if (m) {
          AVDictionaryEntry *tag = NULL;
          while ((tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX))) {
              len += 4 +strlen(tag->key) + 1 + strlen(tag->value);
-             (*count)++;
          }
      }
      return len;
  }
  
  int ff_vorbiscomment_write(uint8_t **p, AVDictionary **m,
-                            const char *vendor_string, const unsigned count)
+                            const char *vendor_string)
  {
      bytestream_put_le32(p, strlen(vendor_string));
      bytestream_put_buffer(p, vendor_string, strlen(vendor_string));
      if (*m) {
+         int count = av_dict_count(*m);
          AVDictionaryEntry *tag = NULL;
          bytestream_put_le32(p, count);
          while ((tag = av_dict_get(*m, "", tag, AV_DICT_IGNORE_SUFFIX))) {
@@@ -2,20 -2,20 +2,20 @@@
   * VorbisComment writer
   * Copyright (c) 2009 James Darnley
   *
 - * 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
   */
  
   * @param m The metadata structure to be parsed. For no metadata, set to NULL.
   * @param vendor_string The vendor string to be added into the VorbisComment.
   * For no string, set to an empty string.
-  * @param count Pointer to store the number of tags in m because m->count is "not allowed"
   * @return The length in bytes.
   */
- int ff_vorbiscomment_length(AVDictionary *m, const char *vendor_string,
-                             unsigned *count);
+ int ff_vorbiscomment_length(AVDictionary *m, const char *vendor_string);
  
  /**
   * Write a VorbisComment into a buffer. The buffer, p, must have enough
   * @param p The buffer in which to write.
   * @param m The metadata struct to write.
   * @param vendor_string The vendor string to write.
-  * @param count The number of tags in m because m->count is "not allowed"
   */
  int ff_vorbiscomment_write(uint8_t **p, AVDictionary **m,
-                            const char *vendor_string, const unsigned count);
+                            const char *vendor_string);
  
  extern const AVMetadataConv ff_vorbiscomment_metadata_conv[];