libavformat/oggparsespeex.c
Go to the documentation of this file.
00001 /*
00002       Copyright (C) 2008  Reimar Döffinger
00003 
00004       Permission is hereby granted, free of charge, to any person
00005       obtaining a copy of this software and associated documentation
00006       files (the "Software"), to deal in the Software without
00007       restriction, including without limitation the rights to use, copy,
00008       modify, merge, publish, distribute, sublicense, and/or sell copies
00009       of the Software, and to permit persons to whom the Software is
00010       furnished to do so, subject to the following conditions:
00011 
00012       The above copyright notice and this permission notice shall be
00013       included in all copies or substantial portions of the Software.
00014 
00015       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00016       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00017       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00018       NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
00019       HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
00020       WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00021       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00022       DEALINGS IN THE SOFTWARE.
00023 **/
00024 
00025 #include <stdlib.h>
00026 #include "libavutil/bswap.h"
00027 #include "libavutil/avstring.h"
00028 #include "libavcodec/get_bits.h"
00029 #include "libavcodec/bytestream.h"
00030 #include "avformat.h"
00031 #include "internal.h"
00032 #include "oggdec.h"
00033 
00034 struct speex_params {
00035     int packet_size;
00036     int final_packet_duration;
00037     int seq;
00038 };
00039 
00040 static int speex_header(AVFormatContext *s, int idx) {
00041     struct ogg *ogg = s->priv_data;
00042     struct ogg_stream *os = ogg->streams + idx;
00043     struct speex_params *spxp = os->private;
00044     AVStream *st = s->streams[idx];
00045     uint8_t *p = os->buf + os->pstart;
00046 
00047     if (!spxp) {
00048         spxp = av_mallocz(sizeof(*spxp));
00049         os->private = spxp;
00050     }
00051 
00052     if (spxp->seq > 1)
00053         return 0;
00054 
00055     if (spxp->seq == 0) {
00056         int frames_per_packet;
00057         st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00058         st->codec->codec_id = CODEC_ID_SPEEX;
00059 
00060         st->codec->sample_rate = AV_RL32(p + 36);
00061         st->codec->channels = AV_RL32(p + 48);
00062 
00063         spxp->packet_size  = AV_RL32(p + 56);
00064         frames_per_packet  = AV_RL32(p + 64);
00065         if (frames_per_packet)
00066             spxp->packet_size *= frames_per_packet;
00067 
00068         st->codec->extradata_size = os->psize;
00069         st->codec->extradata = av_malloc(st->codec->extradata_size
00070                                          + FF_INPUT_BUFFER_PADDING_SIZE);
00071         memcpy(st->codec->extradata, p, st->codec->extradata_size);
00072 
00073         avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
00074     } else
00075         ff_vorbis_comment(s, &st->metadata, p, os->psize);
00076 
00077     spxp->seq++;
00078     return 1;
00079 }
00080 
00081 static int ogg_page_packets(struct ogg_stream *os)
00082 {
00083     int i;
00084     int packets = 0;
00085     for (i = 0; i < os->nsegs; i++)
00086         if (os->segments[i] < 255)
00087             packets++;
00088     return packets;
00089 }
00090 
00091 static int speex_packet(AVFormatContext *s, int idx)
00092 {
00093     struct ogg *ogg = s->priv_data;
00094     struct ogg_stream *os = ogg->streams + idx;
00095     struct speex_params *spxp = os->private;
00096     int packet_size = spxp->packet_size;
00097 
00098     if (os->flags & OGG_FLAG_EOS && os->lastpts != AV_NOPTS_VALUE &&
00099         os->granule > 0) {
00100         /* first packet of final page. we have to calculate the final packet
00101            duration here because it is the only place we know the next-to-last
00102            granule position. */
00103         spxp->final_packet_duration = os->granule - os->lastpts -
00104                                       packet_size * (ogg_page_packets(os) - 1);
00105     }
00106 
00107     if (!os->lastpts && os->granule > 0)
00108         /* first packet */
00109         os->lastpts = os->lastdts = os->granule - packet_size *
00110                                     ogg_page_packets(os);
00111     if (os->flags & OGG_FLAG_EOS && os->segp == os->nsegs &&
00112         spxp->final_packet_duration)
00113         /* final packet */
00114         os->pduration = spxp->final_packet_duration;
00115     else
00116         os->pduration = packet_size;
00117 
00118     return 0;
00119 }
00120 
00121 const struct ogg_codec ff_speex_codec = {
00122     .magic = "Speex   ",
00123     .magicsize = 8,
00124     .header = speex_header,
00125     .packet = speex_packet
00126 };