1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci Copyright (C) 2008 Reimar Döffinger 3cabdff1aSopenharmony_ci 4cabdff1aSopenharmony_ci Permission is hereby granted, free of charge, to any person 5cabdff1aSopenharmony_ci obtaining a copy of this software and associated documentation 6cabdff1aSopenharmony_ci files (the "Software"), to deal in the Software without 7cabdff1aSopenharmony_ci restriction, including without limitation the rights to use, copy, 8cabdff1aSopenharmony_ci modify, merge, publish, distribute, sublicense, and/or sell copies 9cabdff1aSopenharmony_ci of the Software, and to permit persons to whom the Software is 10cabdff1aSopenharmony_ci furnished to do so, subject to the following conditions: 11cabdff1aSopenharmony_ci 12cabdff1aSopenharmony_ci The above copyright notice and this permission notice shall be 13cabdff1aSopenharmony_ci included in all copies or substantial portions of the Software. 14cabdff1aSopenharmony_ci 15cabdff1aSopenharmony_ci THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16cabdff1aSopenharmony_ci EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17cabdff1aSopenharmony_ci MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18cabdff1aSopenharmony_ci NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19cabdff1aSopenharmony_ci HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20cabdff1aSopenharmony_ci WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21cabdff1aSopenharmony_ci OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22cabdff1aSopenharmony_ci DEALINGS IN THE SOFTWARE. 23cabdff1aSopenharmony_ci**/ 24cabdff1aSopenharmony_ci 25cabdff1aSopenharmony_ci#include "libavutil/channel_layout.h" 26cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 27cabdff1aSopenharmony_ci 28cabdff1aSopenharmony_ci#include "avformat.h" 29cabdff1aSopenharmony_ci#include "internal.h" 30cabdff1aSopenharmony_ci#include "oggdec.h" 31cabdff1aSopenharmony_ci 32cabdff1aSopenharmony_cistruct speex_params { 33cabdff1aSopenharmony_ci int packet_size; 34cabdff1aSopenharmony_ci int final_packet_duration; 35cabdff1aSopenharmony_ci int seq; 36cabdff1aSopenharmony_ci}; 37cabdff1aSopenharmony_ci 38cabdff1aSopenharmony_cistatic int speex_header(AVFormatContext *s, int idx) { 39cabdff1aSopenharmony_ci struct ogg *ogg = s->priv_data; 40cabdff1aSopenharmony_ci struct ogg_stream *os = ogg->streams + idx; 41cabdff1aSopenharmony_ci struct speex_params *spxp = os->private; 42cabdff1aSopenharmony_ci AVStream *st = s->streams[idx]; 43cabdff1aSopenharmony_ci uint8_t *p = os->buf + os->pstart; 44cabdff1aSopenharmony_ci int ret; 45cabdff1aSopenharmony_ci 46cabdff1aSopenharmony_ci if (!spxp) { 47cabdff1aSopenharmony_ci spxp = av_mallocz(sizeof(*spxp)); 48cabdff1aSopenharmony_ci if (!spxp) 49cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 50cabdff1aSopenharmony_ci os->private = spxp; 51cabdff1aSopenharmony_ci } 52cabdff1aSopenharmony_ci 53cabdff1aSopenharmony_ci if (spxp->seq > 1) 54cabdff1aSopenharmony_ci return 0; 55cabdff1aSopenharmony_ci 56cabdff1aSopenharmony_ci if (spxp->seq == 0) { 57cabdff1aSopenharmony_ci int frames_per_packet; 58cabdff1aSopenharmony_ci int channels; 59cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; 60cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_SPEEX; 61cabdff1aSopenharmony_ci 62cabdff1aSopenharmony_ci if (os->psize < 68) { 63cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "speex packet too small\n"); 64cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 65cabdff1aSopenharmony_ci } 66cabdff1aSopenharmony_ci 67cabdff1aSopenharmony_ci st->codecpar->sample_rate = AV_RL32(p + 36); 68cabdff1aSopenharmony_ci if (st->codecpar->sample_rate <= 0) { 69cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Invalid sample rate %d\n", st->codecpar->sample_rate); 70cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 71cabdff1aSopenharmony_ci } 72cabdff1aSopenharmony_ci channels = AV_RL32(p + 48); 73cabdff1aSopenharmony_ci if (channels < 1 || channels > 2) { 74cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "invalid channel count. Speex must be mono or stereo.\n"); 75cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 76cabdff1aSopenharmony_ci } 77cabdff1aSopenharmony_ci av_channel_layout_default(&st->codecpar->ch_layout, channels); 78cabdff1aSopenharmony_ci 79cabdff1aSopenharmony_ci spxp->packet_size = AV_RL32(p + 56); 80cabdff1aSopenharmony_ci frames_per_packet = AV_RL32(p + 64); 81cabdff1aSopenharmony_ci if (spxp->packet_size < 0 || 82cabdff1aSopenharmony_ci frames_per_packet < 0 || 83cabdff1aSopenharmony_ci spxp->packet_size * (int64_t)frames_per_packet > INT32_MAX / 256) { 84cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "invalid packet_size, frames_per_packet %d %d\n", spxp->packet_size, frames_per_packet); 85cabdff1aSopenharmony_ci spxp->packet_size = 0; 86cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 87cabdff1aSopenharmony_ci } 88cabdff1aSopenharmony_ci if (frames_per_packet) 89cabdff1aSopenharmony_ci spxp->packet_size *= frames_per_packet; 90cabdff1aSopenharmony_ci 91cabdff1aSopenharmony_ci if ((ret = ff_alloc_extradata(st->codecpar, os->psize)) < 0) 92cabdff1aSopenharmony_ci return ret; 93cabdff1aSopenharmony_ci memcpy(st->codecpar->extradata, p, st->codecpar->extradata_size); 94cabdff1aSopenharmony_ci 95cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate); 96cabdff1aSopenharmony_ci } else 97cabdff1aSopenharmony_ci ff_vorbis_stream_comment(s, st, p, os->psize); 98cabdff1aSopenharmony_ci 99cabdff1aSopenharmony_ci spxp->seq++; 100cabdff1aSopenharmony_ci return 1; 101cabdff1aSopenharmony_ci} 102cabdff1aSopenharmony_ci 103cabdff1aSopenharmony_cistatic int ogg_page_packets(struct ogg_stream *os) 104cabdff1aSopenharmony_ci{ 105cabdff1aSopenharmony_ci int i; 106cabdff1aSopenharmony_ci int packets = 0; 107cabdff1aSopenharmony_ci for (i = 0; i < os->nsegs; i++) 108cabdff1aSopenharmony_ci if (os->segments[i] < 255) 109cabdff1aSopenharmony_ci packets++; 110cabdff1aSopenharmony_ci return packets; 111cabdff1aSopenharmony_ci} 112cabdff1aSopenharmony_ci 113cabdff1aSopenharmony_cistatic int speex_packet(AVFormatContext *s, int idx) 114cabdff1aSopenharmony_ci{ 115cabdff1aSopenharmony_ci struct ogg *ogg = s->priv_data; 116cabdff1aSopenharmony_ci struct ogg_stream *os = ogg->streams + idx; 117cabdff1aSopenharmony_ci struct speex_params *spxp = os->private; 118cabdff1aSopenharmony_ci int packet_size = spxp->packet_size; 119cabdff1aSopenharmony_ci 120cabdff1aSopenharmony_ci if (os->flags & OGG_FLAG_EOS && os->lastpts != AV_NOPTS_VALUE && 121cabdff1aSopenharmony_ci os->granule > 0) { 122cabdff1aSopenharmony_ci /* first packet of final page. we have to calculate the final packet 123cabdff1aSopenharmony_ci duration here because it is the only place we know the next-to-last 124cabdff1aSopenharmony_ci granule position. */ 125cabdff1aSopenharmony_ci spxp->final_packet_duration = os->granule - os->lastpts - 126cabdff1aSopenharmony_ci packet_size * (ogg_page_packets(os) - 1); 127cabdff1aSopenharmony_ci } 128cabdff1aSopenharmony_ci 129cabdff1aSopenharmony_ci if (!os->lastpts && os->granule > 0) 130cabdff1aSopenharmony_ci /* first packet */ 131cabdff1aSopenharmony_ci os->lastpts = os->lastdts = os->granule - packet_size * 132cabdff1aSopenharmony_ci ogg_page_packets(os); 133cabdff1aSopenharmony_ci if (os->flags & OGG_FLAG_EOS && os->segp == os->nsegs && 134cabdff1aSopenharmony_ci spxp->final_packet_duration) 135cabdff1aSopenharmony_ci /* final packet */ 136cabdff1aSopenharmony_ci os->pduration = spxp->final_packet_duration; 137cabdff1aSopenharmony_ci else 138cabdff1aSopenharmony_ci os->pduration = packet_size; 139cabdff1aSopenharmony_ci 140cabdff1aSopenharmony_ci return 0; 141cabdff1aSopenharmony_ci} 142cabdff1aSopenharmony_ci 143cabdff1aSopenharmony_ciconst struct ogg_codec ff_speex_codec = { 144cabdff1aSopenharmony_ci .magic = "Speex ", 145cabdff1aSopenharmony_ci .magicsize = 8, 146cabdff1aSopenharmony_ci .header = speex_header, 147cabdff1aSopenharmony_ci .packet = speex_packet, 148cabdff1aSopenharmony_ci .nb_header = 2, 149cabdff1aSopenharmony_ci}; 150