mirror of
https://github.com/ElvishArtisan/rivendell.git
synced 2025-07-25 17:08:13 +02:00
2021-09-30 Fred Gleason <fredg@paravelsystems.com>
* Overhauled the code for reading MPEG frame headers in 'RDWaveFile'. * Fixed a bug in the rdxport 'Import' service that could result in incorrect end marker placement when processing variable bit rate (VBR) MPEG files. Signed-off-by: Fred Gleason <fredg@paravelsystems.com>
This commit is contained in:
parent
429a41deac
commit
b69efb80ab
@ -20805,3 +20805,8 @@
|
||||
2021-09-16 Fred Gleason <fredg@paravelsystems.com>
|
||||
* Modified the mode of files generated by the
|
||||
'SaveWebgetFilesDirectory=' directive 0440 to 0664.
|
||||
2021-09-30 Fred Gleason <fredg@paravelsystems.com>
|
||||
* Overhauled the code for reading MPEG frame headers in 'RDWaveFile'.
|
||||
* Fixed a bug in the rdxport 'Import' service that could result in
|
||||
incorrect end marker placement when processing variable bit rate
|
||||
(VBR) MPEG files.
|
||||
|
@ -2,7 +2,7 @@
|
||||
//
|
||||
// A class for handling audio files.
|
||||
//
|
||||
// (C) Copyright 2002-2018 Fred Gleason <fredg@paravelsystems.com>
|
||||
// (C) Copyright 2002-2021 Fred Gleason <fredg@paravelsystems.com>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Library General Public License
|
||||
@ -17,7 +17,6 @@
|
||||
// License along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@ -91,7 +90,7 @@ RDWaveFile::RDWaveFile(QString file_name)
|
||||
head_emphasis=1;
|
||||
head_flags=0;
|
||||
pts=0;
|
||||
mpeg_id=RDWaveFile::NonMpeg;
|
||||
// mpeg_id=RDWaveFile::NonMpeg;
|
||||
mpeg_frame_size=0;
|
||||
id3v1_tag=false;
|
||||
id3v2_tag[0]=false;
|
||||
@ -269,9 +268,6 @@ bool RDWaveFile::openWave(RDWaveData *data)
|
||||
}
|
||||
data_length=wave_file.size()-data_start;
|
||||
sample_length=1152*(data_length/mpeg_frame_size);
|
||||
ext_time_length=(unsigned)(1000.0*(double)sample_length/
|
||||
(double)samples_per_sec);
|
||||
time_length=ext_time_length/1000;
|
||||
lseek(wave_file.handle(),data_start,SEEK_SET);
|
||||
format_chunk=true;
|
||||
}
|
||||
@ -328,9 +324,6 @@ bool RDWaveFile::openWave(RDWaveData *data)
|
||||
}
|
||||
data_start=id3v2_offset[0];
|
||||
sample_length=1152*(data_length/mpeg_frame_size);
|
||||
ext_time_length=
|
||||
(unsigned)(1000.0*(double)sample_length/(double)samples_per_sec);
|
||||
time_length=ext_time_length/1000;
|
||||
data_chunk=true;
|
||||
lseek(wave_file.handle(),data_start,SEEK_SET);
|
||||
format_chunk=true;
|
||||
@ -799,7 +792,7 @@ void RDWaveFile::closeWave(int samples)
|
||||
head_emphasis=1;
|
||||
head_flags=0;
|
||||
pts=0;
|
||||
mpeg_id=RDWaveFile::NonMpeg;
|
||||
// mpeg_id=RDWaveFile::NonMpeg;
|
||||
mpeg_frame_size=0;
|
||||
id3v1_tag=false;
|
||||
id3v2_tag[0]=false;
|
||||
@ -1750,14 +1743,6 @@ QString RDWaveFile::getCartTimerLabel(int index) const
|
||||
return QString("");
|
||||
}
|
||||
|
||||
/*
|
||||
void RDWaveFile::setCartTimerLabel(int index,QString label)
|
||||
{
|
||||
if(index<MAX_TIMERS) {
|
||||
cart_timer_label[index]=label;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
unsigned RDWaveFile::getCartTimerSample(int index) const
|
||||
{
|
||||
@ -1767,14 +1752,6 @@ unsigned RDWaveFile::getCartTimerSample(int index) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
void RDWaveFile::setCartTimerSample(int index,unsigned sample)
|
||||
{
|
||||
if(index<MAX_TIMERS) {
|
||||
cart_timer_sample[index]=sample;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
QString RDWaveFile::getCartURL() const
|
||||
{
|
||||
@ -2210,11 +2187,6 @@ QString RDWaveFile::formatText(RDWaveFile::Format fmt)
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum Format {Pcm8=0,Pcm16=1,Float32=2,MpegL1=3,MpegL2=4,MpegL3=5,
|
||||
DolbyAc2=6,DolbyAc3=7,Vorbis=8,Pcm24=9};
|
||||
enum Type {Unknown=0,Wave=1,Mpeg=2,Ogg=3,Atx=4,Tmc=5,Flac=6,Ambos=7,
|
||||
Aiff=8,M4A=9};
|
||||
|
||||
|
||||
QString RDWaveFile::typeText(RDWaveFile::Type type)
|
||||
{
|
||||
@ -3664,552 +3636,255 @@ void RDWaveFile::ReadId3Metadata()
|
||||
|
||||
bool RDWaveFile::GetMpegHeader(int fd,int offset)
|
||||
{
|
||||
unsigned char buffer[4];
|
||||
int n;
|
||||
|
||||
//
|
||||
// See:
|
||||
//
|
||||
// http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm
|
||||
// https://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header
|
||||
//
|
||||
// for helpful information regarding the arcana of interpreting MPEG
|
||||
// header data structures. Sometimes, fasting and prayer can help too!
|
||||
//
|
||||
|
||||
//
|
||||
// Bitrate table
|
||||
//
|
||||
// __bitrates[VERSION_INDEX][LAYER_INDEX][BITRATE_INDEX]
|
||||
//
|
||||
// N.B. Bitrate values in this table are in thousands of bits per second.
|
||||
// Certain other data structures in this class require bits per second!
|
||||
//
|
||||
static int __bitrates[4][4][16]={
|
||||
{ // *** MPEG 2.5 ***
|
||||
{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // Reserved Layer
|
||||
{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1}, // Layer III
|
||||
{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1}, // Layer II
|
||||
{0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,-1} // Layer I
|
||||
},
|
||||
|
||||
{ // *** Invalid MPEG Version ***
|
||||
{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // Reserved Layer
|
||||
{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // Layer III
|
||||
{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // Layer II
|
||||
{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1} // Layer I
|
||||
},
|
||||
|
||||
{ // *** MPEG 2 ***
|
||||
{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // Reserved Layer
|
||||
{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1}, // Layer III
|
||||
{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1}, // Layer II
|
||||
{0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,-1} // Layer I
|
||||
},
|
||||
|
||||
{ // *** MPEG 1 ***
|
||||
{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // Reserved Layer
|
||||
{0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,-1}, // Layer III
|
||||
{0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,-1},// Layer II
|
||||
{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,-1} // Layer I
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Sample Rate Table
|
||||
//
|
||||
// __samplerates[VERSION_INDEX][SAMPRATE_INDEX]
|
||||
static int __samplerates[4][4]={
|
||||
{11025,12000,8000,-1}, // *** MPEG 2.5 ***
|
||||
{-1,-1,-1,-1}, // *** Invalid MPEG Version ***
|
||||
{22050,24000,16000,-1}, // *** MPEG 2 ***
|
||||
{44100,48000,32000,-1} // *** MPEG 1 ***
|
||||
};
|
||||
|
||||
//
|
||||
// Channels table
|
||||
//
|
||||
// __channels[MODE_INDEX]
|
||||
static int __channels[4]={2,2,2,1};
|
||||
|
||||
//
|
||||
// Head Mode Table
|
||||
//
|
||||
// __head_modes[MODE_INDEX];
|
||||
static int __head_modes[4]={ACM_MPEG_STEREO,ACM_MPEG_JOINTSTEREO,
|
||||
ACM_MPEG_DUALCHANNEL,ACM_MPEG_SINGLECHANNEL};
|
||||
|
||||
//
|
||||
// Layer Numbers Table
|
||||
//
|
||||
// __layer_numbers[LAYER_INDEX]
|
||||
static int __layer_numbers[4]={0,3,2,1};
|
||||
|
||||
//
|
||||
// Samples per MPEG Frame Table
|
||||
//
|
||||
// __samples_per_frames[VERSION_INDEX][LAYER_INDEX]
|
||||
static int __samples_per_frame[4][4]={
|
||||
{0,576,1152,384}, // *** MPEG 2.5 ***
|
||||
{0,0,0,384}, // *** Invalid MPEG Version ***
|
||||
{0,576,1152,384}, // *** MPEG 2 ***
|
||||
{0,1152,1152,384} // *** MPEG 1 ***
|
||||
};
|
||||
|
||||
//
|
||||
// Side Data Offset Table (Layer III only)
|
||||
//
|
||||
// __side_data_offset[VERSION_INDEX][MODE]
|
||||
static int __side_data_offset[4][4]={
|
||||
{17,17,17,9}, // *** MPEG 2.5 ***
|
||||
{0,0,0,0}, // *** Invalid MPEG Version ***
|
||||
{17,17,17,9}, // *** MPEG 2 ***
|
||||
{32,32,32,17} // *** MPEG 1 ***
|
||||
};
|
||||
|
||||
char header[4];
|
||||
char *frame=NULL;
|
||||
ssize_t n;
|
||||
// off_t frame_start;
|
||||
int version_index;
|
||||
int layer_index;
|
||||
int bitrate_index;
|
||||
int samprate_index;
|
||||
int padding=0;
|
||||
int mode_index;
|
||||
int frame_size;
|
||||
int total_frame_quan=-1;
|
||||
|
||||
lseek(fd,offset,SEEK_SET);
|
||||
if((n=read(fd,buffer,4))!=4) {
|
||||
if((n=read(fd,header,4))!=4) {
|
||||
return false;
|
||||
}
|
||||
// frame_start=lseek(fd,0,SEEK_CUR)-4;
|
||||
|
||||
//
|
||||
// Sync bits
|
||||
//
|
||||
if(((0xFF&header[0])!=0xFF)||((0xE0&header[1])!=0xE0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Sync
|
||||
// MPEG Audio Version ID
|
||||
//
|
||||
if((buffer[0]!=0xFF)||((buffer[1]&0xE0)!=0xE0)) {
|
||||
version_index=(0x18&header[1])>>3;
|
||||
if(version_index==0x01) { // Illegal Version ID
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// MPEG Id
|
||||
//
|
||||
if((buffer[1]&0x08)==0) {
|
||||
mpeg_id=RDWaveFile::Mpeg2;
|
||||
}
|
||||
else {
|
||||
mpeg_id=RDWaveFile::Mpeg1;
|
||||
}
|
||||
|
||||
//
|
||||
// Layer
|
||||
//
|
||||
switch((buffer[1]&0x06)>>1) {
|
||||
case 1:
|
||||
head_layer=3;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
head_layer=2;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
head_layer=1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
layer_index=(0x06&header[1])>>1;
|
||||
if(layer_index==0x00) { // Illegal Layer
|
||||
return false;
|
||||
}
|
||||
head_layer=__layer_numbers[layer_index];
|
||||
|
||||
//
|
||||
// Bitrate
|
||||
//
|
||||
switch(mpeg_id) {
|
||||
case RDWaveFile::Mpeg1:
|
||||
switch(head_layer) {
|
||||
case 1:
|
||||
switch(buffer[2]>>4) {
|
||||
case 1:
|
||||
head_bit_rate=32000;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
head_bit_rate=64000;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
head_bit_rate=96000;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
head_bit_rate=128000;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
head_bit_rate=160000;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
head_bit_rate=192000;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
head_bit_rate=224000;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
head_bit_rate=256000;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
head_bit_rate=288000;
|
||||
break;
|
||||
|
||||
case 10:
|
||||
head_bit_rate=320000;
|
||||
break;
|
||||
|
||||
case 11:
|
||||
head_bit_rate=352000;
|
||||
break;
|
||||
|
||||
case 12:
|
||||
head_bit_rate=384000;
|
||||
break;
|
||||
|
||||
case 13:
|
||||
head_bit_rate=416000;
|
||||
break;
|
||||
|
||||
case 14:
|
||||
head_bit_rate=448000;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
switch(buffer[2]>>4) {
|
||||
case 1:
|
||||
head_bit_rate=32000;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
head_bit_rate=48000;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
head_bit_rate=56000;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
head_bit_rate=64000;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
head_bit_rate=80000;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
head_bit_rate=96000;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
head_bit_rate=112000;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
head_bit_rate=128000;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
head_bit_rate=160000;
|
||||
break;
|
||||
|
||||
case 10:
|
||||
head_bit_rate=192000;
|
||||
break;
|
||||
|
||||
case 11:
|
||||
head_bit_rate=224000;
|
||||
break;
|
||||
|
||||
case 12:
|
||||
head_bit_rate=256000;
|
||||
break;
|
||||
|
||||
case 13:
|
||||
head_bit_rate=320000;
|
||||
break;
|
||||
|
||||
case 14:
|
||||
head_bit_rate=384000;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
switch(buffer[2]>>4) {
|
||||
case 1:
|
||||
head_bit_rate=32000;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
head_bit_rate=40000;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
head_bit_rate=48000;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
head_bit_rate=56000;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
head_bit_rate=64000;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
head_bit_rate=80000;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
head_bit_rate=96000;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
head_bit_rate=112000;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
head_bit_rate=128000;
|
||||
break;
|
||||
|
||||
case 10:
|
||||
head_bit_rate=160000;
|
||||
break;
|
||||
|
||||
case 11:
|
||||
head_bit_rate=192000;
|
||||
break;
|
||||
|
||||
case 12:
|
||||
head_bit_rate=224000;
|
||||
break;
|
||||
|
||||
case 13:
|
||||
head_bit_rate=256000;
|
||||
break;
|
||||
|
||||
case 14:
|
||||
head_bit_rate=320000;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case RDWaveFile::Mpeg2:
|
||||
switch(head_layer) {
|
||||
case 1:
|
||||
switch(buffer[2]>>4) {
|
||||
case 1:
|
||||
head_bit_rate=32000;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
head_bit_rate=48000;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
head_bit_rate=56000;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
head_bit_rate=64000;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
head_bit_rate=80000;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
head_bit_rate=96000;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
head_bit_rate=112000;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
head_bit_rate=128000;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
head_bit_rate=144000;
|
||||
break;
|
||||
|
||||
case 10:
|
||||
head_bit_rate=160000;
|
||||
break;
|
||||
|
||||
case 11:
|
||||
head_bit_rate=176000;
|
||||
break;
|
||||
|
||||
case 12:
|
||||
head_bit_rate=192000;
|
||||
break;
|
||||
|
||||
case 13:
|
||||
head_bit_rate=224000;
|
||||
break;
|
||||
|
||||
case 14:
|
||||
head_bit_rate=256000;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
switch(buffer[2]>>4) {
|
||||
case 1:
|
||||
head_bit_rate=8000;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
head_bit_rate=16000;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
head_bit_rate=24000;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
head_bit_rate=32000;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
head_bit_rate=40000;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
head_bit_rate=48000;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
head_bit_rate=56000;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
head_bit_rate=64000;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
head_bit_rate=80000;
|
||||
break;
|
||||
|
||||
case 10:
|
||||
head_bit_rate=96000;
|
||||
break;
|
||||
|
||||
case 11:
|
||||
head_bit_rate=112000;
|
||||
break;
|
||||
|
||||
case 12:
|
||||
head_bit_rate=128000;
|
||||
break;
|
||||
|
||||
case 13:
|
||||
head_bit_rate=144000;
|
||||
break;
|
||||
|
||||
case 14:
|
||||
head_bit_rate=160000;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
switch(buffer[2]>>4) {
|
||||
case 1:
|
||||
head_bit_rate=8000;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
head_bit_rate=16000;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
head_bit_rate=24000;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
head_bit_rate=32000;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
head_bit_rate=40000;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
head_bit_rate=48000;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
head_bit_rate=56000;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
head_bit_rate=64000;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
head_bit_rate=80000;
|
||||
break;
|
||||
|
||||
case 10:
|
||||
head_bit_rate=96000;
|
||||
break;
|
||||
|
||||
case 11:
|
||||
head_bit_rate=112000;
|
||||
break;
|
||||
|
||||
case 12:
|
||||
head_bit_rate=128000;
|
||||
break;
|
||||
|
||||
case 13:
|
||||
head_bit_rate=144000;
|
||||
break;
|
||||
|
||||
case 14:
|
||||
head_bit_rate=160000;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
bitrate_index=(0xF0&header[2])>>4;
|
||||
if(__bitrates[version_index][layer_index][bitrate_index]<0) {
|
||||
return false;
|
||||
}
|
||||
head_bit_rate=1000*__bitrates[version_index][layer_index][bitrate_index];
|
||||
|
||||
//
|
||||
// Sample Rate
|
||||
// Samplerate
|
||||
//
|
||||
switch((buffer[2]>>2)&0x03) {
|
||||
case 0:
|
||||
switch(mpeg_id) {
|
||||
case RDWaveFile::Mpeg1:
|
||||
samples_per_sec=44100;
|
||||
break;
|
||||
|
||||
case RDWaveFile::Mpeg2:
|
||||
samples_per_sec=22050;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
switch(mpeg_id) {
|
||||
case RDWaveFile::Mpeg1:
|
||||
samples_per_sec=48000;
|
||||
break;
|
||||
|
||||
case RDWaveFile::Mpeg2:
|
||||
samples_per_sec=24000;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
switch(mpeg_id) {
|
||||
case RDWaveFile::Mpeg1:
|
||||
samples_per_sec=32000;
|
||||
break;
|
||||
|
||||
case RDWaveFile::Mpeg2:
|
||||
samples_per_sec=16000;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
samprate_index=(0x0C&header[2])>>2;
|
||||
if((__samplerates[version_index][samprate_index]<0)&&(bitrate_index!=0)) {
|
||||
return false;
|
||||
}
|
||||
samples_per_sec=__samplerates[version_index][samprate_index];
|
||||
|
||||
//
|
||||
// Padding bit
|
||||
//
|
||||
padding=(0x02&header[2])>>1;
|
||||
|
||||
//
|
||||
// Mode
|
||||
//
|
||||
switch(buffer[3]>>6) {
|
||||
case 0:
|
||||
head_mode=ACM_MPEG_STEREO;
|
||||
channels=2;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
head_mode=ACM_MPEG_JOINTSTEREO;
|
||||
channels=2;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
head_mode=ACM_MPEG_DUALCHANNEL;
|
||||
channels=2;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
head_mode=ACM_MPEG_SINGLECHANNEL;
|
||||
channels=1;
|
||||
break;
|
||||
}
|
||||
mode_index=(0xC0&header[3])>>6;
|
||||
head_mode=__head_modes[mode_index];
|
||||
channels=__channels[mode_index];
|
||||
|
||||
//
|
||||
// Flags
|
||||
//
|
||||
if((buffer[2]&0x01)!=0) {
|
||||
head_flags=0;
|
||||
if((0x01&header[2])!=0) {
|
||||
head_flags|=ACM_MPEG_PRIVATEBIT;
|
||||
}
|
||||
if((buffer[3]&0x08)!=0) {
|
||||
}
|
||||
if((header[3]&0x08)!=0) {
|
||||
head_flags|=ACM_MPEG_COPYRIGHT;
|
||||
}
|
||||
if((buffer[3]&0x04)!=0) {
|
||||
if((header[3]&0x04)!=0) {
|
||||
head_flags|=ACM_MPEG_ORIGINALHOME;
|
||||
}
|
||||
if((buffer[1]&0x01)!=0) {
|
||||
head_flags|=ACM_MPEG_PROTECTIONBIT;
|
||||
}
|
||||
if(mpeg_id==RDWaveFile::Mpeg1) {
|
||||
if(version_index==3) {
|
||||
head_flags|=ACM_MPEG_ID_MPEG1;
|
||||
}
|
||||
|
||||
//
|
||||
// Frame Size (without padding)
|
||||
// Frame Size
|
||||
//
|
||||
if(layer_index==3) { // Layer I
|
||||
frame_size=(12000*__bitrates[version_index][layer_index][bitrate_index]/
|
||||
__samplerates[version_index][samprate_index]+padding)*4;
|
||||
}
|
||||
else { // Layers II and III
|
||||
frame_size=(144000*__bitrates[version_index][layer_index][bitrate_index]/
|
||||
__samplerates[version_index][samprate_index])+padding;
|
||||
}
|
||||
|
||||
//
|
||||
// Load the frame data
|
||||
//
|
||||
frame=new char[frame_size];
|
||||
if((n=read(fd,frame,frame_size-4))!=(frame_size-4)) {
|
||||
delete frame;
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Look for the Xing/Info tag (for VBR data)
|
||||
//
|
||||
if(((frame[__side_data_offset[version_index][mode_index]]=='X')&&
|
||||
(frame[__side_data_offset[version_index][mode_index]+1]=='i')&&
|
||||
(frame[__side_data_offset[version_index][mode_index]+2]=='n')&&
|
||||
(frame[__side_data_offset[version_index][mode_index]+3]=='g'))||
|
||||
((frame[__side_data_offset[version_index][mode_index]]=='I')&&
|
||||
(frame[__side_data_offset[version_index][mode_index]+1]=='n')&&
|
||||
(frame[__side_data_offset[version_index][mode_index]+2]=='f')&&
|
||||
(frame[__side_data_offset[version_index][mode_index]+3]=='o'))) {
|
||||
if((frame[__side_data_offset[version_index][mode_index]+7]&0x01)==0x01) {
|
||||
total_frame_quan=
|
||||
16777216*frame[__side_data_offset[version_index][mode_index]+8]+
|
||||
65536*frame[__side_data_offset[version_index][mode_index]+9]+
|
||||
256*frame[__side_data_offset[version_index][mode_index]+10]+
|
||||
frame[__side_data_offset[version_index][mode_index]+11];
|
||||
time_length=
|
||||
total_frame_quan*__samples_per_frame[version_index][layer_index]/
|
||||
__samplerates[version_index][samprate_index];
|
||||
ext_time_length=1000*total_frame_quan*
|
||||
__samples_per_frame[version_index][layer_index]/
|
||||
__samplerates[version_index][samprate_index];
|
||||
}
|
||||
}
|
||||
if(total_frame_quan<0) {
|
||||
//
|
||||
// No VBR tag, assume CBR
|
||||
//
|
||||
sample_length=1152.0*((double)data_length/(144.0*(double)head_bit_rate/
|
||||
(double)samples_per_sec));
|
||||
ext_time_length=1000.0*(double)sample_length/(double)samples_per_sec;
|
||||
time_length=ext_time_length/1000;
|
||||
}
|
||||
mpeg_frame_size=144*head_bit_rate/samples_per_sec;
|
||||
|
||||
delete frame;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
// rdwavefile.h
|
||||
//
|
||||
// A class for handling Microsoft WAV files.
|
||||
// A class for handling audio files.
|
||||
//
|
||||
// (C) Copyright 2002-2018 Fred Gleason <fredg@paravelsystems.com>
|
||||
// (C) Copyright 2002-2021 Fred Gleason <fredg@paravelsystems.com>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Library General Public License
|
||||
@ -22,14 +22,16 @@
|
||||
#ifndef RDWAVEFILE_H
|
||||
#define RDWAVEFILE_H
|
||||
|
||||
#include <vector>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <qobject.h>
|
||||
#include <qstring.h>
|
||||
#include <qdatetime.h>
|
||||
#include <qfile.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QFile>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#ifdef HAVE_VORBIS
|
||||
#include <vorbis/vorbisfile.h>
|
||||
@ -37,10 +39,9 @@
|
||||
#endif // HAVE_VORBIS
|
||||
|
||||
#include <rdmp4.h>
|
||||
|
||||
#include <rdwavedata.h>
|
||||
#include <rdringbuffer.h>
|
||||
#include <rdsettings.h>
|
||||
#include <rdwavedata.h>
|
||||
|
||||
//
|
||||
// Number of timers allowed in the CartChunk structure.
|
||||
@ -102,8 +103,7 @@
|
||||
* In addition to 'FMT' and 'DATA' chunks, chunk types of particular
|
||||
* interest to broadcast applications are supported, including those
|
||||
* specified by the Broadcast Wave File specification (EBU Tech Document
|
||||
* 3285, with suppliments) and the CartChunk specification (currently
|
||||
* proposed to become AES standard AES-46).
|
||||
* 3285, with suppliments) and AES standard AES-46 (aka CartChunk).
|
||||
**/
|
||||
class RDWaveFile
|
||||
{
|
||||
@ -112,7 +112,6 @@ class RDWaveFile
|
||||
DolbyAc2=6,DolbyAc3=7,Vorbis=8,Pcm24=9};
|
||||
enum Type {Unknown=0,Wave=1,Mpeg=2,Ogg=3,Atx=4,Tmc=5,Flac=6,Ambos=7,
|
||||
Aiff=8,M4A=9};
|
||||
enum MpegID {NonMpeg=0,Mpeg1=1,Mpeg2=2};
|
||||
|
||||
/**
|
||||
* Create an RDWaveFile object.
|
||||
@ -1100,7 +1099,6 @@ class RDWaveFile
|
||||
unsigned short head_flags; // MPEG header flags
|
||||
unsigned long pts; // The MPEG PTS
|
||||
unsigned ptr_offset_msecs;
|
||||
RDWaveFile::MpegID mpeg_id;
|
||||
int mpeg_frame_size;
|
||||
bool id3v1_tag;
|
||||
bool id3v2_tag[2];
|
||||
|
Loading…
x
Reference in New Issue
Block a user