diff options
Diffstat (limited to 'contrib/libmpcdec/streaminfo.c')
-rw-r--r-- | contrib/libmpcdec/streaminfo.c | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/contrib/libmpcdec/streaminfo.c b/contrib/libmpcdec/streaminfo.c new file mode 100644 index 000000000..060da08d0 --- /dev/null +++ b/contrib/libmpcdec/streaminfo.c @@ -0,0 +1,281 @@ +/* + Copyright (c) 2005, The Musepack Development Team + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of the The Musepack Development Team nor the + names of its contributors may be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/// \file streaminfo.c +/// Implementation of streaminfo reading functions. + +#include <mpcdec/mpcdec.h> +#include <mpcdec/internal.h> + +static const char * +Stringify(mpc_uint32_t profile) // profile is 0...15, where 7...13 is used +{ + static const char na[] = "n.a."; + static const char *Names[] = { + na, "'Unstable/Experimental'", na, na, + na, "'quality 0'", "'quality 1'", "'Telephone'", + "'Thumb'", "'Radio'", "'Standard'", "'Xtreme'", + "'Insane'", "'BrainDead'", "'quality 9'", "'quality 10'" + }; + + return profile >= sizeof(Names) / sizeof(*Names) ? na : Names[profile]; +} + +void +mpc_streaminfo_init(mpc_streaminfo * si) +{ + memset(si, 0, sizeof(mpc_streaminfo)); +} + +/// Reads streaminfo from SV7 header. +static mpc_int32_t +streaminfo_read_header_sv7(mpc_streaminfo * si, mpc_uint32_t HeaderData[8]) +{ + const mpc_int32_t samplefreqs[4] = { 44100, 48000, 37800, 32000 }; + + //mpc_uint32_t HeaderData [8]; + mpc_uint16_t Estimatedpeak_title = 0; + + if (si->stream_version > 0x71) { + // Update (si->stream_version); + return 0; + } + + /* + if ( !fp->seek ( si->header_position ) ) // seek to header start + return ERROR_CODE_FILE; + if ( fp->read ( HeaderData, sizeof HeaderData) != sizeof HeaderData ) + return ERROR_CODE_FILE; + */ + + si->bitrate = 0; + si->frames = HeaderData[1]; + si->is = 0; + si->ms = (HeaderData[2] >> 30) & 0x0001; + si->max_band = (HeaderData[2] >> 24) & 0x003F; + si->block_size = 1; + si->profile = (HeaderData[2] << 8) >> 28; + si->profile_name = Stringify(si->profile); + si->sample_freq = samplefreqs[(HeaderData[2] >> 16) & 0x0003]; + Estimatedpeak_title = (mpc_uint16_t) (HeaderData[2] & 0xFFFF); // read the ReplayGain data + si->gain_title = (mpc_uint16_t) ((HeaderData[3] >> 16) & 0xFFFF); + si->peak_title = (mpc_uint16_t) (HeaderData[3] & 0xFFFF); + si->gain_album = (mpc_uint16_t) ((HeaderData[4] >> 16) & 0xFFFF); + si->peak_album = (mpc_uint16_t) (HeaderData[4] & 0xFFFF); + si->is_true_gapless = (HeaderData[5] >> 31) & 0x0001; // true gapless: used? + si->last_frame_samples = (HeaderData[5] >> 20) & 0x07FF; // true gapless: valid samples for last frame + si->fast_seek = (HeaderData[5] >> 19) & 0x0001; // fast seeking + si->encoder_version = (HeaderData[6] >> 24) & 0x00FF; + + if (si->encoder_version == 0) { + sprintf(si->encoder, "Buschmann 1.7.0...9, Klemm 0.90...1.05"); + } + else { + switch (si->encoder_version % 10) { + case 0: + sprintf(si->encoder, "Release %u.%u", si->encoder_version / 100, + si->encoder_version / 10 % 10); + break; + case 2: + case 4: + case 6: + case 8: + sprintf(si->encoder, "Beta %u.%02u", si->encoder_version / 100, + si->encoder_version % 100); + break; + default: + sprintf(si->encoder, "--Alpha-- %u.%02u", + si->encoder_version / 100, si->encoder_version % 100); + break; + } + } + + // if ( si->peak_title == 0 ) // there is no correct peak_title contained within header + // si->peak_title = (mpc_uint16_t)(Estimatedpeak_title * 1.18); + // if ( si->peak_album == 0 ) + // si->peak_album = si->peak_title; // no correct peak_album, use peak_title + + //si->sample_freq = 44100; // AB: used by all files up to SV7 + si->channels = 2; + + return ERROR_CODE_OK; +} + +// read information from SV4-SV6 header +#ifdef MPC_SUPPORT_SV456 +static mpc_int32_t +streaminfo_read_header_sv6(mpc_streaminfo * si, mpc_uint32_t HeaderData[8]) +{ + //mpc_uint32_t HeaderData [8]; + + /* + if ( !fp->seek ( si->header_position ) ) // seek to header start + return ERROR_CODE_FILE; + if ( fp->read ( HeaderData, sizeof HeaderData ) != sizeof HeaderData ) + return ERROR_CODE_FILE; + */ + + si->bitrate = (HeaderData[0] >> 23) & 0x01FF; // read the file-header (SV6 and below) + si->is = (HeaderData[0] >> 22) & 0x0001; + si->ms = (HeaderData[0] >> 21) & 0x0001; + si->stream_version = (HeaderData[0] >> 11) & 0x03FF; + si->max_band = (HeaderData[0] >> 6) & 0x001F; + si->block_size = (HeaderData[0]) & 0x003F; + si->profile = 0; + si->profile_name = Stringify((mpc_uint32_t) (-1)); + if (si->stream_version >= 5) + si->frames = HeaderData[1]; // 32 bit + else + si->frames = (HeaderData[1] >> 16); // 16 bit + + si->gain_title = 0; // not supported + si->peak_title = 0; + si->gain_album = 0; + si->peak_album = 0; + + si->last_frame_samples = 0; + si->is_true_gapless = 0; + + si->encoder_version = 0; + si->encoder[0] = '\0'; + + if (si->stream_version == 7) + return ERROR_CODE_SV7BETA; // are there any unsupported parameters used? + if (si->bitrate != 0) + return ERROR_CODE_CBR; + if (si->is != 0) + return ERROR_CODE_IS; + if (si->block_size != 1) + return ERROR_CODE_BLOCKSIZE; + + if (si->stream_version < 6) // Bugfix: last frame was invalid for up to SV5 + si->frames -= 1; + + si->sample_freq = 44100; // AB: used by all files up to SV7 + si->channels = 2; + + if (si->stream_version < 4 || si->stream_version > 7) + return ERROR_CODE_INVALIDSV; + + return ERROR_CODE_OK; +} +#endif +// reads file header and tags +mpc_int32_t +mpc_streaminfo_read(mpc_streaminfo * si, mpc_reader * r) +{ + mpc_uint32_t HeaderData[8]; + mpc_int32_t Error = 0; + + // get header position + if ((si->header_position = JumpID3v2(r)) < 0) { + return ERROR_CODE_FILE; + } + // seek to first byte of mpc data + if (!r->seek(r->data, si->header_position)) { + return ERROR_CODE_FILE; + } + if (r->read(r->data, HeaderData, 8 * 4) != 8 * 4) { + return ERROR_CODE_FILE; + } + if (!r->seek(r->data, si->header_position + 6 * 4)) { + return ERROR_CODE_FILE; + } + + si->total_file_length = r->get_size(r->data); + si->tag_offset = si->total_file_length; + + if (memcmp(HeaderData, "MP+", 3)) return ERROR_CODE_INVALIDSV; +#ifndef MPC_LITTLE_ENDIAN + { + mpc_uint32_t ptr; + for (ptr = 0; ptr < 8; ptr++) { + HeaderData[ptr] = mpc_swap32(HeaderData[ptr]); + } + } +#endif + + si->stream_version = HeaderData[0] >> 24; + + // stream version 8 + if ((si->stream_version & 15) >= 8) { + return ERROR_CODE_INVALIDSV; + } + // stream version 7 + else if ((si->stream_version & 15) == 7) { + Error = streaminfo_read_header_sv7(si, HeaderData); + if (Error != ERROR_CODE_OK) return Error; + } +#ifdef MPC_SUPPORT_SV456 + else { + // stream version 4-6 + Error = streaminfo_read_header_sv6(si, HeaderData); + if (Error != ERROR_CODE_OK) return Error; + } +#endif + + // estimation, exact value needs too much time + si->pcm_samples = 1152 * si->frames - 576; + + if (si->pcm_samples > 0) { + si->average_bitrate = + (si->tag_offset - + si->header_position) * 8.0 * si->sample_freq / si->pcm_samples; + } + else { + si->average_bitrate = 0; + } + + return ERROR_CODE_OK; +} + +double +mpc_streaminfo_get_length(mpc_streaminfo * si) +{ + return (double)mpc_streaminfo_get_length_samples(si) / + (double)si->sample_freq; +} + +mpc_int64_t +mpc_streaminfo_get_length_samples(mpc_streaminfo * si) +{ + mpc_int64_t samples = (mpc_int64_t) si->frames * MPC_FRAME_LENGTH; + if (si->is_true_gapless) { + samples -= (MPC_FRAME_LENGTH - si->last_frame_samples); + } + else { + samples -= MPC_DECODER_SYNTH_DELAY; + } + return samples; +} |