ref: 733421d40eee2a54756ce800eed4196ab6ef52a8
parent: 3cbad24c861f5bb5126aa5984a97ee69f8c180fe
author: menno <menno>
date: Sat Aug 9 07:28:43 EDT 2003
Case updates
--- a/plugins/foo_mp4/foo_mp4.cpp
+++ b/plugins/foo_mp4/foo_mp4.cpp
@@ -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.45 2003/08/08 11:10:35 menno Exp $
+** $Id: foo_mp4.cpp,v 1.46 2003/08/09 11:28:43 menno Exp $
**/
#include <mp4.h>
@@ -132,7 +132,7 @@
unsigned __int64 length = MP4GetTrackDuration(hFile, track);
__int64 msDuration = MP4ConvertFromTrackDuration(hFile, track,
length, MP4_MSECS_TIME_SCALE);
- info->set_length((double)msDuration/1000.0);
+ m_length = (double)msDuration/1000.0;
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);
@@ -148,9 +148,10 @@
ReadMP4Tag(info);
if (m_samples > 0) {
- info->set_length((double)(signed __int64)m_samples/(double)samplerate);
+ m_length = (double)(signed __int64)m_samples/(double)samplerate;
info->info_set_int("samples", (__int64)m_samples);
}
+ info->set_length(m_length);
return 1;
}
@@ -162,6 +163,7 @@
m_samples = 0;
m_samplepos = 0;
m_seekskip = 0;
+ m_eof = false;
}
~input_mp4()
@@ -175,13 +177,13 @@
virtual int run(audio_chunk * chunk)
{
do {
+ if (m_eof || (m_samples > 0 && m_samplepos >= m_samples)) return 0; // gapless playback
+
faacDecFrameInfo frameInfo;
unsigned char *buffer;
unsigned __int32 buffer_size;
audio_sample *sample_buffer;
- if (m_samples > 0 && m_samplepos >= m_samples) return 0; // gapless playback
-
if (sampleId == MP4_INVALID_SAMPLE_ID)
{
console::error("Invalid sampleId.");
@@ -369,13 +371,16 @@
virtual bool seek(double seconds)
{
- MP4Duration duration;
+ if (seconds >= m_length) {
+ m_eof = true;
+ return true;
+ }
double msecs = seconds * 1.0e3;
do {
if (msecs > 10.0) msecs -= 10.0; else msecs = 0;
- duration = MP4ConvertToTrackDuration(hFile,
+ MP4Duration duration = MP4ConvertToTrackDuration(hFile,
track, msecs, MP4_MSECS_TIME_SCALE);
sampleId = MP4GetSampleIdFromTime(hFile,
track, duration, 0);
@@ -384,6 +389,8 @@
if (msecs == 0) break;
} while (m_seekskip < 0);
+ if (sampleId == MP4_INVALID_SAMPLE_ID) return false;
+
return true;
}
@@ -406,6 +413,8 @@
unsigned int m_framesize;
unsigned __int64 m_samplepos;
int m_seekskip;
+ double m_length;
+ bool m_eof;
int ReadMP4Tag(file_info *info)
{
@@ -645,6 +654,15 @@
faacDecSetConfiguration(hDecoder, config);
tag_reader::g_run_multi(m_reader, info, "ape|id3v2|lyrics3|id3v1");
+ const char *p = info->meta_get("samples");
+ if (p) {
+ m_samples = (unsigned __int64)_atoi64(p);
+ info->info_set("samples", p);
+ info->meta_remove_field("samples");
+ } else {
+ p = info->info_get("samples");
+ if (p) m_samples = (unsigned __int64)_atoi64(p);
+ }
m_at_eof = 0;
@@ -730,21 +748,35 @@
}
advance_buffer(m_aac_bytes_consumed);
- info->info_set("codec", "AAC");
- if (m_header_type == 0)
- info->info_set("stream type", "RAW");
- else if (m_header_type == 1)
- info->info_set("stream type", "ADTS");
- else if (m_header_type == 2)
- info->info_set("stream type", "ADIF");
- info->set_length(length);
+ m_samplerate = samplerate;
+ m_framesize = 1024;
- info->info_set_int("bitrate", bitrate);
- info->info_set_int("channels", (__int64)channels);
- info->info_set_int("samplerate", (__int64)samplerate);
+ if (flags & OPEN_FLAG_GET_INFO) {
+ run(0); // get correct framesize and samplerate
- m_samplerate = samplerate;
+ if (m_samples > 0) {
+ length = (double)(signed __int64)m_samples/(double)samplerate;
+ }
+ if (m_samplerate != samplerate)
+ info->info_set("codec", "AAC+SBR");
+ else
+ info->info_set("codec", "AAC");
+ if (m_header_type == 0)
+ info->info_set("stream type", "RAW");
+ else if (m_header_type == 1)
+ info->info_set("stream type", "ADTS");
+ else if (m_header_type == 2)
+ info->info_set("stream type", "ADIF");
+ info->set_length(length);
+
+ info->info_set_int("bitrate", bitrate);
+ info->info_set_int("channels", (__int64)channels);
+ info->info_set_int("samplerate", (__int64)m_samplerate);
+ }
+
+ m_length = length;
+
return 1;
}
@@ -756,6 +788,10 @@
m_samplerate = 0;
hDecoder = NULL;
m_aac_buffer = NULL;
+ m_samples = 0;
+ m_samplepos = 0;
+ m_seekskip = 0;
+ m_eof = false;
}
~input_aac()
@@ -777,97 +813,129 @@
virtual int run(audio_chunk * chunk)
{
- faacDecFrameInfo frameInfo;
- audio_sample *sample_buffer;
+ do {
+ if (m_eof || (m_samples > 0 && m_samplepos >= m_samples)) return 0; // gapless playback
- memset(&frameInfo, 0, sizeof(faacDecFrameInfo));
+ faacDecFrameInfo frameInfo;
+ audio_sample *sample_buffer;
- do
- {
- fill_buffer();
+ memset(&frameInfo, 0, sizeof(faacDecFrameInfo));
- if (m_aac_bytes_into_buffer != 0)
+ do
{
- sample_buffer = (audio_sample*)faacDecDecode(hDecoder, &frameInfo,
- m_aac_buffer, m_aac_bytes_into_buffer);
+ fill_buffer();
- if (m_header_type != 1)
+ if (m_aac_bytes_into_buffer != 0)
{
- m_tail->offset = m_file_offset;
- m_tail->next = (struct seek_list*)malloc(sizeof(struct seek_list));
- m_tail = m_tail->next;
- m_tail->next = NULL;
- }
+ sample_buffer = (audio_sample*)faacDecDecode(hDecoder, &frameInfo,
+ m_aac_buffer, m_aac_bytes_into_buffer);
- advance_buffer(frameInfo.bytesconsumed);
- } else {
- break;
- }
+ if (m_header_type != 1)
+ {
+ m_tail->offset = m_file_offset;
+ m_tail->next = (struct seek_list*)malloc(sizeof(struct seek_list));
+ m_tail = m_tail->next;
+ m_tail->next = NULL;
+ }
- } while (!frameInfo.samples && !frameInfo.error);
+ advance_buffer(frameInfo.bytesconsumed);
+ } else {
+ break;
+ }
- if (frameInfo.error || (m_aac_bytes_into_buffer == 0))
- {
- if (frameInfo.error)
+ } while (!frameInfo.samples && !frameInfo.error);
+
+ if (frameInfo.error || (m_aac_bytes_into_buffer == 0))
{
- if (faacDecGetErrorMessage(frameInfo.error) != NULL)
- console::error(faacDecGetErrorMessage(frameInfo.error));
+ if (frameInfo.error)
+ {
+ const char *msg = faacDecGetErrorMessage(frameInfo.error);
+ if (msg) console::warning(msg);
+ }
+ return 0;
}
- return 0;
- }
- 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.channels == 6 && frameInfo.num_lfe_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;
+ //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 (chunk)
- {
- if (frameInfo.channels == 0)
+ unsigned int samples = (frameInfo.channels != 0) ? frameInfo.samples/frameInfo.channels : 0;
+
+ m_samplerate = frameInfo.samplerate;
+ m_framesize = samples;
+
+ if (chunk)
{
- chunk->set_data(sample_buffer, 0, frameInfo.channels, frameInfo.samplerate);
- } else {
- chunk->set_data(sample_buffer, frameInfo.samples/frameInfo.channels,
- frameInfo.channels, frameInfo.samplerate);
+ 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);
+ }
+
+ 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_samplepos += samples;
+ }
}
- }
- m_samplerate = frameInfo.samplerate;
- cur_pos_sec += 1024.0/(double)m_samplerate;
+ cur_pos_sec += (double)m_framesize/(double)m_samplerate;
+ } while (m_seekskip > 0);
return 1;
}
- virtual set_info_t set_info(reader *r,const file_info * info)
+ virtual set_info_t set_info(reader *r,const file_info *_info)
{
- return tag_writer::g_run(r,info,"ape") ? SET_INFO_SUCCESS : SET_INFO_FAILURE;
+ file_info_i_full info;
+ info.copy(_info);
+ const char *p = info.info_get("samples");
+ if (p) {
+ info.meta_add("samples", p);
+ info.info_remove_field("samples");
+ }
+ return tag_writer::g_run(r,&info,"ape") ? SET_INFO_SUCCESS : SET_INFO_FAILURE;
}
virtual bool seek(double seconds)
{
- int i, frames;
+ unsigned int i, frames;
int bread;
struct seek_list *target = m_head;
+ if (seconds >= m_length) {
+ m_eof = true;
+ return true;
+ }
+
if (m_reader->can_seek() && ((m_header_type == 1) || (seconds < cur_pos_sec)))
{
- frames = (int)(seconds*((double)m_samplerate/1024.0) + 0.5);
+ frames = (unsigned int)(seconds*((double)m_samplerate/(double)m_framesize));
for (i = 0; i < frames; i++)
{
@@ -874,10 +942,10 @@
if (target->next)
target = target->next;
else
- return true;
+ return false;
}
if (target->offset == 0 && frames > 0)
- return true;
+ return false;
m_reader->seek(target->offset);
bread = m_reader->read(m_aac_buffer, 768*6);
@@ -887,12 +955,14 @@
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) );
return true;
} else {
if (seconds > cur_pos_sec)
{
- frames = (int)((seconds - cur_pos_sec)*((double)m_samplerate/1024.0) + 0.5);
+ frames = (unsigned int)((seconds - cur_pos_sec)*((double)m_samplerate/(double)m_framesize));
if (frames > 0)
{
@@ -899,15 +969,17 @@
for (i = 0; i < frames; i++)
{
if (!run(NULL))
- return 1;
+ return false;
}
}
- return true;
- } else {
- return false;
+ 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) );
}
+ return true;
}
+ return false;
}
virtual bool is_our_content_type(const char *url, const char *type)
@@ -933,6 +1005,13 @@
struct seek_list *m_head;
struct seek_list *m_tail;
+
+ unsigned __int64 m_samples;
+ unsigned int m_framesize;
+ unsigned __int64 m_samplepos;
+ int m_seekskip;
+ double m_length;
+ bool m_eof;
int fill_buffer()
{