libmpcdec: src/streaminfo.c Source File

Main Page | Class List | Directories | File List | Class Members | File Members | Related Pages

# streaminfo.c

Go to the documentation of this file.

    00001 /*
    00002   Copyright (c) 2005, The Musepack Development Team
    00003   All rights reserved.
    00004
    00005   Redistribution and use in source and binary forms, with or without
    00006   modification, are permitted provided that the following conditions are
    00007   met:
    00008
    00009   * Redistributions of source code must retain the above copyright
    00010   notice, this list of conditions and the following disclaimer.
    00011
    00012   * Redistributions in binary form must reproduce the above
    00013   copyright notice, this list of conditions and the following
    00014   disclaimer in the documentation and/or other materials provided
    00015   with the distribution.
    00016
    00017   * Neither the name of the The Musepack Development Team nor the
    00018   names of its contributors may be used to endorse or promote
    00019   products derived from this software without specific prior
    00020   written permission.
    00021
    00022   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    00023   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    00024   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    00025   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    00026   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    00027   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    00028   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    00029   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    00030   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    00031   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    00032   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    00033 */
    00034
    00037
    00038 #include <mpcdec/mpcdec.h>
    00039 #include <mpcdec/internal.h>
    00040
    00041 static const char *
    00042 Stringify(mpc_uint32_t profile) // profile is 0...15, where 7...13 is used
    00043 {
    00044     static const char na[] = "n.a.";
    00045     static const char *Names[] = {
    00046         na, "'Unstable/Experimental'", na, na,
    00047         na, "'quality 0'", "'quality 1'", "'Telephone'",
    00048         "'Thumb'", "'Radio'", "'Standard'", "'Xtreme'",
    00049         "'Insane'", "'BrainDead'", "'quality 9'", "'quality 10'"
    00050     };
    00051
    00052     return profile >= sizeof(Names) / sizeof(*Names) ? na : Names[profile];
    00053 }
    00054
    00055 void
    00056 mpc_streaminfo_init(mpc_streaminfo * si)
    00057 {
    00058     memset(si, 0, sizeof(mpc_streaminfo));
    00059 }
    00060
    00061 // read information from SV8 header
    00062 // not yet implemented
    00063 static mpc_int32_t
    00064 streaminfo_read_header_sv8(mpc_streaminfo * si, mpc_reader * fp)
    00065 {
    00066     (void) si;
    00067     (void) fp;
    00068     return 0;
    00069 }
    00070
    00072 static mpc_int32_t
    00073 streaminfo_read_header_sv7(mpc_streaminfo * si, mpc_uint32_t HeaderData[8])
    00074 {
    00075     const mpc_int32_t samplefreqs[4] = { 44100, 48000, 37800, 32000 };
    00076
    00077     //mpc_uint32_t    HeaderData [8];
    00078     mpc_uint16_t Estimatedpeak_title = 0;
    00079
    00080     if (si->stream_version > 0x71) {
    00081         //        Update (si->stream_version);
    00082         return 0;
    00083     }
    00084
    00085     /*
    00086        if ( !fp->seek ( si->header_position ) )         // seek to header start
    00087        return ERROR_CODE_FILE;
    00088        if ( fp->read ( HeaderData, sizeof HeaderData) != sizeof HeaderData )
    00089        return ERROR_CODE_FILE;
    00090      */
    00091
    00092     si->bitrate = 0;
    00093     si->frames = HeaderData[1];
    00094     si->is = 0;
    00095     si->ms = (HeaderData[2] >> 30) & 0x0001;
    00096     si->max_band = (HeaderData[2] >> 24) & 0x003F;
    00097     si->block_size = 1;
    00098     si->profile = (HeaderData[2] << 8) >> 28;
    00099     si->profile_name = Stringify(si->profile);
    00100     si->sample_freq = samplefreqs[(HeaderData[2] >> 16) & 0x0003];
    00101     Estimatedpeak_title = (mpc_uint16_t) (HeaderData[2] & 0xFFFF);   // read the ReplayGain data
    00102     si->gain_title = (mpc_uint16_t) ((HeaderData[3] >> 16) & 0xFFFF);
    00103     si->peak_title = (mpc_uint16_t) (HeaderData[3] & 0xFFFF);
    00104     si->gain_album = (mpc_uint16_t) ((HeaderData[4] >> 16) & 0xFFFF);
    00105     si->peak_album = (mpc_uint16_t) (HeaderData[4] & 0xFFFF);
    00106     si->is_true_gapless = (HeaderData[5] >> 31) & 0x0001; // true gapless: used?
    00107     si->last_frame_samples = (HeaderData[5] >> 20) & 0x07FF;  // true gapless: valid samples for last frame
    00108     si->encoder_version = (HeaderData[6] >> 24) & 0x00FF;
    00109
    00110     if (si->encoder_version == 0) {
    00111         sprintf(si->encoder, "Buschmann 1.7.0...9, Klemm 0.90...1.05");
    00112     }
    00113     else {
    00114         switch (si->encoder_version % 10) {
    00115         case 0:
    00116             sprintf(si->encoder, "Release %u.%u", si->encoder_version / 100,
    00117                     si->encoder_version / 10 % 10);
    00118             break;
    00119         case 2:
    00120         case 4:
    00121         case 6:
    00122         case 8:
    00123             sprintf(si->encoder, "Beta %u.%02u", si->encoder_version / 100,
    00124                     si->encoder_version % 100);
    00125             break;
    00126         default:
    00127             sprintf(si->encoder, "--Alpha-- %u.%02u",
    00128                     si->encoder_version / 100, si->encoder_version % 100);
    00129             break;
    00130         }
    00131     }
    00132
    00133     //    if ( si->peak_title == 0 )                                      // there is no correct peak_title contained within header
    00134     //        si->peak_title = (mpc_uint16_t)(Estimatedpeak_title * 1.18);
    00135     //    if ( si->peak_album == 0 )
    00136     //        si->peak_album = si->peak_title;                          // no correct peak_album, use peak_title
    00137
    00138     //si->sample_freq    = 44100;                                     // AB: used by all files up to SV7
    00139     si->channels = 2;
    00140
    00141     return ERROR_CODE_OK;
    00142 }
    00143
    00144 // read information from SV4-SV6 header
    00145 static mpc_int32_t
    00146 streaminfo_read_header_sv6(mpc_streaminfo * si, mpc_uint32_t HeaderData[8])
    00147 {
    00148     //mpc_uint32_t    HeaderData [8];
    00149
    00150     /*
    00151        if ( !fp->seek (  si->header_position ) )         // seek to header start
    00152        return ERROR_CODE_FILE;
    00153        if ( fp->read ( HeaderData, sizeof HeaderData ) != sizeof HeaderData )
    00154        return ERROR_CODE_FILE;
    00155      */
    00156
    00157     si->bitrate = (HeaderData[0] >> 23) & 0x01FF;   // read the file-header (SV6 and below)
    00158     si->is = (HeaderData[0] >> 22) & 0x0001;
    00159     si->ms = (HeaderData[0] >> 21) & 0x0001;
    00160     si->stream_version = (HeaderData[0] >> 11) & 0x03FF;
    00161     si->max_band = (HeaderData[0] >> 6) & 0x001F;
    00162     si->block_size = (HeaderData[0]) & 0x003F;
    00163     si->profile = 0;
    00164     si->profile_name = Stringify((mpc_uint32_t) (-1));
    00165     if (si->stream_version >= 5)
    00166         si->frames = HeaderData[1]; // 32 bit
    00167     else
    00168         si->frames = (HeaderData[1] >> 16); // 16 bit
    00169
    00170     si->gain_title = 0;          // not supported
    00171     si->peak_title = 0;
    00172     si->gain_album = 0;
    00173     si->peak_album = 0;
    00174
    00175     si->last_frame_samples = 0;
    00176     si->is_true_gapless = 0;
    00177
    00178     si->encoder_version = 0;
    00179     si->encoder[0] = '\0';
    00180
    00181     if (si->stream_version == 7)
    00182         return ERROR_CODE_SV7BETA;  // are there any unsupported parameters used?
    00183     if (si->bitrate != 0)
    00184         return ERROR_CODE_CBR;
    00185     if (si->is != 0)
    00186         return ERROR_CODE_IS;
    00187     if (si->block_size != 1)
    00188         return ERROR_CODE_BLOCKSIZE;
    00189
    00190     if (si->stream_version < 6) // Bugfix: last frame was invalid for up to SV5
    00191         si->frames -= 1;
    00192
    00193     si->sample_freq = 44100;     // AB: used by all files up to SV7
    00194     si->channels = 2;
    00195
    00196     if (si->stream_version < 4 || si->stream_version > 7)
    00197         return ERROR_CODE_INVALIDSV;
    00198
    00199     return ERROR_CODE_OK;
    00200 }
    00201
    00202 // reads file header and tags
    00203 mpc_int32_t
    00204 mpc_streaminfo_read(mpc_streaminfo * si, mpc_reader * r)
    00205 {
    00206     mpc_uint32_t HeaderData[8];
    00207     mpc_int32_t Error = 0;
    00208
    00209     // get header position
    00210     if ((si->header_position = JumpID3v2(r)) < 0) {
    00211         return ERROR_CODE_FILE;
    00212     }
    00213     // seek to first byte of mpc data
    00214     if (!r->seek(r->data, si->header_position)) {
    00215         return ERROR_CODE_FILE;
    00216     }
    00217     if (r->read(r->data, HeaderData, 8 * 4) != 8 * 4) {
    00218         return ERROR_CODE_FILE;
    00219     }
    00220     if (!r->seek(r->data, si->header_position + 6 * 4)) {
    00221         return ERROR_CODE_FILE;
    00222     }
    00223
    00224     si->total_file_length = r->get_size(r->data);
    00225     si->tag_offset = si->total_file_length;
    00226     if (memcmp(HeaderData, "MP+", 3) == 0) {
    00227 #ifndef MPC_LITTLE_ENDIAN
    00228         mpc_uint32_t ptr;
    00229         for (ptr = 0; ptr < 8; ptr++) {
    00230             HeaderData[ptr] = mpc_swap32(HeaderData[ptr]);
    00231         }
    00232 #endif
    00233         si->stream_version = HeaderData[0] >> 24;
    00234
    00235         // stream version 8
    00236         if ((si->stream_version & 15) >= 8) {
    00237             Error = streaminfo_read_header_sv8(si, r);
    00238         }
    00239         // stream version 7
    00240         else if ((si->stream_version & 15) == 7) {
    00241             Error = streaminfo_read_header_sv7(si, HeaderData);
    00242         }
    00243     }
    00244     else {
    00245         // stream version 4-6
    00246         Error = streaminfo_read_header_sv6(si, HeaderData);
    00247     }
    00248
    00249     // estimation, exact value needs too much time
    00250     si->pcm_samples = 1152 * si->frames - 576;
    00251
    00252     if (si->pcm_samples > 0) {
    00253         si->average_bitrate =
    00254             (si->tag_offset -
    00255              si->header_position) * 8.0 * si->sample_freq / si->pcm_samples;
    00256     }
    00257     else {
    00258         si->average_bitrate = 0;
    00259     }
    00260
    00261     return Error;
    00262 }
    00263
    00264 double
    00265 mpc_streaminfo_get_length(mpc_streaminfo * si)
    00266 {
    00267     return (double)mpc_streaminfo_get_length_samples(si) /
    00268         (double)si->sample_freq;
    00269 }
    00270
    00271 mpc_int64_t
    00272 mpc_streaminfo_get_length_samples(mpc_streaminfo * si)
    00273 {
    00274     mpc_int64_t samples = (mpc_int64_t) si->frames * MPC_FRAME_LENGTH;
    00275     if (si->is_true_gapless) {
    00276         samples -= (MPC_FRAME_LENGTH - si->last_frame_samples);
    00277     }
    00278     else {
    00279         samples -= MPC_DECODER_SYNTH_DELAY;
    00280     }
    00281     return samples;
    00282 }