LCOV - code coverage report
Current view: top level - libavformat - oggdec.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 432 533 81.1 %
Date: 2018-05-20 11:54:08 Functions: 19 20 95.0 %

          Line data    Source code
       1             : /*
       2             :  * Ogg bitstream support
       3             :  * Luca Barbato <lu_zero@gentoo.org>
       4             :  * Based on tcvp implementation
       5             :  */
       6             : 
       7             : /*
       8             :     Copyright (C) 2005  Michael Ahlberg, Måns Rullgård
       9             : 
      10             :     Permission is hereby granted, free of charge, to any person
      11             :     obtaining a copy of this software and associated documentation
      12             :     files (the "Software"), to deal in the Software without
      13             :     restriction, including without limitation the rights to use, copy,
      14             :     modify, merge, publish, distribute, sublicense, and/or sell copies
      15             :     of the Software, and to permit persons to whom the Software is
      16             :     furnished to do so, subject to the following conditions:
      17             : 
      18             :     The above copyright notice and this permission notice shall be
      19             :     included in all copies or substantial portions of the Software.
      20             : 
      21             :     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      22             :     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      23             :     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      24             :     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
      25             :     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
      26             :     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      27             :     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28             :     DEALINGS IN THE SOFTWARE.
      29             :  */
      30             : 
      31             : #include <stdio.h>
      32             : #include "libavutil/avassert.h"
      33             : #include "libavutil/intreadwrite.h"
      34             : #include "oggdec.h"
      35             : #include "avformat.h"
      36             : #include "internal.h"
      37             : #include "vorbiscomment.h"
      38             : 
      39             : #define MAX_PAGE_SIZE 65307
      40             : #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
      41             : 
      42             : static const struct ogg_codec * const ogg_codecs[] = {
      43             :     &ff_skeleton_codec,
      44             :     &ff_daala_codec,
      45             :     &ff_dirac_codec,
      46             :     &ff_speex_codec,
      47             :     &ff_vorbis_codec,
      48             :     &ff_theora_codec,
      49             :     &ff_flac_codec,
      50             :     &ff_celt_codec,
      51             :     &ff_opus_codec,
      52             :     &ff_vp8_codec,
      53             :     &ff_old_dirac_codec,
      54             :     &ff_old_flac_codec,
      55             :     &ff_ogm_video_codec,
      56             :     &ff_ogm_audio_codec,
      57             :     &ff_ogm_text_codec,
      58             :     &ff_ogm_old_codec,
      59             :     NULL
      60             : };
      61             : 
      62             : static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts);
      63             : static int ogg_new_stream(AVFormatContext *s, uint32_t serial);
      64             : static int ogg_restore(AVFormatContext *s);
      65             : 
      66          41 : static void free_stream(AVFormatContext *s, int i)
      67             : {
      68          41 :     struct ogg *ogg = s->priv_data;
      69          41 :     struct ogg_stream *stream = &ogg->streams[i];
      70             : 
      71          41 :     av_freep(&stream->buf);
      72          82 :     if (stream->codec &&
      73          41 :         stream->codec->cleanup) {
      74          25 :         stream->codec->cleanup(s, i);
      75             :     }
      76             : 
      77          41 :     av_freep(&stream->private);
      78          41 :     av_freep(&stream->new_metadata);
      79          41 : }
      80             : 
      81             : //FIXME We could avoid some structure duplication
      82          64 : static int ogg_save(AVFormatContext *s)
      83             : {
      84          64 :     struct ogg *ogg = s->priv_data;
      85          64 :     struct ogg_state *ost =
      86          64 :         av_malloc(sizeof(*ost) + (ogg->nstreams - 1) * sizeof(*ogg->streams));
      87             :     int i;
      88          64 :     int ret = 0;
      89             : 
      90          64 :     if (!ost)
      91           0 :         return AVERROR(ENOMEM);
      92             : 
      93          64 :     ost->pos      = avio_tell(s->pb);
      94          64 :     ost->curidx   = ogg->curidx;
      95          64 :     ost->next     = ogg->state;
      96          64 :     ost->nstreams = ogg->nstreams;
      97          64 :     memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
      98             : 
      99         130 :     for (i = 0; i < ogg->nstreams; i++) {
     100          66 :         struct ogg_stream *os = ogg->streams + i;
     101          66 :         os->buf = av_mallocz(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
     102          66 :         if (os->buf)
     103          66 :             memcpy(os->buf, ost->streams[i].buf, os->bufpos);
     104             :         else
     105           0 :             ret = AVERROR(ENOMEM);
     106          66 :         os->new_metadata      = NULL;
     107          66 :         os->new_metadata_size = 0;
     108             :     }
     109             : 
     110          64 :     ogg->state = ost;
     111             : 
     112          64 :     if (ret < 0)
     113           0 :         ogg_restore(s);
     114             : 
     115          64 :     return ret;
     116             : }
     117             : 
     118          64 : static int ogg_restore(AVFormatContext *s)
     119             : {
     120          64 :     struct ogg *ogg = s->priv_data;
     121          64 :     AVIOContext *bc = s->pb;
     122          64 :     struct ogg_state *ost = ogg->state;
     123             :     int i, err;
     124             : 
     125          64 :     if (!ost)
     126           0 :         return 0;
     127             : 
     128          64 :     ogg->state = ost->next;
     129             : 
     130         130 :         for (i = 0; i < ogg->nstreams; i++) {
     131          66 :             struct ogg_stream *stream = &ogg->streams[i];
     132          66 :             av_freep(&stream->buf);
     133          66 :             av_freep(&stream->new_metadata);
     134             : 
     135          66 :             if (i >= ost->nstreams || !ost->streams[i].private) {
     136           8 :                 free_stream(s, i);
     137             :             }
     138             :         }
     139             : 
     140          64 :         avio_seek(bc, ost->pos, SEEK_SET);
     141          64 :         ogg->page_pos = -1;
     142          64 :         ogg->curidx   = ost->curidx;
     143          64 :         ogg->nstreams = ost->nstreams;
     144          64 :         if ((err = av_reallocp_array(&ogg->streams, ogg->nstreams,
     145             :                                      sizeof(*ogg->streams))) < 0) {
     146           0 :             ogg->nstreams = 0;
     147           0 :             return err;
     148             :         } else
     149          64 :             memcpy(ogg->streams, ost->streams,
     150          64 :                    ost->nstreams * sizeof(*ogg->streams));
     151             : 
     152          64 :     av_free(ost);
     153             : 
     154          64 :     return 0;
     155             : }
     156             : 
     157         392 : static int ogg_reset(AVFormatContext *s)
     158             : {
     159         392 :     struct ogg *ogg = s->priv_data;
     160             :     int i;
     161         392 :     int64_t start_pos = avio_tell(s->pb);
     162             : 
     163         785 :     for (i = 0; i < ogg->nstreams; i++) {
     164         393 :         struct ogg_stream *os = ogg->streams + i;
     165         393 :         os->bufpos     = 0;
     166         393 :         os->pstart     = 0;
     167         393 :         os->psize      = 0;
     168         393 :         os->granule    = -1;
     169         393 :         os->lastpts    = AV_NOPTS_VALUE;
     170         393 :         os->lastdts    = AV_NOPTS_VALUE;
     171         393 :         os->sync_pos   = -1;
     172         393 :         os->page_pos   = 0;
     173         393 :         os->nsegs      = 0;
     174         393 :         os->segp       = 0;
     175         393 :         os->incomplete = 0;
     176         393 :         os->got_data = 0;
     177         393 :         if (start_pos <= s->internal->data_offset) {
     178         157 :             os->lastpts = 0;
     179             :         }
     180         393 :         os->end_trimming = 0;
     181         393 :         av_freep(&os->new_metadata);
     182         393 :         os->new_metadata_size = 0;
     183             :     }
     184             : 
     185         392 :     ogg->page_pos = -1;
     186         392 :     ogg->curidx = -1;
     187             : 
     188         392 :     return 0;
     189             : }
     190             : 
     191          33 : static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
     192             : {
     193             :     int i;
     194             : 
     195         189 :     for (i = 0; ogg_codecs[i]; i++)
     196         378 :         if (size >= ogg_codecs[i]->magicsize &&
     197         189 :             !memcmp(buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
     198          33 :             return ogg_codecs[i];
     199             : 
     200           0 :     return NULL;
     201             : }
     202             : 
     203             : /**
     204             :  * Replace the current stream with a new one. This is a typical webradio
     205             :  * situation where a new audio stream spawn (identified with a new serial) and
     206             :  * must replace the previous one (track switch).
     207             :  */
     208           0 : static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, int nsegs)
     209             : {
     210           0 :     struct ogg *ogg = s->priv_data;
     211             :     struct ogg_stream *os;
     212             :     const struct ogg_codec *codec;
     213           0 :     int i = 0;
     214             : 
     215           0 :     if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
     216             :         uint8_t magic[8];
     217           0 :         int64_t pos = avio_tell(s->pb);
     218           0 :         avio_skip(s->pb, nsegs);
     219           0 :         avio_read(s->pb, magic, sizeof(magic));
     220           0 :         avio_seek(s->pb, pos, SEEK_SET);
     221           0 :         codec = ogg_find_codec(magic, sizeof(magic));
     222           0 :         if (!codec) {
     223           0 :             av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n");
     224           0 :             return AVERROR_INVALIDDATA;
     225             :         }
     226           0 :         for (i = 0; i < ogg->nstreams; i++) {
     227           0 :             if (ogg->streams[i].codec == codec)
     228           0 :                 break;
     229             :         }
     230           0 :         if (i >= ogg->nstreams)
     231           0 :             return ogg_new_stream(s, serial);
     232           0 :     } else if (ogg->nstreams != 1) {
     233           0 :         avpriv_report_missing_feature(s, "Changing stream parameters in multistream ogg");
     234           0 :         return AVERROR_PATCHWELCOME;
     235             :     }
     236             : 
     237           0 :     os = &ogg->streams[i];
     238             : 
     239           0 :     os->serial  = serial;
     240           0 :     return i;
     241             : 
     242             : #if 0
     243             :     buf     = os->buf;
     244             :     bufsize = os->bufsize;
     245             :     codec   = os->codec;
     246             : 
     247             :     if (!ogg->state || ogg->state->streams[i].private != os->private)
     248             :         av_freep(&ogg->streams[i].private);
     249             : 
     250             :     /* Set Ogg stream settings similar to what is done in ogg_new_stream(). We
     251             :      * also re-use the ogg_stream allocated buffer */
     252             :     memset(os, 0, sizeof(*os));
     253             :     os->serial  = serial;
     254             :     os->bufsize = bufsize;
     255             :     os->buf     = buf;
     256             :     os->header  = -1;
     257             :     os->codec   = codec;
     258             : 
     259             :     return i;
     260             : #endif
     261             : }
     262             : 
     263          33 : static int ogg_new_stream(AVFormatContext *s, uint32_t serial)
     264             : {
     265          33 :     struct ogg *ogg = s->priv_data;
     266          33 :     int idx         = ogg->nstreams;
     267             :     AVStream *st;
     268             :     struct ogg_stream *os;
     269             :     size_t size;
     270             : 
     271          33 :     if (ogg->state) {
     272           0 :         av_log(s, AV_LOG_ERROR, "New streams are not supposed to be added "
     273             :                "in between Ogg context save/restore operations.\n");
     274           0 :         return AVERROR_BUG;
     275             :     }
     276             : 
     277             :     /* Allocate and init a new Ogg Stream */
     278          66 :     if (av_size_mult(ogg->nstreams + 1, sizeof(*ogg->streams), &size) < 0 ||
     279          33 :         !(os = av_realloc(ogg->streams, size)))
     280           0 :         return AVERROR(ENOMEM);
     281          33 :     ogg->streams = os;
     282          33 :     os           = ogg->streams + idx;
     283          33 :     memset(os, 0, sizeof(*os));
     284          33 :     os->serial        = serial;
     285          33 :     os->bufsize       = DECODER_BUFFER_SIZE;
     286          33 :     os->buf           = av_malloc(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
     287          33 :     os->header        = -1;
     288          33 :     os->start_granule = OGG_NOGRANULE_VALUE;
     289          33 :     if (!os->buf)
     290           0 :         return AVERROR(ENOMEM);
     291             : 
     292             :     /* Create the associated AVStream */
     293          33 :     st = avformat_new_stream(s, NULL);
     294          33 :     if (!st) {
     295           0 :         av_freep(&os->buf);
     296           0 :         return AVERROR(ENOMEM);
     297             :     }
     298          33 :     st->id = idx;
     299          33 :     avpriv_set_pts_info(st, 64, 1, 1000000);
     300             : 
     301          33 :     ogg->nstreams++;
     302          33 :     return idx;
     303             : }
     304             : 
     305         363 : static int ogg_new_buf(struct ogg *ogg, int idx)
     306             : {
     307         363 :     struct ogg_stream *os = ogg->streams + idx;
     308         363 :     uint8_t *nb = av_malloc(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
     309         363 :     int size = os->bufpos - os->pstart;
     310             : 
     311         363 :     if (!nb)
     312           0 :         return AVERROR(ENOMEM);
     313             : 
     314         363 :     if (os->buf) {
     315         363 :         memcpy(nb, os->buf + os->pstart, size);
     316         363 :         av_free(os->buf);
     317             :     }
     318             : 
     319         363 :     os->buf    = nb;
     320         363 :     os->bufpos = size;
     321         363 :     os->pstart = 0;
     322             : 
     323         363 :     return 0;
     324             : }
     325             : 
     326          33 : static int data_packets_seen(const struct ogg *ogg)
     327             : {
     328             :     int i;
     329             : 
     330          34 :     for (i = 0; i < ogg->nstreams; i++)
     331           1 :         if (ogg->streams[i].got_data)
     332           0 :             return 1;
     333          33 :     return 0;
     334             : }
     335             : 
     336        1339 : static int ogg_read_page(AVFormatContext *s, int *sid)
     337             : {
     338        1339 :     AVIOContext *bc = s->pb;
     339        1339 :     struct ogg *ogg = s->priv_data;
     340             :     struct ogg_stream *os;
     341        1339 :     int ret, i = 0;
     342             :     int flags, nsegs;
     343             :     uint64_t gp;
     344             :     uint32_t serial;
     345             :     int size, idx;
     346             :     uint8_t sync[4];
     347        1339 :     int sp = 0;
     348             : 
     349        1339 :     ret = avio_read(bc, sync, 4);
     350        1339 :     if (ret < 4)
     351          20 :         return ret < 0 ? ret : AVERROR_EOF;
     352             : 
     353             :     do {
     354             :         int c;
     355             : 
     356      641807 :         if (sync[sp & 3] == 'O' &&
     357        4482 :             sync[(sp + 1) & 3] == 'g' &&
     358        2498 :             sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
     359        1245 :             break;
     360             : 
     361      637333 :         if(!i && (bc->seekable & AVIO_SEEKABLE_NORMAL) && ogg->page_pos > 0) {
     362           0 :             memset(sync, 0, 4);
     363           0 :             avio_seek(bc, ogg->page_pos+4, SEEK_SET);
     364           0 :             ogg->page_pos = -1;
     365             :         }
     366             : 
     367      637333 :         c = avio_r8(bc);
     368             : 
     369      637333 :         if (avio_feof(bc))
     370          74 :             return AVERROR_EOF;
     371             : 
     372      637259 :         sync[sp++ & 3] = c;
     373      637259 :     } while (i++ < MAX_PAGE_SIZE);
     374             : 
     375        1245 :     if (i >= MAX_PAGE_SIZE) {
     376           0 :         av_log(s, AV_LOG_INFO, "cannot find sync word\n");
     377           0 :         return AVERROR_INVALIDDATA;
     378             :     }
     379             : 
     380        1245 :     if (avio_r8(bc) != 0) {      /* version */
     381           0 :         av_log (s, AV_LOG_ERROR, "ogg page, unsupported version\n");
     382           0 :         return AVERROR_INVALIDDATA;
     383             :     }
     384             : 
     385        1245 :     flags  = avio_r8(bc);
     386        1245 :     gp     = avio_rl64(bc);
     387        1245 :     serial = avio_rl32(bc);
     388        1245 :     avio_skip(bc, 8); /* seq, crc */
     389        1245 :     nsegs  = avio_r8(bc);
     390             : 
     391        1245 :     idx = ogg_find_stream(ogg, serial);
     392        1245 :     if (idx < 0) {
     393          33 :         if (data_packets_seen(ogg))
     394           0 :             idx = ogg_replace_stream(s, serial, nsegs);
     395             :         else
     396          33 :             idx = ogg_new_stream(s, serial);
     397             : 
     398          33 :         if (idx < 0) {
     399           0 :             av_log(s, AV_LOG_ERROR, "failed to create or replace stream\n");
     400           0 :             return idx;
     401             :         }
     402             :     }
     403             : 
     404        1245 :     os = ogg->streams + idx;
     405        1245 :     ogg->page_pos =
     406        1245 :     os->page_pos = avio_tell(bc) - 27;
     407             : 
     408        1245 :     if (os->psize > 0) {
     409         363 :         ret = ogg_new_buf(ogg, idx);
     410         363 :         if (ret < 0)
     411           0 :             return ret;
     412             :     }
     413             : 
     414        1245 :     ret = avio_read(bc, os->segments, nsegs);
     415        1245 :     if (ret < nsegs)
     416           0 :         return ret < 0 ? ret : AVERROR_EOF;
     417             : 
     418        1245 :     os->nsegs = nsegs;
     419        1245 :     os->segp  = 0;
     420             : 
     421        1245 :     size = 0;
     422       39273 :     for (i = 0; i < nsegs; i++)
     423       38028 :         size += os->segments[i];
     424             : 
     425        1245 :     if (!(flags & OGG_FLAG_BOS))
     426        1191 :         os->got_data = 1;
     427             : 
     428        1245 :     if (flags & OGG_FLAG_CONT || os->incomplete) {
     429        1066 :         if (!os->psize) {
     430             :             // If this is the very first segment we started
     431             :             // playback in the middle of a continuation packet.
     432             :             // Discard it since we missed the start of it.
     433         463 :             while (os->segp < os->nsegs) {
     434         292 :                 int seg = os->segments[os->segp++];
     435         292 :                 os->pstart += seg;
     436         292 :                 if (seg < 255)
     437         171 :                     break;
     438             :             }
     439         171 :             os->sync_pos = os->page_pos;
     440             :         }
     441             :     } else {
     442         712 :         os->psize    = 0;
     443         712 :         os->sync_pos = os->page_pos;
     444             :     }
     445             : 
     446        1245 :     if (os->bufsize - os->bufpos < size) {
     447          32 :         uint8_t *nb = av_malloc((os->bufsize *= 2) + AV_INPUT_BUFFER_PADDING_SIZE);
     448          32 :         if (!nb)
     449           0 :             return AVERROR(ENOMEM);
     450          32 :         memcpy(nb, os->buf, os->bufpos);
     451          32 :         av_free(os->buf);
     452          32 :         os->buf = nb;
     453             :     }
     454             : 
     455        1245 :     ret = avio_read(bc, os->buf + os->bufpos, size);
     456        1245 :     if (ret < size)
     457          44 :         return ret < 0 ? ret : AVERROR_EOF;
     458             : 
     459        1201 :     os->bufpos += size;
     460        1201 :     os->granule = gp;
     461        1201 :     os->flags   = flags;
     462             : 
     463        1201 :     memset(os->buf + os->bufpos, 0, AV_INPUT_BUFFER_PADDING_SIZE);
     464        1201 :     if (sid)
     465        1201 :         *sid = idx;
     466             : 
     467        1201 :     return 0;
     468             : }
     469             : 
     470             : /**
     471             :  * @brief find the next Ogg packet
     472             :  * @param *sid is set to the stream for the packet or -1 if there is
     473             :  *             no matching stream, in that case assume all other return
     474             :  *             values to be uninitialized.
     475             :  * @return negative value on error or EOF.
     476             :  */
     477       10317 : static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize,
     478             :                       int64_t *fpos)
     479             : {
     480       10317 :     struct ogg *ogg = s->priv_data;
     481             :     int idx, i, ret;
     482             :     struct ogg_stream *os;
     483       10317 :     int complete = 0;
     484       10317 :     int segp     = 0, psize = 0;
     485             : 
     486       10317 :     av_log(s, AV_LOG_TRACE, "ogg_packet: curidx=%i\n", ogg->curidx);
     487       10317 :     if (sid)
     488       10193 :         *sid = -1;
     489             : 
     490             :     do {
     491       10664 :         idx = ogg->curidx;
     492             : 
     493       22145 :         while (idx < 0) {
     494         923 :             ret = ogg_read_page(s, &idx);
     495         923 :             if (ret < 0)
     496         106 :                 return ret;
     497             :         }
     498             : 
     499       10558 :         os = ogg->streams + idx;
     500             : 
     501       10558 :         av_log(s, AV_LOG_TRACE, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
     502             :                 idx, os->pstart, os->psize, os->segp, os->nsegs);
     503             : 
     504       10558 :         if (!os->codec) {
     505          33 :             if (os->header < 0) {
     506          33 :                 os->codec = ogg_find_codec(os->buf, os->bufpos);
     507          33 :                 if (!os->codec) {
     508           0 :                     av_log(s, AV_LOG_WARNING, "Codec not found\n");
     509           0 :                     os->header = 0;
     510           0 :                     return 0;
     511             :                 }
     512             :             } else {
     513           0 :                 return 0;
     514             :             }
     515             :         }
     516             : 
     517       10558 :         segp  = os->segp;
     518       10558 :         psize = os->psize;
     519             : 
     520       32511 :         while (os->segp < os->nsegs) {
     521       21606 :             int ss = os->segments[os->segp++];
     522       21606 :             os->psize += ss;
     523       21606 :             if (ss < 255) {
     524       10211 :                 complete = 1;
     525       10211 :                 break;
     526             :             }
     527             :         }
     528             : 
     529       10558 :         if (!complete && os->segp == os->nsegs) {
     530         347 :             ogg->curidx    = -1;
     531             :             // Do not set incomplete for empty packets.
     532             :             // Together with the code in ogg_read_page
     533             :             // that discards all continuation of empty packets
     534             :             // we would get an infinite loop.
     535         347 :             os->incomplete = !!os->psize;
     536             :         }
     537       10558 :     } while (!complete);
     538             : 
     539             : 
     540       10211 :     if (os->granule == -1)
     541         178 :         av_log(s, AV_LOG_WARNING,
     542             :                "Page at %"PRId64" is missing granule\n",
     543             :                os->page_pos);
     544             : 
     545       10211 :     ogg->curidx    = idx;
     546       10211 :     os->incomplete = 0;
     547             : 
     548       10211 :     if (os->header) {
     549         126 :         if ((ret = os->codec->header(s, idx)) < 0) {
     550           0 :             av_log(s, AV_LOG_ERROR, "Header processing failed: %s\n", av_err2str(ret));
     551           0 :             return ret;
     552             :         }
     553         126 :         os->header = ret;
     554         126 :         if (!os->header) {
     555          34 :             os->segp  = segp;
     556          34 :             os->psize = psize;
     557             : 
     558             :             // We have reached the first non-header packet in this stream.
     559             :             // Unfortunately more header packets may still follow for others,
     560             :             // but if we continue with header parsing we may lose data packets.
     561          34 :             ogg->headers = 1;
     562             : 
     563             :             // Update the header state for all streams and
     564             :             // compute the data_offset.
     565          34 :             if (!s->internal->data_offset)
     566          32 :                 s->internal->data_offset = os->sync_pos;
     567             : 
     568          71 :             for (i = 0; i < ogg->nstreams; i++) {
     569          37 :                 struct ogg_stream *cur_os = ogg->streams + i;
     570             : 
     571             :                 // if we have a partial non-header packet, its start is
     572             :                 // obviously at or after the data start
     573          37 :                 if (cur_os->incomplete)
     574           0 :                     s->internal->data_offset = FFMIN(s->internal->data_offset, cur_os->sync_pos);
     575             :             }
     576             :         } else {
     577          92 :             os->nb_header++;
     578          92 :             os->pstart += os->psize;
     579          92 :             os->psize   = 0;
     580             :         }
     581             :     } else {
     582       10085 :         os->pflags    = 0;
     583       10085 :         os->pduration = 0;
     584       10085 :         if (os->codec && os->codec->packet) {
     585        9984 :             if ((ret = os->codec->packet(s, idx)) < 0) {
     586           0 :                 av_log(s, AV_LOG_ERROR, "Packet processing failed: %s\n", av_err2str(ret));
     587           0 :                 return ret;
     588             :             }
     589             :         }
     590       10085 :         if (sid)
     591       10085 :             *sid = idx;
     592       10085 :         if (dstart)
     593       10052 :             *dstart = os->pstart;
     594       10085 :         if (dsize)
     595       10052 :             *dsize = os->psize;
     596       10085 :         if (fpos)
     597       10052 :             *fpos = os->sync_pos;
     598       10085 :         os->pstart  += os->psize;
     599       10085 :         os->psize    = 0;
     600       10085 :         if(os->pstart == os->bufpos)
     601         303 :             os->bufpos = os->pstart = 0;
     602       10085 :         os->sync_pos = os->page_pos;
     603             :     }
     604             : 
     605             :     // determine whether there are more complete packets in this page
     606             :     // if not, the page's granule will apply to this packet
     607       10211 :     os->page_end = 1;
     608       16221 :     for (i = os->segp; i < os->nsegs; i++)
     609       15616 :         if (os->segments[i] < 255) {
     610        9606 :             os->page_end = 0;
     611        9606 :             break;
     612             :         }
     613             : 
     614       10211 :     if (os->segp == os->nsegs)
     615         369 :         ogg->curidx = -1;
     616             : 
     617       10211 :     return 0;
     618             : }
     619             : 
     620          32 : static int ogg_get_length(AVFormatContext *s)
     621             : {
     622          32 :     struct ogg *ogg = s->priv_data;
     623             :     int i, ret;
     624             :     int64_t size, end;
     625          32 :     int streams_left=0;
     626             : 
     627          32 :     if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
     628           0 :         return 0;
     629             : 
     630             : // already set
     631          32 :     if (s->duration != AV_NOPTS_VALUE)
     632           0 :         return 0;
     633             : 
     634          32 :     size = avio_size(s->pb);
     635          32 :     if (size < 0)
     636           0 :         return 0;
     637          32 :     end = size > MAX_PAGE_SIZE ? size - MAX_PAGE_SIZE : 0;
     638             : 
     639          32 :     ret = ogg_save(s);
     640          32 :     if (ret < 0)
     641           0 :         return ret;
     642          32 :     avio_seek(s->pb, end, SEEK_SET);
     643          32 :     ogg->page_pos = -1;
     644             : 
     645         448 :     while (!ogg_read_page(s, &i)) {
     646         740 :         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
     647         356 :             ogg->streams[i].codec) {
     648         712 :             s->streams[i]->duration =
     649         712 :                 ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
     650         356 :             if (s->streams[i]->start_time != AV_NOPTS_VALUE) {
     651           0 :                 s->streams[i]->duration -= s->streams[i]->start_time;
     652           0 :                 streams_left-= (ogg->streams[i].got_start==-1);
     653           0 :                 ogg->streams[i].got_start= 1;
     654         356 :             } else if(!ogg->streams[i].got_start) {
     655          33 :                 ogg->streams[i].got_start= -1;
     656          33 :                 streams_left++;
     657             :             }
     658             :         }
     659             :     }
     660             : 
     661          32 :     ogg_restore(s);
     662             : 
     663          32 :     ret = ogg_save(s);
     664          32 :     if (ret < 0)
     665           0 :         return ret;
     666             : 
     667          32 :     avio_seek (s->pb, s->internal->data_offset, SEEK_SET);
     668          32 :     ogg_reset(s);
     669          98 :     while (streams_left > 0 && !ogg_packet(s, &i, NULL, NULL, NULL)) {
     670             :         int64_t pts;
     671          34 :         if (i < 0) continue;
     672          33 :         pts = ogg_calc_pts(s, i, NULL);
     673          33 :         if (s->streams[i]->duration == AV_NOPTS_VALUE)
     674           0 :             continue;
     675          33 :         if (pts != AV_NOPTS_VALUE && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
     676           3 :             s->streams[i]->duration -= pts;
     677           3 :             ogg->streams[i].got_start= 1;
     678           3 :             streams_left--;
     679          30 :         }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
     680          30 :             ogg->streams[i].got_start= 1;
     681          30 :             streams_left--;
     682             :         }
     683             :     }
     684          32 :     ogg_restore (s);
     685             : 
     686          32 :     return 0;
     687             : }
     688             : 
     689          32 : static int ogg_read_close(AVFormatContext *s)
     690             : {
     691          32 :     struct ogg *ogg = s->priv_data;
     692             :     int i;
     693             : 
     694          65 :     for (i = 0; i < ogg->nstreams; i++) {
     695          33 :         free_stream(s, i);
     696             :     }
     697             : 
     698          32 :     ogg->nstreams = 0;
     699             : 
     700          32 :     av_freep(&ogg->streams);
     701          32 :     return 0;
     702             : }
     703             : 
     704          32 : static int ogg_read_header(AVFormatContext *s)
     705             : {
     706          32 :     struct ogg *ogg = s->priv_data;
     707             :     int ret, i;
     708             : 
     709          32 :     ogg->curidx = -1;
     710             : 
     711             :     //linear headers seek from start
     712             :     do {
     713         124 :         ret = ogg_packet(s, NULL, NULL, NULL, NULL);
     714         124 :         if (ret < 0) {
     715           0 :             ogg_read_close(s);
     716           0 :             return ret;
     717             :         }
     718         124 :     } while (!ogg->headers);
     719          32 :     av_log(s, AV_LOG_TRACE, "found headers\n");
     720             : 
     721          65 :     for (i = 0; i < ogg->nstreams; i++) {
     722          33 :         struct ogg_stream *os = ogg->streams + i;
     723             : 
     724          33 :         if (ogg->streams[i].header < 0) {
     725           0 :             av_log(s, AV_LOG_ERROR, "Header parsing failed for stream %d\n", i);
     726           0 :             ogg->streams[i].codec = NULL;
     727           0 :             av_freep(&ogg->streams[i].private);
     728          33 :         } else if (os->codec && os->nb_header < os->codec->nb_header) {
     729           0 :             av_log(s, AV_LOG_WARNING,
     730             :                    "Headers mismatch for stream %d: "
     731             :                    "expected %d received %d.\n",
     732           0 :                    i, os->codec->nb_header, os->nb_header);
     733           0 :             if (s->error_recognition & AV_EF_EXPLODE) {
     734           0 :                 ogg_read_close(s);
     735           0 :                 return AVERROR_INVALIDDATA;
     736             :             }
     737             :         }
     738          33 :         if (os->start_granule != OGG_NOGRANULE_VALUE)
     739           0 :             os->lastpts = s->streams[i]->start_time =
     740           0 :                 ogg_gptopts(s, i, os->start_granule, NULL);
     741             :     }
     742             : 
     743             :     //linear granulepos seek from end
     744          32 :     ret = ogg_get_length(s);
     745          32 :     if (ret < 0) {
     746           0 :         ogg_read_close(s);
     747           0 :         return ret;
     748             :     }
     749             : 
     750          32 :     return 0;
     751             : }
     752             : 
     753       10085 : static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
     754             : {
     755       10085 :     struct ogg *ogg       = s->priv_data;
     756       10085 :     struct ogg_stream *os = ogg->streams + idx;
     757       10085 :     int64_t pts           = AV_NOPTS_VALUE;
     758             : 
     759       10085 :     if (dts)
     760        9978 :         *dts = AV_NOPTS_VALUE;
     761             : 
     762       10085 :     if (os->lastpts != AV_NOPTS_VALUE) {
     763        9738 :         pts         = os->lastpts;
     764        9738 :         os->lastpts = AV_NOPTS_VALUE;
     765             :     }
     766       10085 :     if (os->lastdts != AV_NOPTS_VALUE) {
     767        9647 :         if (dts)
     768        9605 :             *dts = os->lastdts;
     769        9647 :         os->lastdts = AV_NOPTS_VALUE;
     770             :     }
     771       10085 :     if (os->page_end) {
     772         526 :         if (os->granule != -1LL) {
     773         517 :             if (os->codec && os->codec->granule_is_start)
     774           0 :                 pts = ogg_gptopts(s, idx, os->granule, dts);
     775             :             else
     776         517 :                 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
     777         517 :             os->granule = -1LL;
     778             :         }
     779             :     }
     780       10085 :     return pts;
     781             : }
     782             : 
     783       10052 : static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
     784             : {
     785       10052 :     struct ogg *ogg = s->priv_data;
     786       10052 :     struct ogg_stream *os = ogg->streams + idx;
     787       10052 :     int invalid = 0;
     788       10052 :     if (psize) {
     789       10052 :         switch (s->streams[idx]->codecpar->codec_id) {
     790          18 :         case AV_CODEC_ID_THEORA:
     791          18 :             invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40);
     792          18 :         break;
     793         181 :         case AV_CODEC_ID_VP8:
     794         181 :             invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 1);
     795             :         }
     796       10052 :         if (invalid) {
     797           2 :             os->pflags ^= AV_PKT_FLAG_KEY;
     798           2 :             av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
     799           2 :                    (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
     800             :         }
     801             :     }
     802       10052 : }
     803             : 
     804       10006 : static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
     805             : {
     806             :     struct ogg *ogg;
     807             :     struct ogg_stream *os;
     808             :     int idx, ret;
     809             :     int pstart, psize;
     810             :     int64_t fpos, pts, dts;
     811             : 
     812       10006 :     if (s->io_repositioned) {
     813           0 :         ogg_reset(s);
     814           0 :         s->io_repositioned = 0;
     815             :     }
     816             : 
     817             :     //Get an ogg packet
     818       20014 : retry:
     819             :     do {
     820       10007 :         ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
     821       10007 :         if (ret < 0)
     822          28 :             return ret;
     823       19957 :     } while (idx < 0 || !s->streams[idx]);
     824             : 
     825        9978 :     ogg = s->priv_data;
     826        9978 :     os  = ogg->streams + idx;
     827             : 
     828             :     // pflags might not be set until after this
     829        9978 :     pts = ogg_calc_pts(s, idx, &dts);
     830        9978 :     ogg_validate_keyframe(s, idx, pstart, psize);
     831             : 
     832        9978 :     if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
     833           0 :         goto retry;
     834        9978 :     os->keyframe_seek = 0;
     835             : 
     836             :     //Alloc a pkt
     837        9978 :     ret = av_new_packet(pkt, psize);
     838        9978 :     if (ret < 0)
     839           0 :         return ret;
     840        9978 :     pkt->stream_index = idx;
     841        9978 :     memcpy(pkt->data, os->buf + pstart, psize);
     842             : 
     843        9978 :     pkt->pts      = pts;
     844        9978 :     pkt->dts      = dts;
     845        9978 :     pkt->flags    = os->pflags;
     846        9978 :     pkt->duration = os->pduration;
     847        9978 :     pkt->pos      = fpos;
     848             : 
     849        9978 :     if (os->end_trimming) {
     850           1 :         uint8_t *side_data = av_packet_new_side_data(pkt,
     851             :                                                      AV_PKT_DATA_SKIP_SAMPLES,
     852             :                                                      10);
     853           1 :         if(!side_data)
     854           0 :             goto fail;
     855           1 :         AV_WL32(side_data + 4, os->end_trimming);
     856           1 :         os->end_trimming = 0;
     857             :     }
     858             : 
     859        9978 :     if (os->new_metadata) {
     860          25 :         uint8_t *side_data = av_packet_new_side_data(pkt,
     861             :                                                      AV_PKT_DATA_METADATA_UPDATE,
     862          25 :                                                      os->new_metadata_size);
     863          25 :         if(!side_data)
     864           0 :             goto fail;
     865             : 
     866          25 :         memcpy(side_data, os->new_metadata, os->new_metadata_size);
     867          25 :         av_freep(&os->new_metadata);
     868          25 :         os->new_metadata_size = 0;
     869             :     }
     870             : 
     871        9978 :     return psize;
     872           0 : fail:
     873           0 :     av_packet_unref(pkt);
     874           0 :     return AVERROR(ENOMEM);
     875             : }
     876             : 
     877         152 : static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
     878             :                                   int64_t *pos_arg, int64_t pos_limit)
     879             : {
     880         152 :     struct ogg *ogg = s->priv_data;
     881         152 :     AVIOContext *bc = s->pb;
     882         152 :     int64_t pts     = AV_NOPTS_VALUE;
     883         152 :     int64_t keypos  = -1;
     884             :     int i;
     885             :     int pstart, psize;
     886         152 :     avio_seek(bc, *pos_arg, SEEK_SET);
     887         152 :     ogg_reset(s);
     888             : 
     889         152 :     while (   avio_tell(bc) <= pos_limit
     890         152 :            && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
     891          74 :         if (i == stream_index) {
     892          74 :             struct ogg_stream *os = ogg->streams + stream_index;
     893             :             // Do not trust the last timestamps of an ogm video
     894          74 :             if (    (os->flags & OGG_FLAG_EOS)
     895          26 :                 && !(os->flags & OGG_FLAG_BOS)
     896          26 :                 && os->codec == &ff_ogm_video_codec)
     897           0 :                 continue;
     898          74 :             pts = ogg_calc_pts(s, i, NULL);
     899          74 :             ogg_validate_keyframe(s, i, pstart, psize);
     900          74 :             if (os->pflags & AV_PKT_FLAG_KEY) {
     901           0 :                 keypos = *pos_arg;
     902          74 :             } else if (os->keyframe_seek) {
     903             :                 // if we had a previous keyframe but no pts for it,
     904             :                 // return that keyframe with this pts value.
     905           0 :                 if (keypos >= 0)
     906           0 :                     *pos_arg = keypos;
     907             :                 else
     908           0 :                     pts = AV_NOPTS_VALUE;
     909             :             }
     910             :         }
     911          74 :         if (pts != AV_NOPTS_VALUE)
     912          74 :             break;
     913             :     }
     914         152 :     ogg_reset(s);
     915         152 :     return pts;
     916             : }
     917             : 
     918          28 : static int ogg_read_seek(AVFormatContext *s, int stream_index,
     919             :                          int64_t timestamp, int flags)
     920             : {
     921          28 :     struct ogg *ogg       = s->priv_data;
     922          28 :     struct ogg_stream *os = ogg->streams + stream_index;
     923             :     int ret;
     924             : 
     925          28 :     av_assert0(stream_index < ogg->nstreams);
     926             :     // Ensure everything is reset even when seeking via
     927             :     // the generated index.
     928          28 :     ogg_reset(s);
     929             : 
     930             :     // Try seeking to a keyframe first. If this fails (very possible),
     931             :     // av_seek_frame will fall back to ignoring keyframes
     932          28 :     if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO
     933           0 :         && !(flags & AVSEEK_FLAG_ANY))
     934           0 :         os->keyframe_seek = 1;
     935             : 
     936          28 :     ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
     937          28 :     ogg_reset(s);
     938          28 :     os  = ogg->streams + stream_index;
     939          28 :     if (ret < 0)
     940           0 :         os->keyframe_seek = 0;
     941          28 :     return ret;
     942             : }
     943             : 
     944        6217 : static int ogg_probe(AVProbeData *p)
     945             : {
     946        6217 :     if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
     947          32 :         return AVPROBE_SCORE_MAX;
     948        6185 :     return 0;
     949             : }
     950             : 
     951             : AVInputFormat ff_ogg_demuxer = {
     952             :     .name           = "ogg",
     953             :     .long_name      = NULL_IF_CONFIG_SMALL("Ogg"),
     954             :     .priv_data_size = sizeof(struct ogg),
     955             :     .read_probe     = ogg_probe,
     956             :     .read_header    = ogg_read_header,
     957             :     .read_packet    = ogg_read_packet,
     958             :     .read_close     = ogg_read_close,
     959             :     .read_seek      = ogg_read_seek,
     960             :     .read_timestamp = ogg_read_timestamp,
     961             :     .extensions     = "ogg",
     962             :     .flags          = AVFMT_GENERIC_INDEX | AVFMT_TS_DISCONT | AVFMT_NOBINSEARCH,
     963             : };

Generated by: LCOV version 1.13