static sf_count_t txw_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { BUF_UNION ubuf ; unsigned char *ucptr ; short sample ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; double normfact ; if (psf->norm_double == SF_TRUE) normfact = 1.0 / 0x8000 ; else normfact = 1.0 / 0x10 ; bufferlen = sizeof (ubuf.cbuf) / 3 ; bufferlen -= (bufferlen & 1) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = psf_fread (ubuf.cbuf, 3, readcount, psf) ; ucptr = ubuf.ucbuf ; for (k = 0 ; k < readcount ; k += 2) { sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ; ptr [total + k] = normfact * sample ; sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ; ptr [total + k + 1] = normfact * sample ; ucptr += 3 ; } ; total += count ; len -= readcount ; } ; return total ; } /* txw_read_d */
static sf_count_t txw_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { unsigned char *ucptr ; short sample ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; float normfact ; if (psf->norm_float == SF_TRUE) normfact = 1.0 / 0x8000 ; else normfact = 1.0 / 0x10 ; bufferlen = sizeof (psf->buffer) / 3 ; bufferlen -= (bufferlen & 1) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = psf_fread (psf->buffer, 3, readcount, psf->filedes) ; ucptr = (unsigned char *) psf->buffer ; for (k = 0 ; k < readcount ; k += 2) { sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ; ptr [total + k] = normfact * sample ; sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ; ptr [total + k + 1] = normfact * sample ; ucptr += 3 ; } ; total += count ; len -= readcount ; } ; return total ; } /* txw_read_f */
static sf_count_t txw_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { BUF_UNION ubuf ; unsigned char *ucptr ; short sample ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; bufferlen = sizeof (ubuf.cbuf) / 3 ; bufferlen -= (bufferlen & 1) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = psf_fread (ubuf.cbuf, 3, readcount, psf) ; ucptr = ubuf.ucbuf ; for (k = 0 ; k < readcount ; k += 2) { sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ; ptr [total + k] = sample << 16 ; sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ; ptr [total + k + 1] = sample << 16 ; ucptr += 3 ; } ; total += count ; len -= readcount ; } ; return total ; } /* txw_read_i */
static sf_count_t txw_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { unsigned char *ucptr ; short sample ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; bufferlen = sizeof (psf->buffer) / 3 ; bufferlen -= (bufferlen & 1) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = psf_fread (psf->buffer, 3, readcount, psf->filedes) ; ucptr = (unsigned char *) psf->buffer ; for (k = 0 ; k < readcount ; k += 2) { sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ; ptr [total + k] = sample ; sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ; ptr [total + k + 1] = sample ; ucptr += 3 ; } ; total += count ; len -= readcount ; } ; return total ; } /* txw_read_s */
void wav_w64_analyze (SF_PRIVATE *psf) { AUDIO_DETECT ad ; int format = 0 ; if (psf->is_pipe) { psf_log_printf (psf, "*** Error : Reading from a pipe. Can't analyze data section to figure out real data format.\n\n") ; return ; } ; psf_log_printf (psf, "---------------------------------------------------\n" "Format is known to be broken. Using detection code.\n") ; /* Code goes here. */ ad.endianness = SF_ENDIAN_LITTLE ; ad.channels = psf->sf.channels ; psf_fseek (psf, 3 * 4 * 50, SEEK_SET) ; while (psf_fread (psf->u.ucbuf, 1, 4096, psf) == 4096) { format = audio_detect (psf, &ad, psf->u.ucbuf, 4096) ; if (format != 0) break ; } ; /* Seek to start of DATA section. */ psf_fseek (psf, psf->dataoffset, SEEK_SET) ; if (format == 0) { psf_log_printf (psf, "wav_w64_analyze : detection failed.\n") ; return ; } ; switch (format) { case SF_FORMAT_PCM_32 : case SF_FORMAT_FLOAT : psf_log_printf (psf, "wav_w64_analyze : found format : 0x%X\n", format) ; psf->sf.format = (psf->sf.format & ~SF_FORMAT_SUBMASK) + format ; psf->bytewidth = 4 ; psf->blockwidth = psf->sf.channels * psf->bytewidth ; break ; case SF_FORMAT_PCM_24 : psf_log_printf (psf, "wav_w64_analyze : found format : 0x%X\n", format) ; psf->sf.format = (psf->sf.format & ~SF_FORMAT_SUBMASK) + format ; psf->bytewidth = 3 ; psf->blockwidth = psf->sf.channels * psf->bytewidth ; break ; default : psf_log_printf (psf, "wav_w64_analyze : unhandled format : 0x%X\n", format) ; break ; } ; return ; } /* wav_w64_analyze */
static void test_read_or_die (SF_PRIVATE *psf, void *data, sf_count_t bytes, sf_count_t items, sf_count_t new_position, int linenum) { sf_count_t retval ; retval = psf_fread (data, bytes, items, psf) ; if (retval != items) { printf ("\n\nLine %d: psf_write() returned %ld (should be %ld)\n\n", linenum, (long) retval, (long) items) ; exit (1) ; } ; if ((retval = psf_ftell (psf)) != new_position) { printf ("\n\nLine %d: file length after write is not correct. (%ld should be %ld)\n\n", linenum, (long) retval, (long) new_position) ; exit (1) ; } ; return ; } /* test_write_or_die */
static int vorbis_length_get_next_page (SF_PRIVATE *psf, ogg_sync_state * osync, ogg_page *page) { static const int CHUNK_SIZE = 4500 ; while (ogg_sync_pageout (osync, page) <= 0) { char * buffer = ogg_sync_buffer (osync, CHUNK_SIZE) ; int bytes = psf_fread (buffer, 1, 4096, psf) ; if (bytes <= 0) { ogg_sync_wrote (osync, 0) ; return 0 ; } ; ogg_sync_wrote (osync, bytes) ; } ; return 1 ; } /* vorbis_length_get_next_page */
static int caf_get_chunk_data (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) { int indx ; sf_count_t pos ; if ((indx = psf_find_read_chunk_iterator (&psf->rchunks, iterator)) < 0) return SFE_UNKNOWN_CHUNK ; if (chunk_info->data == NULL) return SFE_BAD_CHUNK_DATA_PTR ; chunk_info->id_size = psf->rchunks.chunks [indx].id_size ; memcpy (chunk_info->id, psf->rchunks.chunks [indx].id, sizeof (chunk_info->id) / sizeof (*chunk_info->id)) ; pos = psf_ftell (psf) ; psf_fseek (psf, psf->rchunks.chunks [indx].offset, SEEK_SET) ; psf_fread (chunk_info->data, SF_MIN (chunk_info->datalen, psf->rchunks.chunks [indx].len), 1, psf) ; psf_fseek (psf, pos, SEEK_SET) ; return SFE_NO_ERROR ; } /* caf_get_chunk_data */
static int spx_read_header (SF_PRIVATE * psf) { static SpeexStereoState STEREO_INIT = SPEEX_STEREO_STATE_INIT ; OGG_PRIVATE* odata = psf->container_data ; SPX_PRIVATE* spx = psf->codec_data ; ogg_int64_t page_granule = 0 ; int stream_init = 0 ; int page_nb_packets = 0 ; int packet_count = 0 ; int enh_enabled = 1 ; int force_mode = -1 ; char * data ; int nb_read ; int lookahead ; printf ("%s %d\n", __func__, __LINE__) ; psf_log_printf (psf, "Speex header\n") ; odata->eos = 0 ; /* Reset ogg stuff which has already been used in src/ogg.c. */ ogg_stream_reset (&odata->ostream) ; ogg_sync_reset (&odata->osync) ; /* Seek to start of stream. */ psf_fseek (psf, 0, SEEK_SET) ; /* Initialize. */ ogg_sync_init (&odata->osync) ; speex_bits_init (&spx->bits) ; /* Set defaults. */ psf->sf.channels = -1 ; psf->sf.samplerate = 0 ; spx->stereo = STEREO_INIT ; /* Get a pointer to the ogg buffer and read data into it. */ data = ogg_sync_buffer (&odata->osync, OGG_SPX_READ_SIZE) ; nb_read = psf_fread (data, 1, OGG_SPX_READ_SIZE, psf) ; ogg_sync_wrote (&odata->osync, nb_read) ; /* Now we chew on Ogg packets. */ while (ogg_sync_pageout (&odata->osync, &odata->opage) == 1) { if (stream_init == 0) { ogg_stream_init (&odata->ostream, ogg_page_serialno (&odata->opage)) ; stream_init = 1 ; } ; if (ogg_page_serialno (&odata->opage) != odata->ostream.serialno) { /* so all streams are read. */ ogg_stream_reset_serialno (&odata->ostream, ogg_page_serialno (&odata->opage)) ; } ; /*Add page to the bitstream*/ ogg_stream_pagein (&odata->ostream, &odata->opage) ; page_granule = ogg_page_granulepos (&odata->opage) ; page_nb_packets = ogg_page_packets (&odata->opage) ; /*Extract all available packets*/ while (odata->eos == 0 && ogg_stream_packetout (&odata->ostream, &odata->opacket) == 1) { if (odata->opacket.bytes >= 8 && memcmp (odata->opacket.packet, "Speex ", 8) == 0) { spx->serialno = odata->ostream.serialno ; } ; if (spx->serialno == -1 || odata->ostream.serialno != spx->serialno) break ; if (packet_count == 0) { spx->state = spx_header_read (psf, &odata->opacket, enh_enabled, force_mode) ; if (! spx->state) break ; speex_decoder_ctl (spx->state, SPEEX_GET_LOOKAHEAD, &lookahead) ; if (spx->nframes == 0) spx->nframes = 1 ; } else if (packet_count == 1) { spx_print_comments ((const char*) odata->opacket.packet, odata->opacket.bytes) ; } else if (packet_count < 2 + spx->header.extra_headers) { /* Ignore extra headers */ } packet_count ++ ; } ; } ; psf_log_printf (psf, "End\n") ; psf_log_printf (psf, "packet_count %d\n", packet_count) ; psf_log_printf (psf, "page_nb_packets %d\n", page_nb_packets) ; psf_log_printf (psf, "page_granule %lld\n", page_granule) ; return 0 ; } /* spx_read_header */
static sf_count_t vorbis_read_sample (SF_PRIVATE *psf, void *ptr, sf_count_t lens, convert_func *transfn) { VORBIS_PRIVATE *vdata = psf->codec_data ; OGG_PRIVATE *odata = psf->container_data ; int len, samples, i = 0 ; float **pcm ; len = lens / psf->sf.channels ; while ((samples = vorbis_synthesis_pcmout (&vdata->vdsp, &pcm)) > 0) { if (samples > len) samples = len ; i += transfn (psf, samples, ptr, i, psf->sf.channels, pcm) ; len -= samples ; /* tell libvorbis how many samples we actually consumed */ vorbis_synthesis_read (&vdata->vdsp, samples) ; vdata->loc += samples ; if (len == 0) return i ; /* Is this necessary */ } goto start0 ; /* Jump into the nasty nest */ while (len > 0 && !odata->eos) { while (len > 0 && !odata->eos) { int result = ogg_sync_pageout (&odata->osync, &odata->opage) ; if (result == 0) break ; /* need more data */ if (result < 0) { /* missing or corrupt data at this page position */ psf_log_printf (psf, "Corrupt or missing data in bitstream ; continuing...\n") ; } else { /* can safely ignore errors at this point */ ogg_stream_pagein (&odata->ostream, &odata->opage) ; start0: while (1) { result = ogg_stream_packetout (&odata->ostream, &odata->opacket) ; if (result == 0) break ; /* need more data */ if (result < 0) { /* missing or corrupt data at this page position */ /* no reason to complain ; already complained above */ } else { /* we have a packet. Decode it */ if (vorbis_synthesis (&vdata->vblock, &odata->opacket) == 0) /* test for success! */ vorbis_synthesis_blockin (&vdata->vdsp, &vdata->vblock) ; /* ** pcm is a multichannel float vector. In stereo, for ** example, pcm [0] is left, and pcm [1] is right. samples is ** the size of each channel. Convert the float values ** (-1.<=range<=1.) to whatever PCM format and write it out. */ while ((samples = vorbis_synthesis_pcmout (&vdata->vdsp, &pcm)) > 0) { if (samples > len) samples = len ; i += transfn (psf, samples, ptr, i, psf->sf.channels, pcm) ; len -= samples ; /* tell libvorbis how many samples we actually consumed */ vorbis_synthesis_read (&vdata->vdsp, samples) ; vdata->loc += samples ; if (len == 0) return i ; /* Is this necessary */ } ; } } if (ogg_page_eos (&odata->opage)) odata->eos = 1 ; } } if (!odata->eos) { char *buffer ; int bytes ; buffer = ogg_sync_buffer (&odata->osync, 4096) ; bytes = psf_fread (buffer, 1, 4096, psf) ; ogg_sync_wrote (&odata->osync, bytes) ; if (bytes == 0) odata->eos = 1 ; } } return i ; } /* vorbis_read_sample */
static int vorbis_read_header (SF_PRIVATE *psf, int log_data) { OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; char *buffer ; int bytes ; int i, nn ; odata->eos = 0 ; /* Weird stuff happens if these aren't called. */ ogg_stream_reset (&odata->ostream) ; ogg_sync_reset (&odata->osync) ; /* ** Grab some data at the head of the stream. We want the first page ** (which is guaranteed to be small and only contain the Vorbis ** stream initial header) We need the first page to get the stream ** serialno. */ /* Expose the buffer */ buffer = ogg_sync_buffer (&odata->osync, 4096L) ; /* Grab the part of the header that has already been read. */ memcpy (buffer, psf->header, psf->headindex) ; bytes = psf->headindex ; /* Submit a 4k block to libvorbis' Ogg layer */ bytes += psf_fread (buffer + psf->headindex, 1, 4096 - psf->headindex, psf) ; ogg_sync_wrote (&odata->osync, bytes) ; /* Get the first page. */ if ((nn = ogg_sync_pageout (&odata->osync, &odata->opage)) != 1) { /* Have we simply run out of data? If so, we're done. */ if (bytes < 4096) return 0 ; /* Error case. Must not be Vorbis data */ psf_log_printf (psf, "Input does not appear to be an Ogg bitstream.\n") ; return SFE_MALFORMED_FILE ; } ; /* ** Get the serial number and set up the rest of decode. ** Serialno first ; use it to set up a logical stream. */ ogg_stream_clear (&odata->ostream) ; ogg_stream_init (&odata->ostream, ogg_page_serialno (&odata->opage)) ; if (ogg_stream_pagein (&odata->ostream, &odata->opage) < 0) { /* Error ; stream version mismatch perhaps. */ psf_log_printf (psf, "Error reading first page of Ogg bitstream data\n") ; return SFE_MALFORMED_FILE ; } ; if (ogg_stream_packetout (&odata->ostream, &odata->opacket) != 1) { /* No page? must not be vorbis. */ psf_log_printf (psf, "Error reading initial header packet.\n") ; return SFE_MALFORMED_FILE ; } ; /* ** This function (vorbis_read_header) gets called multiple times, so the OGG ** and vorbis structs have to be cleared every time we pass through to ** prevent memory leaks. */ vorbis_block_clear (&vdata->vblock) ; vorbis_dsp_clear (&vdata->vdsp) ; vorbis_comment_clear (&vdata->vcomment) ; vorbis_info_clear (&vdata->vinfo) ; /* ** Extract the initial header from the first page and verify that the ** Ogg bitstream is in fact Vorbis data. ** ** I handle the initial header first instead of just having the code ** read all three Vorbis headers at once because reading the initial ** header is an easy way to identify a Vorbis bitstream and it's ** useful to see that functionality seperated out. */ vorbis_info_init (&vdata->vinfo) ; vorbis_comment_init (&vdata->vcomment) ; if (vorbis_synthesis_headerin (&vdata->vinfo, &vdata->vcomment, &odata->opacket) < 0) { /* Error case ; not a vorbis header. */ psf_log_printf (psf, "Found Vorbis in stream header, but vorbis_synthesis_headerin failed.\n") ; return SFE_MALFORMED_FILE ; } ; /* ** Common Ogg metadata fields? ** TITLE, VERSION, ALBUM, TRACKNUMBER, ARTIST, PERFORMER, COPYRIGHT, LICENSE, ** ORGANIZATION, DESCRIPTION, GENRE, DATE, LOCATION, CONTACT, ISRC, */ if (log_data) { int k ; for (k = 0 ; k < ARRAY_LEN (vorbis_metatypes) ; k++) { char *dd ; dd = vorbis_comment_query (&vdata->vcomment, vorbis_metatypes [k].name, 0) ; if (dd == NULL) continue ; psf_store_string (psf, vorbis_metatypes [k].id, dd) ; } ; } ; /* ** At this point, we're sure we're Vorbis. We've set up the logical (Ogg) ** bitstream decoder. Get the comment and codebook headers and set up the ** Vorbis decoder. ** ** The next two packets in order are the comment and codebook headers. ** They're likely large and may span multiple pages. Thus we reead ** and submit data until we get our two pacakets, watching that no ** pages are missing. If a page is missing, error out ; losing a ** header page is the only place where missing data is fatal. */ i = 0 ; /* Count of number of packets read */ while (i < 2) { int result = ogg_sync_pageout (&odata->osync, &odata->opage) ; if (result == 0) { /* Need more data */ buffer = ogg_sync_buffer (&odata->osync, 4096) ; bytes = psf_fread (buffer, 1, 4096, psf) ; if (bytes == 0 && i < 2) { psf_log_printf (psf, "End of file before finding all Vorbis headers!\n") ; return SFE_MALFORMED_FILE ; } ; nn = ogg_sync_wrote (&odata->osync, bytes) ; } else if (result == 1) { /* ** Don't complain about missing or corrupt data yet. We'll ** catch it at the packet output phase. ** ** We can ignore any errors here as they'll also become apparent ** at packetout. */ nn = ogg_stream_pagein (&odata->ostream, &odata->opage) ; while (i < 2) { result = ogg_stream_packetout (&odata->ostream, &odata->opacket) ; if (result == 0) break ; if (result < 0) { /* Uh oh ; data at some point was corrupted or missing! ** We can't tolerate that in a header. Die. */ psf_log_printf (psf, "Corrupt secondary header. Exiting.\n") ; return SFE_MALFORMED_FILE ; } ; vorbis_synthesis_headerin (&vdata->vinfo, &vdata->vcomment, &odata->opacket) ; i++ ; } ; } ; } ; if (log_data) { int printed_metadata_msg = 0 ; int k ; psf_log_printf (psf, "Bitstream is %d channel, %D Hz\n", vdata->vinfo.channels, vdata->vinfo.rate) ; psf_log_printf (psf, "Encoded by : %s\n", vdata->vcomment.vendor) ; /* Throw the comments plus a few lines about the bitstream we're decoding. */ for (k = 0 ; k < ARRAY_LEN (vorbis_metatypes) ; k++) { char *dd ; dd = vorbis_comment_query (&vdata->vcomment, vorbis_metatypes [k].name, 0) ; if (dd == NULL) continue ; if (printed_metadata_msg == 0) { psf_log_printf (psf, "Metadata :\n") ; printed_metadata_msg = 1 ; } ; psf_store_string (psf, vorbis_metatypes [k].id, dd) ; psf_log_printf (psf, " %-10s : %s\n", vorbis_metatypes [k].name, dd) ; } ; psf_log_printf (psf, "End\n") ; } ; psf->sf.samplerate = vdata->vinfo.rate ; psf->sf.channels = vdata->vinfo.channels ; psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ; /* OK, got and parsed all three headers. Initialize the Vorbis ** packet->PCM decoder. ** Central decode state. */ vorbis_synthesis_init (&vdata->vdsp, &vdata->vinfo) ; /* Local state for most of the decode so multiple block decodes can ** proceed in parallel. We could init multiple vorbis_block structures ** for vd here. */ vorbis_block_init (&vdata->vdsp, &vdata->vblock) ; vdata->loc = 0 ; return 0 ; } /* vorbis_read_header */
static int ogg_stream_classify (SF_PRIVATE *psf, OGG_PRIVATE* odata) { char *buffer ; int bytes, nn ; /* Call this here so it only gets called once, so no memory is leaked. */ ogg_sync_init (&odata->osync) ; odata->eos = 0 ; /* Weird stuff happens if these aren't called. */ ogg_stream_reset (&odata->ostream) ; ogg_sync_reset (&odata->osync) ; /* ** Grab some data at the head of the stream. We want the first page ** (which is guaranteed to be small and only contain the Vorbis ** stream initial header) We need the first page to get the stream ** serialno. */ /* Expose the buffer */ buffer = ogg_sync_buffer (&odata->osync, 4096L) ; /* Grab the part of the header that has already been read. */ memcpy (buffer, psf->header, psf->headindex) ; bytes = psf->headindex ; /* Submit a 4k block to libvorbis' Ogg layer */ bytes += psf_fread (buffer + psf->headindex, 1, 4096 - psf->headindex, psf) ; ogg_sync_wrote (&odata->osync, bytes) ; /* Get the first page. */ if ((nn = ogg_sync_pageout (&odata->osync, &odata->opage)) != 1) { /* Have we simply run out of data? If so, we're done. */ if (bytes < 4096) return 0 ; /* Error case. Must not be Vorbis data */ psf_log_printf (psf, "Input does not appear to be an Ogg bitstream.\n") ; return SFE_MALFORMED_FILE ; } ; /* ** Get the serial number and set up the rest of decode. ** Serialno first ; use it to set up a logical stream. */ ogg_stream_clear (&odata->ostream) ; ogg_stream_init (&odata->ostream, ogg_page_serialno (&odata->opage)) ; if (ogg_stream_pagein (&odata->ostream, &odata->opage) < 0) { /* Error ; stream version mismatch perhaps. */ psf_log_printf (psf, "Error reading first page of Ogg bitstream data\n") ; return SFE_MALFORMED_FILE ; } ; if (ogg_stream_packetout (&odata->ostream, &odata->opacket) != 1) { /* No page? must not be vorbis. */ psf_log_printf (psf, "Error reading initial header packet.\n") ; return SFE_MALFORMED_FILE ; } ; odata->codec = ogg_page_classify (psf, &odata->opage) ; switch (odata->codec) { case OGG_VORBIS : psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ; return 0 ; case OGG_FLAC : case OGG_FLAC0 : psf->sf.format = SF_FORMAT_OGGFLAC ; return 0 ; case OGG_SPEEX : psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_SPEEX ; return 0 ; case OGG_PCM : psf_log_printf (psf, "Detected Ogg/PCM data. This is not supported yet.\n") ; return SFE_UNIMPLEMENTED ; default : break ; } ; psf_log_printf (psf, "This Ogg bitstream contains some uknown data type.\n") ; return SFE_UNIMPLEMENTED ; } /* ogg_stream_classify */