我不能使用任何由Fraunhofer专利的mp3代码,因此没有编码器或解码器(例如ffmpeg,lame,MAD等),而且它太大了。
我在Windows上这样做,但DirectShow的IMediaDet似乎随着时间的推移慢降低,调用它几百次使我的系统爬行,甚至重新使用相同的接口对象而且只是放置文件名并获取持续时间!
那么,是否有一些代码可以用C / C ++读取VBR文件并获得持续时间?
这里有另一篇文章用C ++做CBR,但代码做了很多假设,当然不适用于VBR。
答案 0 :(得分:4)
大多数MP3文件都有ID3 header。解码并获得持续时间并不难。
这是一些非常基本和丑陋的代码,用于说明该技术。
#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 :(得分:1)
我找到了一个库,LGPL v3:http://www.codeproject.com/KB/audio-video/mpegaudioinfo.aspx
答案 2 :(得分:0)
答案 3 :(得分:0)
杰夫,
唯一有效的方法是浏览整个mp3文件,查找其中的每个mp3帧并计算它们的总持续时间。
mp3文件的主要特点是它们的密度可能不同,而且其他二进制数据的批次也可能包含在其中。例如,ID3标签,任何解码器在阅读时都会跳过。
无论如何 - 看这里的mp3帧头信息:
http://www.mp3-converter.com/mp3codec/mp3_anatomy.htm
尝试创建将按标头正确解析标头的代码,计算它们的持续时间(从采样频率开始),然后计算所有帧的持续时间。
您不必解码帧,只需使用它们的标题。
如果您不介意LGPL,请尝试http://sourceforge.net/projects/mpg123net/