2010-08-17 19 views
4

Je ne peux pas utiliser de code mp3 breveté par Fraunhofer, donc pas de codeurs OU de décodeurs (par exemple ffmpeg, lame, MAD, etc.), plus c'est trop gros.Comment puis-je obtenir la durée d'un fichier MP3 (CBR ou VBR) avec une très petite bibliothèque ou un code natif c/C++?

Je fais cela sur Windows, mais IMediaDet de DirectShow semble lent au fil du temps, appeler quelques centaines de fois apporte mon système à une exploration, même réutilisant le même objet d'interface et juste mettre le nom du fichier et obtenir la durée!

Alors, existe-t-il du code qui peut lire les fichiers VBR en C/C++ et obtenir la durée?

Il y avait un autre post sur ici pour faire CBR en C++, mais le code fait une tonne d'hypothèses et ne fonctionnera pas pour VBR bien sûr.

+0

Je l'ai fait en utilisant NAudio et un petit fragment de code. La licence NAudio vous permet de sortir une partie du code, dans votre classe Mp3Frame. Ensuite, il suffit de parcourir les cadres et d'ajouter les durées, comme ici: http://stackoverflow.com/questions/383164/how-to-retrieve-duration-of-mp3-in-net/13269914#13269914 –

Répondre

0

Que diriez-vous tagLib ou id3lib?

Ils ne sont pas des décodeurs en soi, ils sont plus d'extraire la piste/artiste/album et foule d'autres informations qui vous permettront de faire ce que vous devez faire ...

3

La plupart des fichiers MP3 ont une ID3 header. Il n'est pas difficile de décoder cela et d'obtenir la durée.

Voici quelques très code de base et laide qui illustre la technique.

#include <iostream> 
#include <iomanip> 

size_t GetMP3Duration(const std::string sFileName); 

int main(int argc, char* argv[]) 
{ 
    try 
    { 
     size_t nLen = GetMP3Duration(argv[1]); 
     if (nLen==0) 
     { 
      std::cout << "Not Found" << std::endl; 
     } 
     else 
     { 
      std::cout << nLen << " miliseconds" << std::endl; 
      std::cout << nLen/60000 << ":"; 
      nLen %= 60000; 
      std::cout << nLen/1000 << "."; 
      std::cout << std::setw(3) << std::setfill('0') << nLen%1000 << std::endl; 
     } 
    } 
    catch (std::exception &e) 
    { 
     std::cout << "Exception: " << e.what() << std::endl; 
    } 
    return 0; 
} 

#include <cstring> 
#include <vector> 
#include <iostream> 
#include <fstream> 
#include <cctype> 
#include <cstdlib> 

unsigned DecodeMP3SafeInt(unsigned nVal) 
{ 
    // nVal has 4 bytes (8-bits each) 
    // - discard most significant bit from each byte 
    // - reverse byte order 
    // - concatenate the 4 * 7-bit nibbles into a 24-bit size. 
    unsigned char *pValParts = reinterpret_cast<unsigned char *>(&nVal); 
    return (pValParts[3] & 0x7F)   | 
      ((pValParts[2] & 0x7F) << 7) | 
      ((pValParts[1] & 0x7F) << 14) | 
      ((pValParts[0] & 0x7F) << 21); 
} 

#pragma pack(1) 
struct MP3Hdr { 
    char tag[3]; 
    unsigned char maj_ver; 
    unsigned char min_ver; 
    unsigned char flags; 
    unsigned int size; 
}; 
struct MP3ExtHdr { 
    unsigned int size; 
    unsigned char num_flag_bytes; 
    unsigned char extended_flags; 
}; 
struct MP3FrameHdr { 
    char frame_id[4]; 
    unsigned size; 
    unsigned char flags[2]; 
}; 
#pragma pack() 

size_t GetMP3Duration(const std::string sFileName) 
{ 
    std::ifstream fin(sFileName.c_str(), std::ifstream::binary); 
    if (!fin) 
     throw std::invalid_argument("Cannot open file"); 

    // Read Header 
    MP3Hdr hdr = { 0 }; 
    fin.read(reinterpret_cast<char *>(&hdr), sizeof(hdr)); 
    if (!fin.good()) 
     throw std::invalid_argument("Error reading file"); 

    if (0 != ::memcmp(hdr.tag, "ID3", 3)) 
     throw std::invalid_argument("Not an MP3 File"); 

    // Read extended header, if present 
    if (0 != (hdr.flags&0x40)) 
    { 
     fin.seekg(sizeof(MP3ExtHdr), std::ifstream::cur); 
     if (!fin.good()) 
      throw std::invalid_argument("Error reading file"); 
    } 

    // read a chunk of file. 
    const size_t nDefaultSize(2048); 
    std::vector<char> vBuff(nDefaultSize); 
    fin.read(&vBuff[0], vBuff.size()); 
    size_t nSize = fin.gcount(); 
    if (!nSize) 
     throw std::invalid_argument("Error reading file"); 
    vBuff.resize(nSize); 

    size_t nUsed = 0; 
    while (nSize-nUsed > sizeof(MP3FrameHdr)) 
    { 
     MP3FrameHdr *pFrame = reinterpret_cast<MP3FrameHdr *>(&vBuff[nUsed]); 
     nUsed += sizeof(MP3FrameHdr); 
     size_t nDataLen = DecodeMP3SafeInt(pFrame->size); 
     if (nDataLen > (nSize-nUsed)) 
      throw std::invalid_argument("Corrupt file"); 

     if (!::isupper(pFrame->flags[0])) // past end of tags 
      return 0; 

     if (0 == ::memcmp(pFrame->frame_id, "TLEN", 4)) 
     { 
      // skip an int 
      nUsed += sizeof(int); 
      // data is next 
      return atol(&vBuff[nUsed]); 
     } 
     else 
     { 
      nUsed += nDataLen; 
     } 
    } 
    return 0; 
} 
+1

Vous pouvez ' Cela dépend de cela, puisque ce n'est pas la partie standard des fichiers MPEG1-layer 3. –

+2

L'en-tête ID3 n'est pas obligatoire et, même s'il est présent, il n'est pas garanti d'avoir une étiquette TLEN. Cependant, dans mon expérience (limitée), la grande majorité des MP3 ont un en-tête ID3 et ont une étiquette TLEN. Le code doit être écrit pour être tolérant aux erreurs, mais vous pouvez aussi bien utiliser l'information si elle est là.Vous serez presque toujours OK et sur les quelques cas où l'information n'est pas disponible, vous pouvez le détecter en toute sécurité et contourner le problème. –

0

Jeff,

la seule façon valable est de passer par tout fichier mp3, trouver toutes les images mp3 de l'intérieur et calculer la durée totale pour eux.

La caractéristique principale du fichier mp3 est que sa densité peut différer, et que beaucoup d'autres données binaires pourraient être incluses à l'intérieur. Les tags ID3 par exemple, que tout décodeur sautera lors de la lecture.

Quoi qu'il en soit - regardez ici pour plus d'informations d'en-tête frame mp3:

http://www.mp3-converter.com/mp3codec/mp3_anatomy.htm

essayer de créer un code qui correctement analyser en-tête par tête, calculer leur durée (de la fréquence d'échantillonnage) et le total des durées pour tous cadres.

Vous n'avez pas besoin de décoder les images, utilisez simplement des en-têtes.

Si vous ne me dérange pas LGPL essayer http://sourceforge.net/projects/mpg123net/