LCOV - code coverage report
Current view: top level - libavformat - oggparseopus.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 83 97 85.6 %
Date: 2017-12-16 13:57:32 Functions: 3 3 100.0 %

          Line data    Source code
       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_SEEK_PREROLL_MS 80
      36             : #define OPUS_HEAD_SIZE 19
      37             : 
      38           6 : static int opus_header(AVFormatContext *avf, int idx)
      39             : {
      40           6 :     struct ogg *ogg              = avf->priv_data;
      41           6 :     struct ogg_stream *os        = &ogg->streams[idx];
      42           6 :     AVStream *st                 = avf->streams[idx];
      43           6 :     struct oggopus_private *priv = os->private;
      44           6 :     uint8_t *packet              = os->buf + os->pstart;
      45             : 
      46           6 :     if (!priv) {
      47           2 :         priv = os->private = av_mallocz(sizeof(*priv));
      48           2 :         if (!priv)
      49           0 :             return AVERROR(ENOMEM);
      50             :     }
      51             : 
      52           6 :     if (os->flags & OGG_FLAG_BOS) {
      53           2 :         if (os->psize < OPUS_HEAD_SIZE || (AV_RL8(packet + 8) & 0xF0) != 0)
      54           0 :             return AVERROR_INVALIDDATA;
      55           2 :         st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
      56           2 :         st->codecpar->codec_id   = AV_CODEC_ID_OPUS;
      57           2 :         st->codecpar->channels   = AV_RL8(packet + 9);
      58             : 
      59           2 :         priv->pre_skip        = AV_RL16(packet + 10);
      60           2 :         st->codecpar->initial_padding = priv->pre_skip;
      61             :         /*orig_sample_rate    = AV_RL32(packet + 12);*/
      62             :         /*gain                = AV_RL16(packet + 16);*/
      63             :         /*channel_map         = AV_RL8 (packet + 18);*/
      64             : 
      65           2 :         av_freep(&st->codecpar->extradata);
      66           2 :         if (ff_alloc_extradata(st->codecpar, os->psize))
      67           0 :             return AVERROR(ENOMEM);
      68             : 
      69           2 :         memcpy(st->codecpar->extradata, packet, os->psize);
      70             : 
      71           2 :         st->codecpar->sample_rate = 48000;
      72           2 :         st->codecpar->seek_preroll = av_rescale(OPUS_SEEK_PREROLL_MS,
      73           2 :                                                 st->codecpar->sample_rate, 1000);
      74           2 :         avpriv_set_pts_info(st, 64, 1, 48000);
      75           2 :         priv->need_comments = 1;
      76           2 :         return 1;
      77             :     }
      78             : 
      79           4 :     if (priv->need_comments) {
      80           2 :         if (os->psize < 8 || memcmp(packet, "OpusTags", 8))
      81           0 :             return AVERROR_INVALIDDATA;
      82           2 :         ff_vorbis_stream_comment(avf, st, packet + 8, os->psize - 8);
      83           2 :         priv->need_comments--;
      84           2 :         return 1;
      85             :     }
      86             : 
      87           2 :     return 0;
      88             : }
      89             : 
      90        2693 : static int opus_duration(uint8_t *src, int size)
      91             : {
      92        2693 :     unsigned nb_frames  = 1;
      93        2693 :     unsigned toc        = src[0];
      94        2693 :     unsigned toc_config = toc >> 3;
      95        2693 :     unsigned toc_count  = toc & 3;
      96        2735 :     unsigned frame_size = toc_config < 12 ? FFMAX(480, 960 * (toc_config & 3)) :
      97          84 :                           toc_config < 16 ? 480 << (toc_config & 1) :
      98          42 :                                             120 << (toc_config & 3);
      99        2693 :     if (toc_count == 3) {
     100           0 :         if (size<2)
     101           0 :             return AVERROR_INVALIDDATA;
     102           0 :         nb_frames = src[1] & 0x3F;
     103        2693 :     } else if (toc_count) {
     104           0 :         nb_frames = 2;
     105             :     }
     106             : 
     107        2693 :     return frame_size * nb_frames;
     108             : }
     109             : 
     110         143 : static int opus_packet(AVFormatContext *avf, int idx)
     111             : {
     112         143 :     struct ogg *ogg              = avf->priv_data;
     113         143 :     struct ogg_stream *os        = &ogg->streams[idx];
     114         143 :     AVStream *st                 = avf->streams[idx];
     115         143 :     struct oggopus_private *priv = os->private;
     116         143 :     uint8_t *packet              = os->buf + os->pstart;
     117             :     int ret;
     118             : 
     119         143 :     if (!os->psize)
     120           0 :         return AVERROR_INVALIDDATA;
     121         143 :     if (os->granule > (1LL << 62)) {
     122           0 :         av_log(avf, AV_LOG_ERROR, "Unsupported huge granule pos %"PRId64 "\n", os->granule);
     123           0 :         return AVERROR_INVALIDDATA;
     124             :     }
     125             : 
     126         143 :     if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) {
     127             :         int seg, d;
     128             :         int duration;
     129         100 :         uint8_t *last_pkt  = os->buf + os->pstart;
     130         100 :         uint8_t *next_pkt  = last_pkt;
     131             : 
     132         100 :         duration = 0;
     133         100 :         seg = os->segp;
     134         100 :         d = opus_duration(last_pkt, os->psize);
     135         100 :         if (d < 0) {
     136           0 :             os->pflags |= AV_PKT_FLAG_CORRUPT;
     137           0 :             return 0;
     138             :         }
     139         100 :         duration += d;
     140         100 :         last_pkt = next_pkt =  next_pkt + os->psize;
     141        2550 :         for (; seg < os->nsegs; seg++) {
     142        2450 :             next_pkt += os->segments[seg];
     143        2450 :             if (os->segments[seg] < 255 && next_pkt != last_pkt) {
     144        2450 :                 int d = opus_duration(last_pkt, next_pkt - last_pkt);
     145        2450 :                 if (d > 0)
     146        2450 :                     duration += d;
     147        2450 :                 last_pkt = next_pkt;
     148             :             }
     149             :         }
     150         100 :         os->lastpts                 =
     151         100 :         os->lastdts                 = os->granule - duration;
     152             :     }
     153             : 
     154         143 :     if ((ret = opus_duration(packet, os->psize)) < 0)
     155           0 :         return ret;
     156             : 
     157         143 :     os->pduration = ret;
     158         143 :     if (os->lastpts != AV_NOPTS_VALUE) {
     159         103 :         if (st->start_time == AV_NOPTS_VALUE)
     160           2 :             st->start_time = os->lastpts;
     161         103 :         priv->cur_dts = os->lastdts = os->lastpts -= priv->pre_skip;
     162             :     }
     163             : 
     164         143 :     priv->cur_dts += os->pduration;
     165         143 :     if ((os->flags & OGG_FLAG_EOS)) {
     166          42 :         int64_t skip = priv->cur_dts - os->granule + priv->pre_skip;
     167          42 :         skip = FFMIN(skip, os->pduration);
     168          42 :         if (skip > 0) {
     169           1 :             os->pduration = skip < os->pduration ? os->pduration - skip : 1;
     170           1 :             os->end_trimming = skip;
     171           1 :             av_log(avf, AV_LOG_DEBUG,
     172             :                    "Last packet was truncated to %d due to end trimming.\n",
     173             :                    os->pduration);
     174             :         }
     175             :     }
     176             : 
     177         143 :     return 0;
     178             : }
     179             : 
     180             : const struct ogg_codec ff_opus_codec = {
     181             :     .name             = "Opus",
     182             :     .magic            = "OpusHead",
     183             :     .magicsize        = 8,
     184             :     .header           = opus_header,
     185             :     .packet           = opus_packet,
     186             :     .nb_header        = 1,
     187             : };

Generated by: LCOV version 1.13