/*! * \brief Create a new OGG/Speex filestream and set it up for reading. * \param fs File that points to on disk storage of the OGG/Speex data. * \return The new filestream. */ static int ogg_speex_open(struct ast_filestream *fs) { char *buffer; size_t bytes; struct speex_desc *s = (struct speex_desc *)fs->_private; SpeexHeader *hdr = NULL; int i, result, expected_rate; expected_rate = ast_format_get_sample_rate(fs->fmt->format); s->serialno = -1; ogg_sync_init(&s->oy); buffer = ogg_sync_buffer(&s->oy, BLOCK_SIZE); bytes = fread(buffer, 1, BLOCK_SIZE, fs->f); ogg_sync_wrote(&s->oy, bytes); result = ogg_sync_pageout(&s->oy, &s->og); if (result != 1) { if(bytes < BLOCK_SIZE) { ast_log(LOG_ERROR, "Run out of data...\n"); } else { ast_log(LOG_ERROR, "Input does not appear to be an Ogg bitstream.\n"); } ogg_sync_clear(&s->oy); return -1; } ogg_stream_init(&s->os, ogg_page_serialno(&s->og)); if (ogg_stream_pagein(&s->os, &s->og) < 0) { ast_log(LOG_ERROR, "Error reading first page of Ogg bitstream data.\n"); goto error; } if (read_packet(fs) < 0) { ast_log(LOG_ERROR, "Error reading initial header packet.\n"); goto error; } hdr = speex_packet_to_header((char*)s->op.packet, s->op.bytes); if (memcmp(hdr->speex_string, "Speex ", 8)) { ast_log(LOG_ERROR, "OGG container does not contain Speex audio!\n"); goto error; } if (hdr->frames_per_packet != 1) { ast_log(LOG_ERROR, "Only one frame-per-packet OGG/Speex files are currently supported!\n"); goto error; } if (hdr->nb_channels != 1) { ast_log(LOG_ERROR, "Only monophonic OGG/Speex files are currently supported!\n"); goto error; } if (hdr->rate != expected_rate) { ast_log(LOG_ERROR, "Unexpected sampling rate (%d != %d)!\n", hdr->rate, expected_rate); goto error; } /* this packet is the comment */ if (read_packet(fs) < 0) { ast_log(LOG_ERROR, "Error reading comment packet.\n"); goto error; } for (i = 0; i < hdr->extra_headers; i++) { if (read_packet(fs) < 0) { ast_log(LOG_ERROR, "Error reading extra header packet %d.\n", i+1); goto error; } } speex_header_free(hdr); return 0; error: if (hdr) { speex_header_free(hdr); } ogg_stream_clear(&s->os); ogg_sync_clear(&s->oy); return -1; }
ogg_codec_t *initial_speex_page (format_plugin_t *plugin, ogg_page *page) { ogg_state_t *ogg_info = plugin->_state; ogg_codec_t *codec = acalloc (1, sizeof (ogg_codec_t)); ogg_packet packet; SpeexHeader *header; ogg_stream_init (&codec->os, ogg_page_serialno (page)); ogg_stream_pagein (&codec->os, page); ogg_stream_packetout (&codec->os, &packet); DEBUG0("checking for speex codec"); header = speex_packet_to_header ((char*)packet.packet, packet.bytes); if (header == NULL) { ogg_stream_clear (&codec->os); free (header); free (codec); return NULL; } INFO0 ("seen initial speex header"); codec->process_page = process_speex_page; codec->codec_free = speex_codec_free; codec->headers = 1; format_ogg_attach_header (ogg_info, page); free (header); return codec; }
static av_cold int libspeex_decode_init(AVCodecContext *avctx) { LibSpeexContext *s = avctx->priv_data; const SpeexMode *mode; // defaults in the case of a missing header if (avctx->sample_rate <= 8000) mode = &speex_nb_mode; else if (avctx->sample_rate <= 16000) mode = &speex_wb_mode; else mode = &speex_uwb_mode; if (avctx->extradata_size >= 80) s->header = speex_packet_to_header(avctx->extradata, avctx->extradata_size); avctx->sample_fmt = AV_SAMPLE_FMT_S16; if (s->header) { avctx->sample_rate = s->header->rate; avctx->channels = s->header->nb_channels; s->frame_size = s->header->frame_size; mode = speex_lib_get_mode(s->header->mode); if (!mode) { av_log(avctx, AV_LOG_ERROR, "Unknown Speex mode %d", s->header->mode); return AVERROR_INVALIDDATA; } } else av_log(avctx, AV_LOG_INFO, "Missing Speex header, assuming defaults.\n"); if (avctx->channels > 2) { av_log(avctx, AV_LOG_ERROR, "Only stereo and mono are supported.\n"); return AVERROR(EINVAL); } speex_bits_init(&s->bits); s->dec_state = speex_decoder_init(mode); if (!s->dec_state) { av_log(avctx, AV_LOG_ERROR, "Error initializing libspeex decoder.\n"); return -1; } if (!s->header) { speex_decoder_ctl(s->dec_state, SPEEX_GET_FRAME_SIZE, &s->frame_size); } if (avctx->channels == 2) { SpeexCallback callback; callback.callback_id = SPEEX_INBAND_STEREO; callback.func = speex_std_stereo_request_handler; callback.data = &s->stereo; s->stereo = (SpeexStereoState)SPEEX_STEREO_STATE_INIT; speex_decoder_ctl(s->dec_state, SPEEX_SET_HANDLER, &callback); } avcodec_get_frame_defaults(&s->frame); avctx->coded_frame = &s->frame; return 0; }
static void *process_header (struct spx_data *data) { void *st; const SpeexMode *mode; int modeID; SpeexCallback callback; int enhance = ENHANCE_AUDIO; data->header = speex_packet_to_header ((char*)data->op.packet, data->op.bytes); if (!data->header) { decoder_error (&data->error, ERROR_FATAL, 0, "Can't open speex file: can't read header"); return NULL; } if (data->header->mode >= SPEEX_NB_MODES) { decoder_error (&data->error, ERROR_FATAL, 0, "Can't open speex file: Mode number %"PRId32 " does not exist in this version", data->header->mode); return NULL; } modeID = data->header->mode; mode = speex_mode_list[modeID]; if (mode->bitstream_version < data->header->mode_bitstream_version) { decoder_error (&data->error, ERROR_FATAL, 0, "Can't open speex file: The file was encoded " "with a newer version of Speex."); return NULL; } if (mode->bitstream_version > data->header->mode_bitstream_version) { decoder_error (&data->error, ERROR_FATAL, 0, "Can't open speex file: The file was encoded " "with an older version of Speex."); return NULL; } st = speex_decoder_init (mode); speex_decoder_ctl(st, SPEEX_SET_ENH, &enhance); speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, &data->frame_size); callback.callback_id = SPEEX_INBAND_STEREO; callback.func = speex_std_stereo_request_handler; callback.data = &data->stereo; speex_decoder_ctl(st, SPEEX_SET_HANDLER, &callback); speex_decoder_ctl(st, SPEEX_SET_SAMPLING_RATE, &data->header->rate); return st; }
ogg_codec_t *initial_speex_page (format_plugin_t *plugin, ogg_page *page) { ogg_state_t *ogg_info = plugin->_state; ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t)); ogg_packet packet; SpeexHeader *header; ogg_stream_init (&codec->os, ogg_page_serialno (page)); ogg_stream_pagein (&codec->os, page); ogg_stream_packetout (&codec->os, &packet); /* Check for te first packet to be at least of the minimal size for a Speex header. * The header size is 80 bytes as per specs. You can find the specs here: * https://speex.org/docs/manual/speex-manual/node8.html#SECTION00830000000000000000 * * speex_packet_to_header() will also check the header size for us. However * that function generates noise on stderr in case the header is too short. * This is dangerous as we may have closed stderr already and the handle may be use * again for something else. */ if (packet.bytes < 80) { return NULL; } ICECAST_LOG_DEBUG("checking for speex codec"); header = speex_packet_to_header ((char*)packet.packet, packet.bytes); if (header == NULL) { ogg_stream_clear (&codec->os); free (header); free (codec); return NULL; } ICECAST_LOG_INFO("seen initial speex header"); codec->process_page = process_speex_page; codec->codec_free = speex_codec_free; codec->headers = 1; format_ogg_attach_header (ogg_info, page); free (header); return codec; }
static int init(sh_audio_t *sh) { context_t *ctx = calloc(1, sizeof(context_t)); const SpeexMode *spx_mode; const SpeexStereoState st_st = SPEEX_STEREO_STATE_INIT; // hack if (!sh->wf || sh->wf->cbSize < 80) { mp_msg(MSGT_DECAUDIO, MSGL_FATAL, "Missing extradata!\n"); return 0; } ctx->hdr = speex_packet_to_header((char *)&sh->wf[1], sh->wf->cbSize); if (ctx->hdr->nb_channels != 1 && ctx->hdr->nb_channels != 2) { mp_msg(MSGT_DECAUDIO, MSGL_WARN, "Invalid number of channels (%i), " "assuming mono\n", ctx->hdr->nb_channels); ctx->hdr->nb_channels = 1; } if (ctx->hdr->frames_per_packet > MAX_FRAMES_PER_PACKET) { mp_msg(MSGT_DECAUDIO, MSGL_WARN, "Invalid number of frames per packet (%i), " "assuming 1\n", ctx->hdr->frames_per_packet); ctx->hdr->frames_per_packet = 1; } switch (ctx->hdr->mode) { case 0: spx_mode = &speex_nb_mode; break; case 1: spx_mode = &speex_wb_mode; break; case 2: spx_mode = &speex_uwb_mode; break; default: mp_msg(MSGT_DECAUDIO, MSGL_WARN, "Unknown speex mode (%i)\n", ctx->hdr->mode); spx_mode = &speex_nb_mode; } ctx->dec_context = speex_decoder_init(spx_mode); speex_bits_init(&ctx->bits); memcpy(&ctx->stereo, &st_st, sizeof(ctx->stereo)); // hack part 2 sh->channels = ctx->hdr->nb_channels; sh->samplerate = ctx->hdr->rate; sh->samplesize = 2; sh->sample_format = AF_FORMAT_S16_NE; sh->context = ctx; return 1; }
void SndSysSpeexSoundData::Initialize() { ogg_sync_state oy; ogg_page og; ogg_packet op; ogg_stream_state os; // Process enough to get the header. ogg_sync_init(&oy); oy.data = m_DataStore.data; oy.storage = (int)m_DataStore.length; ogg_sync_wrote(&oy, (long)m_DataStore.length); ogg_sync_pageout(&oy, &og); ogg_stream_init(&os, ogg_page_serialno(&og)); ogg_stream_pagein(&os, &og); ogg_stream_packetout(&os, &op); SpeexHeader* header = speex_packet_to_header((char*)op.packet, op.bytes); m_SoundFormat.Channels = header->nb_channels; m_SoundFormat.Freq = header->rate; // Is there a better way to do this? // Get number of packets (-1 as the second contains misc info). int count = -1; while(ogg_sync_pageout(&oy, &og)==1) { ogg_stream_pagein(&os, &og); count += ogg_page_packets(&og); } m_FrameCount = header->frames_per_packet * count; // Free memory. speex_header_free(header); ogg_stream_clear(&os); // No need to call this again. m_bInfoReady=true; }
/* -- speex functions -- */ int _shout_open_speex(ogg_codec_t *codec, ogg_page *page) { speex_data_t *speex_data = calloc(1, sizeof(speex_data_t)); ogg_packet packet; if (!speex_data) return SHOUTERR_MALLOC; ogg_stream_packetout(&codec->os, &packet); if (!(speex_data->sh = speex_packet_to_header(packet.packet,packet.bytes))) { free_speex_data(speex_data); return SHOUTERR_UNSUPPORTED; } codec->codec_data = speex_data; codec->read_page = read_speex_page; codec->free_data = free_speex_data; return SHOUTERR_SUCCESS; }
static int init(sh_audio_t *sh) { context_t *ctx = calloc(1, sizeof(context_t)); const uint8_t *hdr = (const uint8_t *)(sh->wf + 1); const SpeexMode *spx_mode; const SpeexStereoState st_st = SPEEX_STEREO_STATE_INIT; // hack if (sh->wf && sh->wf->cbSize >= 80) ctx->hdr = speex_packet_to_header((char *)&sh->wf[1], sh->wf->cbSize); if (!ctx->hdr && sh->wf->cbSize == 0x72 && hdr[0] == 1 && hdr[1] == 0) { // speex.acm format: raw SpeexHeader dump ctx->hdr = calloc(1, sizeof(*ctx->hdr)); hdr += 2; hdr += 8; // identifier string hdr += 20; // version string ctx->hdr->speex_version_id = read_le32(&hdr); ctx->hdr->header_size = read_le32(&hdr); ctx->hdr->rate = read_le32(&hdr); ctx->hdr->mode = read_le32(&hdr); ctx->hdr->mode_bitstream_version = read_le32(&hdr); ctx->hdr->nb_channels = read_le32(&hdr); ctx->hdr->bitrate = read_le32(&hdr); ctx->hdr->frame_size = read_le32(&hdr); ctx->hdr->vbr = read_le32(&hdr); ctx->hdr->frames_per_packet = read_le32(&hdr); } if (!ctx->hdr) { mp_msg(MSGT_DECAUDIO, MSGL_ERR, "Invalid or missing extradata! Assuming defaults.\n"); ctx->hdr = calloc(1, sizeof(*ctx->hdr)); ctx->hdr->frames_per_packet = 1; ctx->hdr->mode = 0; if (sh->wf) { ctx->hdr->nb_channels = sh->wf->nChannels; ctx->hdr->rate = sh->wf->nSamplesPerSec; if (ctx->hdr->rate > 16000) ctx->hdr->mode = 2; else if (ctx->hdr->rate > 8000) ctx->hdr->mode = 1; } } if (ctx->hdr->nb_channels != 1 && ctx->hdr->nb_channels != 2) { mp_msg(MSGT_DECAUDIO, MSGL_WARN, "Invalid number of channels (%i), " "assuming mono\n", ctx->hdr->nb_channels); ctx->hdr->nb_channels = 1; } if (ctx->hdr->frames_per_packet > MAX_FRAMES_PER_PACKET) { mp_msg(MSGT_DECAUDIO, MSGL_WARN, "Invalid number of frames per packet (%i), " "assuming 1\n", ctx->hdr->frames_per_packet); ctx->hdr->frames_per_packet = 1; } switch (ctx->hdr->mode) { case 0: spx_mode = &speex_nb_mode; break; case 1: spx_mode = &speex_wb_mode; break; case 2: spx_mode = &speex_uwb_mode; break; default: mp_msg(MSGT_DECAUDIO, MSGL_WARN, "Unknown speex mode (%i)\n", ctx->hdr->mode); spx_mode = &speex_nb_mode; } ctx->dec_context = speex_decoder_init(spx_mode); speex_bits_init(&ctx->bits); memcpy(&ctx->stereo, &st_st, sizeof(ctx->stereo)); // hack part 2 sh->channels = ctx->hdr->nb_channels; sh->samplerate = ctx->hdr->rate; sh->samplesize = 2; sh->sample_format = AF_FORMAT_S16_NE; sh->context = ctx; return 1; }
/***************************************************************************** * ProcessInitialHeader: processes the inital Speex header packet. *****************************************************************************/ static int ProcessInitialHeader( decoder_t *p_dec, ogg_packet *p_oggpacket ) { decoder_sys_t *p_sys = p_dec->p_sys; void *p_state; SpeexHeader *p_header; const SpeexMode *p_mode; SpeexCallback callback; p_sys->p_header = p_header = speex_packet_to_header( (char *)p_oggpacket->packet, p_oggpacket->bytes ); if( !p_header ) { msg_Err( p_dec, "cannot read Speex header" ); return VLC_EGENERIC; } if( p_header->mode >= SPEEX_NB_MODES || p_header->mode < 0 ) { msg_Err( p_dec, "mode number %d does not (yet/any longer) exist in " "this version of libspeex.", p_header->mode ); return VLC_EGENERIC; } p_mode = speex_mode_list[p_header->mode]; if( p_mode == NULL ) return VLC_EGENERIC; if( p_header->speex_version_id > 1 ) { msg_Err( p_dec, "this file was encoded with Speex bit-stream " "version %d which is not supported by this decoder.", p_header->speex_version_id ); return VLC_EGENERIC; } if( p_mode->bitstream_version < p_header->mode_bitstream_version ) { msg_Err( p_dec, "file encoded with a newer version of Speex." ); return VLC_EGENERIC; } if( p_mode->bitstream_version > p_header->mode_bitstream_version ) { msg_Err( p_dec, "file encoded with an older version of Speex." ); return VLC_EGENERIC; } msg_Dbg( p_dec, "Speex %d Hz audio using %s mode %s%s", p_header->rate, p_mode->modeName, ( p_header->nb_channels == 1 ) ? " (mono" : " (stereo", p_header->vbr ? ", VBR)" : ")" ); /* Take care of speex decoder init */ speex_bits_init( &p_sys->bits ); p_sys->p_state = p_state = speex_decoder_init( p_mode ); if( !p_state ) { msg_Err( p_dec, "decoder initialization failed" ); return VLC_EGENERIC; } if( p_header->nb_channels == 2 ) { SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT; p_sys->stereo = stereo; callback.callback_id = SPEEX_INBAND_STEREO; callback.func = speex_std_stereo_request_handler; callback.data = &p_sys->stereo; speex_decoder_ctl( p_state, SPEEX_SET_HANDLER, &callback ); } if( p_header->nb_channels <= 0 || p_header->nb_channels > 5 ) { msg_Err( p_dec, "invalid number of channels (not between 1 and 5): %i", p_header->nb_channels ); return VLC_EGENERIC; } /* Setup the format */ p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = pi_channels_maps[p_header->nb_channels]; p_dec->fmt_out.audio.i_channels = p_header->nb_channels; p_dec->fmt_out.audio.i_rate = p_header->rate; date_Init( &p_sys->end_date, p_header->rate, 1 ); return VLC_SUCCESS; }
static void *process_header(ogg_packet *op, spx_int32_t enh_enabled, spx_int32_t *frame_size, int *granule_frame_size, spx_int32_t *rate, int *nframes, int forceMode, int *channels, SpeexStereoState *stereo, int *extra_headers, int quiet) { void *st; const SpeexMode *mode; SpeexHeader *header; int modeID; SpeexCallback callback; header = speex_packet_to_header((char*)op->packet, op->bytes); if (!header) { WriteDebugLog("Cannot read header"); //fprintf (stderr, "Cannot read header\n"); return NULL; } if (header->mode >= SPEEX_NB_MODES || header->mode<0) { WriteDebugLog("Mode number %d does not (yet/any longer) exist in this version"); //fprintf (stderr, "Mode number %d does not (yet/any longer) exist in this version\n", // header->mode); free(header); return NULL; } modeID = header->mode; if (forceMode!=-1) modeID = forceMode; mode = speex_lib_get_mode (modeID); if (header->speex_version_id > 1) { char Error[256] = {0}; sprintf(Error,"This file was encoded with Speex bit-stream version %d, which I don't know how to decode\n", header->speex_version_id); WriteDebugLog(Error); //fprintf (stderr, "This file was encoded with Speex bit-stream version %d, which I don't know how to decode\n", header->speex_version_id); free(header); return NULL; } if (mode->bitstream_version < header->mode_bitstream_version) { WriteDebugLog("The file was encoded with a newer version of Speex. You need to upgrade in order to play it."); //fprintf (stderr, "The file was encoded with a newer version of Speex. You need to upgrade in order to play it.\n"); free(header); return NULL; } if (mode->bitstream_version > header->mode_bitstream_version) { WriteDebugLog("The file was encoded with an older version of Speex. You would need to downgrade the version in order to play it."); //fprintf (stderr, "The file was encoded with an older version of Speex. You would need to downgrade the version in order to play it.\n"); free(header); return NULL; } st = speex_decoder_init(mode); if (!st) { WriteDebugLog("Decoder initialization failed."); //fprintf (stderr, "Decoder initialization failed.\n"); free(header); return NULL; } speex_decoder_ctl(st, SPEEX_SET_ENH, &enh_enabled); speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size); *granule_frame_size = *frame_size; if (!*rate) *rate = header->rate; /* Adjust rate if --force-* options are used */ if (forceMode!=-1) { if (header->mode < forceMode) { *rate <<= (forceMode - header->mode); *granule_frame_size >>= (forceMode - header->mode); } if (header->mode > forceMode) { *rate >>= (header->mode - forceMode); *granule_frame_size <<= (header->mode - forceMode); }
static GstFlowReturn gst_speex_dec_parse_header (GstSpeexDec * dec, GstBuffer * buf) { GstCaps *caps; /* get the header */ dec->header = speex_packet_to_header ((char *) GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); if (!dec->header) goto no_header; if (dec->header->mode >= SPEEX_NB_MODES || dec->header->mode < 0) goto mode_too_old; dec->mode = speex_lib_get_mode (dec->header->mode); /* initialize the decoder */ dec->state = speex_decoder_init (dec->mode); if (!dec->state) goto init_failed; speex_decoder_ctl (dec->state, SPEEX_SET_ENH, &dec->enh); speex_decoder_ctl (dec->state, SPEEX_GET_FRAME_SIZE, &dec->frame_size); if (dec->header->nb_channels != 1) { dec->stereo = speex_stereo_state_init (); dec->callback.callback_id = SPEEX_INBAND_STEREO; dec->callback.func = speex_std_stereo_request_handler; dec->callback.data = dec->stereo; speex_decoder_ctl (dec->state, SPEEX_SET_HANDLER, &dec->callback); } speex_decoder_ctl (dec->state, SPEEX_SET_SAMPLING_RATE, &dec->header->rate); dec->frame_duration = gst_util_uint64_scale_int (dec->frame_size, GST_SECOND, dec->header->rate); speex_bits_init (&dec->bits); /* set caps */ caps = gst_caps_new_simple ("audio/x-raw-int", "rate", G_TYPE_INT, dec->header->rate, "channels", G_TYPE_INT, dec->header->nb_channels, "signed", G_TYPE_BOOLEAN, TRUE, "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, NULL); if (!gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (dec), caps)) goto nego_failed; gst_caps_unref (caps); return GST_FLOW_OK; /* ERRORS */ no_header: { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("couldn't read header")); return GST_FLOW_ERROR; } mode_too_old: { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("Mode number %d does not (yet/any longer) exist in this version", dec->header->mode)); return GST_FLOW_ERROR; } init_failed: { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("couldn't initialize decoder")); return GST_FLOW_ERROR; } nego_failed: { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("couldn't negotiate format")); gst_caps_unref (caps); return GST_FLOW_NOT_NEGOTIATED; } }
static GstFlowReturn gst_speex_dec_parse_header (GstSpeexDec * dec, GstBuffer * buf) { SpeexHeader *header; GstMapInfo map; GstAudioInfo info; static const GstAudioChannelPosition chan_pos[2][2] = { {GST_AUDIO_CHANNEL_POSITION_MONO}, {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT} }; /* get the header */ gst_buffer_map (buf, &map, GST_MAP_READ); header = speex_packet_to_header ((gchar *) map.data, map.size); gst_buffer_unmap (buf, &map); if (!header) goto no_header; if (dec->header) { GST_DEBUG_OBJECT (dec, "Replacing speex-header, resetting state"); gst_speex_dec_reset (dec); } dec->header = header; if (dec->header->mode >= SPEEX_NB_MODES || dec->header->mode < 0) goto mode_too_old; dec->mode = speex_lib_get_mode (dec->header->mode); /* initialize the decoder */ dec->state = speex_decoder_init (dec->mode); if (!dec->state) goto init_failed; speex_decoder_ctl (dec->state, SPEEX_SET_ENH, &dec->enh); speex_decoder_ctl (dec->state, SPEEX_GET_FRAME_SIZE, &dec->frame_size); if (dec->header->nb_channels != 1) { dec->stereo = speex_stereo_state_init (); dec->callback.callback_id = SPEEX_INBAND_STEREO; dec->callback.func = speex_std_stereo_request_handler; dec->callback.data = dec->stereo; speex_decoder_ctl (dec->state, SPEEX_SET_HANDLER, &dec->callback); } speex_decoder_ctl (dec->state, SPEEX_SET_SAMPLING_RATE, &dec->header->rate); dec->frame_duration = gst_util_uint64_scale_int (dec->frame_size, GST_SECOND, dec->header->rate); speex_bits_init (&dec->bits); /* set caps */ gst_audio_info_init (&info); gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16, dec->header->rate, dec->header->nb_channels, chan_pos[dec->header->nb_channels - 1]); if (!gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (dec), &info)) goto nego_failed; return GST_FLOW_OK; /* ERRORS */ no_header: { GST_INFO_OBJECT (dec, "couldn't read header"); return GST_FLOW_NO_HEADER; } mode_too_old: { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("Mode number %d does not (yet/any longer) exist in this version", dec->header->mode)); return GST_FLOW_ERROR; } init_failed: { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("couldn't initialize decoder")); return GST_FLOW_ERROR; } nego_failed: { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("couldn't negotiate format")); return GST_FLOW_NOT_NEGOTIATED; } }
static void * spx_header_read (SF_PRIVATE * psf, ogg_packet *op, spx_int32_t enh_enabled, int force_mode) { SPX_PRIVATE* spx = psf->codec_data ; void *st ; const SpeexMode *mode ; SpeexHeader *tmp_header ; int modeID ; SpeexCallback callback ; tmp_header = speex_packet_to_header ((char*) op->packet, op->bytes) ; if (tmp_header == NULL) { psf_log_printf (psf, "Cannot read Speex header\n") ; return NULL ; } ; memcpy (&spx->header, tmp_header, sizeof (spx->header)) ; free (tmp_header) ; tmp_header = NULL ; if (spx->header.mode >= SPEEX_NB_MODES || spx->header.mode < 0) { psf_log_printf (psf, "Mode number %d does not (yet/any longer) exist in this version\n", spx->header.mode) ; return NULL ; } ; modeID = spx->header.mode ; if (force_mode != -1) modeID = force_mode ; mode = speex_lib_get_mode (modeID) ; if (spx->header.speex_version_id > 1) { psf_log_printf (psf, "This file was encoded with Speex bit-stream version %d, which I don't know how to decode\n", spx->header.speex_version_id) ; return NULL ; } ; if (mode->bitstream_version < spx->header.mode_bitstream_version) { psf_log_printf (psf, "The file was encoded with a newer version of Speex. You need to upgrade in order to play it.\n") ; return NULL ; } ; if (mode->bitstream_version > spx->header.mode_bitstream_version) { psf_log_printf (psf, "The file was encoded with an older version of Speex. You would need to downgrade the version in order to play it.\n") ; return NULL ; } ; st = speex_decoder_init (mode) ; if (!st) { psf_log_printf (psf, "Decoder initialization failed.\n") ; return NULL ; } ; speex_decoder_ctl (st, SPEEX_SET_ENH, &enh_enabled) ; speex_decoder_ctl (st, SPEEX_GET_FRAME_SIZE, &spx->frame_size) ; spx->granule_frame_size = spx->frame_size ; if (!psf->sf.samplerate) psf->sf.samplerate = spx->header.rate ; /* Adjust rate if --force-* options are used */ if (force_mode != -1) { if (spx->header.mode < force_mode) { psf->sf.samplerate <<= (force_mode - spx->header.mode) ; spx->granule_frame_size >>= (force_mode - spx->header.mode) ; } ; if (spx->header.mode > force_mode) { psf->sf.samplerate >>= (spx->header.mode - force_mode) ; spx->granule_frame_size <<= (spx->header.mode - force_mode) ; } ;
bool OggSpeexDecoder::Open(CFErrorRef *error) { if(IsOpen()) { LOGGER_WARNING("org.sbooth.AudioEngine.AudioDecoder.OggSpeex", "Open() called on an AudioDecoder that is already open"); return true; } // Ensure the input source is open if(!mInputSource->IsOpen() && !mInputSource->Open(error)) return false; // Initialize Ogg data struct ogg_sync_init(&mOggSyncState); // Get the ogg buffer for writing char *data = ogg_sync_buffer(&mOggSyncState, READ_SIZE_BYTES); // Read bitstream from input file ssize_t bytesRead = GetInputSource()->Read(data, READ_SIZE_BYTES); if(-1 == bytesRead) { if(error) { CFMutableDictionaryRef errorDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFStringRef displayName = CreateDisplayNameForURL(mInputSource->GetURL()); CFStringRef errorString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFCopyLocalizedString(CFSTR("The file “%@” could not be read."), ""), displayName); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedDescriptionKey, errorString); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedFailureReasonKey, CFCopyLocalizedString(CFSTR("Read error"), "")); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedRecoverySuggestionKey, CFCopyLocalizedString(CFSTR("Unable to read from the input file."), "")); CFRelease(errorString), errorString = NULL; CFRelease(displayName), displayName = NULL; *error = CFErrorCreate(kCFAllocatorDefault, AudioDecoderErrorDomain, AudioDecoderInputOutputError, errorDictionary); CFRelease(errorDictionary), errorDictionary = NULL; } ogg_sync_destroy(&mOggSyncState); return false; } // Tell the sync layer how many bytes were written to its internal buffer int result = ogg_sync_wrote(&mOggSyncState, bytesRead); if(-1 == result) { if(error) { CFMutableDictionaryRef errorDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFStringRef displayName = CreateDisplayNameForURL(mInputSource->GetURL()); CFStringRef errorString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFCopyLocalizedString(CFSTR("The file “%@” does not appear to be an Ogg file."), ""), displayName); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedDescriptionKey, errorString); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedFailureReasonKey, CFCopyLocalizedString(CFSTR("Not an Ogg file"), "")); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedRecoverySuggestionKey, CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); CFRelease(errorString), errorString = NULL; CFRelease(displayName), displayName = NULL; *error = CFErrorCreate(kCFAllocatorDefault, AudioDecoderErrorDomain, AudioDecoderFileFormatNotRecognizedError, errorDictionary); CFRelease(errorDictionary), errorDictionary = NULL; } ogg_sync_destroy(&mOggSyncState); return false; } // Turn the data we wrote into an ogg page result = ogg_sync_pageout(&mOggSyncState, &mOggPage); if(1 != result) { if(error) { CFMutableDictionaryRef errorDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFStringRef displayName = CreateDisplayNameForURL(mInputSource->GetURL()); CFStringRef errorString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFCopyLocalizedString(CFSTR("The file “%@” does not appear to be an Ogg file."), ""), displayName); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedDescriptionKey, errorString); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedFailureReasonKey, CFCopyLocalizedString(CFSTR("Not an Ogg file"), "")); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedRecoverySuggestionKey, CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); CFRelease(errorString), errorString = NULL; CFRelease(displayName), displayName = NULL; *error = CFErrorCreate(kCFAllocatorDefault, AudioDecoderErrorDomain, AudioDecoderFileFormatNotRecognizedError, errorDictionary); CFRelease(errorDictionary), errorDictionary = NULL; } ogg_sync_destroy(&mOggSyncState); return false; } // Initialize the stream and grab the serial number ogg_stream_init(&mOggStreamState, ogg_page_serialno(&mOggPage)); // Get the first Ogg page result = ogg_stream_pagein(&mOggStreamState, &mOggPage); if(0 != result) { if(error) { CFMutableDictionaryRef errorDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFStringRef displayName = CreateDisplayNameForURL(mInputSource->GetURL()); CFStringRef errorString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFCopyLocalizedString(CFSTR("The file “%@” does not appear to be an Ogg file."), ""), displayName); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedDescriptionKey, errorString); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedFailureReasonKey, CFCopyLocalizedString(CFSTR("Not an Ogg file"), "")); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedRecoverySuggestionKey, CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); CFRelease(errorString), errorString = NULL; CFRelease(displayName), displayName = NULL; *error = CFErrorCreate(kCFAllocatorDefault, AudioDecoderErrorDomain, AudioDecoderFileFormatNotRecognizedError, errorDictionary); CFRelease(errorDictionary), errorDictionary = NULL; } ogg_sync_destroy(&mOggSyncState); return false; } // Get the first packet (should be the header) from the page ogg_packet op; result = ogg_stream_packetout(&mOggStreamState, &op); if(1 != result) { if(error) { CFMutableDictionaryRef errorDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFStringRef displayName = CreateDisplayNameForURL(mInputSource->GetURL()); CFStringRef errorString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFCopyLocalizedString(CFSTR("The file “%@” does not appear to be an Ogg file."), ""), displayName); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedDescriptionKey, errorString); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedFailureReasonKey, CFCopyLocalizedString(CFSTR("Not an Ogg file"), "")); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedRecoverySuggestionKey, CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); CFRelease(errorString), errorString = NULL; CFRelease(displayName), displayName = NULL; *error = CFErrorCreate(kCFAllocatorDefault, AudioDecoderErrorDomain, AudioDecoderFileFormatNotRecognizedError, errorDictionary); CFRelease(errorDictionary), errorDictionary = NULL; } ogg_sync_destroy(&mOggSyncState); return false; } if(op.bytes >= 5 && !memcmp(op.packet, "Speex", 5)) mSpeexSerialNumber = mOggStreamState.serialno; ++mOggPacketCount; // Convert the packet to the Speex header SpeexHeader *header = speex_packet_to_header((char *)op.packet, static_cast<int>(op.bytes)); if(NULL == header) { if(error) { CFMutableDictionaryRef errorDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFStringRef displayName = CreateDisplayNameForURL(mInputSource->GetURL()); CFStringRef errorString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFCopyLocalizedString(CFSTR("The file “%@” does not appear to be an Ogg Speex file."), ""), displayName); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedDescriptionKey, errorString); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedFailureReasonKey, CFCopyLocalizedString(CFSTR("Not an Ogg Speex file"), "")); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedRecoverySuggestionKey, CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); CFRelease(errorString), errorString = NULL; CFRelease(displayName), displayName = NULL; *error = CFErrorCreate(kCFAllocatorDefault, AudioDecoderErrorDomain, AudioDecoderFileFormatNotRecognizedError, errorDictionary); CFRelease(errorDictionary), errorDictionary = NULL; } ogg_sync_destroy(&mOggSyncState); return false; } else if(SPEEX_NB_MODES <= header->mode) { if(error) { CFMutableDictionaryRef errorDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFStringRef displayName = CreateDisplayNameForURL(mInputSource->GetURL()); CFStringRef errorString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFCopyLocalizedString(CFSTR("The Speex mode in the file “%@” is not supported."), ""), displayName); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedDescriptionKey, errorString); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedFailureReasonKey, CFCopyLocalizedString(CFSTR("Unsupported Ogg Speex file mode"), "")); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedRecoverySuggestionKey, CFCopyLocalizedString(CFSTR("This file may have been encoded with a newer version of Speex."), "")); CFRelease(errorString), errorString = NULL; CFRelease(displayName), displayName = NULL; *error = CFErrorCreate(kCFAllocatorDefault, AudioDecoderErrorDomain, AudioDecoderFileFormatNotSupportedError, errorDictionary); CFRelease(errorDictionary), errorDictionary = NULL; } speex_header_free(header), header = NULL; ogg_sync_destroy(&mOggSyncState); return false; } const SpeexMode *mode = speex_lib_get_mode(header->mode); if(mode->bitstream_version != header->mode_bitstream_version) { if(error) { CFMutableDictionaryRef errorDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFStringRef displayName = CreateDisplayNameForURL(mInputSource->GetURL()); CFStringRef errorString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFCopyLocalizedString(CFSTR("The Speex version in the file “%@” is not supported."), ""), displayName); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedDescriptionKey, errorString); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedFailureReasonKey, CFCopyLocalizedString(CFSTR("Unsupported Ogg Speex file version"), "")); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedRecoverySuggestionKey, CFCopyLocalizedString(CFSTR("This file was encoded with a different version of Speex."), "")); CFRelease(errorString), errorString = NULL; CFRelease(displayName), displayName = NULL; *error = CFErrorCreate(kCFAllocatorDefault, AudioDecoderErrorDomain, AudioDecoderFileFormatNotSupportedError, errorDictionary); CFRelease(errorDictionary), errorDictionary = NULL; } speex_header_free(header), header = NULL; ogg_sync_destroy(&mOggSyncState); return false; } // Initialize the decoder mSpeexDecoder = speex_decoder_init(mode); if(NULL== mSpeexDecoder) { if(error) { CFMutableDictionaryRef errorDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedDescriptionKey, CFCopyLocalizedString(CFSTR("Unable to initialize the Speex decoder."), "")); // CFDictionarySetValue(errorDictionary, // kCFErrorLocalizedFailureReasonKey, // CFCopyLocalizedString(CFSTR("Unsupported Ogg Speex file version"), "")); // CFDictionarySetValue(errorDictionary, // kCFErrorLocalizedRecoverySuggestionKey, // CFCopyLocalizedString(CFSTR("This file was encoded with a different version of Speex."), "")); *error = CFErrorCreate(kCFAllocatorDefault, AudioDecoderErrorDomain, AudioDecoderInputOutputError, errorDictionary); CFRelease(errorDictionary), errorDictionary = NULL; } speex_header_free(header), header = NULL; ogg_sync_destroy(&mOggSyncState); return false; } speex_decoder_ctl(mSpeexDecoder, SPEEX_SET_SAMPLING_RATE, &header->rate); mSpeexFramesPerOggPacket = (0 == header->frames_per_packet ? 1 : header->frames_per_packet); mExtraSpeexHeaderCount = header->extra_headers; // Initialize the speex bit-packing data structure speex_bits_init(&mSpeexBits); // Initialize the stereo mode mSpeexStereoState = speex_stereo_state_init(); if(2 == header->nb_channels) { SpeexCallback callback; callback.callback_id = SPEEX_INBAND_STEREO; callback.func = speex_std_stereo_request_handler; callback.data = mSpeexStereoState; speex_decoder_ctl(mSpeexDecoder, SPEEX_SET_HANDLER, &callback); } // Canonical Core Audio format mFormat.mFormatID = kAudioFormatLinearPCM; mFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved; mFormat.mBitsPerChannel = 8 * sizeof(float); mFormat.mSampleRate = header->rate; mFormat.mChannelsPerFrame = header->nb_channels; mFormat.mBytesPerPacket = (mFormat.mBitsPerChannel / 8); mFormat.mFramesPerPacket = 1; mFormat.mBytesPerFrame = mFormat.mBytesPerPacket * mFormat.mFramesPerPacket; mFormat.mReserved = 0; // Set up the source format mSourceFormat.mFormatID = 'SPEE'; mSourceFormat.mSampleRate = header->rate; mSourceFormat.mChannelsPerFrame = header->nb_channels; switch(header->nb_channels) { case 1: mChannelLayout = CreateChannelLayoutWithTag(kAudioChannelLayoutTag_Mono); break; case 2: mChannelLayout = CreateChannelLayoutWithTag(kAudioChannelLayoutTag_Stereo); break; } speex_header_free(header), header = NULL; // Allocate the buffer list spx_int32_t speexFrameSize = 0; speex_decoder_ctl(mSpeexDecoder, SPEEX_GET_FRAME_SIZE, &speexFrameSize); mBufferList = AllocateABL(mFormat, speexFrameSize); if(NULL == mBufferList) { if(error) *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX, ENOMEM, NULL); speex_header_free(header), header = NULL; speex_stereo_state_destroy(mSpeexStereoState), mSpeexStereoState = NULL; speex_decoder_destroy(mSpeexDecoder), mSpeexDecoder = NULL; speex_bits_destroy(&mSpeexBits); ogg_sync_destroy(&mOggSyncState); return false; } for(UInt32 i = 0; i < mBufferList->mNumberBuffers; ++i) mBufferList->mBuffers[i].mDataByteSize = 0; mIsOpen = true; return true; }
static gboolean xmms_speex_init (xmms_xform_t *xform) { gint pe; xmms_config_property_t *val; xmms_speex_data_t *data; xmms_error_t error; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_speex_data_t, 1); g_return_val_if_fail (data, FALSE); xmms_xform_private_data_set (xform, data); ogg_sync_init (&data->sync_state); speex_bits_init (&data->speex_bits); /* Find the speex header */ while (42) { gint ret; data->ogg_data = ogg_sync_buffer (&data->sync_state, 1024); ret = xmms_xform_read (xform, data->ogg_data, 1024, &error); ogg_sync_wrote (&data->sync_state, ret); if (ret <= 0) { return FALSE; } if (ogg_sync_pageout (&data->sync_state, &data->ogg_page) == 1) { break; } } ogg_stream_init (&data->stream_state, ogg_page_serialno (&data->ogg_page)); if (ogg_stream_pagein (&data->stream_state, &data->ogg_page) < 0) { return FALSE; } if (ogg_stream_packetout (&data->stream_state, &data->ogg_packet) != 1) { return FALSE; } data->speexheader = speex_packet_to_header ((char *)data->ogg_packet.packet, data->ogg_packet.bytes); data->speex_state = speex_decoder_init (speex_mode_list[data->speexheader->mode]); val = xmms_xform_config_lookup (xform, "perceptual_enhancer"); pe = xmms_config_property_get_int (val); speex_decoder_ctl (data->speex_state, SPEEX_SET_ENH, &pe); ogg_sync_pageout (&data->sync_state, &data->ogg_page); ogg_stream_pagein (&data->stream_state, &data->ogg_page); ogg_stream_packetout (&data->stream_state, &data->ogg_packet); data->samples_buf = g_new (gint16, data->speexheader->frames_per_packet * data->speexheader->frame_size * data->speexheader->nb_channels); data->samples_start = data->samples_buf; data->samples_count = 0; xmms_speex_read_metadata (xform, data); xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_S16, XMMS_STREAM_TYPE_FMT_CHANNELS, data->speexheader->nb_channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, data->speexheader->rate, XMMS_STREAM_TYPE_END); return TRUE; }
static int read_ogg_packet(OGGZ * oggz, oggz_packet * zp, long serialno, void * user_data) { ogg_packet * op = &zp->op; decoder_t * dec = (decoder_t *)user_data; speex_pdata_t * pd = (speex_pdata_t *)dec->pdata; if (pd->exploring && (pd->packetno == 0)) { /* Speex header */ int i; int ptr = 0; char speex_string[9]; int enh = 1; SpeexHeader * header; for (i = 0; i < 8; i++) { speex_string[i] = op->packet[ptr++]; } speex_string[i] = '\0'; if (strcmp(speex_string, "Speex ") != 0) { printf("read_ogg_packet(): Not a Speex stream\n"); pd->error = 1; return 0; } speex_bits_init(&(pd->bits)); header = speex_packet_to_header((char *)op->packet, op->bytes); if (!header) { printf("Cannot read Speex header\n"); pd->error = 1; return 0; } pd->mode = speex_mode_list[header->mode]; if (pd->mode->bitstream_version > header->mode_bitstream_version) { fprintf(stderr, "Unknown bitstream version! The file was encoded with an older version of Speex.\n" "You need to downgrade Speex in order to play it.\n"); pd->error = 1; return 0; } if (pd->mode->bitstream_version < header->mode_bitstream_version) { fprintf(stderr, "Unknown bitstream version! The file was encoded with a newer version of Speex.\n" "You need to upgrade Speex in order to play it.\n"); pd->error = 1; return 0; } pd->sample_rate = header->rate; pd->channels = header->nb_channels; pd->vbr = header->vbr; if (header->frames_per_packet != 0) pd->nframes = header->frames_per_packet; pd->decoder = speex_decoder_init(pd->mode); speex_decoder_ctl(pd->decoder, SPEEX_GET_FRAME_SIZE, &(pd->frame_size)); speex_decoder_ctl(pd->decoder, SPEEX_SET_ENH, &enh); } else if (pd->packetno >= 2) { int j; float output_frame[SPEEX_BUFSIZE]; pd->granulepos = op->granulepos; if (!pd->exploring) { speex_bits_read_from(&(pd->bits), (char *)op->packet, op->bytes); for (j = 0; j < pd->nframes; j++) { int k; speex_decode(pd->decoder, &(pd->bits), output_frame); for (k = 0; k < pd->frame_size * pd->channels; k++) { output_frame[k] /= 32768.0f; if (output_frame[k] > 1.0f) { output_frame[k] = 1.0f; } else if (output_frame[k] < -1.0f) { output_frame[k] = -1.0f; } } rb_write(pd->rb, (char *)output_frame, pd->channels * pd->frame_size * sample_size); } } } ++pd->packetno; return 0; }
bool SFB::Audio::OggSpeexDecoder::_Open(CFErrorRef *error) { // Initialize Ogg data struct ogg_sync_init(&mOggSyncState); // Get the ogg buffer for writing char *data = ogg_sync_buffer(&mOggSyncState, READ_SIZE_BYTES); // Read bitstream from input file ssize_t bytesRead = (ssize_t)GetInputSource().Read(data, READ_SIZE_BYTES); if(-1 == bytesRead) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” could not be read."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Read error"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("Unable to read from the input file."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } ogg_sync_destroy(&mOggSyncState); return false; } // Tell the sync layer how many bytes were written to its internal buffer int result = ogg_sync_wrote(&mOggSyncState, bytesRead); if(-1 == result) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg file."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg file"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } ogg_sync_destroy(&mOggSyncState); return false; } // Turn the data we wrote into an ogg page result = ogg_sync_pageout(&mOggSyncState, &mOggPage); if(1 != result) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg file."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg file"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } ogg_sync_destroy(&mOggSyncState); return false; } // Initialize the stream and grab the serial number ogg_stream_init(&mOggStreamState, ogg_page_serialno(&mOggPage)); // Get the first Ogg page result = ogg_stream_pagein(&mOggStreamState, &mOggPage); if(0 != result) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg file."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg file"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } ogg_sync_destroy(&mOggSyncState); return false; } // Get the first packet (should be the header) from the page ogg_packet op; result = ogg_stream_packetout(&mOggStreamState, &op); if(1 != result) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg file."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg file"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } ogg_sync_destroy(&mOggSyncState); return false; } if(op.bytes >= 5 && !memcmp(op.packet, "Speex", 5)) mSpeexSerialNumber = mOggStreamState.serialno; ++mOggPacketCount; // Convert the packet to the Speex header SpeexHeader *header = speex_packet_to_header((char *)op.packet, (int)op.bytes); if(nullptr == header) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg Speex file."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg Speex file"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::FileFormatNotRecognizedError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } ogg_sync_destroy(&mOggSyncState); return false; } else if(SPEEX_NB_MODES <= header->mode) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The Speex mode in the file “%@” is not supported."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Unsupported Ogg Speex file mode"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("This file may have been encoded with a newer version of Speex."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::FileFormatNotSupportedError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } speex_header_free(header); header = nullptr; ogg_sync_destroy(&mOggSyncState); return false; } const SpeexMode *mode = speex_lib_get_mode(header->mode); if(mode->bitstream_version != header->mode_bitstream_version) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The Speex version in the file “%@” is not supported."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Unsupported Ogg Speex file version"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("This file was encoded with a different version of Speex."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::FileFormatNotSupportedError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } speex_header_free(header); header = nullptr; ogg_sync_destroy(&mOggSyncState); return false; } // Initialize the decoder mSpeexDecoder = speex_decoder_init(mode); if(nullptr== mSpeexDecoder) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("Unable to initialize the Speex decoder."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Error initializing Speex decoder"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("An unknown error occurred."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } speex_header_free(header); header = nullptr; ogg_sync_destroy(&mOggSyncState); return false; } speex_decoder_ctl(mSpeexDecoder, SPEEX_SET_SAMPLING_RATE, &header->rate); mSpeexFramesPerOggPacket = (0 == header->frames_per_packet ? 1 : header->frames_per_packet); mExtraSpeexHeaderCount = (UInt32)header->extra_headers; // Initialize the speex bit-packing data structure speex_bits_init(&mSpeexBits); // Initialize the stereo mode mSpeexStereoState = speex_stereo_state_init(); if(2 == header->nb_channels) { SpeexCallback callback; callback.callback_id = SPEEX_INBAND_STEREO; callback.func = speex_std_stereo_request_handler; callback.data = mSpeexStereoState; speex_decoder_ctl(mSpeexDecoder, SPEEX_SET_HANDLER, &callback); } // Canonical Core Audio format mFormat.mFormatID = kAudioFormatLinearPCM; mFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved; mFormat.mBitsPerChannel = 8 * sizeof(float); mFormat.mSampleRate = header->rate; mFormat.mChannelsPerFrame = (UInt32)header->nb_channels; mFormat.mBytesPerPacket = (mFormat.mBitsPerChannel / 8); mFormat.mFramesPerPacket = 1; mFormat.mBytesPerFrame = mFormat.mBytesPerPacket * mFormat.mFramesPerPacket; mFormat.mReserved = 0; // Set up the source format mSourceFormat.mFormatID = 'SPEE'; mSourceFormat.mSampleRate = header->rate; mSourceFormat.mChannelsPerFrame = (UInt32)header->nb_channels; switch(header->nb_channels) { case 1: mChannelLayout = ChannelLayout::ChannelLayoutWithTag(kAudioChannelLayoutTag_Mono); break; case 2: mChannelLayout = ChannelLayout::ChannelLayoutWithTag(kAudioChannelLayoutTag_Stereo); break; } speex_header_free(header); header = nullptr; // Allocate the buffer list spx_int32_t speexFrameSize = 0; speex_decoder_ctl(mSpeexDecoder, SPEEX_GET_FRAME_SIZE, &speexFrameSize); if(!mBufferList.Allocate(mFormat, (UInt32)speexFrameSize)) { if(error) *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX, ENOMEM, nullptr); speex_stereo_state_destroy(mSpeexStereoState); mSpeexStereoState = nullptr; speex_decoder_destroy(mSpeexDecoder); mSpeexDecoder = nullptr; speex_bits_destroy(&mSpeexBits); ogg_sync_destroy(&mOggSyncState); return false; } for(UInt32 i = 0; i < mBufferList->mNumberBuffers; ++i) mBufferList->mBuffers[i].mDataByteSize = 0; return true; }
static av_cold int libspeex_decode_init(AVCodecContext *avctx) { LibSpeexContext *s = avctx->priv_data; const SpeexMode *mode; SpeexHeader *header = NULL; int spx_mode; avctx->sample_fmt = AV_SAMPLE_FMT_S16; if (avctx->extradata && avctx->extradata_size >= 80) { header = speex_packet_to_header(avctx->extradata, avctx->extradata_size); if (!header) av_log(avctx, AV_LOG_WARNING, "Invalid Speex header\n"); } if (avctx->codec_tag == MKTAG('S', 'P', 'X', 'N')) { if (!avctx->extradata || avctx->extradata && avctx->extradata_size < 47) { av_log(avctx, AV_LOG_ERROR, "Missing or invalid extradata.\n"); return AVERROR_INVALIDDATA; } if (avctx->extradata[37] != 10) { av_log(avctx, AV_LOG_ERROR, "Unsupported quality mode.\n"); return AVERROR_PATCHWELCOME; } spx_mode = 0; } else if (header) { avctx->sample_rate = header->rate; avctx->channels = header->nb_channels; spx_mode = header->mode; speex_header_free(header); } else { switch (avctx->sample_rate) { case 8000: spx_mode = 0; break; case 16000: spx_mode = 1; break; case 32000: spx_mode = 2; break; default: /* libspeex can handle any mode if initialized as ultra-wideband */ av_log(avctx, AV_LOG_WARNING, "Invalid sample rate: %d\n" "Decoding as 32kHz ultra-wideband\n", avctx->sample_rate); spx_mode = 2; } } mode = speex_lib_get_mode(spx_mode); if (!mode) { av_log(avctx, AV_LOG_ERROR, "Unknown Speex mode %d", spx_mode); return AVERROR_INVALIDDATA; } s->frame_size = 160 << spx_mode; if (!avctx->sample_rate) avctx->sample_rate = 8000 << spx_mode; if (avctx->channels < 1 || avctx->channels > 2) { /* libspeex can handle mono or stereo if initialized as stereo */ av_log(avctx, AV_LOG_ERROR, "Invalid channel count: %d.\n" "Decoding as stereo.\n", avctx->channels); avctx->channels = 2; } avctx->channel_layout = avctx->channels == 2 ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO; speex_bits_init(&s->bits); s->dec_state = speex_decoder_init(mode); if (!s->dec_state) { av_log(avctx, AV_LOG_ERROR, "Error initializing libspeex decoder.\n"); return -1; } if (avctx->channels == 2) { SpeexCallback callback; callback.callback_id = SPEEX_INBAND_STEREO; callback.func = speex_std_stereo_request_handler; callback.data = &s->stereo; s->stereo = (SpeexStereoState)SPEEX_STEREO_STATE_INIT; speex_decoder_ctl(s->dec_state, SPEEX_SET_HANDLER, &callback); } return 0; }
void SndSysSpeexSoundStream::AdvancePosition(size_t frame_delta) { if (m_bPaused || m_bPlaybackReadComplete || frame_delta==0) return; // Figure out how many bytes we need to fill for this advancement size_t needed_bytes = frame_delta * (m_RenderFormat.Bits/8) * m_RenderFormat.Channels; // If we need more space than is available in the whole cyclic buffer, then we already underbuffered, reduce to just 1 cycle full if ((size_t)needed_bytes > m_pCyclicBuffer->GetLength()) needed_bytes=(size_t)(m_pCyclicBuffer->GetLength() & 0x7FFFFFFF); // Free space in the cyclic buffer if necessary if ((size_t)needed_bytes > m_pCyclicBuffer->GetFreeBytes()) m_pCyclicBuffer->AdvanceStartValue(needed_bytes - (size_t)(m_pCyclicBuffer->GetFreeBytes() & 0x7FFFFFFF)); // Fill in leftover decoded data if needed if (m_PreparedDataBufferUsage > 0) needed_bytes-=CopyBufferBytes(needed_bytes); while (needed_bytes > 0) { if(newPage) { if(ogg_sync_pageout(&oy, &og) != 1) { // Mark as complete if not looping. if (!m_bLooping) { m_bPlaybackReadComplete = true; } // Reset stream. ResetPosition(); return; } if (!stream_init) { ogg_stream_init(&os, ogg_page_serialno(&og)); stream_init = true; } if (ogg_page_serialno(&og) != os.serialno) { ogg_stream_reset_serialno(&os, ogg_page_serialno(&og)); } ogg_stream_pagein(&os, &og); newPage = false; } if(ogg_stream_packetout(&os, &op) != 1) { newPage = true; continue; } // First packets contain header data. if(packet_count == 0) { if(header) { speex_header_free(header); } header = speex_packet_to_header((char*)op.packet, op.bytes); // const_cast for version compatibility. SpeexMode* mode = const_cast<SpeexMode*>(speex_lib_get_mode (header->mode)); state = speex_decoder_init(mode); speex_decoder_ctl(state, SPEEX_SET_SAMPLING_RATE, &header->rate); m_OutputFrequency=m_NewOutputFrequency; // Create the pcm sample converter if it's not yet created if (m_pPCMConverter == 0) m_pPCMConverter = new PCMSampleConverter ( m_RenderFormat.Channels, m_RenderFormat.Bits, m_RenderFormat.Freq); // Calculate the size of one source sample int source_sample_size = m_RenderFormat.Channels * m_RenderFormat.Bits; // Calculate the needed buffer size for this conversion int needed_buffer = (m_pPCMConverter->GetRequiredOutputBufferMultiple ( m_RenderFormat.Channels, m_RenderFormat.Bits, m_OutputFrequency) * (4096 + source_sample_size))/1024; // Allocate a new buffer. if (m_PreparedDataBufferSize < needed_buffer) { delete[] m_pPreparedDataBuffer; m_pPreparedDataBuffer = new char[needed_buffer]; m_PreparedDataBufferSize=needed_buffer; } } if(packet_count++ < uint(2+header->extra_headers)) { continue; } // Read and decode. speex_bits_read_from(&bits, (char*)op.packet, op.bytes); speex_decode_int(state, &bits, (int16*)m_pPreparedDataBuffer); // Frame size is in shorts. speex_decoder_ctl(state, SPEEX_GET_FRAME_SIZE, &m_PreparedDataBufferUsage); m_PreparedDataBufferUsage *= sizeof(short); if (m_PreparedDataBufferUsage > 0) needed_bytes -= CopyBufferBytes (needed_bytes); } }
static void *process_header(spx_ogg_packet *op, int enh_enabled, int *frame_size, int *rate, int *nframes, int *channels, SpeexStereoState *stereo, int *extra_headers ) { void *st; const SpeexMode *mode; SpeexHeader *header; int modeID; SpeexCallback callback; header = speex_packet_to_header((char*)op->packet, op->bytes); if (!header){ DEBUGF ("Cannot read header\n"); return NULL; } if (header->mode >= SPEEX_NB_MODES){ DEBUGF ("Mode does not exist\n"); return NULL; } modeID = header->mode; mode = speex_lib_get_mode(modeID); if (header->speex_version_id > 1) { DEBUGF("Undecodeable bitstream"); return NULL; } if (mode->bitstream_version < header->mode_bitstream_version){ DEBUGF("Undecodeable bitstream, newer bitstream"); return NULL; } if (mode->bitstream_version > header->mode_bitstream_version){ DEBUGF("Too old bitstream"); return NULL; } st = speex_decoder_init(mode); if (!st){ DEBUGF("Decoder init failed"); return NULL; } speex_decoder_ctl(st, SPEEX_SET_ENH, &enh_enabled); speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size); if (header->nb_channels!=1){ callback.callback_id = SPEEX_INBAND_STEREO; callback.func = speex_std_stereo_request_handler; callback.data = stereo; speex_decoder_ctl(st, SPEEX_SET_HANDLER, &callback); } *channels = header->nb_channels; if (!*rate) *rate = header->rate; speex_decoder_ctl(st, SPEEX_SET_SAMPLING_RATE, rate); *nframes = header->frames_per_packet; *extra_headers = header->extra_headers; return st; }
void *AudioStreamPlaybackSpeex::process_header(ogg_packet *op, int *frame_size, int *rate, int *nframes, int *channels, int *extra_headers) { SpeexHeader *header; int modeID; header = speex_packet_to_header((char *)op->packet, op->bytes); if (!header) { OS::get_singleton()->printerr("Cannot read header\n"); return NULL; } if (header->mode >= SPEEX_NB_MODES) { OS::get_singleton()->printerr("Mode number %d does not (yet/any longer) exist in this version\n", header->mode); return NULL; } modeID = header->mode; const SpeexMode *mode = speex_lib_get_mode(modeID); if (header->speex_version_id > 1) { OS::get_singleton()->printerr("This file was encoded with Speex bit-stream version %d, which I don't know how to decode\n", header->speex_version_id); return NULL; } if (mode->bitstream_version < header->mode_bitstream_version) { OS::get_singleton()->printerr("The file was encoded with a newer version of Speex. You need to upgrade in order to play it.\n"); return NULL; } if (mode->bitstream_version > header->mode_bitstream_version) { OS::get_singleton()->printerr("The file was encoded with an older version of Speex. You would need to downgrade the version in order to play it.\n"); return NULL; } void *state = speex_decoder_init(mode); if (!state) { OS::get_singleton()->printerr("Decoder initialization failed.\n"); return NULL; } //speex_decoder_ctl(state, SPEEX_SET_ENH, &enh_enabled); speex_decoder_ctl(state, SPEEX_GET_FRAME_SIZE, frame_size); if (!*rate) *rate = header->rate; speex_decoder_ctl(state, SPEEX_SET_SAMPLING_RATE, rate); *nframes = header->frames_per_packet; *channels = header->nb_channels; if (*channels != 1) { OS::get_singleton()->printerr("Only MONO speex streams supported\n"); return NULL; } *extra_headers = header->extra_headers; speex_free(header); return state; }