summaryrefslogtreecommitdiff
path: root/ffmpeg/libavformat/oggparsespeex.c
diff options
context:
space:
mode:
Diffstat (limited to 'ffmpeg/libavformat/oggparsespeex.c')
-rw-r--r--ffmpeg/libavformat/oggparsespeex.c139
1 files changed, 139 insertions, 0 deletions
diff --git a/ffmpeg/libavformat/oggparsespeex.c b/ffmpeg/libavformat/oggparsespeex.c
new file mode 100644
index 0000000..63e6370
--- /dev/null
+++ b/ffmpeg/libavformat/oggparsespeex.c
@@ -0,0 +1,139 @@
+/*
+ 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>
+#include "libavutil/bswap.h"
+#include "libavutil/avstring.h"
+#include "libavutil/channel_layout.h"
+#include "libavcodec/get_bits.h"
+#include "libavcodec/bytestream.h"
+#include "avformat.h"
+#include "internal.h"
+#include "oggdec.h"
+
+struct speex_params {
+ int packet_size;
+ int final_packet_duration;
+ int seq;
+};
+
+static int speex_header(AVFormatContext *s, int idx) {
+ struct ogg *ogg = s->priv_data;
+ struct ogg_stream *os = ogg->streams + idx;
+ struct speex_params *spxp = os->private;
+ AVStream *st = s->streams[idx];
+ uint8_t *p = os->buf + os->pstart;
+
+ if (!spxp) {
+ spxp = av_mallocz(sizeof(*spxp));
+ os->private = spxp;
+ }
+
+ if (spxp->seq > 1)
+ return 0;
+
+ if (spxp->seq == 0) {
+ int frames_per_packet;
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id = AV_CODEC_ID_SPEEX;
+
+ if (os->psize < 68) {
+ av_log(s, AV_LOG_ERROR, "speex packet too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ st->codec->sample_rate = AV_RL32(p + 36);
+ st->codec->channels = AV_RL32(p + 48);
+ if (st->codec->channels < 1 || st->codec->channels > 2) {
+ av_log(s, AV_LOG_ERROR, "invalid channel count. Speex must be mono or stereo.\n");
+ return AVERROR_INVALIDDATA;
+ }
+ st->codec->channel_layout = st->codec->channels == 1 ? AV_CH_LAYOUT_MONO :
+ AV_CH_LAYOUT_STEREO;
+
+ spxp->packet_size = AV_RL32(p + 56);
+ frames_per_packet = AV_RL32(p + 64);
+ if (frames_per_packet)
+ spxp->packet_size *= frames_per_packet;
+
+ st->codec->extradata_size = os->psize;
+ st->codec->extradata = av_malloc(st->codec->extradata_size
+ + FF_INPUT_BUFFER_PADDING_SIZE);
+ memcpy(st->codec->extradata, p, st->codec->extradata_size);
+
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+ } else
+ ff_vorbis_comment(s, &st->metadata, p, os->psize);
+
+ spxp->seq++;
+ return 1;
+}
+
+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 = spxp->packet_size;
+
+ if (os->flags & OGG_FLAG_EOS && os->lastpts != AV_NOPTS_VALUE &&
+ os->granule > 0) {
+ /* 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. */
+ spxp->final_packet_duration = os->granule - os->lastpts -
+ packet_size * (ogg_page_packets(os) - 1);
+ }
+
+ if (!os->lastpts && os->granule > 0)
+ /* first packet */
+ os->lastpts = os->lastdts = os->granule - packet_size *
+ ogg_page_packets(os);
+ 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;
+}
+
+const struct ogg_codec ff_speex_codec = {
+ .magic = "Speex ",
+ .magicsize = 8,
+ .header = speex_header,
+ .packet = speex_packet,
+ .nb_header = 2,
+};