ref: 3b4bd3b3a9fe05d468babe5d654a5f0cd4b0e28c
parent: c63edacc48d2209d212d178c951cbdb324701cb5
author: menno <menno>
date: Sun Aug 17 15:36:54 EDT 2003
fixes
--- a/plugins/foo_mp4/foo_mp4.cpp
+++ b/plugins/foo_mp4/foo_mp4.cpp
@@ -1,19 +1,19 @@
/*
** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com
-**
+**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
-**
+**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
-**
+**
** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
+** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
** Any non-GPL usage of this software or parts of this software is strictly
@@ -22,7 +22,7 @@
** Commercial non-GPL licensing of this software is possible.
** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
**
-** $Id: foo_mp4.cpp,v 1.48 2003/08/16 13:14:51 menno Exp $
+** $Id: foo_mp4.cpp,v 1.49 2003/08/17 19:36:54 menno Exp $
**/
#include <mp4.h>
@@ -46,7 +46,7 @@
#endif
DECLARE_COMPONENT_VERSION ("MPEG-4 AAC decoder",
- "1.50",
+ "1.51",
"Based on FAAD2 v" FAAD2_VERSION "\nCopyright (C) 2002-2003 http://www.audiocoding.com" );
class input_mp4 : public input
@@ -125,17 +125,18 @@
numSamples = MP4GetTrackNumberOfSamples(hFile, track);
sampleId = 1;
+ m_timescale = MP4GetTrackTimeScale(hFile, track);
m_samplerate = samplerate;
+ m_seekto = 0;
m_framesize = 1024;
if (mp4ASC.frameLengthFlag == 1) m_framesize = 960;
MP4Duration trackDuration = MP4GetTrackDuration(hFile, track);
- m_samples = trackDuration;
- m_length = (double)(__int64)trackDuration / (double)mp4ASC.samplingFrequency;
+ m_length = (double)(__int64)trackDuration / (double)m_timescale;
info->set_length(m_length);
info->info_set_int("bitrate",(__int64)(1.0/1000.0 *
(double)(__int64)MP4GetTrackIntegerProperty(hFile,
- track, "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.avgBitrate")) + 0.5);
+ track, "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.avgBitrate") + 0.5));
info->info_set_int("channels", (__int64)channels);
info->info_set_int("samplerate", (__int64)samplerate);
if (mp4ASC.sbr_present_flag == 1) {
@@ -155,9 +156,6 @@
{
hFile = MP4_INVALID_FILE_HANDLE;
hDecoder = NULL;
- m_samples = 0;
- m_samplepos = 0;
- m_seekskip = 0;
m_eof = false;
}
@@ -171,16 +169,17 @@
virtual int run(audio_chunk * chunk)
{
+ faacDecFrameInfo frameInfo;
+ audio_sample *sample_buffer;
+ MP4Timestamp sample_pos;
+ MP4Duration sample_dur;
+ unsigned __int64 sample_count;
+ unsigned __int64 delay = 0;
+ bool initial = (sampleId == 1);
+
do {
- if (m_eof || (m_samples > 0 && m_samplepos >= m_samples)) return 0; // gapless playback
+ if (m_eof || (sampleId > numSamples)) return 0;
- faacDecFrameInfo frameInfo;
- unsigned char *buffer;
- unsigned __int32 buffer_size;
- audio_sample *sample_buffer;
-
- if (sampleId > numSamples) return 0;
-
if (sampleId == MP4_INVALID_SAMPLE_ID)
{
console::error("Invalid sampleId.");
@@ -188,12 +187,12 @@
}
do {
- buffer = NULL;
- buffer_size = 0;
+ unsigned char *buffer = NULL;
+ unsigned __int32 buffer_size = 0;
MP4ReadSample(hFile, track, sampleId,
(unsigned __int8**)&buffer, &buffer_size,
- NULL, NULL, NULL, NULL);
+ &sample_pos, &sample_dur, NULL, NULL);
sampleId++;
sample_buffer = (audio_sample*)faacDecDecode(hDecoder, &frameInfo, buffer, buffer_size);
@@ -200,58 +199,56 @@
if (buffer) free(buffer);
- } while ((frameInfo.error == 0) && (frameInfo.samples == 0));
+ if (m_timescale != m_samplerate) {
+ sample_count = frameInfo.channels ? frameInfo.samples/frameInfo.channels : 0;
+ } else {
+ sample_count = sample_dur;
+ }
- if (frameInfo.error)
- {
- console::warning(faacDecGetErrorMessage(frameInfo.error));
- console::warning("Skipping frame");
- if (sampleId > numSamples) return -1;
- }
+ if (initial && (sample_count < m_framesize) && frameInfo.channels)
+ delay = (frameInfo.samples/frameInfo.channels) - sample_count;
- if (frameInfo.channels == 6 && frameInfo.num_lfe_channels)
- {
- //channel order for 5.1: L/R/C/LF/BL/BR
- audio_sample r1, r2, r3, r4, r5, r6;
- for (unsigned int i = 0; i < frameInfo.samples; i += frameInfo.channels)
+ if (frameInfo.error)
{
- r1 = sample_buffer[i];
- r2 = sample_buffer[i+1];
- r3 = sample_buffer[i+2];
- r4 = sample_buffer[i+3];
- r5 = sample_buffer[i+4];
- r6 = sample_buffer[i+5];
- sample_buffer[i] = r2;
- sample_buffer[i+1] = r3;
- sample_buffer[i+2] = r1;
- sample_buffer[i+3] = r6;
- sample_buffer[i+4] = r4;
- sample_buffer[i+5] = r5;
+ console::warning(faacDecGetErrorMessage(frameInfo.error));
+ if (sampleId > numSamples) return -1;
+ console::warning("Skipping frame");
}
- }
+ } while (frameInfo.error || frameInfo.samples == 0 || frameInfo.channels == 0 || sample_count == 0);
- if (frameInfo.channels == 0)
- {
- chunk->set_data(sample_buffer, 0, frameInfo.channels, frameInfo.samplerate);
- } else {
- unsigned int samples = frameInfo.samples/frameInfo.channels;
+ unsigned __int64 skip = (sample_pos < m_seekto) ? (m_seekto - sample_pos) : 0;
- if (m_samples > 0) { // gapless playback
- if (m_samplepos + samples > m_samples) samples = (unsigned int)(m_samples - m_samplepos);
+ if (skip < sample_count)
+ {
+ if (frameInfo.channels == 6 && frameInfo.num_lfe_channels)
+ {
+ //channel order for 5.1: L/R/C/LF/BL/BR
+ audio_sample r1, r2, r3, r4, r5, r6;
+ for (unsigned int i = 0; i < frameInfo.samples; i += frameInfo.channels)
+ {
+ r1 = sample_buffer[i];
+ r2 = sample_buffer[i+1];
+ r3 = sample_buffer[i+2];
+ r4 = sample_buffer[i+3];
+ r5 = sample_buffer[i+4];
+ r6 = sample_buffer[i+5];
+ sample_buffer[i] = r2;
+ sample_buffer[i+1] = r3;
+ sample_buffer[i+2] = r1;
+ sample_buffer[i+3] = r6;
+ sample_buffer[i+4] = r4;
+ sample_buffer[i+5] = r5;
+ }
}
- if (m_seekskip < samples) {
- samples -= m_seekskip;
- chunk->set_data((audio_sample*)sample_buffer + m_seekskip*frameInfo.channels,
- samples, frameInfo.channels, frameInfo.samplerate);
- m_seekskip = 0;
- } else {
- m_seekskip -= samples;
- }
+ unsigned int samples = (unsigned int)(sample_count - skip);
- m_samplepos += samples;
+ chunk->set_data((audio_sample*)sample_buffer + (unsigned int)(skip+delay)*frameInfo.channels,
+ samples, frameInfo.channels, frameInfo.samplerate);
+
+ m_seekto = 0;
}
- } while (m_seekskip > 0);
+ } while (sample_pos + sample_dur < m_seekto);
return 1;
}
@@ -269,6 +266,9 @@
/* replay gain writing */
const char *p = NULL;
+ p = info->info_get("TOOL");
+ if (p)
+ MP4SetMetadataTool(hFile, p);
p = info->info_get("REPLAYGAIN_TRACK_PEAK");
if (p)
MP4SetMetadataFreeForm(hFile, "REPLAYGAIN_TRACK_PEAK", (unsigned __int8*)p, strlen(p));
@@ -282,37 +282,6 @@
if (p)
MP4SetMetadataFreeForm(hFile, "REPLAYGAIN_ALBUM_GAIN", (unsigned __int8*)p, strlen(p));
- m_samples = 0;
- p = info->info_get("samples");
- if (p) m_samples = (unsigned __int64)_atoi64(p);
-
- if (m_samples > 0)
- {
- if (m_samples < ((unsigned __int64)1<<32)) {
- unsigned __int8 length[4];
-
- length[0] = (unsigned __int8)((unsigned int)(m_samples >> 24) & 0xFF);
- length[1] = (unsigned __int8)((unsigned int)(m_samples >> 16) & 0xFF);
- length[2] = (unsigned __int8)((unsigned int)(m_samples >> 8) & 0xFF);
- length[3] = (unsigned __int8)((unsigned int)(m_samples ) & 0xFF);
-
- MP4SetMetadataFreeForm(hFile, "NDFL", length, 4);
- } else {
- unsigned __int8 length[8];
-
- length[0] = (unsigned __int8)((unsigned __int64)(m_samples >> 56) & 0xFF);
- length[1] = (unsigned __int8)((unsigned __int64)(m_samples >> 48) & 0xFF);
- length[2] = (unsigned __int8)((unsigned __int64)(m_samples >> 40) & 0xFF);
- length[3] = (unsigned __int8)((unsigned __int64)(m_samples >> 32) & 0xFF);
- length[4] = (unsigned __int8)((unsigned __int64)(m_samples >> 24) & 0xFF);
- length[5] = (unsigned __int8)((unsigned __int64)(m_samples >> 16) & 0xFF);
- length[6] = (unsigned __int8)((unsigned __int64)(m_samples >> 8) & 0xFF);
- length[7] = (unsigned __int8)((unsigned __int64)(m_samples ) & 0xFF);
-
- MP4SetMetadataFreeForm(hFile, "NDFL", length, 8);
- }
- }
-
int numItems = info->meta_get_count();
if (numItems > 0)
{
@@ -333,8 +302,6 @@
MP4SetMetadataAlbum(hFile, val);
} else if (stricmp(pName, "YEAR") == 0 || stricmp(pName, "DATE") == 0) {
MP4SetMetadataYear(hFile, val);
- } else if (stricmp(pName, "TOOL") == 0) {
- MP4SetMetadataTool(hFile, val);
} else if (stricmp(pName, "COMMENT") == 0) {
MP4SetMetadataComment(hFile, val);
} else if (stricmp(pName, "GENRE") == 0) {
@@ -343,7 +310,7 @@
unsigned __int16 trkn = 0, tot = 0;
sscanf(val, "%d", &trkn);
MP4SetMetadataTrack(hFile, trkn, tot);
- } else if (stricmp(pName, "DISKNUMBER") == 0) {
+ } else if (stricmp(pName, "DISKNUMBER") == 0 || stricmp(pName, "DISC") == 0) {
unsigned __int16 disk = 0, tot = 0;
sscanf(val, "%d", &disk);
MP4SetMetadataDisk(hFile, disk, tot);
@@ -372,18 +339,23 @@
return true;
}
- MP4Duration sample = (MP4Duration)(seconds * m_samplerate + 0.5);
+ unsigned int frame = (unsigned int)((double)m_framesize * ((double)m_samplerate / (double)m_timescale) + 0.5);
+ if (frame == 0) frame = 1;
- do {
- if (sample > 2048) sample -= 2048; else sample = 0;
- MP4Duration duration = MP4ConvertToTrackDuration(hFile, track, sample, m_samplerate);
+ m_seekto = (unsigned __int64)(seconds * m_timescale + 0.5) + frame;
+ MP4Duration target = m_seekto - frame;
+
+ while (1) {
+ MP4Duration duration = MP4ConvertToTrackDuration(hFile, track, target, m_timescale);
sampleId = MP4GetSampleIdFromTime(hFile, track, duration, 0);
- m_samplepos = (unsigned __int64)sampleId * m_framesize;
- m_seekskip = (int)((unsigned __int64)(seconds * m_samplerate + 0.5) - m_samplepos);
- if (sample == 0) break;
- } while (m_seekskip < 0);
+ if (sampleId == MP4_INVALID_SAMPLE_ID) return false;
+ MP4Timestamp position = MP4GetSampleTime(hFile, track, sampleId);
+ if (position <= m_seekto) break;
+ if (target == 0) return false;
+ if (target > frame) target -= frame; else target = 0;
+ }
- if (sampleId == MP4_INVALID_SAMPLE_ID) return false;
+ faacDecPostSeekReset(hDecoder, -1);
return true;
}
@@ -402,11 +374,10 @@
MP4FileHandle hFile;
MP4SampleId sampleId, numSamples;
MP4TrackId track;
- unsigned __int64 m_samples;
+ unsigned int m_timescale;
unsigned int m_samplerate;
unsigned int m_framesize;
- unsigned __int64 m_samplepos;
- int m_seekskip;
+ unsigned __int64 m_seekto;
double m_length;
bool m_eof;
@@ -442,7 +413,7 @@
} else if (memcmp(pName, "�day", 4) == 0) {
info->meta_add("DATE", val);
} else if (memcmp(pName, "�too", 4) == 0) {
- info->info_set("TOOL", val);
+ info->info_set("tool", val);
} else if (memcmp(pName, "�cmt", 4) == 0) {
info->meta_add("COMMENT", val);
} else if (memcmp(pName, "�gen", 4) == 0) {
@@ -465,7 +436,8 @@
char t[200];
MP4GetMetadataDisk(hFile, &disk, &tot);
wsprintf(t, "%d", disk);
- info->meta_add("DISKNUMBER", t);
+ //info->meta_add("DISKNUMBER", t);
+ info->meta_add("DISC", t);
} else if (memcmp(pName, "cpil", 4) == 0) {
unsigned __int8 cpil = 0;
char t[200];
@@ -479,21 +451,7 @@
wsprintf(t, "%d BPM", tempo);
info->meta_add("TEMPO", t);
} else if (memcmp(pName, "NDFL", 4) == 0) {
- /*
- unsigned __int8 *data = NULL;
- unsigned __int32 valueSize = 0;
- MP4GetMetadataFreeForm(hFile, "NDFL", &data, &valueSize);
- if (data && valueSize == 4)
- {
- // len = number of samples in whole file per channel
- m_samples = ((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]);
- }
- else if (data && valueSize == 8)
- {
- // len = number of samples in whole file per channel
- m_samples = ((data[0] << 56) | (data[1] << 48) | (data[2] << 40) | (data[3] << 32) | (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7]);
- }
- */
+ /* Removed */
} else {
float f = 0;
if (!stricmp(pName, "REPLAYGAIN_TRACK_PEAK"))
@@ -802,7 +760,6 @@
{
m_head = NULL;
m_tail = NULL;
- cur_pos_sec = 0.0;
m_samplerate = 0;
hDecoder = NULL;
m_aac_buffer = NULL;
@@ -831,7 +788,7 @@
virtual int run(audio_chunk * chunk)
{
- do {
+ while (1) {
if (m_eof || (m_samples > 0 && m_samplepos >= m_samples)) return 0; // gapless playback
if (m_aac_bytes_into_buffer == 0) return 0;
@@ -859,71 +816,66 @@
}
advance_buffer(frameInfo.bytesconsumed);
- } else {
- break;
}
- } while (!frameInfo.samples && !frameInfo.error);
-
- if (frameInfo.error || !sample_buffer)
- {
- const char *msg = faacDecGetErrorMessage(frameInfo.error);
- if (msg) console::warning(msg);
- return -1;
- }
-
- if (frameInfo.channels == 6 && frameInfo.num_lfe_channels)
- {
- //channel order for 5.1: L/R/C/LF/BL/BR
- audio_sample r1, r2, r3, r4, r5, r6;
- for (unsigned int i = 0; i < frameInfo.samples; i += frameInfo.channels)
+ if (frameInfo.error || !sample_buffer)
{
- r1 = sample_buffer[i];
- r2 = sample_buffer[i+1];
- r3 = sample_buffer[i+2];
- r4 = sample_buffer[i+3];
- r5 = sample_buffer[i+4];
- r6 = sample_buffer[i+5];
- sample_buffer[i] = r2;
- sample_buffer[i+1] = r3;
- sample_buffer[i+2] = r1;
- sample_buffer[i+3] = r6;
- sample_buffer[i+4] = r4;
- sample_buffer[i+5] = r5;
+ const char *msg = faacDecGetErrorMessage(frameInfo.error);
+ if (msg) console::warning(msg);
+ return -1;
}
- }
- unsigned int samples = (frameInfo.channels != 0) ? frameInfo.samples/frameInfo.channels : 0;
+ if (m_aac_bytes_into_buffer == 0) break;
+ } while (!frameInfo.samples || !frameInfo.channels);
- m_samplerate = frameInfo.samplerate;
- m_framesize = samples;
+ if (!frameInfo.samples || !frameInfo.channels) return 0;
if (chunk)
{
- if (frameInfo.channels == 0)
- {
- chunk->set_data(sample_buffer, 0, frameInfo.channels, frameInfo.samplerate);
- } else {
- if (m_samples > 0) { // gapless playback
- if (m_samplepos + samples > m_samples) samples = (unsigned int)(m_samples - m_samplepos);
- }
+ unsigned int samples = frameInfo.samples/frameInfo.channels;
- if (m_seekskip < samples) {
- samples -= m_seekskip;
- chunk->set_data((audio_sample*)sample_buffer + m_seekskip*frameInfo.channels,
- samples, frameInfo.channels, frameInfo.samplerate);
- m_seekskip = 0;
- } else {
- m_seekskip -= samples;
+ m_samplerate = frameInfo.samplerate;
+ m_framesize = samples;
+
+ if (m_samples > 0) { // gapless playback
+ if (m_samplepos + samples > m_samples) samples = (unsigned int)(m_samples - m_samplepos);
+ }
+
+ m_samplepos += samples;
+
+ if ((unsigned)m_seekskip < samples) {
+ if (frameInfo.channels == 6 && frameInfo.num_lfe_channels)
+ {
+ //channel order for 5.1: L/R/C/LF/BL/BR
+ audio_sample r1, r2, r3, r4, r5, r6;
+ for (unsigned int i = 0; i < frameInfo.samples; i += frameInfo.channels)
+ {
+ r1 = sample_buffer[i];
+ r2 = sample_buffer[i+1];
+ r3 = sample_buffer[i+2];
+ r4 = sample_buffer[i+3];
+ r5 = sample_buffer[i+4];
+ r6 = sample_buffer[i+5];
+ sample_buffer[i] = r2;
+ sample_buffer[i+1] = r3;
+ sample_buffer[i+2] = r1;
+ sample_buffer[i+3] = r6;
+ sample_buffer[i+4] = r4;
+ sample_buffer[i+5] = r5;
+ }
}
- m_samplepos += samples;
+ samples -= m_seekskip;
+ chunk->set_data((audio_sample*)sample_buffer + m_seekskip*frameInfo.channels,
+ samples, frameInfo.channels, frameInfo.samplerate);
+ m_seekskip = 0;
+ break;
+ } else {
+ m_seekskip -= samples;
}
}
+ }
- cur_pos_sec += (double)m_framesize/(double)m_samplerate;
- } while (m_seekskip > 0);
-
return 1;
}
@@ -950,9 +902,12 @@
return true;
}
+ double cur_pos_sec = (double)(__int64)m_samplepos / (double)(__int64)m_samplerate;
+
if (m_reader->can_seek() && ((m_header_type == 1) || (seconds < cur_pos_sec)))
{
frames = (unsigned int)(seconds*((double)m_samplerate/(double)m_framesize));
+ if (frames > 1) frames--;
for (i = 0; i < frames; i++)
{
@@ -963,7 +918,8 @@
}
if (target->offset == 0 && frames > 0)
return false;
- m_reader->seek(target->offset);
+ m_file_offset = target->offset;
+ m_reader->seek(m_file_offset);
bread = m_reader->read(m_aac_buffer, 768*6);
if (bread != 768*6)
@@ -972,9 +928,11 @@
m_at_eof = 0;
m_aac_bytes_into_buffer = bread;
m_aac_bytes_consumed = 0;
- m_samplepos = (unsigned __int64)frames * m_framesize;
- m_seekskip = (int)((unsigned __int64)(seconds * m_samplerate + 0.5) - m_samplepos);
- console::info ( string_printf ("seekskip: %i", m_seekskip) );
+ m_file_offset += bread;
+ m_samplepos = (frames > 1) ? (unsigned __int64)(frames-1) * m_framesize : 0;
+ m_seekskip = (int)((unsigned __int64)(seconds * m_samplerate + 0.5) - m_samplepos) + m_framesize;
+ if (m_seekskip < 0) return false; // should never happen
+ faacDecPostSeekReset(hDecoder, -1);
return true;
} else {
if (seconds > cur_pos_sec)
@@ -990,9 +948,11 @@
}
}
- m_samplepos = (unsigned __int64)frames * m_framesize;
+ m_samplepos = (unsigned __int64)(seconds * m_samplerate) / m_framesize;
+ m_samplepos *= m_framesize;
m_seekskip = (int)((unsigned __int64)(seconds * m_samplerate + 0.5) - m_samplepos);
- console::info ( string_printf ("seekskip: %i", m_seekskip) );
+ if (m_seekskip < 0) return false; // should never happen
+ faacDecPostSeekReset(hDecoder, -1);
}
return true;
}
@@ -1017,7 +977,6 @@
int m_at_eof;
unsigned long m_samplerate;
- double cur_pos_sec;
int m_header_type;
struct seek_list *m_head;