shithub: aacdec

Download patch

ref: fa036e6261e0eeabbe9ef410abc5acf75cba2ff5
parent: d79790588cb4a863b20d8303bf4df10bfb02d11f
author: menno <menno>
date: Mon Dec 15 12:47:56 EST 2003

foo_mp4 updates

--- a/plugins/foo_mp4/input_aac.cpp
+++ b/plugins/foo_mp4/input_aac.cpp
@@ -22,11 +22,11 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
 **
-** $Id: input_aac.cpp,v 1.3 2003/12/14 16:47:32 menno Exp $
+** $Id: input_aac.cpp,v 1.4 2003/12/15 17:47:56 menno Exp $
 **/
 
-#include "../SDK/foobar2000.h"
-#include "../foo_input_std/id3v2_hacks.h"
+#include "foobar2000/SDK/foobar2000.h"
+#include "foobar2000/foo_input_std/id3v2_hacks.h"
 #include <faad.h>
 
 //#define DBG_OUT(A) OutputDebugString(A)
--- a/plugins/foo_mp4/mp4_parser.cpp
+++ b/plugins/foo_mp4/mp4_parser.cpp
@@ -1,4 +1,4 @@
-#include "../SDK/foobar2000.h"
+#include "foobar2000/SDK/foobar2000.h"
 #define USE_TAGGING
 #include <mp4ff.h>
 
@@ -97,21 +97,35 @@
 	packet_decoder * p_decoder;
 
 
-    unsigned char *buffer;
-    unsigned int buffer_size;
 
-
     /* for gapless decoding */
 
 	mp4ff_callback_t mp4cb;
 	
 	double m_length;
-	uint32_t m_timescale;
-	int m_skip_samples;
-	uint32_t m_skip_frames;
-
+	unsigned m_timescale;
+	unsigned m_skip_samples;
+	unsigned m_skip_frames;
+	double m_timescale_div;
 	unsigned m_expected_sample_rate,m_expected_channels;
+	
+	double m_vbr_last_duration;
+	unsigned m_vbr_update_frames,m_vbr_update_bytes;
+	double m_vbr_update_time;
+	bool m_vbr_update_enabled;
+	unsigned m_vbr_update_interval;
 
+
+	int64_t duration_to_samples(int64_t val)
+	{
+		return (int64_t) ( (double)val * (double) m_expected_sample_rate * m_timescale_div + 0.5);
+	}
+
+	int64_t samples_to_duration(int64_t val)
+	{
+		return (int64_t) ( (double)val * (double)m_timescale / (double)m_expected_sample_rate + 0.5);
+	}
+
 	audio_chunk_i m_tempchunk;
 
     static uint32_t callback_read(void *udata, void *buffer, uint32_t length)
@@ -134,6 +148,14 @@
 		return reinterpret_cast<input_mp4*>(udata)->mp4file->set_eof() ? 1 : 0;
 	}
 	
+	void vbr_update_reset()
+	{
+		m_vbr_update_frames = 0; m_vbr_update_bytes = 0;
+		m_vbr_update_time = 0;
+		m_vbr_update_enabled = true;//make this configurable ?
+		m_vbr_update_interval = 16;
+	}
+
 	void cleanup()
 	{
 		if (infile) {mp4ff_close(infile);infile=0;}
@@ -142,6 +164,7 @@
 			p_decoder->service_release();
 			p_decoder = 0;
 		}
+		vbr_update_reset();
 	}
 
     input_mp4()
@@ -157,6 +180,9 @@
 		infile = 0;
 		m_offset = 0;
 		m_skip_samples = 0;
+
+		vbr_update_reset();
+
     }
 
     ~input_mp4()
@@ -169,6 +195,57 @@
         return (!stricmp(ext,"MP4") || !stricmp(ext,"M4A"));
     }
 
+	bool read_mp4_track_info(file_info * info)
+	{
+		m_expected_sample_rate = mp4ff_get_sample_rate(infile,track);
+		m_expected_channels = mp4ff_get_channel_count(infile,track);
+
+		if (m_expected_sample_rate == 0)
+		{
+			console::error("Invalid MP4 sample rate.");
+			return false;
+		}
+
+		if (m_expected_channels == 0)
+		{
+			console::error("Invalid MP4 channel count.");
+			return false;
+		}
+		m_timescale = mp4ff_time_scale(infile,track);
+		
+		if (m_timescale == 0)
+		{
+			console::error("Invalid MP4 time scale.");
+			return false;
+		}
+/*		if (m_timescale != m_expected_sample_rate)
+		{
+			console::error("Different sample rate / time scales not supported.");
+			return false;
+		}*/
+
+		m_timescale_div = 1.0 / (double) m_timescale;
+
+		{
+			int64_t duration = mp4ff_get_track_duration_use_offsets(infile,track);
+			if (duration == -1)
+				m_length = -1.0;
+			else
+			{
+				m_length = (double)duration * m_timescale_div;
+			}
+		}
+
+		info->set_length(m_length);
+
+		info->info_set_int("bitrate",(mp4ff_get_avg_bitrate(infile,track) + 500) / 1000);
+		info->info_set_int("channels",m_expected_channels);
+		info->info_set_int("samplerate",m_expected_sample_rate);
+//		info->info_set_int("mp4_timescale",m_timescale);
+		
+		return true;
+	}
+
     virtual bool open(reader *r, file_info *info, unsigned flags)
     {
 		if (!r->can_seek())
@@ -189,7 +266,7 @@
 		{
 			cleanup();
 			console::error("Error parsing MP4 file.");
-			return 0;
+			return false;
 		}
 
 		if ((track = find_track_to_decode(infile,codecname)) < 0)
@@ -196,18 +273,27 @@
 		{
 			cleanup();
 			console::error("Unable to find correct sound track in the MP4 file.");
-			return 0;
+			return false;
 		}
 
+		info->info_set("codec",codecname);
+
+		if (!read_mp4_track_info(info))
+		{
+			cleanup();
+			return false;
+		}
+
 		p_decoder = packet_decoder::create(codecname);
 		if (p_decoder == 0)
 		{
 			cleanup();
 			console::error("Unable to find correct packet decoder object.");
-			return 0;
+			return false;
 		}
 
-		info->info_set("codec",codecname);
+	    unsigned char *buffer;
+		unsigned int buffer_size;
 
 		buffer = NULL;
 		buffer_size = 0;
@@ -218,51 +304,31 @@
 			if (buffer) free(buffer);
 			cleanup();
 			console::error("Error initializing decoder.");
-			return 0;
+			return false;
 		}
 
-		m_timescale = mp4ff_time_scale(infile,track);
+		m_expected_channels = (unsigned)info->info_get_int("channels");
+		m_expected_sample_rate = (unsigned)info->info_get_int("samplerate");
 
+		if (m_expected_channels==0 || m_expected_sample_rate==0)
+		{
+			cleanup();
+			console::error("Decoder returned invalid info.");
+			return false;
+		}
+
 		if (buffer)
 		{
 			free(buffer);
 		}
 
-		{
-			m_expected_sample_rate = mp4ff_get_sample_rate(infile,track);
-			m_expected_channels = mp4ff_get_channel_count(infile,track);
-			if (m_timescale != m_expected_sample_rate)
-			{
-				cleanup();
-				console::error("Different sample rate / time scales not supported.");
-				return 0;
-			}
 
+		{
 			char *tag = NULL, *item = NULL;
 			int k, j;
 			
-			
-			if (m_timescale<=0)
-				m_length = -1.0;
-			else
-			{
-				int64_t duration = mp4ff_get_track_duration_use_offsets(infile,track);
-				if (duration == -1)
-					m_length = -1.0;
-				else
-				{
-					m_length = (double)duration / (double)m_timescale;
-				}
-			}
-
-			info->set_length(m_length);
-
-
 			if (flags & OPEN_FLAG_GET_INFO)
 			{
-				info->info_set_int("bitrate",(mp4ff_get_avg_bitrate(infile,track) + 500) / 1000);
-				info->info_set_int("channels",m_expected_channels);
-				info->info_set_int("samplerate",m_expected_sample_rate);
 
 				j = mp4ff_meta_get_num_items(infile);
 				for (k = 0; k < j; k++)
@@ -286,6 +352,8 @@
 
 		m_offset = 0;
 
+		vbr_update_reset();
+
 		sampleId = 0;
 
         return 1;
@@ -305,6 +373,9 @@
 
 		do		
 		{
+			unsigned char *buffer;
+			unsigned int buffer_size;
+
 			/* get acces unit from MP4 file */
 			buffer = NULL;
 			buffer_size = 0;
@@ -329,8 +400,8 @@
 			if (m_skip_frames>0) m_skip_frames--;
 			else
 			{
-				unsigned offset = mp4ff_get_sample_offset(infile,track,sampleId);
-				unsigned duration = mp4ff_get_sample_duration(infile, track, sampleId);
+				unsigned offset = (unsigned)duration_to_samples(mp4ff_get_sample_offset(infile,track,sampleId));
+				unsigned duration = (unsigned)duration_to_samples(mp4ff_get_sample_duration(infile, track, sampleId));
 	//			console::info(uStringPrintf("duration: %u, offset: %u",duration,offset));
 
 				if (m_tempchunk.is_empty())
@@ -345,6 +416,10 @@
 				}
 				else
 				{
+					m_vbr_update_frames++;
+					m_vbr_update_bytes += buffer_size;
+					m_vbr_update_time += (m_vbr_last_duration = m_tempchunk.get_duration());
+
 					if (m_tempchunk.get_srate() != m_expected_sample_rate)
 					{
 						cleanup();
@@ -351,12 +426,12 @@
 						console::error(uStringPrintf("Expected sample rate: %u, got: %u.",m_expected_sample_rate,m_tempchunk.get_srate()));
 						return -1;
 					}
-					if (m_tempchunk.get_channels() != m_expected_channels)
+/*					if (m_tempchunk.get_channels() != m_expected_channels)
 					{
 						cleanup();
 						console::error(uStringPrintf("Expected channels: %u, got: %u.",m_expected_channels,m_tempchunk.get_channels()));
 						return -1;
-					}
+					}*/
 				}
 				unsigned samplerate,channels,decoded_sample_count;
 
@@ -499,11 +574,13 @@
 
 		sampleId = dest_sample;
 		
-		m_skip_samples = skip_samples;
+		m_skip_samples = (unsigned)duration_to_samples(skip_samples);
 
 		m_offset = 0;
 
 		p_decoder->reset_after_seek();
+		
+		vbr_update_reset();
 
         return true;
 
@@ -513,6 +590,30 @@
     {
         return !stricmp(type, "audio/mp4") || !stricmp(type, "audio/x-mp4");
     }
+
+	virtual bool get_dynamic_info(file_info * out,double * timestamp_delta,bool * b_track_change)
+	{
+		bool ret = false;
+		if (m_vbr_update_enabled)
+		{
+			if (m_vbr_update_time > 0 && m_vbr_update_frames >= m_vbr_update_interval)
+			{
+				double delay = - (m_vbr_update_time - m_vbr_last_duration);
+				int val = (int) ( ((double)m_vbr_update_bytes * 8.0 / m_vbr_update_time + 500.0) / 1000.0 );
+				if (val != out->info_get_bitrate_vbr())
+				{
+					*timestamp_delta = delay;
+					out->info_set_bitrate_vbr(val);
+					ret = true;
+				}
+				m_vbr_update_frames = 0; m_vbr_update_bytes = 0;
+				m_vbr_update_time = 0;
+			}
+		}
+
+		return ret;
+	}
+
 };
 
 static service_factory_t<input, input_mp4> foo_mp4;
\ No newline at end of file
--- a/plugins/foo_mp4/packet_decoder_aac.cpp
+++ b/plugins/foo_mp4/packet_decoder_aac.cpp
@@ -1,4 +1,4 @@
-#include "../SDK/foobar2000.h"
+#include "foobar2000/SDK/foobar2000.h"
 #include <faad.h>
 
 
@@ -61,6 +61,9 @@
 			return false;
 		}
 
+		info->info_set_int("samplerate",t_samplerate);
+		info->info_set_int("channels",t_channels);
+
 		{
 			mp4AudioSpecificConfig mp4ASC;
 			if (AudioSpecificConfig((unsigned char*)data, bytes, &mp4ASC) >= 0)
@@ -87,7 +90,7 @@
 
 	virtual bool decode(const void * buffer,unsigned bytes,audio_chunk * out)
 	{
-		const audio_sample * sample_buffer = (const audio_sample*)faacDecDecode(hDecoder, &frameInfo, (unsigned char*)buffer, bytes);
+		audio_sample * sample_buffer = (audio_sample*)faacDecDecode(hDecoder, &frameInfo, (unsigned char*)buffer, bytes);
 
 		if (frameInfo.error > 0)
 		{
@@ -105,6 +108,27 @@
 
 		if (frameInfo.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;
+                }
+            }
+
 			return out->set_data(sample_buffer,frameInfo.samples / frameInfo.channels,frameInfo.channels,frameInfo.samplerate);
 		}
 		else