00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <stdlib.h>
00026 #include "libavutil/bswap.h"
00027 #include "libavutil/avstring.h"
00028 #include "libavutil/channel_layout.h"
00029 #include "libavcodec/get_bits.h"
00030 #include "libavcodec/bytestream.h"
00031 #include "avformat.h"
00032 #include "internal.h"
00033 #include "oggdec.h"
00034
00035 struct speex_params {
00036 int packet_size;
00037 int final_packet_duration;
00038 int seq;
00039 };
00040
00041 static int speex_header(AVFormatContext *s, int idx) {
00042 struct ogg *ogg = s->priv_data;
00043 struct ogg_stream *os = ogg->streams + idx;
00044 struct speex_params *spxp = os->private;
00045 AVStream *st = s->streams[idx];
00046 uint8_t *p = os->buf + os->pstart;
00047
00048 if (!spxp) {
00049 spxp = av_mallocz(sizeof(*spxp));
00050 os->private = spxp;
00051 }
00052
00053 if (spxp->seq > 1)
00054 return 0;
00055
00056 if (spxp->seq == 0) {
00057 int frames_per_packet;
00058 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00059 st->codec->codec_id = AV_CODEC_ID_SPEEX;
00060
00061 if (os->psize < 68) {
00062 av_log(s, AV_LOG_ERROR, "speex packet too small\n");
00063 return AVERROR_INVALIDDATA;
00064 }
00065
00066 st->codec->sample_rate = AV_RL32(p + 36);
00067 st->codec->channels = AV_RL32(p + 48);
00068 if (st->codec->channels < 1 || st->codec->channels > 2) {
00069 av_log(s, AV_LOG_ERROR, "invalid channel count. Speex must be mono or stereo.\n");
00070 return AVERROR_INVALIDDATA;
00071 }
00072 st->codec->channel_layout = st->codec->channels == 1 ? AV_CH_LAYOUT_MONO :
00073 AV_CH_LAYOUT_STEREO;
00074
00075 spxp->packet_size = AV_RL32(p + 56);
00076 frames_per_packet = AV_RL32(p + 64);
00077 if (frames_per_packet)
00078 spxp->packet_size *= frames_per_packet;
00079
00080 st->codec->extradata_size = os->psize;
00081 st->codec->extradata = av_malloc(st->codec->extradata_size
00082 + FF_INPUT_BUFFER_PADDING_SIZE);
00083 memcpy(st->codec->extradata, p, st->codec->extradata_size);
00084
00085 avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
00086 } else
00087 ff_vorbis_comment(s, &st->metadata, p, os->psize);
00088
00089 spxp->seq++;
00090 return 1;
00091 }
00092
00093 static int ogg_page_packets(struct ogg_stream *os)
00094 {
00095 int i;
00096 int packets = 0;
00097 for (i = 0; i < os->nsegs; i++)
00098 if (os->segments[i] < 255)
00099 packets++;
00100 return packets;
00101 }
00102
00103 static int speex_packet(AVFormatContext *s, int idx)
00104 {
00105 struct ogg *ogg = s->priv_data;
00106 struct ogg_stream *os = ogg->streams + idx;
00107 struct speex_params *spxp = os->private;
00108 int packet_size = spxp->packet_size;
00109
00110 if (os->flags & OGG_FLAG_EOS && os->lastpts != AV_NOPTS_VALUE &&
00111 os->granule > 0) {
00112
00113
00114
00115 spxp->final_packet_duration = os->granule - os->lastpts -
00116 packet_size * (ogg_page_packets(os) - 1);
00117 }
00118
00119 if (!os->lastpts && os->granule > 0)
00120
00121 os->lastpts = os->lastdts = os->granule - packet_size *
00122 ogg_page_packets(os);
00123 if (os->flags & OGG_FLAG_EOS && os->segp == os->nsegs &&
00124 spxp->final_packet_duration)
00125
00126 os->pduration = spxp->final_packet_duration;
00127 else
00128 os->pduration = packet_size;
00129
00130 return 0;
00131 }
00132
00133 const struct ogg_codec ff_speex_codec = {
00134 .magic = "Speex ",
00135 .magicsize = 8,
00136 .header = speex_header,
00137 .packet = speex_packet,
00138 .nb_header = 2,
00139 };