From 68e04b453d97459c7b4e137af1d86f6ec422f0d4 Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Tue, 12 Jan 2010 16:21:43 +0000 Subject: [PATCH] Fixed an MS compile problem. Added code to add an audio stream to a camera file recorded on the mac to avoid a movie rate bug in some quicktime versions. Added a linux makefile for the amalgamator. --- extras/amalgamator/linux/Amalgamator.make | 96 +++++++++++++++++++++++ extras/amalgamator/linux/Makefile | 25 ++++++ extras/amalgamator/linux/premake.lua | 46 +++++++++++ extras/amalgamator/linux/runpremake | 1 + juce_amalgamated.cpp | 58 +++++++++++++- juce_amalgamated.h | 4 +- src/gui/graphics/fonts/juce_TextLayout.h | 4 +- src/native/linux/juce_linux_Clipboard.cpp | 2 +- src/native/linux/juce_linux_Messaging.cpp | 4 +- src/native/mac/juce_mac_CameraDevice.mm | 58 +++++++++++++- 10 files changed, 291 insertions(+), 7 deletions(-) create mode 100644 extras/amalgamator/linux/Amalgamator.make create mode 100644 extras/amalgamator/linux/Makefile create mode 100644 extras/amalgamator/linux/premake.lua create mode 100644 extras/amalgamator/linux/runpremake diff --git a/extras/amalgamator/linux/Amalgamator.make b/extras/amalgamator/linux/Amalgamator.make new file mode 100644 index 0000000000..4857a1f8f2 --- /dev/null +++ b/extras/amalgamator/linux/Amalgamator.make @@ -0,0 +1,96 @@ +# C++ Console Executable Makefile autogenerated by premake +# Don't edit this file! Instead edit `premake.lua` then rerun `make` + +ifndef CONFIG + CONFIG=Debug +endif + +# if multiple archs are defined turn off automated dependency generation +DEPFLAGS := $(if $(word 2, $(TARGET_ARCH)), , -MMD) + +ifeq ($(CONFIG),Debug) + BINDIR := build + LIBDIR := build + OBJDIR := build/intermediate/Debug + OUTDIR := build + CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" + CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -g -D_DEBUG -ggdb + CXXFLAGS += $(CFLAGS) + LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -L"/usr/X11R6/lib/" -lpthread -lrt -ldl + LDDEPS := + RESFLAGS := -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" + TARGET := amalgamator + BLDCMD = $(CXX) -o $(OUTDIR)/$(TARGET) $(OBJECTS) $(LDFLAGS) $(RESOURCES) $(TARGET_ARCH) +endif + +ifeq ($(CONFIG),Release) + BINDIR := build + LIBDIR := build + OBJDIR := build/intermediate/Release + OUTDIR := build + CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "NDEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" + CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -O2 + CXXFLAGS += $(CFLAGS) + LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -s -L"/usr/X11R6/lib/" -lpthread -lrt -ldl + LDDEPS := + RESFLAGS := -D "LINUX=1" -D "NDEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" + TARGET := amalgamator + BLDCMD = $(CXX) -o $(OUTDIR)/$(TARGET) $(OBJECTS) $(LDFLAGS) $(RESOURCES) $(TARGET_ARCH) +endif + +OBJECTS := \ + $(OBJDIR)/juce_AmalgamatorMain.o \ + $(OBJDIR)/juce_LibrarySource.o \ + +MKDIR_TYPE := msdos +CMD := $(subst \,\\,$(ComSpec)$(COMSPEC)) +ifeq (,$(CMD)) + MKDIR_TYPE := posix +endif +ifeq (/bin,$(findstring /bin,$(SHELL))) + MKDIR_TYPE := posix +endif +ifeq ($(MKDIR_TYPE),posix) + CMD_MKBINDIR := mkdir -p $(BINDIR) + CMD_MKLIBDIR := mkdir -p $(LIBDIR) + CMD_MKOUTDIR := mkdir -p $(OUTDIR) + CMD_MKOBJDIR := mkdir -p $(OBJDIR) +else + CMD_MKBINDIR := $(CMD) /c if not exist $(subst /,\\,$(BINDIR)) mkdir $(subst /,\\,$(BINDIR)) + CMD_MKLIBDIR := $(CMD) /c if not exist $(subst /,\\,$(LIBDIR)) mkdir $(subst /,\\,$(LIBDIR)) + CMD_MKOUTDIR := $(CMD) /c if not exist $(subst /,\\,$(OUTDIR)) mkdir $(subst /,\\,$(OUTDIR)) + CMD_MKOBJDIR := $(CMD) /c if not exist $(subst /,\\,$(OBJDIR)) mkdir $(subst /,\\,$(OBJDIR)) +endif + +.PHONY: clean + +$(OUTDIR)/$(TARGET): $(OBJECTS) $(LDDEPS) $(RESOURCES) + @echo Linking Amalgamator + -@$(CMD_MKBINDIR) + -@$(CMD_MKLIBDIR) + -@$(CMD_MKOUTDIR) + @$(BLDCMD) + +clean: + @echo Cleaning Amalgamator +ifeq ($(MKDIR_TYPE),posix) + -@rm -f $(OUTDIR)/$(TARGET) + -@rm -rf $(OBJDIR) +else + -@if exist $(subst /,\,$(OUTDIR)/$(TARGET)) del /q $(subst /,\,$(OUTDIR)/$(TARGET)) + -@if exist $(subst /,\,$(OBJDIR)) del /q $(subst /,\,$(OBJDIR)) + -@if exist $(subst /,\,$(OBJDIR)) rmdir /s /q $(subst /,\,$(OBJDIR)) +endif + +$(OBJDIR)/juce_AmalgamatorMain.o: ../juce_AmalgamatorMain.cpp + -@$(CMD_MKOBJDIR) + @echo $(notdir $<) + @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" + +$(OBJDIR)/juce_LibrarySource.o: ../juce_LibrarySource.cpp + -@$(CMD_MKOBJDIR) + @echo $(notdir $<) + @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" + +-include $(OBJECTS:%.o=%.d) + diff --git a/extras/amalgamator/linux/Makefile b/extras/amalgamator/linux/Makefile new file mode 100644 index 0000000000..00f7a7e29a --- /dev/null +++ b/extras/amalgamator/linux/Makefile @@ -0,0 +1,25 @@ +# Makefile autogenerated by premake +# Don't edit this file! Instead edit `premake.lua` then rerun `make` +# Options: +# CONFIG=[Debug|Release] + +ifndef CONFIG + CONFIG=Debug +endif + +export CONFIG + +.PHONY: all clean Amalgamator + +all: Amalgamator + +Makefile: premake.lua + @echo ==== Regenerating Makefiles ==== + @premake --file $^ --cc gcc --target gnu + +Amalgamator: + @echo ==== Building Amalgamator ==== + @$(MAKE) --no-print-directory -C . -f Amalgamator.make + +clean: + @$(MAKE) --no-print-directory -C . -f Amalgamator.make clean diff --git a/extras/amalgamator/linux/premake.lua b/extras/amalgamator/linux/premake.lua new file mode 100644 index 0000000000..80ce7991a2 --- /dev/null +++ b/extras/amalgamator/linux/premake.lua @@ -0,0 +1,46 @@ + +project.name = "Amalgamator" +project.bindir = "build" +project.libdir = "build" + +project.configs = { "Debug", "Release" } + +package = newpackage() +package.name = "Amalgamator" +package.target = "amalgamator" +package.kind = "exe" +package.language = "c++" + +package.objdir = "build/intermediate" +package.config["Debug"].objdir = "build/intermediate/Debug" +package.config["Release"].objdir = "build/intermediate/Release" + +package.config["Debug"].defines = { "LINUX=1", "DEBUG=1", "_DEBUG=1" }; +package.config["Debug"].buildoptions = { "-D_DEBUG -ggdb" } + +package.config["Release"].defines = { "LINUX=1", "NDEBUG=1" }; + +package.includepaths = { + "/usr/include", + "/usr/include/freetype2" +} + +package.libpaths = { + "/usr/X11R6/lib/" +} + +package.config["Debug"].links = { + "pthread", "rt", "dl" +} + +package.config["Release"].links = { + "pthread", "rt", "dl" +} + +package.linkflags = { "static-runtime" } + +package.files = { matchfiles ( + "../*.h", + "../*.cpp" + ) +} diff --git a/extras/amalgamator/linux/runpremake b/extras/amalgamator/linux/runpremake new file mode 100644 index 0000000000..0c37e39aeb --- /dev/null +++ b/extras/amalgamator/linux/runpremake @@ -0,0 +1 @@ +premake --file premake.lua --cc gcc --target gnu diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 0e1b2cb086..e3f85d2923 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -274010,6 +274010,8 @@ public: NSArray* devs = [QTCaptureDevice inputDevicesWithMediaType: QTMediaTypeVideo]; device = (QTCaptureDevice*) [devs objectAtIndex: index]; input = 0; + audioInput = 0; + audioDevice = 0; fileOutput = 0; imageOutput = 0; callbackDelegate = [[QTCaptureCallbackDelegate alloc] initWithOwner: owner @@ -274022,6 +274024,7 @@ public: if (err == 0) { input = [[QTCaptureDeviceInput alloc] initWithDevice: device]; + audioInput = [[QTCaptureDeviceInput alloc] initWithDevice: device]; [session addInput: input error: &err]; @@ -274052,6 +274055,8 @@ public: [session release]; [input release]; [device release]; + [audioDevice release]; + [audioInput release]; [fileOutput release]; [imageOutput release]; [callbackDelegate release]; @@ -274063,9 +274068,33 @@ public: [session removeOutput: fileOutput]; [fileOutput release]; fileOutput = [[QTCaptureMovieFileOutput alloc] init]; + + [session removeInput: audioInput]; + [audioInput release]; + audioInput = 0; + [audioDevice release]; + audioDevice = 0; + [fileOutput setDelegate: callbackDelegate]; } + void addDefaultAudioInput() + { + NSError* err = nil; + audioDevice = [QTCaptureDevice defaultInputDeviceWithMediaType: QTMediaTypeSound]; + + if ([audioDevice open: &err]) + [audioDevice retain]; + else + audioDevice = nil; + + if (audioDevice != 0) + { + audioInput = [[QTCaptureDeviceInput alloc] initWithDevice: audioDevice]; + [session addInput: audioInput error: &err]; + } + } + void addListener (CameraImageListener* listenerToAdd) { const ScopedLock sl (listenerLock); @@ -274105,6 +274134,8 @@ public: QTCaptureDevice* device; QTCaptureDeviceInput* input; + QTCaptureDevice* audioDevice; + QTCaptureDeviceInput* audioInput; QTCaptureSession* session; QTCaptureMovieFileOutput* fileOutput; QTCaptureDecompressedVideoOutput* imageOutput; @@ -274218,8 +274249,33 @@ void CameraDevice::startRecordingToFile (const File& file) QTCameraDeviceInteral* const d = (QTCameraDeviceInteral*) internal; deleteAndZero (d->callbackDelegate->firstRecordedTime); file.deleteFile(); - [d->fileOutput recordToOutputFileURL: [NSURL fileURLWithPath: juceStringToNS (file.getFullPathName())]]; + + // In some versions of QT (e.g. on 10.5), if you record video without audio, the speed comes + // out wrong, so we'll put some audio in there too.., + d->addDefaultAudioInput(); + [d->session addOutput: d->fileOutput error: nil]; + + NSEnumerator* connectionEnumerator = [[d->fileOutput connections] objectEnumerator]; + + for (;;) + { + QTCaptureConnection* connection = [connectionEnumerator nextObject]; + if (connection == 0) + break; + + QTCompressionOptions* options = 0; + NSString* mediaType = [connection mediaType]; + + if ([mediaType isEqualToString: QTMediaTypeVideo]) + options = [QTCompressionOptions compressionOptionsWithIdentifier: @"QTCompressionOptionsSD480SizeH264Video"]; + else if ([mediaType isEqualToString: QTMediaTypeSound]) + options = [QTCompressionOptions compressionOptionsWithIdentifier: @"QTCompressionOptionsHighQualityAACAudio"]; + + [d->fileOutput setCompressionOptions: options forConnection: connection]; + } + + [d->fileOutput recordToOutputFileURL: [NSURL fileURLWithPath: juceStringToNS (file.getFullPathName())]]; isRecording = true; } diff --git a/juce_amalgamated.h b/juce_amalgamated.h index bc2094292c..ebb011d633 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -50453,8 +50453,10 @@ public: juce_UseDebuggingNewOperator -private: + /** @internal */ class Token; + +private: OwnedArray tokens; int totalLines; }; diff --git a/src/gui/graphics/fonts/juce_TextLayout.h b/src/gui/graphics/fonts/juce_TextLayout.h index aa6ccad609..e0d7ece9f0 100644 --- a/src/gui/graphics/fonts/juce_TextLayout.h +++ b/src/gui/graphics/fonts/juce_TextLayout.h @@ -142,8 +142,10 @@ public: //============================================================================== juce_UseDebuggingNewOperator -private: + /** @internal */ class Token; + +private: OwnedArray tokens; int totalLines; }; diff --git a/src/native/linux/juce_linux_Clipboard.cpp b/src/native/linux/juce_linux_Clipboard.cpp index 6a513a0a99..620212b934 100644 --- a/src/native/linux/juce_linux_Clipboard.cpp +++ b/src/native/linux/juce_linux_Clipboard.cpp @@ -100,7 +100,7 @@ static bool juce_requestSelectionContent (String &selection_content, Atom select // The selection owner will be asked to set the JUCE_SEL property on the // juce_messageWindowHandle with the selection content - XConvertSelection (display, selection, requested_format, property_name, + XConvertSelection (display, selection, requested_format, property_name, juce_messageWindowHandle, CurrentTime); int timeoutMs = 200; // will wait at most for 200 ms diff --git a/src/native/linux/juce_linux_Messaging.cpp b/src/native/linux/juce_linux_Messaging.cpp index 34c39dacda..bcab453db6 100644 --- a/src/native/linux/juce_linux_Messaging.cpp +++ b/src/native/linux/juce_linux_Messaging.cpp @@ -101,7 +101,7 @@ public: } int getWaitHandle() const { return fd[1]; } - + private: CriticalSection lock; OwnedArray queue; @@ -352,7 +352,7 @@ void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* func messageCallContext.func = func; messageCallContext.parameter = parameter; - juce_internalMessageQueue->postMessage (new Message (MessageThreadFuncCall::uniqueID, + juce_internalMessageQueue->postMessage (new Message (MessageThreadFuncCall::uniqueID, 0, 0, &messageCallContext)); // Wait for it to complete before continuing diff --git a/src/native/mac/juce_mac_CameraDevice.mm b/src/native/mac/juce_mac_CameraDevice.mm index a689123d58..6b5a75f20b 100644 --- a/src/native/mac/juce_mac_CameraDevice.mm +++ b/src/native/mac/juce_mac_CameraDevice.mm @@ -70,6 +70,8 @@ public: NSArray* devs = [QTCaptureDevice inputDevicesWithMediaType: QTMediaTypeVideo]; device = (QTCaptureDevice*) [devs objectAtIndex: index]; input = 0; + audioInput = 0; + audioDevice = 0; fileOutput = 0; imageOutput = 0; callbackDelegate = [[QTCaptureCallbackDelegate alloc] initWithOwner: owner @@ -82,6 +84,7 @@ public: if (err == 0) { input = [[QTCaptureDeviceInput alloc] initWithDevice: device]; + audioInput = [[QTCaptureDeviceInput alloc] initWithDevice: device]; [session addInput: input error: &err]; @@ -112,6 +115,8 @@ public: [session release]; [input release]; [device release]; + [audioDevice release]; + [audioInput release]; [fileOutput release]; [imageOutput release]; [callbackDelegate release]; @@ -123,9 +128,33 @@ public: [session removeOutput: fileOutput]; [fileOutput release]; fileOutput = [[QTCaptureMovieFileOutput alloc] init]; + + [session removeInput: audioInput]; + [audioInput release]; + audioInput = 0; + [audioDevice release]; + audioDevice = 0; + [fileOutput setDelegate: callbackDelegate]; } + void addDefaultAudioInput() + { + NSError* err = nil; + audioDevice = [QTCaptureDevice defaultInputDeviceWithMediaType: QTMediaTypeSound]; + + if ([audioDevice open: &err]) + [audioDevice retain]; + else + audioDevice = nil; + + if (audioDevice != 0) + { + audioInput = [[QTCaptureDeviceInput alloc] initWithDevice: audioDevice]; + [session addInput: audioInput error: &err]; + } + } + void addListener (CameraImageListener* listenerToAdd) { const ScopedLock sl (listenerLock); @@ -165,6 +194,8 @@ public: QTCaptureDevice* device; QTCaptureDeviceInput* input; + QTCaptureDevice* audioDevice; + QTCaptureDeviceInput* audioInput; QTCaptureSession* session; QTCaptureMovieFileOutput* fileOutput; QTCaptureDecompressedVideoOutput* imageOutput; @@ -280,8 +311,33 @@ void CameraDevice::startRecordingToFile (const File& file) QTCameraDeviceInteral* const d = (QTCameraDeviceInteral*) internal; deleteAndZero (d->callbackDelegate->firstRecordedTime); file.deleteFile(); - [d->fileOutput recordToOutputFileURL: [NSURL fileURLWithPath: juceStringToNS (file.getFullPathName())]]; + + // In some versions of QT (e.g. on 10.5), if you record video without audio, the speed comes + // out wrong, so we'll put some audio in there too.., + d->addDefaultAudioInput(); + [d->session addOutput: d->fileOutput error: nil]; + + NSEnumerator* connectionEnumerator = [[d->fileOutput connections] objectEnumerator]; + + for (;;) + { + QTCaptureConnection* connection = [connectionEnumerator nextObject]; + if (connection == 0) + break; + + QTCompressionOptions* options = 0; + NSString* mediaType = [connection mediaType]; + + if ([mediaType isEqualToString: QTMediaTypeVideo]) + options = [QTCompressionOptions compressionOptionsWithIdentifier: @"QTCompressionOptionsSD480SizeH264Video"]; + else if ([mediaType isEqualToString: QTMediaTypeSound]) + options = [QTCompressionOptions compressionOptionsWithIdentifier: @"QTCompressionOptionsHighQualityAACAudio"]; + + [d->fileOutput setCompressionOptions: options forConnection: connection]; + } + + [d->fileOutput recordToOutputFileURL: [NSURL fileURLWithPath: juceStringToNS (file.getFullPathName())]]; isRecording = true; }