Using quicktime optionally

Yes, I think you’re right about that too:

int framesToDo = jmin (numSamples, bufferList->mBuffers[0].mDataByteSize / inputStreamDesc.mBytesPerFrame);

Sorry if I’m not 100% on top of this - I don’t really have a test system set up for QT files…

thanks, i will check this.
On the mac, I have also some creepy exceptions at the end of a decoding session which chrash the application.
On windows, i have some exceptions at the beginning, but they are handled somewhere :slight_smile:
I create the reader on the message thread, and read on it on a background thread.

At the end of a decoding session i get this error.
Is there any chance to catch or avoid this exception?

Program received signal: “EXC_BAD_ACCESS”.

#0	0x9394bc6b in SetMovieMovieControllerAssociationForIdleManager_priv
#1	0x9397f513 in DisposeMovieController_priv
#2	0x941b85f8 in -[QTMovie_QuickTime _setController:]
#3	0x941b3634 in -[QTMovie_QuickTime dealloc]
#4	0x9419d61c in -[QTMovie dealloc]
#5	0x98b92c68 in CFRelease
#6	0x98bbf91d in _CFAutoreleasePoolPop
#7	0x92dd5db6 in NSPopAutoreleasePool
#8	0x92dd6c12 in -[NSAutoreleasePool release]
#9	0x002d0704 in juce::ScopedAutoReleasePool::~ScopedAutoReleasePool at juce_mac_MiscUtilities.mm:39
#10	0x002f8591 in juce::AppDelegateRedirector::runLoopCallback at juce_mac_MessageManager.mm:162
#11	0x002f85f9 in juce::AppDelegateRedirector::runLoopSourceCallback at juce_mac_MessageManager.mm:172
#12	0x98bc50fb in __CFRunLoopDoSources0
#13	0x98bc2bbf in __CFRunLoopRun
#14	0x98bc2094 in CFRunLoopRunSpecific
#15	0x98bc1ec1 in CFRunLoopRunInMode
#16	0x972baf9c in RunCurrentEventLoopInMode
#17	0x972bad51 in ReceiveNextEventCommon
#18	0x972babd6 in BlockUntilNextEventMatchingListInMode
#19	0x90788a89 in _DPSNextEvent
#20	0x907882ca in -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:]
#21	0x9074a55b in -[NSApplication run]
#22	0x002d7aab in juce::MessageManager::runDispatchLoop at juce_mac_MessageManager.mm:324
#23	0x0008ada0 in juce::JUCEApplication::main at juce_Application.cpp:229
#24	0x0008afbc in juce::JUCEApplication::main at juce_Application.cpp:263
#25	0x0000d865 in main at Main.cpp:155

Looks like something is releasing the QTMovie object too many times - maybe you’re double-deleting the quicktime decoder somewhere?

no, i think not.
I extracted my import code from my project, you can easily insert it into a new jucer project

[code]/*

This file was auto-generated by the Jucer!

It contains the basic startup code for a Juce application.

==============================================================================
*/

#include “…/JuceLibraryCode/JuceHeader.h”

class ReadMp3 : public ThreadWithProgressWindow
{
public:
ReadMp3(File mp3File)
: ThreadWithProgressWindow(“read mp3”,true,true)
{
blocksize=32768;

	AudioFormatManager formatManager;
	formatManager.registerBasicFormats();
	formatManager.registerFormat(new QuickTimeAudioFormat(),false);
	reader  = formatManager.createReaderFor (mp3File);
	if (reader!=0) 
	{
		if ((reader->lengthInSamples>0) && (reader->lengthInSamples < 2147483646))
		{
			buffer = new AudioSampleBuffer(2,(int)reader->lengthInSamples);	
		}
	} else jassertfalse;
	
}

~ReadMp3()
{
}

void run()
{
	if ((reader!=0) && (buffer!=0))
	{
		int position=0;
		while ((!threadShouldExit()) && (position<reader->lengthInSamples))
		{
			buffer->readFromAudioReader(reader,position,jmin(blocksize,(int)reader->lengthInSamples-position),position,true,true);
			setProgress (position / (double) reader->lengthInSamples);
			position+=blocksize;
		}
	} else jassertfalse;
}

private:

ScopedPointer<AudioFormatReader> reader;
ScopedPointer<AudioSampleBuffer> buffer;
int blocksize;

};

//==============================================================================
class testImportApplication : public JUCEApplication
{
public:
//==============================================================================
testImportApplication()
{
}

~testImportApplication()
{
}

//==============================================================================
void initialise (const String& commandLine)
{
    {
		// init on message thread
		ReadMp3 readmp3(File("/Applications/iPhoto.app/Contents/Resources/Music/Minuet in G.mp3"));

		//run on background
		readmp3.runThread();
	}
	AlertWindow::showMessageBox(AlertWindow::InfoIcon,"ready","","OK");
	
	JUCEApplication::quit();
}

void shutdown()
{
    // Do your application's shutdown code here..
    
}

//==============================================================================
void systemRequestedQuit()
{
    quit();
}

//==============================================================================
const String getApplicationName()
{
    return "testImport";
}

const String getApplicationVersion()
{
    return ProjectInfo::versionString;
}

bool moreThanOneInstanceAllowed()
{
    return true;
}

void anotherInstanceStarted (const String& commandLine)
{
    
}

private:

};

//==============================================================================
// This macro generates the main() routine that starts the app.
START_JUCE_APPLICATION(testImportApplication)[/code]

Good old Quicktime… What a heap of crap.

Ok, I’ve found a way around its bizarre leakiness by wrapping all the functions in autorelease pools - try it out and see if it works for you…

wow thanks :slight_smile: but the library build seems to be broken now…

Builds fine for me! What problem are you seeing?

the only change i did, was setting JUCE_QUICKTIME to 1 in juce_config

[code]

/Users/Christian/cpp_projects/juceGit/Builds/MacOSX/…/…/src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp: In constructor ‘juce::QTAudioReader::QTAudioReader(juce::InputStream*, int)’:
/Users/Christian/cpp_projects/juceGit/Builds/MacOSX/…/…/src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp:93: error: ‘JUCE_AUTORELEASEPOOL’ was not declared in this scope
/Users/Christian/cpp_projects/juceGit/Builds/MacOSX/…/…/src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp:94: error: expected ;' before 'bufferList' /Users/Christian/cpp_projects/juceGit/Builds/MacOSX/../../src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp: In destructor 'virtual juce::QTAudioReader::~QTAudioReader()': /Users/Christian/cpp_projects/juceGit/Builds/MacOSX/../../src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp:219: error: 'JUCE_AUTORELEASEPOOL' was not declared in this scope /Users/Christian/cpp_projects/juceGit/Builds/MacOSX/../../src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp:220: error: expected;’ before ‘checkThreadIsAttached’
/Users/Christian/cpp_projects/juceGit/Builds/MacOSX/…/…/src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp: In member function ‘virtual bool juce::QTAudioReader::readSamples(int**, int, int, juce::int64, int)’:
/Users/Christian/cpp_projects/juceGit/Builds/MacOSX/…/…/src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp:241: error: ‘JUCE_AUTORELEASEPOOL’ was not declared in this scope
/Users/Christian/cpp_projects/juceGit/Builds/MacOSX/…/…/src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp:242: error: expected `;’ before ‘checkThreadIsAttached’[/code]

Ah, I was using the amalgamated build. It just needs an extra header file adding, I’ll do that when I get a moment.

I was wondering if there is any more news to this, because we’re looking to speed up the mp3 / quicktime code. I recently checked out the current git version, but the juce_QuicktimeAudioFormat.cpp file didn’t seem to have changed recently.
I noticed as well that sometimes I would get framesToDo = 1 when reading samples from mp3 files. I think I’ve found something.

I’ve changed (in readSamples())

to

Because .mDataByteSize is altered and used in the calculation of framesToDo the next time round, framesToDo will get smaller, untill it will eventually will stick to 1 forever.

I think the mixed usage of samples and frames for different things is quite confusing. But this is mostly quicktime’s fault.

Another problem I’ve encountered is when using long (2 hrs) mp3’s, is that lengthInSamples will report the wrong length. Any suggestions on solving this? It seems that quickTime is responsible:

I’ll try to find a solution and post it here.

I truly hate Apple and the way they treat developers. QuickTime and iTunes are not allowed on my LAN or any of my computers. I use MPG123 to decode mp3 files. It works great and it is super fast:

http://www.mpg123.de/

Thanks for the suggestion, I’ll keep it in mind for when I’m not stuck to using Quicktime ( and Apple :slight_smile: )

[quote]I’ve changed (in readSamples())

 int framesToDo = jmin (numSamples, (int) (bufferList->mBuffers[0].mDataByteSize / inputStreamDesc.mBytesPerFrame));

to

    int framesToDo = jmin (numSamples, samplesPerFrame);

I’m not sure if this is a good idea, because samplesPerFrame can also be 1 ( read the post above http://www.rawmaterialsoftware.com/viewtopic.php?f=2&t=5589&start=0#p32453 )

are you reading sample by sample?

maybe we just do ( but i didn’t checked yet) ?!?

Hmm this is getting a bit confusing… Let me clarify the way I see things.

The offending piece of code looks like this on my machine: (juce_QuicktimeAudioFormat.cpp:readSamples())

[code] int framesToDo = jmin (numSamples, samplesPerFrame);
bufferList->mBuffers[0].mDataByteSize = inputStreamDesc.mBytesPerFrame * framesToDo;

        UInt32 outFlags = 0;
        UInt32 actualNumFrames = framesToDo;
        OSStatus err = MovieAudioExtractionFillBuffer (extractor, &actualNumFrames, bufferList, &outFlags);
        if (err != noErr)
        {
            ok = false;
            break;
        }

        lastSampleRead = startSampleInFile + actualNumFrames;
        const int samplesReceived = actualNumFrames;[/code]

As far as I’ve tested (with different file containers / formats), samples per frame has always been > 1. The naming of int framesToDo is rather confusing because there is a difference in a MP3 frame (around 1152 samples when i’m debugging) and a PCM / Audio frame (4 bytes, mBytesPerFrame).
Also There is the confusing case of the sample, because quicktime also uses the terminology media sample (a quicktime-legacy thingie) and there’s ofcoure the sample (1 value of audio channel data).

Anyway, we shouldn’t do int framesToDo = numSaples; because I don’t think quicktime likes it when we request a lot of data at once, and the buffer we are using the to extract the data is only (samplesPerFrame * inputStreamDesc.mBytesPerFrame) + 16 big.

So, no, I’m not reading sample by sample. I’m reading numSamplesPerFrame most of the times, which has been 1152 every time when reading mp3’s

yes! i was a little bit to fast, this was wrong!

but changing this to samplesPerFrame will cause new problems, because GetMediaDecodeDuration (media) / GetMediaSampleCount (media) can be 1 too! (believe me, i had issues with that :slight_smile:

yes, but this is not always the case, the number is unpredictable, and the extraction function needs the number of PCM samples and has nothing to do with other kinds of frames.

i think the problem is that the .mDataByteSize is altered, and then the next calcualation is based on .mDataByteSize, it should have the maximum size, and only should decreased when the needed buffer is smaller ( sorry, have’ time yet…

The problem is indeed that .mDataByteSize is altered…

But when GetMediaDecodeDuration (media) / GetMediaSampleCount (media) == 1, then logically samplesPerFrame will be 1 too? So then we’ll only request 1 sample per “extraction” as we would do before…
Or am I not understanding you correctly?

Maybe you can find out for what kind of file GetMediaDecodeDuration (media) / GetMediaSampleCount (media) == 1, then we know if it fails. I’ll be busy wrestling with the evil beast that’s called QuickTime for the next couple of days, and will be testing it with different formats, so I’ll let you know if anything goes wrong.

yes, and that will be ultra slow (look a few post above), thats why samplesPerFrame was removed and the size of samples is as much as the buffersize allows.

your problem never occured to me, cause i always load bigger buffersizes at once.

Here is the old extraction api doc (it seems to be removed from the apple site)

http://webcache.googleusercontent.com/search?q=cache:4mxUqriL590J:developer.apple.com/QuickTime//audioextraction.html+quicktime+extraction+api&cd=2&hl=en&ct=clnk&source=www.google.com

If you load you mp3 partwise you should also know this: http://rawmaterialsoftware.com/viewtopic.php?f=2&t=6379