Ignore:
Timestamp:
10/06/06 17:14:05 (18 years ago)
Author:
zorg
Message:

Separated public interface from private headers
Use opaque objects whenever possible
Some (useless?) cosmetics on libmpcdec
Remove sv5-6 outdated support
Added libwavformat for upcoming mpcdec
New layout
Work in progress...

File:
1 edited

Legend:

Unmodified
Added
Removed
  • libmpcdec/branches/zorg/src/streaminfo.c

    r37 r68  
    3232  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    3333*/
    34 
    3534/// \file streaminfo.c
    3635/// Implementation of streaminfo reading functions.
    3736
    38 #include <mpcdec/mpcdec.h>
    39 #include <mpcdec/internal.h>
     37#include <mpcdec/streaminfo.h>
     38#include <stdio.h>
     39#include "internal.h"
     40
     41static const char na[] = "n.a.";
     42static const char *versionNames[] = {
     43    na, "'Unstable/Experimental'", na, na, na, "'quality 0'", "'quality 1'",
     44    "'Telephone'", "'Thumb'", "'Radio'", "'Standard'", "'Extreme'", "'Insane'",
     45    "'BrainDead'", "'quality 9'", "'quality 10'"
     46};
     47static const mpc_int32_t samplefreqs[4] = { 44100, 48000, 37800, 32000 };
    4048
    4149static const char *
    42 Stringify(mpc_uint32_t profile) // profile is 0...15, where 7...13 is used
     50mpc_get_version_string(mpc_uint32_t profile) // profile is 0...15, where 7...13 is used
    4351{
    44     static const char na[] = "n.a.";
    45     static const char *Names[] = {
    46         na, "'Unstable/Experimental'", na, na,
    47         na, "'quality 0'", "'quality 1'", "'Telephone'",
    48         "'Thumb'", "'Radio'", "'Standard'", "'Xtreme'",
    49         "'Insane'", "'BrainDead'", "'quality 9'", "'quality 10'"
    50     };
    51 
    52     return profile >= sizeof(Names) / sizeof(*Names) ? na : Names[profile];
     52    return profile >= sizeof versionNames / sizeof *versionNames ? na : versionNames[profile];
    5353}
    5454
    5555void
    56 mpc_streaminfo_init(mpc_streaminfo * si)
     56mpc_streaminfo_init(mpc_streaminfo* si)
    5757{
    58     memset(si, 0, sizeof(mpc_streaminfo));
     58    memset(si, 0, sizeof *si);
    5959}
    6060
    6161/// Reads streaminfo from SV7 header.
    62 static mpc_int32_t
    63 streaminfo_read_header_sv7(mpc_streaminfo * si, mpc_uint32_t HeaderData[8])
     62static mpc_status
     63streaminfo_read_header_sv7(mpc_streaminfo* si, mpc_uint32_t HeaderData[8])
    6464{
    65     const mpc_int32_t samplefreqs[4] = { 44100, 48000, 37800, 32000 };
    66 
    67     //mpc_uint32_t    HeaderData [8];
    6865    mpc_uint16_t Estimatedpeak_title = 0;
    6966
    7067    if (si->stream_version > 0x71) {
    7168        //        Update (si->stream_version);
    72         return 0;
     69        return MPC_STATUS_OK;
    7370    }
    7471
    75     /*
    76        if ( !fp->seek ( si->header_position ) )         // seek to header start
    77        return ERROR_CODE_FILE;
    78        if ( fp->read ( HeaderData, sizeof HeaderData) != sizeof HeaderData )
    79        return ERROR_CODE_FILE;
    80      */
    81 
    82     si->bitrate = 0;
    83     si->frames = HeaderData[1];
    84     si->is = 0;
    85     si->ms = (HeaderData[2] >> 30) & 0x0001;
    86     si->max_band = (HeaderData[2] >> 24) & 0x003F;
    87     si->block_size = 1;
    88     si->profile = (HeaderData[2] << 8) >> 28;
    89     si->profile_name = Stringify(si->profile);
    90     si->sample_freq = samplefreqs[(HeaderData[2] >> 16) & 0x0003];
    91     Estimatedpeak_title = (mpc_uint16_t) (HeaderData[2] & 0xFFFF);   // read the ReplayGain data
    92     si->gain_title = (mpc_uint16_t) ((HeaderData[3] >> 16) & 0xFFFF);
    93     si->peak_title = (mpc_uint16_t) (HeaderData[3] & 0xFFFF);
    94     si->gain_album = (mpc_uint16_t) ((HeaderData[4] >> 16) & 0xFFFF);
    95     si->peak_album = (mpc_uint16_t) (HeaderData[4] & 0xFFFF);
    96     si->is_true_gapless = (HeaderData[5] >> 31) & 0x0001; // true gapless: used?
    97     si->last_frame_samples = (HeaderData[5] >> 20) & 0x07FF;  // true gapless: valid samples for last frame
    98     si->fast_seek = (HeaderData[5] >> 19) & 0x0001;  // fast seeking
    99     si->encoder_version = (HeaderData[6] >> 24) & 0x00FF;
     72    si->bitrate            = 0;
     73    si->frames             = HeaderData[1];
     74    si->is                 = 0;
     75    si->ms                 = (HeaderData[2] >> 30) & 0x0001;
     76    si->max_band           = (HeaderData[2] >> 24) & 0x003F;
     77    si->block_size         = 1;
     78    si->profile            = (HeaderData[2] << 8) >> 28;
     79    si->profile_name       = mpc_get_version_string(si->profile);
     80    si->sample_freq        = samplefreqs[(HeaderData[2] >> 16) & 0x0003];
     81    Estimatedpeak_title    = (mpc_uint16_t) (HeaderData[2] & 0xFFFF);   // read the ReplayGain data
     82    si->gain_title         = (mpc_uint16_t) ((HeaderData[3] >> 16) & 0xFFFF);
     83    si->peak_title         = (mpc_uint16_t) (HeaderData[3] & 0xFFFF);
     84    si->gain_album         = (mpc_uint16_t) ((HeaderData[4] >> 16) & 0xFFFF);
     85    si->peak_album         = (mpc_uint16_t) (HeaderData[4] & 0xFFFF);
     86    si->is_true_gapless    = (HeaderData[5] >> 31) & 0x0001; // true gapless: used?
     87    si->last_frame_samples = (HeaderData[5] >> 20) & 0x07FF; // true gapless: valid samples for last frame
     88    si->fast_seek          = (HeaderData[5] >> 19) & 0x0001; // fast seeking
     89    si->encoder_version    = (HeaderData[6] >> 24) & 0x00FF;
     90    si->channels           = 2;
    10091
    10192    if (si->encoder_version == 0) {
     
    10899                    si->encoder_version / 10 % 10);
    109100            break;
    110         case 2:
    111         case 4:
    112         case 6:
    113         case 8:
     101        case 2: case 4: case 6: case 8:
    114102            sprintf(si->encoder, "Beta %u.%02u", si->encoder_version / 100,
    115103                    si->encoder_version % 100);
     
    122110    }
    123111
    124     //    if ( si->peak_title == 0 )                                      // there is no correct peak_title contained within header
    125     //        si->peak_title = (mpc_uint16_t)(Estimatedpeak_title * 1.18);
    126     //    if ( si->peak_album == 0 )
    127     //        si->peak_album = si->peak_title;                          // no correct peak_album, use peak_title
    128 
    129     //si->sample_freq    = 44100;                                     // AB: used by all files up to SV7
    130     si->channels = 2;
    131 
    132     return ERROR_CODE_OK;
     112    return MPC_STATUS_OK;
    133113}
    134114
    135 // read information from SV4-SV6 header
    136 #ifdef MPC_SUPPORT_SV456
    137 static mpc_int32_t
    138 streaminfo_read_header_sv6(mpc_streaminfo * si, mpc_uint32_t HeaderData[8])
     115// reads file header and tags
     116mpc_status
     117mpc_streaminfo_read(mpc_streaminfo * si, mpc_reader *p_reader)
    139118{
    140     //mpc_uint32_t    HeaderData [8];
    141 
    142     /*
    143        if ( !fp->seek (  si->header_position ) )         // seek to header start
    144        return ERROR_CODE_FILE;
    145        if ( fp->read ( HeaderData, sizeof HeaderData ) != sizeof HeaderData )
    146        return ERROR_CODE_FILE;
    147      */
    148 
    149     si->bitrate = (HeaderData[0] >> 23) & 0x01FF;   // read the file-header (SV6 and below)
    150     si->is = (HeaderData[0] >> 22) & 0x0001;
    151     si->ms = (HeaderData[0] >> 21) & 0x0001;
    152     si->stream_version = (HeaderData[0] >> 11) & 0x03FF;
    153     si->max_band = (HeaderData[0] >> 6) & 0x001F;
    154     si->block_size = (HeaderData[0]) & 0x003F;
    155     si->profile = 0;
    156     si->profile_name = Stringify((mpc_uint32_t) (-1));
    157     if (si->stream_version >= 5)
    158         si->frames = HeaderData[1]; // 32 bit
    159     else
    160         si->frames = (HeaderData[1] >> 16); // 16 bit
    161 
    162     si->gain_title = 0;          // not supported
    163     si->peak_title = 0;
    164     si->gain_album = 0;
    165     si->peak_album = 0;
    166 
    167     si->last_frame_samples = 0;
    168     si->is_true_gapless = 0;
    169 
    170     si->encoder_version = 0;
    171     si->encoder[0] = '\0';
    172 
    173     if (si->stream_version == 7)
    174         return ERROR_CODE_SV7BETA;  // are there any unsupported parameters used?
    175     if (si->bitrate != 0)
    176         return ERROR_CODE_CBR;
    177     if (si->is != 0)
    178         return ERROR_CODE_IS;
    179     if (si->block_size != 1)
    180         return ERROR_CODE_BLOCKSIZE;
    181 
    182     if (si->stream_version < 6) // Bugfix: last frame was invalid for up to SV5
    183         si->frames -= 1;
    184 
    185     si->sample_freq = 44100;     // AB: used by all files up to SV7
    186     si->channels = 2;
    187 
    188     if (si->stream_version < 4 || si->stream_version > 7)
    189         return ERROR_CODE_INVALIDSV;
    190 
    191     return ERROR_CODE_OK;
    192 }
    193 #endif
    194 // reads file header and tags
    195 mpc_int32_t
    196 mpc_streaminfo_read(mpc_streaminfo * si, mpc_reader * r)
    197 {
    198     mpc_uint32_t HeaderData[8];
    199     mpc_int32_t Error = 0;
     119    mpc_uint32_t headerData[8]; int err;
    200120
    201121    // get header position
    202     if ((si->header_position = JumpID3v2(r)) < 0) {
    203         return ERROR_CODE_FILE;
     122    err = si->header_position = mpc_skip_id3v2(p_reader);
     123    if(err < 0) return MPC_STATUS_FILE;
     124
     125    // seek to first byte of mpc data
     126    err = p_reader->seek(p_reader, si->header_position);
     127    if(!err) return MPC_STATUS_FILE;
     128    err = p_reader->read(p_reader, headerData, 8 * 4);
     129    if(err != 8 * 4) return MPC_STATUS_FILE;
     130    err = p_reader->seek(p_reader, si->header_position + 6 * 4);
     131    if(!err) return MPC_STATUS_FILE;
     132
     133    err = p_reader->get_size(p_reader);
     134    if(err < 0) return MPC_STATUS_FILE;
     135    si->tag_offset = si->total_file_length = err;
     136
     137    err = memcmp(headerData, "MP+", 3);
     138    if(!err) return MPC_STATUS_INVALIDSV;
     139
     140#ifndef MPC_LITTLE_ENDIAN
     141    {
     142        mpc_uint32_t ptr;
     143        for (ptr = 0; ptr < 8; ptr++)
     144            headerData[ptr] = mpc_swap32(headerData[ptr]);
    204145    }
    205     // seek to first byte of mpc data
    206     if (!r->seek(r->data, si->header_position)) {
    207         return ERROR_CODE_FILE;
    208     }
    209     if (r->read(r->data, HeaderData, 8 * 4) != 8 * 4) {
    210         return ERROR_CODE_FILE;
    211     }
    212     if (!r->seek(r->data, si->header_position + 6 * 4)) {
    213         return ERROR_CODE_FILE;
    214     }
     146#endif
     147     si->stream_version = headerData[0] >> 24;
    215148
    216     si->total_file_length = r->get_size(r->data);
    217     si->tag_offset = si->total_file_length;
    218     if (memcmp(HeaderData, "MP+", 3) == 0) {
    219 #ifndef MPC_LITTLE_ENDIAN
    220         mpc_uint32_t ptr;
    221         for (ptr = 0; ptr < 8; ptr++) {
    222             HeaderData[ptr] = mpc_swap32(HeaderData[ptr]);
    223         }
    224 #endif
    225         si->stream_version = HeaderData[0] >> 24;
    226 
    227         // stream version 8
    228         if ((si->stream_version & 15) >= 8) {
    229             return ERROR_CODE_INVALIDSV;
    230         }
    231         // stream version 7
    232         else if ((si->stream_version & 15) == 7) {
    233             Error = streaminfo_read_header_sv7(si, HeaderData);
    234             if (Error != ERROR_CODE_OK) return Error;
    235         }
    236     } else {
    237 #ifdef MPC_SUPPORT_SV456
    238         // stream version 4-6
    239         Error = streaminfo_read_header_sv6(si, HeaderData);
    240 #else
    241         return ERROR_CODE_INVALIDSV;
    242 #endif
    243     }
     149     if ((si->stream_version & 15) >= 8)
     150        return MPC_STATUS_INVALIDSV;
     151     else if ((si->stream_version & 15) == 7)
     152     {
     153        err = streaminfo_read_header_sv7(si, headerData);
     154        if(err < 0) return err;
     155     }
    244156
    245157    // estimation, exact value needs too much time
    246     si->pcm_samples = 1152 * si->frames - 576;
     158    si->pcm_samples     = 1152 * si->frames - 576;
     159    si->average_bitrate = 0;
     160    if (si->pcm_samples > 0)
     161        si->average_bitrate = (si->tag_offset  - si->header_position) * 8.0
     162                            *  si->sample_freq / si->pcm_samples;
    247163
    248     if (si->pcm_samples > 0) {
    249         si->average_bitrate =
    250             (si->tag_offset -
    251              si->header_position) * 8.0 * si->sample_freq / si->pcm_samples;
    252     }
    253     else {
    254         si->average_bitrate = 0;
    255     }
    256 
    257     return ERROR_CODE_OK;
     164    return MPC_STATUS_OK;
    258165}
    259166
     
    261168mpc_streaminfo_get_length(mpc_streaminfo * si)
    262169{
    263     return (double)mpc_streaminfo_get_length_samples(si) /
    264         (double)si->sample_freq;
     170    return (double) mpc_streaminfo_get_length_samples(si) / si->sample_freq;
    265171}
    266172
     
    269175{
    270176    mpc_int64_t samples = (mpc_int64_t) si->frames * MPC_FRAME_LENGTH;
    271     if (si->is_true_gapless) {
     177    if (si->is_true_gapless)
    272178        samples -= (MPC_FRAME_LENGTH - si->last_frame_samples);
    273     }
    274     else {
     179    else
    275180        samples -= MPC_DECODER_SYNTH_DELAY;
    276     }
    277181    return samples;
    278182}
Note: See TracChangeset for help on using the changeset viewer.