示例#1
0
文件: vgm.c 项目: IlVerz/rockbox
static long check_gd3_header( byte* h, long remain )
{
    if ( remain < gd3_header_size ) return 0;
    if ( memcmp( h, "Gd3 ", 4 ) ) return 0;
    if ( get_long_le( h + 4 ) >= 0x200 ) return 0;

    long gd3_size = get_long_le( h + 8 );
    if ( gd3_size > remain - gd3_header_size )
        gd3_size = remain - gd3_header_size;

    return gd3_size;
}
示例#2
0
文件: vgm.c 项目: IlVerz/rockbox
bool get_vgm_metadata(int fd, struct mp3entry* id3)
{
    /* Use the id3v2 part of the id3 structure as a temporary buffer */
    unsigned char* buf = (unsigned char *)id3->id3v2buf;
    int read_bytes;

    memset(buf, 0, ID3V2_BUF_SIZE);
    if ((lseek(fd, 0, SEEK_SET) < 0) 
         || ((read_bytes = read(fd, buf, header_size)) < header_size))
    {
        return false;
    }

    id3->vbr = false;
    id3->filesize = filesize(fd);

    id3->bitrate = 706;
    id3->frequency = 44100;

    /* If file is gzipped, will get metadata later */
    if (memcmp(buf, "Vgm ", 4))
    {
        /* We must set a default song length here because
            the codec can't do it anymore */
        id3->length = 150 * 1000; /* 2.5 minutes */
        return true;
    }

    /* Get song length from header */
    struct header_t* header = (struct header_t*) buf;
    get_vgm_length( header, id3 );

    long gd3_offset = get_long_le( header->gd3_offset ) - 0x2C;
    
    /* No gd3 tag found */
    if ( gd3_offset < 0 )
        return true;

    /*  Seek to gd3 offset and read as 
         many bytes posible */
    gd3_offset = id3->filesize - (header_size + gd3_offset);
    if ((lseek(fd, -gd3_offset, SEEK_END) < 0) 
         || ((read_bytes = read(fd, buf, ID3V2_BUF_SIZE)) <= 0))
        return true;

    byte* gd3 = buf;
    long gd3_size = check_gd3_header( gd3, read_bytes );

    /* GD3 tag is zero */
    if ( gd3_size == 0 )
        return true;

    /* Finally, parse gd3 tag */
    if ( gd3 )
        parse_gd3( gd3 + gd3_header_size, gd3 + read_bytes, id3 );

    return true;
}
示例#3
0
/* Read an int32 from file. Returns false if a read error occurred.
 */
static bool file_read_int32(struct file* file, int32_t* value)
{
    char buf[sizeof(int32_t)];

    if (file_read(file, buf, sizeof(buf)) < (ssize_t) sizeof(buf))
    {
        return false;
    }
    
    *value = get_long_le(buf);
    return true;
}
示例#4
0
文件: vgm.c 项目: IlVerz/rockbox
static void get_vgm_length( struct header_t* h, struct mp3entry* id3 )
{
    long length = get_long_le( h->track_duration ) * 10 / 441;
    if ( length > 0 )
    {
        long loop_length = 0, intro_length = 0;
        long loop = get_long_le( h->loop_duration );
        if ( loop > 0 && get_long_le( h->loop_offset ) )
        {
            loop_length = loop * 10 / 441;
            intro_length = length - loop_length;
        }
        else
        {
            intro_length = length; /* make it clear that track is no longer than length */
            loop_length = 0;
        }
        
         id3->length = intro_length + 2 * loop_length; /* intro + 2 loops */
         return;
    }

    id3->length = 150 * 1000; /* 2.5 minutes */
}
示例#5
0
文件: wavpack.c 项目: IlVerz/rockbox
bool get_wavpack_metadata(int fd, struct mp3entry* id3)
{
    /* Use the trackname part of the id3 structure as a temporary buffer */
    unsigned char* buf = (unsigned char *)id3->path;
    uint32_t totalsamples = (uint32_t) -1;
    int i;

    for (i = 0; i < 256; ++i) {

        /* at every 256 bytes into file, try to read a WavPack header */

        if ((lseek(fd, i * 256, SEEK_SET) < 0) || (read(fd, buf, 32) < 32))
            return false;

        /* if valid WavPack 4 header version, break */

        if (memcmp (buf, "wvpk", 4) == 0 && buf [9] == 4 &&
            (buf [8] >= 2 && buf [8] <= 0x10))
                break;
    }

    if (i == 256) {
        logf ("Not a WavPack file");
        return false;
    }

    id3->vbr = true;   /* All WavPack files are VBR */
    id3->filesize = filesize (fd);

    /* check up to 16 headers before we give up finding one with audio */

    for (i = 0; i < 16; ++i) {
        uint32_t meta_bytes = get_long_le(&buf [4]) - 24;
        uint32_t trial_totalsamples = get_long_le(&buf[12]);
        uint32_t blockindex = get_long_le(&buf[16]);
        uint32_t blocksamples = get_long_le(&buf[20]);
        uint32_t flags = get_long_le(&buf[24]);

        if (totalsamples == (uint32_t) -1 && blockindex == 0)
            totalsamples = trial_totalsamples;

        if (blocksamples) {
            int srindx = ((buf [26] >> 7) & 1) + ((buf [27] << 1) & 14);

            if (srindx == 15) {
                uint32_t meta_size;

                id3->frequency = 44100;

                while (meta_bytes >= 6) {
                    if (read(fd, buf, 2) < 2)
                        break;

                    if (buf [0] & ID_LARGE) {
                        if (read(fd, buf + 2, 2) < 2)
                            break;

                        meta_size = (buf [1] << 1) + (buf [2] << 9) + (buf [3] << 17);
                        meta_bytes -= meta_size + 4;
                    }
                    else {
                        meta_size = buf [1] << 1;
                        meta_bytes -= meta_size + 2;

                        if ((buf [0] & ID_UNIQUE) == ID_SAMPLE_RATE) {
                            if (meta_size == 4 && read(fd, buf + 2, 4) == 4)
                                id3->frequency = buf [2] + (buf [3] << 8) + (buf [4] << 16);

                            break;
                        }
                    }

                    if (meta_size > 0 && lseek(fd, meta_size, SEEK_CUR) < 0)
                        break;
                }
            }
            else
                id3->frequency = wavpack_sample_rates[srindx];

            /* if the total number of samples is still unknown, make a guess on the high side (for now) */

            if (totalsamples == (uint32_t) -1) {
                totalsamples = id3->filesize * 3;

                if (!(flags & HYBRID_FLAG))
                    totalsamples /= 2;

                if (!(flags & MONO_FLAG))
                    totalsamples /= 2;
            }

            id3->length = ((int64_t) totalsamples * 1000) / id3->frequency;
            id3->bitrate = id3->filesize / (id3->length / 8);

            read_ape_tags(fd, id3);
            return true;
        }
        else {   /* block did not contain audio, so seek to the end and see if there's another */
            if ((meta_bytes > 0 && lseek(fd, meta_bytes, SEEK_CUR) < 0) ||
                read(fd, buf, 32) < 32 || memcmp (buf, "wvpk", 4) != 0)
                    break;
        }
    }
示例#6
0
文件: ogg.c 项目: 4nykey/rockbox
/* A simple parser to read vital metadata from an Ogg Vorbis file. 
 * Can also handle parsing Ogg Speex files for metadata. Returns
 * false if metadata needed by the codec couldn't be read.
 */
bool get_ogg_metadata(int fd, struct mp3entry* id3)
{
    /* An Ogg File is split into pages, each starting with the string 
     * "OggS". Each page has a timestamp (in PCM samples) referred to as
     * the "granule position".
     *
     * An Ogg Vorbis has the following structure:
     * 1) Identification header (containing samplerate, numchannels, etc)
     * 2) Comment header - containing the Vorbis Comments
     * 3) Setup header - containing codec setup information
     * 4) Many audio packets...
     *
     * An Ogg Speex has the following structure:
     * 1) Identification header (containing samplerate, numchannels, etc)
     *    Described in this page: (http://www.speex.org/manual2/node7.html)
     * 2) Comment header - containing the Vorbis Comments
     * 3) Many audio packets.
     */

    /* Use the path name of the id3 structure as a temporary buffer. */
    unsigned char* buf = (unsigned char *)id3->path;
    long comment_size;
    long remaining = 0;
    long last_serial = 0;
    long serial, r;
    int segments, header_size;
    int i;
    bool eof = false;

    /* 92 bytes is enough for both Vorbis and Speex headers */
    if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 92) < 92))
    {
        return false;
    }

    /* All Ogg streams start with OggS */
    if (memcmp(buf, "OggS", 4) != 0)
    {
        return false;
    }

    /* Check for format magic and then get metadata */
    if (memcmp(&buf[29], "vorbis", 6) == 0)
    {
        id3->codectype = AFMT_OGG_VORBIS;
        id3->frequency = get_long_le(&buf[40]);
        id3->vbr = true;

        /* Comments are in second Ogg page (byte 58 onwards for Vorbis) */
        if (lseek(fd, 58, SEEK_SET) < 0)
        {
            return false;
        }
    }
    else if (memcmp(&buf[28], "Speex   ", 8) == 0)
    {
        id3->codectype = AFMT_SPEEX;
        id3->frequency = get_slong(&buf[64]);
        id3->vbr = get_long_le(&buf[88]);

        header_size = get_long_le(&buf[60]);

        /* Comments are in second Ogg page (byte 108 onwards for Speex) */
        if (lseek(fd, 28 + header_size, SEEK_SET) < 0)
        {
            return false;
        }
    }
    else if (memcmp(&buf[28], "OpusHead", 8) == 0)
    {
        id3->codectype = AFMT_OPUS;
        id3->frequency = 48000;
        id3->vbr = true;

// FIXME handle an actual channel mapping table
        /* Comments are in second Ogg page (byte 108 onwards for Speex) */
        if (lseek(fd, 47, SEEK_SET) < 0)
        {
            DEBUGF("Couldnotseektoogg");
            return false;
        }
    }
    else
    {
        /* Unsupported format, try to print the marker, catches Ogg/FLAC at least */
        DEBUGF("Usupported format in Ogg stream: %16s\n", &buf[28]);
        return false;
    }

    id3->filesize = filesize(fd);
    
    /* We need to ensure the serial number from this page is the same as the
     * one from the last page (since we only support a single bitstream).
     */
    serial = get_long_le(&buf[14]);
    comment_size = read_vorbis_tags(fd, id3, remaining);

    /* We now need to search for the last page in the file - identified by 
     * by ('O','g','g','S',0) and retrieve totalsamples.
     */

    /* A page is always < 64 kB */
    if (lseek(fd, -(MIN(64 * 1024, id3->filesize)), SEEK_END) < 0)
    {
        return false;
    }

    remaining = 0;

    while (!eof) 
    {
        r = read(fd, &buf[remaining], MAX_PATH - remaining);
        
        if (r <= 0) 
        {
            eof = true;
        } 
        else 
        {
            remaining += r;
        }
        
        /* Inefficient (but simple) search */
        i = 0;
        
        while (i < (remaining - 3)) 
        {
            if ((buf[i] == 'O') && (memcmp(&buf[i], "OggS", 4) == 0))
            {
                if (i < (remaining - 17)) 
                {
                    /* Note that this only reads the low 32 bits of a
                     * 64 bit value.
                     */
                     id3->samples = get_long_le(&buf[i + 6]);
                     last_serial = get_long_le(&buf[i + 14]);

                    /* If this page is very small the beginning of the next
                     * header could be in buffer. Jump near end of this header
                     * and continue */
                    i += 27;
                } 
                else 
                {
                    break;
                }
            } 
            else 
            {
                i++;
            }
        }

        if (i < remaining) 
        {
            /* Move the remaining bytes to start of buffer.
             * Reuse var 'segments' as it is no longer needed */
            segments = 0;
            while (i < remaining)
            {
                buf[segments++] = buf[i++];
            }
            remaining = segments;
        }
        else
        {
            /* Discard the rest of the buffer */
            remaining = 0;
        }
    }

    /* This file has mutiple vorbis bitstreams (or is corrupt). */
    /* FIXME we should display an error here. */
    if (serial != last_serial)
    {
        logf("serialno mismatch");
        logf("%ld", serial);
        logf("%ld", last_serial);
        return false;
    }

    id3->length = ((int64_t) id3->samples * 1000) / id3->frequency;
    if (id3->length <= 0)
    {
        logf("ogg length invalid!");
        return false;
    }
    
    id3->bitrate = (((int64_t) id3->filesize - comment_size) * 8) / id3->length;
    
    return true;
}
示例#7
0
bool get_monkeys_metadata(int fd, struct mp3entry* id3)
{
    /* Use the trackname part of the id3 structure as a temporary buffer */
    unsigned char* buf = (unsigned char *)id3->path;
    unsigned char* header;
    bool rc = false;
    uint32_t descriptorlength;
    uint32_t totalsamples;
    uint32_t blocksperframe, finalframeblocks, totalframes;
    int fileversion;

    lseek(fd, 0, SEEK_SET);

    if (read(fd, buf, 4) < 4)
    {
        return rc;
    }
    
    if (memcmp(buf, "MAC ", 4) != 0) 
    {
        return rc;
    }

    read(fd, buf + 4, MAX_PATH - 4);

    fileversion = get_short_le(buf+4);
    if (fileversion < 3970)
    {
        /* Not supported */
        return false;
    }

    if (fileversion >= 3980)
    {
        descriptorlength = get_long_le(buf+8);

        header = buf + descriptorlength;

        blocksperframe = get_long_le(header+4);
        finalframeblocks = get_long_le(header+8);
        totalframes = get_long_le(header+12);
        id3->frequency = get_long_le(header+20);
    } 
    else 
    {
        /* v3.95 and later files all have a fixed framesize */
        blocksperframe = 73728 * 4;

        finalframeblocks = get_long_le(buf+28);
        totalframes = get_long_le(buf+24);
        id3->frequency = get_long_le(buf+12);
    }

    id3->vbr = true;   /* All APE files are VBR */
    id3->filesize = filesize(fd);

    totalsamples = finalframeblocks;
    if (totalframes > 1)
        totalsamples += blocksperframe * (totalframes-1);

    id3->length = ((int64_t) totalsamples * 1000) / id3->frequency;
    id3->bitrate = (id3->filesize * 8) / id3->length;
    return true;
}