Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Opus parser for Ogg
  3.  * Copyright (c) 2012 Nicolas George
  4.  *
  5.  * This file is part of FFmpeg.
  6.  *
  7.  * FFmpeg is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  *
  12.  * FFmpeg is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with FFmpeg; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20.  */
  21.  
  22. #include <string.h>
  23.  
  24. #include "libavutil/intreadwrite.h"
  25. #include "avformat.h"
  26. #include "internal.h"
  27. #include "oggdec.h"
  28.  
  29. struct oggopus_private {
  30.     int need_comments;
  31.     unsigned pre_skip;
  32.     int64_t cur_dts;
  33. };
  34.  
  35. #define OPUS_HEAD_SIZE 19
  36.  
  37. static int opus_header(AVFormatContext *avf, int idx)
  38. {
  39.     struct ogg *ogg              = avf->priv_data;
  40.     struct ogg_stream *os        = &ogg->streams[idx];
  41.     AVStream *st                 = avf->streams[idx];
  42.     struct oggopus_private *priv = os->private;
  43.     uint8_t *packet              = os->buf + os->pstart;
  44.  
  45.     if (!priv) {
  46.         priv = os->private = av_mallocz(sizeof(*priv));
  47.         if (!priv)
  48.             return AVERROR(ENOMEM);
  49.     }
  50.  
  51.     if (os->flags & OGG_FLAG_BOS) {
  52.         if (os->psize < OPUS_HEAD_SIZE || (AV_RL8(packet + 8) & 0xF0) != 0)
  53.             return AVERROR_INVALIDDATA;
  54.         st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
  55.         st->codec->codec_id   = AV_CODEC_ID_OPUS;
  56.         st->codec->channels   = AV_RL8 (packet + 9);
  57.         priv->pre_skip        = AV_RL16(packet + 10);
  58.         /*orig_sample_rate    = AV_RL32(packet + 12);*/
  59.         /*gain                = AV_RL16(packet + 16);*/
  60.         /*channel_map         = AV_RL8 (packet + 18);*/
  61.  
  62.         if (ff_alloc_extradata(st->codec, os->psize))
  63.             return AVERROR(ENOMEM);
  64.  
  65.         memcpy(st->codec->extradata, packet, os->psize);
  66.  
  67.         st->codec->sample_rate = 48000;
  68.         avpriv_set_pts_info(st, 64, 1, 48000);
  69.         priv->need_comments = 1;
  70.         return 1;
  71.     }
  72.  
  73.     if (priv->need_comments) {
  74.         if (os->psize < 8 || memcmp(packet, "OpusTags", 8))
  75.             return AVERROR_INVALIDDATA;
  76.         ff_vorbis_comment(avf, &st->metadata, packet + 8, os->psize - 8);
  77.         priv->need_comments--;
  78.         return 1;
  79.     }
  80.  
  81.     return 0;
  82. }
  83.  
  84. static int opus_packet(AVFormatContext *avf, int idx)
  85. {
  86.     struct ogg *ogg              = avf->priv_data;
  87.     struct ogg_stream *os        = &ogg->streams[idx];
  88.     AVStream *st                 = avf->streams[idx];
  89.     struct oggopus_private *priv = os->private;
  90.     uint8_t *packet              = os->buf + os->pstart;
  91.     unsigned toc, toc_config, toc_count, frame_size, nb_frames = 1;
  92.  
  93.     if (!os->psize)
  94.         return AVERROR_INVALIDDATA;
  95.  
  96.     toc        = *packet;
  97.     toc_config = toc >> 3;
  98.     toc_count  = toc & 3;
  99.     frame_size = toc_config < 12 ? FFMAX(480, 960 * (toc_config & 3)) :
  100.                  toc_config < 16 ? 480 << (toc_config & 1) :
  101.                                    120 << (toc_config & 3);
  102.     if (toc_count == 3) {
  103.         if (os->psize < 2)
  104.             return AVERROR_INVALIDDATA;
  105.         nb_frames = packet[1] & 0x3F;
  106.     } else if (toc_count) {
  107.         nb_frames = 2;
  108.     }
  109.  
  110.     os->pduration = frame_size * nb_frames;
  111.     if (os->lastpts != AV_NOPTS_VALUE) {
  112.         if (st->start_time == AV_NOPTS_VALUE)
  113.             st->start_time = os->lastpts;
  114.         priv->cur_dts = os->lastdts = os->lastpts -= priv->pre_skip;
  115.     }
  116.  
  117.     priv->cur_dts += os->pduration;
  118.     if ((os->flags & OGG_FLAG_EOS)) {
  119.         int64_t skip = priv->cur_dts - os->granule + priv->pre_skip;
  120.         skip = FFMIN(skip, os->pduration);
  121.         if (skip > 0) {
  122.             os->pduration = skip < os->pduration ? os->pduration - skip : 1;
  123.             os->end_trimming = skip;
  124.             av_log(avf, AV_LOG_DEBUG,
  125.                    "Last packet was truncated to %d due to end trimming.\n",
  126.                    os->pduration);
  127.         }
  128.     }
  129.  
  130.     return 0;
  131. }
  132.  
  133. const struct ogg_codec ff_opus_codec = {
  134.     .name             = "Opus",
  135.     .magic            = "OpusHead",
  136.     .magicsize        = 8,
  137.     .header           = opus_header,
  138.     .packet           = opus_packet,
  139.     .nb_header        = 1,
  140. };
  141.