diff options
Diffstat (limited to 'ffmpeg/libavformat/oggparsespeex.c')
| -rw-r--r-- | ffmpeg/libavformat/oggparsespeex.c | 139 |
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, +}; |
