Libav
|
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 "oggdec.h" 00032 00033 struct speex_params { 00034 int final_packet_duration; 00035 int seq; 00036 }; 00037 00038 static int speex_header(AVFormatContext *s, int idx) { 00039 struct ogg *ogg = s->priv_data; 00040 struct ogg_stream *os = ogg->streams + idx; 00041 struct speex_params *spxp = os->private; 00042 AVStream *st = s->streams[idx]; 00043 uint8_t *p = os->buf + os->pstart; 00044 00045 if (!spxp) { 00046 spxp = av_mallocz(sizeof(*spxp)); 00047 os->private = spxp; 00048 } 00049 00050 if (spxp->seq > 1) 00051 return 0; 00052 00053 if (spxp->seq == 0) { 00054 int frames_per_packet; 00055 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; 00056 st->codec->codec_id = CODEC_ID_SPEEX; 00057 00058 st->codec->sample_rate = AV_RL32(p + 36); 00059 st->codec->channels = AV_RL32(p + 48); 00060 00061 /* We treat the whole Speex packet as a single frame everywhere Speex 00062 is handled in FFmpeg. This avoids the complexities of splitting 00063 and joining individual Speex frames, which are not always 00064 byte-aligned. */ 00065 st->codec->frame_size = AV_RL32(p + 56); 00066 frames_per_packet = AV_RL32(p + 64); 00067 if (frames_per_packet) 00068 st->codec->frame_size *= frames_per_packet; 00069 00070 st->codec->extradata_size = os->psize; 00071 st->codec->extradata = av_malloc(st->codec->extradata_size 00072 + FF_INPUT_BUFFER_PADDING_SIZE); 00073 memcpy(st->codec->extradata, p, st->codec->extradata_size); 00074 00075 st->time_base.num = 1; 00076 st->time_base.den = st->codec->sample_rate; 00077 } else 00078 ff_vorbis_comment(s, &st->metadata, p, os->psize); 00079 00080 spxp->seq++; 00081 return 1; 00082 } 00083 00084 static int ogg_page_packets(struct ogg_stream *os) 00085 { 00086 int i; 00087 int packets = 0; 00088 for (i = 0; i < os->nsegs; i++) 00089 if (os->segments[i] < 255) 00090 packets++; 00091 return packets; 00092 } 00093 00094 static int speex_packet(AVFormatContext *s, int idx) 00095 { 00096 struct ogg *ogg = s->priv_data; 00097 struct ogg_stream *os = ogg->streams + idx; 00098 struct speex_params *spxp = os->private; 00099 int packet_size = s->streams[idx]->codec->frame_size; 00100 00101 if (os->flags & OGG_FLAG_EOS && os->lastpts != AV_NOPTS_VALUE && 00102 os->granule > 0) { 00103 /* first packet of final page. we have to calculate the final packet 00104 duration here because it is the only place we know the next-to-last 00105 granule position. */ 00106 spxp->final_packet_duration = os->granule - os->lastpts - 00107 packet_size * (ogg_page_packets(os) - 1); 00108 } 00109 00110 if (!os->lastpts && os->granule > 0) 00111 /* first packet */ 00112 os->pduration = os->granule - packet_size * (ogg_page_packets(os) - 1); 00113 else if (os->flags & OGG_FLAG_EOS && os->segp == os->nsegs && 00114 spxp->final_packet_duration) 00115 /* final packet */ 00116 os->pduration = spxp->final_packet_duration; 00117 else 00118 os->pduration = packet_size; 00119 00120 return 0; 00121 } 00122 00123 const struct ogg_codec ff_speex_codec = { 00124 .magic = "Speex ", 00125 .magicsize = 8, 00126 .header = speex_header, 00127 .packet = speex_packet 00128 };