📄 maddecoder.cpp
字号:
*/
getframeinfo();
// if(iFrameCount==0) {
// getframeinfo();
// gettaginfo();
// }
/* Accounting. The computed frame duration is in the frame
* header structure. It is expressed as a fixed point number
* whole data type is mad_timer_t. It is different from the
* samples fixed point format and unlike it, it can't directly
* be added or subtracted. The timer module provides several
* functions to operate on such numbers. Be careful there, as
* some functions of libmad's timer module receive some of
* their mad_timer_t arguments by value!
*/
iFrameCount++;
mad_timer_add(&iTimer,iFrame.header.duration);
if(iPlaystate==EREVERSE) {
jumpseek();
continue;
}
if(iPlaystate==EFASTFORWARD) {
/* This should be the right way to do it.
Unfortunately, it's too slow on flash-based low power devices
like ours.
if(mad_timer_compare(iGlobalTimer,iTimer)>0) {
continue;
} else {
iPlaystate=EPLAY;
}
*/
jumpseek();
continue;
}
/* Once decoded the frame is synthesized to PCM samples. No errors
* are reported by mad_synth_frame();
*/
mad_synth_frame(&iSynth,&iFrame);
/* Synthesized samples must be converted from libmad's fixed
* point number to the consumer format. Here we use unsigned
* 16 bit little endian integers on two channels. Integer samples
* are temporarily stored in a buffer that is flushed when
* full.
*/
if(outputbuffer) {
int CurrentBytesWritten=mad_outputpacket(iOutputPtr,iOutputBufferEnd);
BytesWritten+=CurrentBytesWritten;
iOutputPtr+=CurrentBytesWritten;
// it's full already
if(!CurrentBytesWritten||iRememberPcmSamples) return BytesWritten;
}
else {
// remember the remaining samples:
iRememberPcmSamples=iSynth.pcm.length;
return BytesWritten;
}
}
}
TInt CMadDecoder::Channels()
{
if(iFrame.header.mode==MAD_MODE_SINGLE_CHANNEL) {
//TRACEF(_L("CMadDecoder::Channels: 1 channel"));
return 1;
}
//TRACEF(_L("CMadDecoder::Channels: 2 channels"));
return 2;
}
TInt CMadDecoder::Rate()
{
//TRACEF(COggLog::VA(_L("CMadDecoder::Rate:%d"), iFrame.header.samplerate ));
return iFrame.header.samplerate;
}
TInt CMadDecoder::Bitrate()
{
//TRACEF(COggLog::VA(_L("CMadDecoder::Bitrate:%d"), iFrame.header.bitrate ));
return iFrame.header.bitrate;
}
TInt64 CMadDecoder::Position()
{
signed long timer=mad_timer_count(iTimer,MAD_UNITS_MILLISECONDS);
TInt64 pos;
pos=(TInt)timer;
return pos;
}
void CMadDecoder::Setposition(TInt64 aPosition)
{
unsigned long ms;
if(aPosition<0) aPosition=0;
ms=(unsigned long) aPosition.Low();
mad_timer_set(&iGlobalTimer,0,ms,1000);
if(mad_timer_compare(iGlobalTimer,iTimer)>0) {
iPlaystate=EFASTFORWARD;
} else {
iPlaystate=EREVERSE;
}
}
TInt64 CMadDecoder::TimeTotal()
{
signed long timer;
if(mad_timer_compare(iTotalTime,mad_timer_zero)!=0)
timer=mad_timer_count(iTotalTime,MAD_UNITS_MILLISECONDS);
else if(mad_timer_compare(iEstTotalTime,mad_timer_zero)!=0)
timer=mad_timer_count(iEstTotalTime,MAD_UNITS_MILLISECONDS);
else
timer=0;
TInt64 pos;
pos=(TInt)timer;
return pos;
}
TInt CMadDecoder::FileSize()
{
return iFilesize;
}
void CMadDecoder::ParseTags(TDes& aTitle, TDes& aArtist, TDes& aAlbum, TDes& aGenre, TDes& aTrackNumber) {
//TRACEF(_L("CMadDecoder::ParseTags"));
aArtist.SetLength(0);
aTitle.SetLength(0);
aAlbum.SetLength(0);
aGenre.SetLength(0);
aTrackNumber.SetLength(0);
if(id3tag || filetag) {
Id3GetString(aTitle,ID3_FRAME_TITLE);
Id3GetString(aArtist,ID3_FRAME_ARTIST);
Id3GetString(aAlbum,ID3_FRAME_ALBUM);
Id3GetString(aTrackNumber,ID3_FRAME_TRACK);
Id3GetString(aGenre,ID3_FRAME_GENRE);
} else {
//FIXMAD: breakpoint for testing
int i=5;
i++;
}
}
void CMadDecoder::Id3GetString(TDes& aString,char const *id)
{
struct id3_frame const *frame;
id3_ucs4_t const *ucs4;
id3_utf8_t* utf8;
union id3_field const *field;
struct id3_tag* tagtouse;
if(id3tag) { tagtouse=id3tag; } // ID3V2 tag
else if(filetag) { tagtouse=id3_file_tag(filetag); } //ID3V1
else return;
frame = id3_tag_findframe(tagtouse,id,0);
if (frame)
{
field = id3_frame_field(frame, 1);
ucs4 = id3_field_getstrings(field, 0);
if (strcmp(id, ID3_FRAME_GENRE) == 0) ucs4 = id3_genre_name(ucs4);
if(ucs4)
{
utf8=id3_ucs4_utf8duplicate(ucs4);
TPtrC8 p((const unsigned char *)utf8);
CnvUtfConverter::ConvertToUnicodeFromUtf8(aString,p);
free(utf8);
utf8=NULL;
}
}
}
void CMadDecoder::GetFrequencyBins(TInt32* /*aBins*/,TInt /*NumberOfBins*/)
{
}
/*
* NAME: get_id3()
* DESCRIPTION: read and parse an ID3 tag from a stream
*/
struct id3_tag* CMadDecoder::get_id3(struct mad_stream *stream, id3_length_t tagsize)
{
// struct id3_tag *tag = 0;
id3_length_t count;
id3_byte_t const *data;
id3_byte_t *allocated = 0;
count = stream->bufend - stream->this_frame;
if (tagsize <= count) {
data = stream->this_frame;
mad_stream_skip(stream, tagsize);
}
else {
allocated = (id3_byte_t*)malloc(tagsize);
if (allocated == 0) {
//error("id3", _("not enough memory to allocate tag data buffer"));
goto fail;
}
memcpy(allocated, stream->this_frame, count);
mad_stream_skip(stream, count);
while (count < tagsize) {
int len;
do
len = BstdRead(allocated + count, 1,tagsize - count,iBstdFile );
while (len == -1 );
if (len == -1) {
// error("id3", ":read");
goto fail;
}
if (len == 0) {
// error("id3", _("EOF while reading tag data"));
goto fail;
}
count += len;
}
data = allocated;
}
id3tag = id3_tag_parse(data, tagsize); //FXIMAD: leak?
fail:
if (allocated) {
free(allocated);
allocated=NULL;
}
return id3tag;
}
void CMadDecoder::MadHandleError()
{
signed long tagsize;
/* Do nothing if the error is a loss of
* synchronization and this loss is due to the end of
* stream guard bytes. (See the comments marked {3}
* supra for more informations about guard bytes.)
*/
if(iStream.error!=MAD_ERROR_LOSTSYNC ||
iStream.this_frame!=iGuardPtr)
{
// recoverable frame level error:
// ahm, do ... nothing
}
if(iStream.error== MAD_ERROR_LOSTSYNC) {
tagsize = id3_tag_query(iStream.this_frame,iStream.bufend - iStream.this_frame);
if (tagsize > 0) {
id3tag = get_id3(&iStream, tagsize);
if (id3tag) {
process_id3(id3tag);
}
}
}
}
/*
* NAME: process_id3()
* DESCRIPTION: display and process ID3 tag information
*/
void CMadDecoder::process_id3(struct id3_tag const *tag)
{
struct id3_frame const *frame;
/* length information */
frame = id3_tag_findframe(tag, "TLEN", 0);
if (frame) {
union id3_field const *field;
unsigned int nstrings;
field = id3_frame_field(frame, 1);
nstrings = id3_field_getnstrings(field);
if (nstrings > 0) {
id3_latin1_t *latin1;
latin1 = id3_ucs4_latin1duplicate(id3_field_getstrings(field, 0));
if (latin1) {
signed long ms;
/*
* "The 'Length' frame contains the length of the audio file
* in milliseconds, represented as a numeric string."
*/
ms = atoi((const char*)latin1);
if (ms > 0)
mad_timer_set(&iTotalTime, 0, ms, 1000);
free(latin1);
latin1=NULL;
}
}
}
/* relative volume adjustment information */
//IMPROVE_MAD: RGAIN_SUPPORT
// if ((player->options & PLAYER_OPTION_SHOWTAGSONLY) ||
// !(player->options & PLAYER_OPTION_IGNOREVOLADJ)) {
if(0) {
frame = id3_tag_findframe(tag, "RVA2", 0);
if (frame) {
id3_latin1_t const *id;
id3_byte_t const *data;
id3_length_t length;
enum {
CHANNEL_OTHER = 0x00,
CHANNEL_MASTER_VOLUME = 0x01,
CHANNEL_FRONT_RIGHT = 0x02,
CHANNEL_FRONT_LEFT = 0x03,
CHANNEL_BACK_RIGHT = 0x04,
CHANNEL_BACK_LEFT = 0x05,
CHANNEL_FRONT_CENTRE = 0x06,
CHANNEL_BACK_CENTRE = 0x07,
CHANNEL_SUBWOOFER = 0x08
};
id = id3_field_getlatin1(id3_frame_field(frame, 0));
data = id3_field_getbinarydata(id3_frame_field(frame, 1), &length);
// assert(id && data);
/*
* "The 'identification' string is used to identify the situation
* and/or device where this adjustment should apply. The following is
* then repeated for every channel
*
* Type of channel $xx
* Volume adjustment $xx xx
* Bits representing peak $xx
* Peak volume $xx (xx ...)"
*/
while (length >= 4) {
unsigned int peak_bytes;
peak_bytes = (data[3] + 7) / 8;
if (4 + peak_bytes > length)
break;
if (data[0] == CHANNEL_MASTER_VOLUME) {
signed int voladj_fixed;
double voladj_float;
/*
* "The volume adjustment is encoded as a fixed point decibel
* value, 16 bit signed integer representing (adjustment*512),
* giving +/- 64 dB with a precision of 0.001953125 dB."
*/
voladj_fixed = (data[1] << 8) | (data[2] << 0);
voladj_fixed |= -(voladj_fixed & 0x8000);
voladj_float = (double) voladj_fixed / 512;
// set_gain(player, GAIN_VOLADJ, voladj_float);
// if (player->verbosity >= 0) {
// detail(_("Relative Volume"),
// _("%+.1f dB adjustment (%s)"), voladj_float, id);
// }
break;
}
data += 4 + peak_bytes;
length -= 4 + peak_bytes;
}
}
}
//IMPROVE_MAD: RGAIN_SUPPORT
/* Replay Gain */
// if ((player->options & PLAYER_OPTION_SHOWTAGSONLY) ||
// ((player->output.replay_gain & PLAYER_RGAIN_ENABLED) &&
// !(player->output.replay_gain & PLAYER_RGAIN_SET))) {
// frame = id3_tag_findframe(tag, "RGAD", 0);
// if (frame) {
// id3_byte_t const *data;
// id3_length_t length;
//
// data = id3_field_getbinarydata(id3_frame_field(frame, 0), &length);
// assert(data);
//
// /*
// * Peak Amplitude $xx $xx $xx $xx
// * Radio Replay Gain Adjustment $xx $xx
// * Audiophile Replay Gain Adjustment $xx $xx
// */
//
// if (length >= 8) {
// struct mad_bitptr ptr;
// mad_fixed_t peak;
// struct rgain rgain[2];
//
// mad_bit_init(&ptr, data);
//
// peak = mad_bit_read(&ptr, 32) << 5;
//
// rgain_parse(&rgain[0], &ptr);
// rgain_parse(&rgain[1], &ptr);
//
// use_rgain(player, rgain);
//
// mad_bit_finish(&ptr);
// }
// }
// }
}
void CMadDecoder::gettaginfo(void) {
if (xltag.flags == 0 && tag_parse(&xltag, &iStream) == 0) {
unsigned int frame_size;
//IMPROVE_MAD: RGAIN_SUPPORT
// if ((xltag.flags & xltag_LAME) &&
// (player->output.replay_gain & PLAYER_RGAIN_ENABLED) &&
// !(player->output.replay_gain & PLAYER_RGAIN_SET))
// use_rgain(player, xltag.lame.replay_gain);
// }
if ((xltag.flags & TAG_XING) &&
(xltag.xing.flags & TAG_XING_FRAMES)) {
iTotalTime = iFrame.header.duration;
mad_timer_multiply(&iTotalTime, xltag.xing.frames);
}
/* total stream byte size adjustment */
frame_size = iStream.next_frame - iStream.this_frame;
if (iFilesize == 0) {
if ((xltag.flags & TAG_XING) && (xltag.xing.flags & TAG_XING_BYTES) &&
xltag.xing.bytes > frame_size)
iFilesize = xltag.xing.bytes - frame_size;
}
else if (iFilesize >= iStream.next_frame - iStream.this_frame)
iFilesize -= frame_size;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -