Ticket #3041: mythmusic_lengthcalc_new.diff

File mythmusic_lengthcalc_new.diff, 5.8 KB (added by stuartm, 12 years ago)

Uses Xing header for VBR mp3 length calculation

  • mythmusic/mythmusic/metaioid3v2.cpp

     
    1212
    1313#include "metaio_libid3hack.h"
    1414
    15 
    1615#include <mythtv/mythcontext.h>
    1716
    1817//==========================================================================
     
    241240            free(p_utf8);
    242241        }
    243242
     243         //length = getComment(tag, "TLEN").toInt();
     244
    244245        id3_file_close(p_input);
    245246    }
    246247
     
    250251        readFromFilename(filename, artist, album, title, genre, tracknum);
    251252    }
    252253
    253     length = getTrackLength(filename);
     254    if (length <= 0)
     255        length = getTrackLength(filename);
    254256
    255257    // If we don't have title and artist or don't have the length return NULL
    256258    if ((title.isEmpty() && artist.isEmpty()) || length<=0)
     
    262264
    263265    Metadata *retdata = new Metadata(filename, artist, compilation_artist, album,
    264266                                     title, genre, year, tracknum, length);
    265                                      
     267
    266268    retdata->setCompilation(compilation);
    267269
    268270    return retdata;
     
    280282{
    281283    struct mad_stream stream;
    282284    struct mad_header header;
     285    struct mad_frame frame;
    283286    mad_timer_t timer;
    284287
    285288    unsigned char buffer[8192];
     
    287290
    288291    mad_stream_init(&stream);
    289292    mad_header_init(&header);
    290    
     293    mad_frame_init(&frame);
     294
    291295    timer = mad_timer_zero;
    292296
    293297    FILE *input = fopen(filename.local8Bit(), "r");
     
    340344            }
    341345            else
    342346            {
     347
     348                if (amount_checked == 0)
     349                {
     350                    frame.header = header;
     351                    if (mad_frame_decode(&frame, &stream) == -1)
     352                    {
     353                            if (!MAD_RECOVERABLE(stream.error))
     354                            {
     355                                    VERBOSE(VB_IMPORTANT, "Unrecoverable libmad stream error.");
     356                                    break;
     357                            }
     358                    }
     359
     360                    xing xing;
     361                    xing.frames = 0;
     362                    xing.bytes = 0;
     363
     364                    if (findXingHeader(&xing, stream.anc_ptr, stream.anc_bitlen))
     365                    {
     366                        unsigned long frames = xing.frames;
     367                        mad_timer_t duration = header.duration;
     368                        mad_timer_multiply(&duration, frames);
     369                        alt_length = mad_timer_count(duration, MAD_UNITS_MILLISECONDS);
     370                        loop_de_doo = false;
     371                        break;
     372                    }
     373                }
     374
    343375                if(amount_checked == 0)
    344376                {
    345377                    old_bitrate = header.bitrate;
     
    357389                amount_checked++;
    358390                mad_timer_add(&timer, header.duration);
    359391            }
    360            
     392
    361393        }
    362        
     394
    363395        if (stream.error != MAD_ERROR_BUFLEN)
    364396            break;
    365397
     
    369401
    370402    mad_header_finish(&header);
    371403    mad_stream_finish(&stream);
     404    mad_frame_finish(&frame);
    372405
    373406    fclose(input);
    374407
     
    378411    return alt_length;
    379412}
    380413
     414bool MetaIOID3v2::findXingHeader(xing *xing, struct mad_bitptr ptr, unsigned int bitlen)
     415{
     416    if (bitlen < 64 || mad_bit_read(&ptr, 32) != XING_MAGIC)
     417        goto fail;
    381418
     419    xing->flags = mad_bit_read(&ptr, 32);
     420    bitlen -= 64;
     421
     422    if (xing->flags & XING_FRAMES) {
     423        if (bitlen < 32)
     424            goto fail;
     425
     426        xing->frames = mad_bit_read(&ptr, 32);
     427        bitlen -= 32;
     428    }
     429
     430    if (xing->flags & XING_BYTES) {
     431        if (bitlen < 32)
     432            goto fail;
     433
     434        xing->bytes = mad_bit_read(&ptr, 32);
     435        bitlen -= 32;
     436    }
     437
     438    if (xing->flags & XING_TOC) {
     439        int i;
     440
     441        if (bitlen < 800)
     442            goto fail;
     443
     444        for (i = 0; i < 100; ++i)
     445            xing->toc[i] = mad_bit_read(&ptr, 8);
     446
     447        bitlen -= 800;
     448    }
     449
     450    if (xing->flags & XING_SCALE) {
     451        if (bitlen < 32)
     452            goto fail;
     453
     454        xing->scale = mad_bit_read(&ptr, 32);
     455        bitlen -= 32;
     456    }
     457
     458    return true;
     459
     460 fail:
     461    xing->flags = 0;
     462    xing->frames = 0;
     463    xing->bytes = 0;
     464    xing->scale = 0;
     465    return false;
     466}
     467
    382468inline QString MetaIOID3v2::getRawID3String(union id3_field *pField)
    383469{
    384470    QString tmp = "";
  • mythmusic/mythmusic/metaioid3v2.h

     
    1212#define MYTH_ID3_FRAME_COMMENT "TXXX"
    1313#define MYTH_ID3_FRAME_MUSICBRAINZ_ALBUMARTISTDESC "MusicBrainz Album Artist Id"
    1414
     15#define XING_MAGIC     (('X' << 24) | ('i' << 16) | ('n' << 8) | 'g')
     16
     17typedef struct {
     18    int flags;
     19    unsigned long frames;
     20    unsigned long bytes;
     21    unsigned char toc[100];
     22    long scale;
     23} xing;
     24
    1525class MetaIOID3v2 : public MetaIO
    1626{
    1727public:
    1828    MetaIOID3v2(void);
    1929    virtual ~MetaIOID3v2(void);
    20    
     30
    2131    bool write(Metadata* mdata, bool exclusive = false);
    2232    Metadata* read(QString filename);
    23    
     33
    2434private:
     35    enum {
     36        XING_FRAMES = 0x0001,
     37        XING_BYTES  = 0x0002,
     38        XING_TOC    = 0x0004,
     39        XING_SCALE  = 0x0008
     40    };
     41
    2542    int getTrackLength(QString filename);
    2643
    2744    QString getRawID3String(union id3_field *pField);
    2845    void removeComment(id3_tag *pTag, const char* pLabel, const QString desc = "");
    2946    QString getComment(id3_tag *pTag, const char* pLabel,
    3047                       const QString desc = "");
    31    
     48
    3249    bool setComment(id3_tag *pTag, const char* pLabel, const QString value,
    3350                    const QString desc = "");
     51
     52    bool findXingHeader(xing *xing, struct mad_bitptr ptr, unsigned int bitlen);
    3453};
    3554
    3655#endif