libavformat/oggparsespeex.c
cb4ddf77
 /*
       Copyright (C) 2008  Reimar Döffinger
 
       Permission is hereby granted, free of charge, to any person
       obtaining a copy of this software and associated documentation
       files (the "Software"), to deal in the Software without
       restriction, including without limitation the rights to use, copy,
       modify, merge, publish, distribute, sublicense, and/or sell copies
       of the Software, and to permit persons to whom the Software is
       furnished to do so, subject to the following conditions:
 
       The above copyright notice and this permission notice shall be
       included in all copies or substantial portions of the Software.
 
       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
       NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
       WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
       DEALINGS IN THE SOFTWARE.
 **/
 
 #include <stdlib.h>
245976da
 #include "libavutil/bswap.h"
 #include "libavutil/avstring.h"
9106a698
 #include "libavcodec/get_bits.h"
245976da
 #include "libavcodec/bytestream.h"
cb4ddf77
 #include "avformat.h"
 #include "oggdec.h"
 
15299b38
 struct speex_params {
     int final_packet_duration;
8f8320d7
     int seq;
15299b38
 };
 
cb4ddf77
 static int speex_header(AVFormatContext *s, int idx) {
77be08ee
     struct ogg *ogg = s->priv_data;
     struct ogg_stream *os = ogg->streams + idx;
8f8320d7
     struct speex_params *spxp = os->private;
cb4ddf77
     AVStream *st = s->streams[idx];
     uint8_t *p = os->buf + os->pstart;
 
8f8320d7
     if (!spxp) {
         spxp = av_mallocz(sizeof(*spxp));
         os->private = spxp;
     }
 
     if (spxp->seq > 1)
6e6abd02
         return 0;
cb4ddf77
 
8f8320d7
     if (spxp->seq == 0) {
eb5f3c54
         int frames_per_packet;
72415b2a
         st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
1a4ab332
         st->codec->codec_id = CODEC_ID_SPEEX;
cb4ddf77
 
1a4ab332
         st->codec->sample_rate = AV_RL32(p + 36);
         st->codec->channels = AV_RL32(p + 48);
eb5f3c54
 
         /* We treat the whole Speex packet as a single frame everywhere Speex
2d2b5a14
            is handled in FFmpeg.  This avoids the complexities of splitting
eb5f3c54
            and joining individual Speex frames, which are not always
            byte-aligned. */
533c3c84
         st->codec->frame_size = AV_RL32(p + 56);
eb5f3c54
         frames_per_packet     = AV_RL32(p + 64);
         if (frames_per_packet)
             st->codec->frame_size *= frames_per_packet;
 
1a4ab332
         st->codec->extradata_size = os->psize;
12d7c079
         st->codec->extradata = av_malloc(st->codec->extradata_size
                                          + FF_INPUT_BUFFER_PADDING_SIZE);
1a4ab332
         memcpy(st->codec->extradata, p, st->codec->extradata_size);
cb4ddf77
 
a351110e
         av_set_pts_info(st, 64, 1, st->codec->sample_rate);
6e6abd02
     } else
b53cde48
         ff_vorbis_comment(s, &st->metadata, p, os->psize);
cb4ddf77
 
8f8320d7
     spxp->seq++;
6e6abd02
     return 1;
cb4ddf77
 }
 
15299b38
 static int ogg_page_packets(struct ogg_stream *os)
 {
     int i;
     int packets = 0;
     for (i = 0; i < os->nsegs; i++)
         if (os->segments[i] < 255)
             packets++;
     return packets;
 }
 
 static int speex_packet(AVFormatContext *s, int idx)
 {
     struct ogg *ogg = s->priv_data;
     struct ogg_stream *os = ogg->streams + idx;
     struct speex_params *spxp = os->private;
     int packet_size = s->streams[idx]->codec->frame_size;
 
5e15c7d9
     if (os->flags & OGG_FLAG_EOS && os->lastpts != AV_NOPTS_VALUE &&
         os->granule > 0) {
15299b38
         /* first packet of final page. we have to calculate the final packet
            duration here because it is the only place we know the next-to-last
            granule position. */
5e15c7d9
         spxp->final_packet_duration = os->granule - os->lastpts -
15299b38
                                       packet_size * (ogg_page_packets(os) - 1);
     }
 
5e15c7d9
     if (!os->lastpts && os->granule > 0)
15299b38
         /* first packet */
         os->pduration = os->granule - packet_size * (ogg_page_packets(os) - 1);
     else if (os->flags & OGG_FLAG_EOS && os->segp == os->nsegs &&
              spxp->final_packet_duration)
         /* final packet */
         os->pduration = spxp->final_packet_duration;
     else
         os->pduration = packet_size;
 
     return 0;
 }
 
77be08ee
 const struct ogg_codec ff_speex_codec = {
cb4ddf77
     .magic = "Speex   ",
     .magicsize = 8,
15299b38
     .header = speex_header,
     .packet = speex_packet
cb4ddf77
 };