You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
263 lines
5.5 KiB
263 lines
5.5 KiB
15 years ago
|
/*
|
||
|
length detection etc.. for mpeg audio
|
||
|
Copyright (C) 2001 Martin Vogt
|
||
|
|
||
|
This program is free software; you can redistribute it and/or modify
|
||
|
it under the terms of the GNU Library General Public License as published by
|
||
|
the Free Software Foundation.
|
||
|
|
||
|
For more information look at the file COPYRIGHT in this package
|
||
|
|
||
|
*/
|
||
|
|
||
|
#ifndef _FROM_SOURCE
|
||
|
#define _FROM_SOURCE 1
|
||
|
#endif
|
||
|
#include "dxHead.h"
|
||
|
#include <string.h>
|
||
|
#include "mpegAudioInfo.h"
|
||
|
#include "mpegAudioHeader.h"
|
||
|
#include "mpegAudioStream.h"
|
||
|
#include "mpegAudioFrame.h"
|
||
|
|
||
|
#include <iostream>
|
||
|
|
||
|
using namespace std;
|
||
|
|
||
|
#define _NEED_LENGTH 1
|
||
|
#define _NEED_ID3 2
|
||
|
#define _NEED_NOTHING 3
|
||
|
|
||
|
|
||
|
MpegAudioInfo::MpegAudioInfo(FileAccess* input) {
|
||
|
xHeadData=new XHEADDATA();
|
||
|
xHeadData->toc=new unsigned char[101];
|
||
|
lXingVBR=false;
|
||
|
id3=new ID3TAG();
|
||
|
this->input=input;
|
||
|
mpegAudioFrame =new MpegAudioFrame();
|
||
|
mpegAudioStream=new MpegAudioStream();
|
||
|
mpegAudioHeader=new MpegAudioHeader();
|
||
|
reset();
|
||
|
}
|
||
|
|
||
|
|
||
|
MpegAudioInfo::~MpegAudioInfo() {
|
||
|
delete[] (xHeadData->toc);
|
||
|
delete xHeadData;
|
||
|
delete id3;
|
||
|
delete mpegAudioStream;
|
||
|
delete mpegAudioHeader;
|
||
|
delete mpegAudioFrame;
|
||
|
}
|
||
|
|
||
|
|
||
|
int MpegAudioInfo::getByteDirect() {
|
||
|
unsigned char byte;
|
||
|
if (input->read((char*)&byte,1) != 1) {
|
||
|
leof=true;
|
||
|
return -1;
|
||
|
}
|
||
|
return (int)byte;
|
||
|
}
|
||
|
|
||
|
void MpegAudioInfo::reset() {
|
||
|
length=0;
|
||
|
initState=_NEED_LENGTH;
|
||
|
lNeedInit=true;
|
||
|
}
|
||
|
|
||
|
|
||
|
int MpegAudioInfo::getNeedInit() {
|
||
|
return lNeedInit;
|
||
|
}
|
||
|
|
||
|
void MpegAudioInfo::setNeedInit(int lNeedInit) {
|
||
|
this->lNeedInit=lNeedInit;
|
||
|
}
|
||
|
|
||
|
|
||
|
int MpegAudioInfo::initialize() {
|
||
|
long fileSize=input->getByteLength();
|
||
|
switch(initState) {
|
||
|
case _NEED_NOTHING:
|
||
|
return true;
|
||
|
break;
|
||
|
case _NEED_LENGTH:
|
||
|
if (initializeLength(fileSize) == true) {
|
||
|
initState=_NEED_ID3;
|
||
|
}
|
||
|
return false;
|
||
|
case _NEED_ID3:
|
||
|
if (initializeID3(fileSize) == true) {
|
||
|
initState=_NEED_NOTHING;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
default:
|
||
|
cout << "unknown initState in MpegAudioInfo::initialize"<<endl;
|
||
|
exit(0);
|
||
|
}
|
||
|
// never happens
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
int MpegAudioInfo::initializeLength(long fileSize) {
|
||
|
// if we are streaming don't touch the stream for length detection
|
||
|
if (fileSize == 0) {
|
||
|
return true;
|
||
|
}
|
||
|
int back=getFrame(mpegAudioFrame);
|
||
|
if (back != true) {
|
||
|
return back;
|
||
|
}
|
||
|
// found a valid frame (back == true)
|
||
|
// store information in header.
|
||
|
if (mpegAudioHeader->parseHeader(mpegAudioFrame->outdata()) == false) {
|
||
|
cout << "parse header false"<<endl;
|
||
|
return false;
|
||
|
}
|
||
|
calculateLength(fileSize);
|
||
|
return back;
|
||
|
}
|
||
|
|
||
|
int MpegAudioInfo::initializeID3(long fileSize) {
|
||
|
int pos=input->getBytePosition();
|
||
|
if (input->seek(fileSize-128)<0) {
|
||
|
return true;
|
||
|
}
|
||
|
parseID3();
|
||
|
input->seek(pos);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
long MpegAudioInfo::getLength() {
|
||
|
return length;
|
||
|
}
|
||
|
|
||
|
|
||
|
void MpegAudioInfo::calculateLength(long fileSize) {
|
||
|
|
||
|
int totalframe=0;
|
||
|
int framesize=mpegAudioHeader->getFramesize();
|
||
|
if (framesize > 0) {
|
||
|
totalframe=fileSize/framesize;
|
||
|
|
||
|
if (parseXing(mpegAudioFrame->outdata(),mpegAudioFrame->len()) == true) {
|
||
|
lXingVBR=true;
|
||
|
totalframe=xHeadData->frames;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
float pcm=mpegAudioHeader->getpcmperframe();
|
||
|
float wavfilesize=(totalframe*pcm);
|
||
|
float frequence=(float)mpegAudioHeader->getFrequencyHz();
|
||
|
length=0;
|
||
|
if (frequence != 0) {
|
||
|
length=(int)(wavfilesize/frequence);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
int MpegAudioInfo::parseXing(unsigned char* frame,int size) {
|
||
|
|
||
|
int back=false;
|
||
|
if (size < 152) {
|
||
|
return false;
|
||
|
}
|
||
|
back=GetXingHeader(xHeadData,(unsigned char*)frame);
|
||
|
return back;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
long MpegAudioInfo::getSeekPosition(int second) {
|
||
|
float length=getLength();
|
||
|
long fileSize=input->getByteLength();
|
||
|
long pos=0;
|
||
|
if (length<1.0) {
|
||
|
return 0;
|
||
|
}
|
||
|
float percent=(float)second/length;
|
||
|
|
||
|
if (lXingVBR) {
|
||
|
pos=SeekPoint(xHeadData->toc,(int)fileSize,100.0*percent);
|
||
|
return pos;
|
||
|
}
|
||
|
pos=(long)(percent*(float)fileSize);
|
||
|
return pos;
|
||
|
}
|
||
|
|
||
|
|
||
|
void MpegAudioInfo::parseID3() {
|
||
|
|
||
|
id3->name [0]=0;
|
||
|
id3->artist [0]=0;
|
||
|
id3->album [0]=0;
|
||
|
id3->year [0]=0;
|
||
|
id3->comment [0]=0;
|
||
|
id3->genre =0;
|
||
|
|
||
|
leof=false;
|
||
|
|
||
|
while(leof == false) {
|
||
|
if(getByteDirect()==0x54)
|
||
|
if(getByteDirect()==0x41)
|
||
|
if(getByteDirect()==0x47) {
|
||
|
input->read((char*)&id3->name ,30);id3->name[30]=0;
|
||
|
input->read((char*)&id3->artist ,30);id3->artist[30]=0;
|
||
|
input->read((char*)&id3->album ,30);id3->album[30]=0;
|
||
|
input->read((char*)&id3->year , 4);id3->year[4]=0;
|
||
|
input->read((char*)&id3->comment ,30);id3->comment[30]=0;
|
||
|
input->read((char*)&id3->genre ,1);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void MpegAudioInfo::print(const char* msg) {
|
||
|
cout << "MpegAudioInfo:"<<msg<<endl;
|
||
|
cout << "Length (sec):"<<length<<endl;
|
||
|
cout << "VBR:"<<lXingVBR<<endl;
|
||
|
cout << "ID3: Name:"<<id3->name<<endl;
|
||
|
cout << "ID3: Artist:"<<id3->artist<<endl;
|
||
|
cout << "ID3: Album:"<<id3->album<<endl;
|
||
|
cout << "ID3: year:"<<id3->year<<endl;
|
||
|
cout << "ID3: genre:"<<(int)(id3->genre)<<endl;
|
||
|
cout << "ID3: comment:"<<id3->comment<<endl;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
int MpegAudioInfo::getFrame(MpegAudioFrame* frame) {
|
||
|
int state=frame->getState();
|
||
|
switch(state) {
|
||
|
case FRAME_NEED: {
|
||
|
int bytes=frame->canStore();
|
||
|
int read=input->read((char*)inputbuffer,bytes);
|
||
|
if (read <= 0) {
|
||
|
// read error. reset framer
|
||
|
frame->reset();
|
||
|
break;
|
||
|
}
|
||
|
frame->store(inputbuffer,bytes);
|
||
|
break;
|
||
|
}
|
||
|
case FRAME_WORK:
|
||
|
frame->work();
|
||
|
break;
|
||
|
case FRAME_HAS:
|
||
|
return true;
|
||
|
break;
|
||
|
default:
|
||
|
cout << "unknown state in mpeg audio framing"<<endl;
|
||
|
exit(0);
|
||
|
}
|
||
|
return false;
|
||
|
}
|