diff --git a/Builds/Linux/Makefile b/Builds/Linux/Makefile
index ff04a9469b..3ccc60f94c 100644
--- a/Builds/Linux/Makefile
+++ b/Builds/Linux/Makefile
@@ -318,6 +318,7 @@ OBJECTS := \
$(OBJDIR)/juce_win32_AudioCDReader_66c7252.o \
$(OBJDIR)/juce_win32_CameraDevice_ea35306d.o \
$(OBJDIR)/juce_win32_Direct2DGraphicsContext_9f1b6be1.o \
+ $(OBJDIR)/juce_win32_DirectShowComponent_e4030c4f.o \
$(OBJDIR)/juce_win32_DirectSound_3462415e.o \
$(OBJDIR)/juce_win32_FileChooser_18a257.o \
$(OBJDIR)/juce_win32_Files_f3e9a2ef.o \
@@ -1782,6 +1783,11 @@ $(OBJDIR)/juce_win32_Direct2DGraphicsContext_9f1b6be1.o: ../../src/native/window
@echo "Compiling juce_win32_Direct2DGraphicsContext.cpp"
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
+$(OBJDIR)/juce_win32_DirectShowComponent_e4030c4f.o: ../../src/native/windows/juce_win32_DirectShowComponent.cpp
+ -@mkdir -p $(OBJDIR)
+ @echo "Compiling juce_win32_DirectShowComponent.cpp"
+ @$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
+
$(OBJDIR)/juce_win32_DirectSound_3462415e.o: ../../src/native/windows/juce_win32_DirectSound.cpp
-@mkdir -p $(OBJDIR)
@echo "Compiling juce_win32_DirectSound.cpp"
diff --git a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj
index ded6dda5a0..d030e10356 100644
--- a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj
+++ b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj
@@ -313,6 +313,7 @@
9686F29C29D1C26E353DE68A = { isa = PBXBuildFile; fileRef = F3B50EE3939E9F16D13C3C7C; };
79B4C2F1C0CF592ACE8093C0 = { isa = PBXBuildFile; fileRef = 3A37CD82212075940421CE4F; };
88A87D28B3809665F28DC16E = { isa = PBXBuildFile; fileRef = 7F3EF672D07ECE3E13AAF267; };
+ 6BDBEFD97E643E5BB27637FF = { isa = PBXBuildFile; fileRef = 249959E338D7750E56A9F2F8; };
BC3C22F5350ED7433D303A04 = { isa = PBXBuildFile; fileRef = 58B70C726D186B4E770300BC; };
0B41EC4D7839F8CBCB8F9A0D = { isa = PBXBuildFile; fileRef = DCD09B6EF4A4A109DE01F152; };
B420CD4B589C08EAFA6E3DA4 = { isa = PBXBuildFile; fileRef = 7527A5E8F4F39581159D3E5B; };
@@ -785,6 +786,7 @@
C25DFA2F2B673EB0146412BB = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_BubbleMessageComponent.h; path = ../../src/gui/components/special/juce_BubbleMessageComponent.h; sourceTree = SOURCE_ROOT; };
0A20E7E561633610A76A34AB = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ColourSelector.cpp; path = ../../src/gui/components/special/juce_ColourSelector.cpp; sourceTree = SOURCE_ROOT; };
CD9F817B7EF0DA080668A3A8 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ColourSelector.h; path = ../../src/gui/components/special/juce_ColourSelector.h; sourceTree = SOURCE_ROOT; };
+ 4BF7A01BCE61A5068CA13D8F = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_DirectShowComponent.h; path = ../../src/gui/components/special/juce_DirectShowComponent.h; sourceTree = SOURCE_ROOT; };
9C1D5CDA61FB51F657DA8B22 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_DropShadower.cpp; path = ../../src/gui/components/special/juce_DropShadower.cpp; sourceTree = SOURCE_ROOT; };
7DB8CFB77EA690ACF54C63B4 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_DropShadower.h; path = ../../src/gui/components/special/juce_DropShadower.h; sourceTree = SOURCE_ROOT; };
3C8C1AAF32DFECB89EB83271 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_MidiKeyboardComponent.cpp; path = ../../src/gui/components/special/juce_MidiKeyboardComponent.cpp; sourceTree = SOURCE_ROOT; };
@@ -1015,6 +1017,7 @@
9C4D1018ECC0BA07346453EF = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_win32_AutoLinkLibraries.h; path = ../../src/native/windows/juce_win32_AutoLinkLibraries.h; sourceTree = SOURCE_ROOT; };
3A37CD82212075940421CE4F = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_CameraDevice.cpp; path = ../../src/native/windows/juce_win32_CameraDevice.cpp; sourceTree = SOURCE_ROOT; };
7F3EF672D07ECE3E13AAF267 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_Direct2DGraphicsContext.cpp; path = ../../src/native/windows/juce_win32_Direct2DGraphicsContext.cpp; sourceTree = SOURCE_ROOT; };
+ 249959E338D7750E56A9F2F8 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_DirectShowComponent.cpp; path = ../../src/native/windows/juce_win32_DirectShowComponent.cpp; sourceTree = SOURCE_ROOT; };
58B70C726D186B4E770300BC = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_DirectSound.cpp; path = ../../src/native/windows/juce_win32_DirectSound.cpp; sourceTree = SOURCE_ROOT; };
BA66E265749F75DBA86EC3F1 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_win32_DynamicLibraryLoader.h; path = ../../src/native/windows/juce_win32_DynamicLibraryLoader.h; sourceTree = SOURCE_ROOT; };
DCD09B6EF4A4A109DE01F152 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_FileChooser.cpp; path = ../../src/native/windows/juce_win32_FileChooser.cpp; sourceTree = SOURCE_ROOT; };
@@ -1565,6 +1568,7 @@
C25DFA2F2B673EB0146412BB,
0A20E7E561633610A76A34AB,
CD9F817B7EF0DA080668A3A8,
+ 4BF7A01BCE61A5068CA13D8F,
9C1D5CDA61FB51F657DA8B22,
7DB8CFB77EA690ACF54C63B4,
3C8C1AAF32DFECB89EB83271,
@@ -1851,6 +1855,7 @@
9C4D1018ECC0BA07346453EF,
3A37CD82212075940421CE4F,
7F3EF672D07ECE3E13AAF267,
+ 249959E338D7750E56A9F2F8,
58B70C726D186B4E770300BC,
BA66E265749F75DBA86EC3F1,
DCD09B6EF4A4A109DE01F152,
@@ -2361,6 +2366,7 @@
9686F29C29D1C26E353DE68A,
79B4C2F1C0CF592ACE8093C0,
88A87D28B3809665F28DC16E,
+ 6BDBEFD97E643E5BB27637FF,
BC3C22F5350ED7433D303A04,
0B41EC4D7839F8CBCB8F9A0D,
B420CD4B589C08EAFA6E3DA4,
diff --git a/Builds/VisualStudio2005/Juce.vcproj b/Builds/VisualStudio2005/Juce.vcproj
index e1e0c0e6cc..a37a9211f1 100644
--- a/Builds/VisualStudio2005/Juce.vcproj
+++ b/Builds/VisualStudio2005/Juce.vcproj
@@ -646,6 +646,7 @@
+
@@ -919,6 +920,7 @@
+
diff --git a/Builds/VisualStudio2008/Juce.vcproj b/Builds/VisualStudio2008/Juce.vcproj
index cd0c98a40b..f789ed2030 100644
--- a/Builds/VisualStudio2008/Juce.vcproj
+++ b/Builds/VisualStudio2008/Juce.vcproj
@@ -646,6 +646,7 @@
+
@@ -919,6 +920,7 @@
+
diff --git a/Builds/VisualStudio2008_DLL/Juce.vcproj b/Builds/VisualStudio2008_DLL/Juce.vcproj
index eb8810c17b..071c104db2 100644
--- a/Builds/VisualStudio2008_DLL/Juce.vcproj
+++ b/Builds/VisualStudio2008_DLL/Juce.vcproj
@@ -648,6 +648,7 @@
+
@@ -921,6 +922,7 @@
+
diff --git a/Builds/VisualStudio2010/Juce.vcxproj b/Builds/VisualStudio2010/Juce.vcxproj
index 0a97ed77a1..68d92ebf05 100644
--- a/Builds/VisualStudio2010/Juce.vcxproj
+++ b/Builds/VisualStudio2010/Juce.vcxproj
@@ -401,6 +401,7 @@
+
@@ -683,6 +684,7 @@
+
diff --git a/Builds/VisualStudio2010/Juce.vcxproj.filters b/Builds/VisualStudio2010/Juce.vcxproj.filters
index 14a733545d..a46857739c 100644
--- a/Builds/VisualStudio2010/Juce.vcxproj.filters
+++ b/Builds/VisualStudio2010/Juce.vcxproj.filters
@@ -1138,6 +1138,9 @@
Juce\Source\native\windows
+
+ Juce\Source\native\windows
+
Juce\Source\native\windows
@@ -1980,6 +1983,9 @@
Juce\Source\gui\components\special
+
+ Juce\Source\gui\components\special
+
Juce\Source\gui\components\special
diff --git a/Builds/iOS/Juce.xcodeproj/project.pbxproj b/Builds/iOS/Juce.xcodeproj/project.pbxproj
index 964e6feeba..9a9a9b0825 100644
--- a/Builds/iOS/Juce.xcodeproj/project.pbxproj
+++ b/Builds/iOS/Juce.xcodeproj/project.pbxproj
@@ -313,6 +313,7 @@
9686F29C29D1C26E353DE68A = { isa = PBXBuildFile; fileRef = F3B50EE3939E9F16D13C3C7C; };
79B4C2F1C0CF592ACE8093C0 = { isa = PBXBuildFile; fileRef = 3A37CD82212075940421CE4F; };
88A87D28B3809665F28DC16E = { isa = PBXBuildFile; fileRef = 7F3EF672D07ECE3E13AAF267; };
+ 6BDBEFD97E643E5BB27637FF = { isa = PBXBuildFile; fileRef = 249959E338D7750E56A9F2F8; };
BC3C22F5350ED7433D303A04 = { isa = PBXBuildFile; fileRef = 58B70C726D186B4E770300BC; };
0B41EC4D7839F8CBCB8F9A0D = { isa = PBXBuildFile; fileRef = DCD09B6EF4A4A109DE01F152; };
B420CD4B589C08EAFA6E3DA4 = { isa = PBXBuildFile; fileRef = 7527A5E8F4F39581159D3E5B; };
@@ -785,6 +786,7 @@
C25DFA2F2B673EB0146412BB = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_BubbleMessageComponent.h; path = ../../src/gui/components/special/juce_BubbleMessageComponent.h; sourceTree = SOURCE_ROOT; };
0A20E7E561633610A76A34AB = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ColourSelector.cpp; path = ../../src/gui/components/special/juce_ColourSelector.cpp; sourceTree = SOURCE_ROOT; };
CD9F817B7EF0DA080668A3A8 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ColourSelector.h; path = ../../src/gui/components/special/juce_ColourSelector.h; sourceTree = SOURCE_ROOT; };
+ 4BF7A01BCE61A5068CA13D8F = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_DirectShowComponent.h; path = ../../src/gui/components/special/juce_DirectShowComponent.h; sourceTree = SOURCE_ROOT; };
9C1D5CDA61FB51F657DA8B22 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_DropShadower.cpp; path = ../../src/gui/components/special/juce_DropShadower.cpp; sourceTree = SOURCE_ROOT; };
7DB8CFB77EA690ACF54C63B4 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_DropShadower.h; path = ../../src/gui/components/special/juce_DropShadower.h; sourceTree = SOURCE_ROOT; };
3C8C1AAF32DFECB89EB83271 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_MidiKeyboardComponent.cpp; path = ../../src/gui/components/special/juce_MidiKeyboardComponent.cpp; sourceTree = SOURCE_ROOT; };
@@ -1015,6 +1017,7 @@
9C4D1018ECC0BA07346453EF = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_win32_AutoLinkLibraries.h; path = ../../src/native/windows/juce_win32_AutoLinkLibraries.h; sourceTree = SOURCE_ROOT; };
3A37CD82212075940421CE4F = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_CameraDevice.cpp; path = ../../src/native/windows/juce_win32_CameraDevice.cpp; sourceTree = SOURCE_ROOT; };
7F3EF672D07ECE3E13AAF267 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_Direct2DGraphicsContext.cpp; path = ../../src/native/windows/juce_win32_Direct2DGraphicsContext.cpp; sourceTree = SOURCE_ROOT; };
+ 249959E338D7750E56A9F2F8 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_DirectShowComponent.cpp; path = ../../src/native/windows/juce_win32_DirectShowComponent.cpp; sourceTree = SOURCE_ROOT; };
58B70C726D186B4E770300BC = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_DirectSound.cpp; path = ../../src/native/windows/juce_win32_DirectSound.cpp; sourceTree = SOURCE_ROOT; };
BA66E265749F75DBA86EC3F1 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_win32_DynamicLibraryLoader.h; path = ../../src/native/windows/juce_win32_DynamicLibraryLoader.h; sourceTree = SOURCE_ROOT; };
DCD09B6EF4A4A109DE01F152 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_FileChooser.cpp; path = ../../src/native/windows/juce_win32_FileChooser.cpp; sourceTree = SOURCE_ROOT; };
@@ -1565,6 +1568,7 @@
C25DFA2F2B673EB0146412BB,
0A20E7E561633610A76A34AB,
CD9F817B7EF0DA080668A3A8,
+ 4BF7A01BCE61A5068CA13D8F,
9C1D5CDA61FB51F657DA8B22,
7DB8CFB77EA690ACF54C63B4,
3C8C1AAF32DFECB89EB83271,
@@ -1851,6 +1855,7 @@
9C4D1018ECC0BA07346453EF,
3A37CD82212075940421CE4F,
7F3EF672D07ECE3E13AAF267,
+ 249959E338D7750E56A9F2F8,
58B70C726D186B4E770300BC,
BA66E265749F75DBA86EC3F1,
DCD09B6EF4A4A109DE01F152,
@@ -2365,6 +2370,7 @@
9686F29C29D1C26E353DE68A,
79B4C2F1C0CF592ACE8093C0,
88A87D28B3809665F28DC16E,
+ 6BDBEFD97E643E5BB27637FF,
BC3C22F5350ED7433D303A04,
0B41EC4D7839F8CBCB8F9A0D,
B420CD4B589C08EAFA6E3DA4,
diff --git a/Juce.jucer b/Juce.jucer
index ca75a7d61b..ad3bcfb40c 100644
--- a/Juce.jucer
+++ b/Juce.jucer
@@ -926,6 +926,8 @@
file="src/gui/components/special/juce_ColourSelector.cpp"/>
+
+
+ JUCE_DIRECT2D="default" JUCE_MEDIAFOUNDATION="default" JUCE_DIRECTSHOW="default"/>
diff --git a/extras/Introjucer/Introjucer.jucer b/extras/Introjucer/Introjucer.jucer
index 7cb449f08d..41178e556d 100644
--- a/extras/Introjucer/Introjucer.jucer
+++ b/extras/Introjucer/Introjucer.jucer
@@ -186,5 +186,6 @@
JUCE_USE_XINERAMA="default" JUCE_USE_XSHM="default" JUCE_ONLY_BUILD_CORE_LIBRARY="default"
JUCE_WEB_BROWSER="default" JUCE_SUPPORT_CARBON="default" JUCE_CHECK_MEMORY_LEAKS="default"
JUCE_CATCH_UNHANDLED_EXCEPTIONS="default" JUCE_STRINGS_ARE_UNICODE="default"
- JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default" JUCE_DIRECT2D="default"/>
+ JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default" JUCE_DIRECT2D="default"
+ JUCE_DIRECTSHOW="default" JUCE_MEDIAFOUNDATION="default"/>
diff --git a/extras/Introjucer/JuceLibraryCode/AppConfig.h b/extras/Introjucer/JuceLibraryCode/AppConfig.h
index 0dc80c4954..e66cbe123d 100644
--- a/extras/Introjucer/JuceLibraryCode/AppConfig.h
+++ b/extras/Introjucer/JuceLibraryCode/AppConfig.h
@@ -16,6 +16,8 @@
#define JUCE_ASIO 0
#define JUCE_WASAPI 0
#define JUCE_DIRECTSOUND 0
+//#define JUCE_DIRECTSHOW
+//#define JUCE_MEDIAFOUNDATION
#define JUCE_ALSA 0
#define JUCE_QUICKTIME 0
#define JUCE_OPENGL 0
diff --git a/extras/JuceDemo/Builds/Android/jni/Android.mk b/extras/JuceDemo/Builds/Android/jni/Android.mk
index bda2d33078..930c7f3c30 100644
--- a/extras/JuceDemo/Builds/Android/jni/Android.mk
+++ b/extras/JuceDemo/Builds/Android/jni/Android.mk
@@ -18,6 +18,7 @@ LOCAL_SRC_FILES := \
../../../Source/demos/AudioDemoTabComponent.cpp\
../../../Source/demos/CameraDemo.cpp\
../../../Source/demos/CodeEditorDemo.cpp\
+ ../../../Source/demos/DirectShowDemo.cpp\
../../../Source/demos/DragAndDropDemo.cpp\
../../../Source/demos/FontsAndTextDemo.cpp\
../../../Source/demos/InterprocessCommsDemo.cpp\
diff --git a/extras/JuceDemo/Builds/Linux/Makefile b/extras/JuceDemo/Builds/Linux/Makefile
index 67658c58c4..31decfca9c 100644
--- a/extras/JuceDemo/Builds/Linux/Makefile
+++ b/extras/JuceDemo/Builds/Linux/Makefile
@@ -53,6 +53,7 @@ OBJECTS := \
$(OBJDIR)/AudioDemoTabComponent_81185e3.o \
$(OBJDIR)/CameraDemo_954a4a30.o \
$(OBJDIR)/CodeEditorDemo_55f35645.o \
+ $(OBJDIR)/DirectShowDemo_2e0bc311.o \
$(OBJDIR)/DragAndDropDemo_f8c9e5d7.o \
$(OBJDIR)/FontsAndTextDemo_2cefcecb.o \
$(OBJDIR)/InterprocessCommsDemo_aa1c1119.o \
@@ -135,6 +136,11 @@ $(OBJDIR)/CodeEditorDemo_55f35645.o: ../../Source/demos/CodeEditorDemo.cpp
@echo "Compiling CodeEditorDemo.cpp"
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
+$(OBJDIR)/DirectShowDemo_2e0bc311.o: ../../Source/demos/DirectShowDemo.cpp
+ -@mkdir -p $(OBJDIR)
+ @echo "Compiling DirectShowDemo.cpp"
+ @$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
+
$(OBJDIR)/DragAndDropDemo_f8c9e5d7.o: ../../Source/demos/DragAndDropDemo.cpp
-@mkdir -p $(OBJDIR)
@echo "Compiling DragAndDropDemo.cpp"
diff --git a/extras/JuceDemo/Builds/MacOSX/Juce Demo.xcodeproj/project.pbxproj b/extras/JuceDemo/Builds/MacOSX/Juce Demo.xcodeproj/project.pbxproj
index 5f835b6dd6..ef48b77bd6 100644
--- a/extras/JuceDemo/Builds/MacOSX/Juce Demo.xcodeproj/project.pbxproj
+++ b/extras/JuceDemo/Builds/MacOSX/Juce Demo.xcodeproj/project.pbxproj
@@ -28,6 +28,7 @@
7EFB4E7D738BFFF90F49E0C0 = { isa = PBXBuildFile; fileRef = 048CEE4CC06227D8A57E47F2; };
B69F5957B1729915BFB18735 = { isa = PBXBuildFile; fileRef = 7D65727C8F72F2BCC9A17D34; };
F920A5AB6D0FF01022575079 = { isa = PBXBuildFile; fileRef = 268D7AFE2F3822C2C8E9A612; };
+ 940BE0338CC1FEB65B4B82E2 = { isa = PBXBuildFile; fileRef = E072353A8A1F26CFB7090905; };
A3AF0F559DD97F1B908AC1CA = { isa = PBXBuildFile; fileRef = F23738E4EFD2323063F82F1C; };
2C0AB902CB01E38D87A2A6A5 = { isa = PBXBuildFile; fileRef = B7F4DAFA5F8F1FC976C8B55D; };
ACD2210FDE1137548F995F85 = { isa = PBXBuildFile; fileRef = F7620D8D567CCE463ADDE0A6; };
@@ -76,6 +77,7 @@
8BEA0B754661F3038DBAF558 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AudioDemoTabComponent.h; path = ../../Source/demos/AudioDemoTabComponent.h; sourceTree = SOURCE_ROOT; };
7D65727C8F72F2BCC9A17D34 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CameraDemo.cpp; path = ../../Source/demos/CameraDemo.cpp; sourceTree = SOURCE_ROOT; };
268D7AFE2F3822C2C8E9A612 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CodeEditorDemo.cpp; path = ../../Source/demos/CodeEditorDemo.cpp; sourceTree = SOURCE_ROOT; };
+ E072353A8A1F26CFB7090905 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DirectShowDemo.cpp; path = ../../Source/demos/DirectShowDemo.cpp; sourceTree = SOURCE_ROOT; };
F23738E4EFD2323063F82F1C = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DragAndDropDemo.cpp; path = ../../Source/demos/DragAndDropDemo.cpp; sourceTree = SOURCE_ROOT; };
B7F4DAFA5F8F1FC976C8B55D = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FontsAndTextDemo.cpp; path = ../../Source/demos/FontsAndTextDemo.cpp; sourceTree = SOURCE_ROOT; };
F7620D8D567CCE463ADDE0A6 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = InterprocessCommsDemo.cpp; path = ../../Source/demos/InterprocessCommsDemo.cpp; sourceTree = SOURCE_ROOT; };
@@ -117,6 +119,7 @@
8BEA0B754661F3038DBAF558,
7D65727C8F72F2BCC9A17D34,
268D7AFE2F3822C2C8E9A612,
+ E072353A8A1F26CFB7090905,
F23738E4EFD2323063F82F1C,
B7F4DAFA5F8F1FC976C8B55D,
F7620D8D567CCE463ADDE0A6,
@@ -258,6 +261,7 @@
7EFB4E7D738BFFF90F49E0C0,
B69F5957B1729915BFB18735,
F920A5AB6D0FF01022575079,
+ 940BE0338CC1FEB65B4B82E2,
A3AF0F559DD97F1B908AC1CA,
2C0AB902CB01E38D87A2A6A5,
ACD2210FDE1137548F995F85,
diff --git a/extras/JuceDemo/Builds/VisualStudio2005/Juce Demo.vcproj b/extras/JuceDemo/Builds/VisualStudio2005/Juce Demo.vcproj
index 559037762e..e0a519bb3c 100644
--- a/extras/JuceDemo/Builds/VisualStudio2005/Juce Demo.vcproj
+++ b/extras/JuceDemo/Builds/VisualStudio2005/Juce Demo.vcproj
@@ -148,6 +148,7 @@
+
diff --git a/extras/JuceDemo/Builds/VisualStudio2008/Juce Demo.vcproj b/extras/JuceDemo/Builds/VisualStudio2008/Juce Demo.vcproj
index 4a0a7a49e9..63dd1025ff 100644
--- a/extras/JuceDemo/Builds/VisualStudio2008/Juce Demo.vcproj
+++ b/extras/JuceDemo/Builds/VisualStudio2008/Juce Demo.vcproj
@@ -148,6 +148,7 @@
+
diff --git a/extras/JuceDemo/Builds/VisualStudio2010/Juce Demo.vcxproj b/extras/JuceDemo/Builds/VisualStudio2010/Juce Demo.vcxproj
index 7835779251..fd1ba5c5c4 100644
--- a/extras/JuceDemo/Builds/VisualStudio2010/Juce Demo.vcxproj
+++ b/extras/JuceDemo/Builds/VisualStudio2010/Juce Demo.vcxproj
@@ -132,6 +132,7 @@
+
diff --git a/extras/JuceDemo/Builds/VisualStudio2010/Juce Demo.vcxproj.filters b/extras/JuceDemo/Builds/VisualStudio2010/Juce Demo.vcxproj.filters
index 17106637a0..2eb22b293e 100644
--- a/extras/JuceDemo/Builds/VisualStudio2010/Juce Demo.vcxproj.filters
+++ b/extras/JuceDemo/Builds/VisualStudio2010/Juce Demo.vcxproj.filters
@@ -49,6 +49,9 @@
Juce Demo\Source\Demos
+
+ Juce Demo\Source\Demos
+
Juce Demo\Source\Demos
diff --git a/extras/JuceDemo/Builds/iOS/Juce Demo.xcodeproj/project.pbxproj b/extras/JuceDemo/Builds/iOS/Juce Demo.xcodeproj/project.pbxproj
index 384ecb815e..006fddff51 100644
--- a/extras/JuceDemo/Builds/iOS/Juce Demo.xcodeproj/project.pbxproj
+++ b/extras/JuceDemo/Builds/iOS/Juce Demo.xcodeproj/project.pbxproj
@@ -24,6 +24,7 @@
7EFB4E7D738BFFF90F49E0C0 = { isa = PBXBuildFile; fileRef = 048CEE4CC06227D8A57E47F2; };
B69F5957B1729915BFB18735 = { isa = PBXBuildFile; fileRef = 7D65727C8F72F2BCC9A17D34; };
F920A5AB6D0FF01022575079 = { isa = PBXBuildFile; fileRef = 268D7AFE2F3822C2C8E9A612; };
+ 940BE0338CC1FEB65B4B82E2 = { isa = PBXBuildFile; fileRef = E072353A8A1F26CFB7090905; };
A3AF0F559DD97F1B908AC1CA = { isa = PBXBuildFile; fileRef = F23738E4EFD2323063F82F1C; };
2C0AB902CB01E38D87A2A6A5 = { isa = PBXBuildFile; fileRef = B7F4DAFA5F8F1FC976C8B55D; };
ACD2210FDE1137548F995F85 = { isa = PBXBuildFile; fileRef = F7620D8D567CCE463ADDE0A6; };
@@ -68,6 +69,7 @@
8BEA0B754661F3038DBAF558 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AudioDemoTabComponent.h; path = ../../Source/demos/AudioDemoTabComponent.h; sourceTree = SOURCE_ROOT; };
7D65727C8F72F2BCC9A17D34 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CameraDemo.cpp; path = ../../Source/demos/CameraDemo.cpp; sourceTree = SOURCE_ROOT; };
268D7AFE2F3822C2C8E9A612 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CodeEditorDemo.cpp; path = ../../Source/demos/CodeEditorDemo.cpp; sourceTree = SOURCE_ROOT; };
+ E072353A8A1F26CFB7090905 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DirectShowDemo.cpp; path = ../../Source/demos/DirectShowDemo.cpp; sourceTree = SOURCE_ROOT; };
F23738E4EFD2323063F82F1C = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DragAndDropDemo.cpp; path = ../../Source/demos/DragAndDropDemo.cpp; sourceTree = SOURCE_ROOT; };
B7F4DAFA5F8F1FC976C8B55D = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FontsAndTextDemo.cpp; path = ../../Source/demos/FontsAndTextDemo.cpp; sourceTree = SOURCE_ROOT; };
F7620D8D567CCE463ADDE0A6 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = InterprocessCommsDemo.cpp; path = ../../Source/demos/InterprocessCommsDemo.cpp; sourceTree = SOURCE_ROOT; };
@@ -109,6 +111,7 @@
8BEA0B754661F3038DBAF558,
7D65727C8F72F2BCC9A17D34,
268D7AFE2F3822C2C8E9A612,
+ E072353A8A1F26CFB7090905,
F23738E4EFD2323063F82F1C,
B7F4DAFA5F8F1FC976C8B55D,
F7620D8D567CCE463ADDE0A6,
@@ -249,6 +252,7 @@
7EFB4E7D738BFFF90F49E0C0,
B69F5957B1729915BFB18735,
F920A5AB6D0FF01022575079,
+ 940BE0338CC1FEB65B4B82E2,
A3AF0F559DD97F1B908AC1CA,
2C0AB902CB01E38D87A2A6A5,
ACD2210FDE1137548F995F85,
diff --git a/extras/JuceDemo/Juce Demo.jucer b/extras/JuceDemo/Juce Demo.jucer
index c05c6eae9d..08a6892b45 100644
--- a/extras/JuceDemo/Juce Demo.jucer
+++ b/extras/JuceDemo/Juce Demo.jucer
@@ -72,6 +72,8 @@
file="Source/demos/CameraDemo.cpp"/>
+
+ JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default" JUCE_DIRECT2D="default"
+ JUCE_MEDIAFOUNDATION="default" JUCE_DIRECTSHOW="default"/>
diff --git a/extras/JuceDemo/JuceLibraryCode/AppConfig.h b/extras/JuceDemo/JuceLibraryCode/AppConfig.h
index d878651b93..122c4df422 100644
--- a/extras/JuceDemo/JuceLibraryCode/AppConfig.h
+++ b/extras/JuceDemo/JuceLibraryCode/AppConfig.h
@@ -16,6 +16,8 @@
//#define JUCE_ASIO
//#define JUCE_WASAPI
//#define JUCE_DIRECTSOUND
+//#define JUCE_DIRECTSHOW
+//#define JUCE_MEDIAFOUNDATION
//#define JUCE_ALSA
//#define JUCE_QUICKTIME
//#define JUCE_OPENGL
diff --git a/extras/JuceDemo/Source/MainDemoWindow.cpp b/extras/JuceDemo/Source/MainDemoWindow.cpp
index 9207b01364..a2bad8e515 100644
--- a/extras/JuceDemo/Source/MainDemoWindow.cpp
+++ b/extras/JuceDemo/Source/MainDemoWindow.cpp
@@ -86,6 +86,7 @@ public:
menu.addCommandItem (commandManager, showDragAndDrop);
menu.addCommandItem (commandManager, showOpenGL);
menu.addCommandItem (commandManager, showQuicktime);
+ menu.addCommandItem (commandManager, showDirectShow);
menu.addCommandItem (commandManager, showInterprocessComms);
menu.addCommandItem (commandManager, showCamera);
menu.addCommandItem (commandManager, showWebBrowser);
@@ -157,6 +158,7 @@ public:
showDragAndDrop,
showOpenGL,
showQuicktime,
+ showDirectShow,
showCamera,
showWebBrowser,
showCodeEditor,
@@ -251,6 +253,15 @@ public:
#endif
break;
+ case showDirectShow:
+ result.setInfo ("DirectShow", "Shows the DirectShow demo", demosCategory, 0);
+ result.addDefaultKeypress ('b', ModifierKeys::commandModifier);
+ result.setTicked (currentDemoId == showDirectShow);
+#if ! JUCE_DIRECTSHOW
+ result.setActive (false);
+#endif
+ break;
+
case showCamera:
result.setInfo ("Camera Capture", "Shows the camera demo", demosCategory, 0);
result.addDefaultKeypress ('c', ModifierKeys::commandModifier);
@@ -374,6 +385,13 @@ public:
#endif
break;
+ case showDirectShow:
+#if JUCE_DIRECTSHOW
+ showDemo (createDirectShowDemo());
+ currentDemoId = showDirectShow;
+#endif
+ break;
+
case showCamera:
#if JUCE_USE_CAMERA
showDemo (createCameraDemo());
@@ -474,6 +492,7 @@ private:
showCamera = 0x2011,
showWebBrowser = 0x2012,
showCodeEditor = 0x2013,
+ showDirectShow = 0x2014,
setDefaultLookAndFeel = 0x200b,
setOldSchoolLookAndFeel = 0x200c,
diff --git a/extras/JuceDemo/Source/demos/DirectShowDemo.cpp b/extras/JuceDemo/Source/demos/DirectShowDemo.cpp
new file mode 100644
index 0000000000..a7de04f553
--- /dev/null
+++ b/extras/JuceDemo/Source/demos/DirectShowDemo.cpp
@@ -0,0 +1,155 @@
+
+#include "../jucedemo_headers.h"
+
+#if JUCE_DIRECTSHOW
+
+//==============================================================================
+class DirectShowWindowWithFileBrowser : public Component,
+ public FilenameComponentListener
+{
+public:
+ DirectShowWindowWithFileBrowser (DirectShowComponent::VideoRendererType type)
+ : fileChooser ("movie", File::nonexistent, true, false, false,
+ "*", String::empty, "(choose a video file to play)"),
+ dshowComp (type)
+ {
+ addAndMakeVisible (&dshowComp);
+ addAndMakeVisible (&fileChooser);
+ fileChooser.addListener (this);
+ fileChooser.setBrowseButtonText ("browse");
+ }
+
+ void resized()
+ {
+ dshowComp.setBounds (0, 0, getWidth(), getHeight() - 60);
+
+ if (transportControl != 0)
+ transportControl->setBounds (0, dshowComp.getBottom() + 4, getWidth(), 26);
+
+ fileChooser.setBounds (0, getHeight() - 24, getWidth(), 24);
+ }
+
+ void filenameComponentChanged (FilenameComponent*)
+ {
+ // this is called when the user changes the filename in the file chooser box
+ if (dshowComp.loadMovie (fileChooser.getCurrentFile()))
+ {
+ addAndMakeVisible (transportControl = new TransportControl (dshowComp));
+ resized();
+
+ dshowComp.play();
+ }
+ else
+ {
+ AlertWindow::showMessageBox (AlertWindow::WarningIcon,
+ "Couldn't load the file!",
+ "Sorry, DirectShow didn't manage to load that file!");
+ }
+ }
+
+private:
+ DirectShowComponent dshowComp;
+ FilenameComponent fileChooser;
+
+ //==============================================================================
+ // A quick-and-dirty transport control, containing a play button and a position slider..
+ class TransportControl : public Component,
+ public ButtonListener,
+ public SliderListener,
+ public Timer
+ {
+ public:
+ TransportControl (DirectShowComponent& dshowComp_)
+ : playButton ("Play/Pause"),
+ position (String::empty),
+ dshowComp (dshowComp_)
+ {
+ addAndMakeVisible (&playButton);
+ playButton.addListener (this);
+
+ addAndMakeVisible (&position);
+ position.setRange (0, dshowComp.getMovieDuration(), 0);
+ position.setSliderStyle (Slider::LinearHorizontal);
+ position.setTextBoxStyle (Slider::NoTextBox, false, 80, 20);
+ position.addListener (this);
+
+ startTimer (1000 / 50);
+ }
+
+ void buttonClicked (Button* buttonThatWasClicked)
+ {
+ if (dshowComp.isPlaying())
+ dshowComp.stop();
+ else
+ dshowComp.play();
+ }
+
+ void sliderValueChanged (Slider* sliderThatWasMoved)
+ {
+ dshowComp.setPosition (position.getValue());
+ }
+
+ void resized()
+ {
+ const int playButtonWidth = 90;
+ playButton.setBounds (0, 0, playButtonWidth, getHeight());
+ position.setBounds (playButtonWidth, 0, getWidth() - playButtonWidth, getHeight());
+ }
+
+ void timerCallback()
+ {
+ if (! position.isMouseButtonDown())
+ position.setValue (dshowComp.getPosition(), false);
+ }
+
+ private:
+ TextButton playButton;
+ Slider position;
+ DirectShowComponent& dshowComp;
+ };
+
+ ScopedPointer transportControl;
+};
+
+
+//==============================================================================
+class DirectShowDemo : public Component
+{
+public:
+ //==============================================================================
+ DirectShowDemo()
+ : dsComp1 (DirectShowComponent::dshowVMR7),
+ dsComp2 (DirectShowComponent::dshowEVR)
+ {
+ setName ("DirectShow");
+
+ // add a movie component..
+ addAndMakeVisible (&dsComp1);
+ addAndMakeVisible (&dsComp2);
+ }
+
+ ~DirectShowDemo()
+ {
+ dsComp1.setVisible (false);
+ dsComp2.setVisible (false);
+ }
+
+ void resized()
+ {
+ dsComp1.setBoundsRelative (0.05f, 0.05f, 0.425f, 0.9f);
+ dsComp2.setBoundsRelative (0.525f, 0.05f, 0.425f, 0.9f);
+ }
+
+private:
+ //==============================================================================
+ DirectShowWindowWithFileBrowser dsComp1, dsComp2;
+};
+
+
+//==============================================================================
+Component* createDirectShowDemo()
+{
+ return new DirectShowDemo();
+}
+
+#endif
diff --git a/extras/JuceDemo/Source/jucedemo_headers.h b/extras/JuceDemo/Source/jucedemo_headers.h
index 36a5e27c73..cafaf8dbf2 100644
--- a/extras/JuceDemo/Source/jucedemo_headers.h
+++ b/extras/JuceDemo/Source/jucedemo_headers.h
@@ -61,5 +61,8 @@ Component* createCodeEditorDemo();
Component* createCameraDemo();
#endif
+#if JUCE_DIRECTSHOW
+ Component* createDirectShowDemo();
+#endif
#endif // __JUCEDEMO_HEADERS_JUCEHEADER__
diff --git a/extras/amalgamator/Amalgamator.jucer b/extras/amalgamator/Amalgamator.jucer
index fb070464db..44037ce364 100644
--- a/extras/amalgamator/Amalgamator.jucer
+++ b/extras/amalgamator/Amalgamator.jucer
@@ -37,5 +37,6 @@
JUCE_PLUGINHOST_AU="default" JUCE_ONLY_BUILD_CORE_LIBRARY="enabled"
JUCE_WEB_BROWSER="default" JUCE_SUPPORT_CARBON="default" JUCE_CHECK_MEMORY_LEAKS="default"
JUCE_CATCH_UNHANDLED_EXCEPTIONS="default" JUCE_STRINGS_ARE_UNICODE="default"
- JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default" JUCE_DIRECT2D="default"/>
+ JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default" JUCE_DIRECT2D="default"
+ JUCE_DIRECTSHOW="default" JUCE_MEDIAFOUNDATION="default"/>
diff --git a/extras/amalgamator/JuceLibraryCode/AppConfig.h b/extras/amalgamator/JuceLibraryCode/AppConfig.h
index 654892fe15..139a284556 100644
--- a/extras/amalgamator/JuceLibraryCode/AppConfig.h
+++ b/extras/amalgamator/JuceLibraryCode/AppConfig.h
@@ -16,6 +16,8 @@
//#define JUCE_ASIO
//#define JUCE_WASAPI
//#define JUCE_DIRECTSOUND
+//#define JUCE_DIRECTSHOW
+//#define JUCE_MEDIAFOUNDATION
//#define JUCE_ALSA
//#define JUCE_QUICKTIME
//#define JUCE_OPENGL
diff --git a/extras/audio plugin host/JuceLibraryCode/AppConfig.h b/extras/audio plugin host/JuceLibraryCode/AppConfig.h
index 13a0dc7f9e..3fc04623c6 100644
--- a/extras/audio plugin host/JuceLibraryCode/AppConfig.h
+++ b/extras/audio plugin host/JuceLibraryCode/AppConfig.h
@@ -16,6 +16,8 @@
//#define JUCE_ASIO
#define JUCE_WASAPI 1
#define JUCE_DIRECTSOUND 1
+//#define JUCE_DIRECTSHOW
+//#define JUCE_MEDIAFOUNDATION
#define JUCE_ALSA 1
//#define JUCE_QUICKTIME
//#define JUCE_OPENGL
diff --git a/extras/audio plugin host/Plugin Host.jucer b/extras/audio plugin host/Plugin Host.jucer
index 973841362d..609c598f9d 100644
--- a/extras/audio plugin host/Plugin Host.jucer
+++ b/extras/audio plugin host/Plugin Host.jucer
@@ -57,5 +57,6 @@
JUCE_PLUGINHOST_AU="enabled" JUCE_ONLY_BUILD_CORE_LIBRARY="default"
JUCE_WEB_BROWSER="default" JUCE_SUPPORT_CARBON="default" JUCE_CHECK_MEMORY_LEAKS="default"
JUCE_CATCH_UNHANDLED_EXCEPTIONS="default" JUCE_STRINGS_ARE_UNICODE="default"
- JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default" JUCE_DIRECT2D="default"/>
+ JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default" JUCE_DIRECT2D="default"
+ JUCE_DIRECTSHOW="default" JUCE_MEDIAFOUNDATION="default"/>
diff --git a/extras/audio plugins/demo/JuceDemoPlugin.jucer b/extras/audio plugins/demo/JuceDemoPlugin.jucer
index 7c5823b250..d22020447c 100644
--- a/extras/audio plugins/demo/JuceDemoPlugin.jucer
+++ b/extras/audio plugins/demo/JuceDemoPlugin.jucer
@@ -45,5 +45,5 @@
JUCE_PLUGINHOST_VST="default" JUCE_PLUGINHOST_AU="default" JUCE_ONLY_BUILD_CORE_LIBRARY="default"
JUCE_WEB_BROWSER="default" JUCE_SUPPORT_CARBON="default" JUCE_CHECK_MEMORY_LEAKS="default"
JUCE_CATCH_UNHANDLED_EXCEPTIONS="default" JUCE_USE_XCURSOR="default"
- JUCE_DIRECT2D="default"/>
+ JUCE_DIRECT2D="default" JUCE_DIRECTSHOW="default" JUCE_MEDIAFOUNDATION="default"/>
diff --git a/extras/audio plugins/demo/JuceLibraryCode/AppConfig.h b/extras/audio plugins/demo/JuceLibraryCode/AppConfig.h
index e16565bdf8..6d8293c3d5 100644
--- a/extras/audio plugins/demo/JuceLibraryCode/AppConfig.h
+++ b/extras/audio plugins/demo/JuceLibraryCode/AppConfig.h
@@ -16,6 +16,8 @@
//#define JUCE_ASIO
//#define JUCE_WASAPI
//#define JUCE_DIRECTSOUND
+//#define JUCE_DIRECTSHOW
+//#define JUCE_MEDIAFOUNDATION
//#define JUCE_ALSA
#define JUCE_QUICKTIME 0
//#define JUCE_OPENGL
diff --git a/extras/binarybuilder/BinaryBuilder.jucer b/extras/binarybuilder/BinaryBuilder.jucer
index 772fd76846..b025dd7d80 100644
--- a/extras/binarybuilder/BinaryBuilder.jucer
+++ b/extras/binarybuilder/BinaryBuilder.jucer
@@ -38,5 +38,6 @@
JUCE_PLUGINHOST_AU="default" JUCE_ONLY_BUILD_CORE_LIBRARY="enabled"
JUCE_WEB_BROWSER="default" JUCE_SUPPORT_CARBON="default" JUCE_CHECK_MEMORY_LEAKS="default"
JUCE_CATCH_UNHANDLED_EXCEPTIONS="default" JUCE_STRINGS_ARE_UNICODE="default"
- JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default" JUCE_DIRECT2D="default"/>
+ JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default" JUCE_DIRECT2D="default"
+ JUCE_DIRECTSHOW="default" JUCE_MEDIAFOUNDATION="default"/>
diff --git a/extras/binarybuilder/JuceLibraryCode/AppConfig.h b/extras/binarybuilder/JuceLibraryCode/AppConfig.h
index 654892fe15..139a284556 100644
--- a/extras/binarybuilder/JuceLibraryCode/AppConfig.h
+++ b/extras/binarybuilder/JuceLibraryCode/AppConfig.h
@@ -16,6 +16,8 @@
//#define JUCE_ASIO
//#define JUCE_WASAPI
//#define JUCE_DIRECTSOUND
+//#define JUCE_DIRECTSHOW
+//#define JUCE_MEDIAFOUNDATION
//#define JUCE_ALSA
//#define JUCE_QUICKTIME
//#define JUCE_OPENGL
diff --git a/extras/example projects/HelloWorld.jucer b/extras/example projects/HelloWorld.jucer
index 5b78c3f465..ab81767438 100644
--- a/extras/example projects/HelloWorld.jucer
+++ b/extras/example projects/HelloWorld.jucer
@@ -45,5 +45,6 @@
JUCE_PLUGINHOST_AU="default" JUCE_ONLY_BUILD_CORE_LIBRARY="default"
JUCE_WEB_BROWSER="default" JUCE_SUPPORT_CARBON="default" JUCE_CHECK_MEMORY_LEAKS="default"
JUCE_CATCH_UNHANDLED_EXCEPTIONS="default" JUCE_STRINGS_ARE_UNICODE="default"
- JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default" JUCE_DIRECT2D="default"/>
+ JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default" JUCE_DIRECT2D="default"
+ JUCE_DIRECTSHOW="default" JUCE_MEDIAFOUNDATION="default"/>
diff --git a/extras/example projects/JuceLibraryCode/AppConfig.h b/extras/example projects/JuceLibraryCode/AppConfig.h
index 23094fe3f3..8489a36b4d 100644
--- a/extras/example projects/JuceLibraryCode/AppConfig.h
+++ b/extras/example projects/JuceLibraryCode/AppConfig.h
@@ -16,6 +16,8 @@
//#define JUCE_ASIO
//#define JUCE_WASAPI
//#define JUCE_DIRECTSOUND
+//#define JUCE_DIRECTSHOW
+//#define JUCE_MEDIAFOUNDATION
//#define JUCE_ALSA
//#define JUCE_QUICKTIME
//#define JUCE_OPENGL
diff --git a/juce_Config.h b/juce_Config.h
index eb96130714..2397a93b9d 100644
--- a/juce_Config.h
+++ b/juce_Config.h
@@ -86,6 +86,25 @@
#define JUCE_DIRECTSOUND 1
#endif
+/** JUCE_DIRECTSHOW: Enables DirectShow media-streaming architecture
+ (MS Windows only).
+*/
+#ifndef JUCE_DIRECTSHOW
+ #define JUCE_DIRECTSHOW 1
+#endif
+
+/** JUCE_MEDIAFOUNDATION: Enables Media Foundation multimedia platform
+ (Windows Vista and above).
+*/
+#ifndef JUCE_MEDIAFOUNDATION
+ #define JUCE_MEDIAFOUNDATION 1
+#endif
+
+#if ! JUCE_WINDOWS
+ #undef JUCE_DIRECTSHOW
+ #undef JUCE_MEDIAFOUNDATION
+#endif
+
/** JUCE_ALSA: Enables ALSA audio devices (Linux only). */
#ifndef JUCE_ALSA
#define JUCE_ALSA 1
diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp
index 00f6d02b4f..beb6cfc446 100644
--- a/juce_amalgamated.cpp
+++ b/juce_amalgamated.cpp
@@ -257,6 +257,25 @@
#define JUCE_DIRECTSOUND 1
#endif
+/** JUCE_DIRECTSHOW: Enables DirectShow media-streaming architecture
+ (MS Windows only).
+*/
+#ifndef JUCE_DIRECTSHOW
+ #define JUCE_DIRECTSHOW 1
+#endif
+
+/** JUCE_MEDIAFOUNDATION: Enables Media Foundation multimedia platform
+ (Windows Vista and above).
+*/
+#ifndef JUCE_MEDIAFOUNDATION
+ #define JUCE_MEDIAFOUNDATION 1
+#endif
+
+#if ! JUCE_WINDOWS
+ #undef JUCE_DIRECTSHOW
+ #undef JUCE_MEDIAFOUNDATION
+#endif
+
/** JUCE_ALSA: Enables ALSA audio devices (Linux only). */
#ifndef JUCE_ALSA
#define JUCE_ALSA 1
@@ -645,6 +664,14 @@
#import
#endif
+#if JUCE_DIRECTSHOW && JUCE_BUILD_NATIVE
+ #include
+#endif
+
+#if JUCE_MEDIAFOUNDATION && JUCE_BUILD_NATIVE
+ #include
+#endif
+
#if JUCE_MSVC
#pragma warning (pop)
#endif
@@ -78179,11 +78206,7 @@ void OpenGLComponent::updateContextPosition()
const ScopedLock sl (contextLock);
if (context != nullptr)
- context->updateWindowPosition (getScreenX() - topComp->getScreenX(),
- getScreenY() - topComp->getScreenY(),
- getWidth(),
- getHeight(),
- topComp->getHeight());
+ context->updateWindowPosition (topComp->getLocalArea (this, getLocalBounds()));
}
}
}
@@ -245592,7 +245615,7 @@ MemoryMappedFile::MemoryMappedFile (const File& file, MemoryMappedFile::AccessMo
{
jassert (mode == readOnly || mode == readWrite);
- DWORD accessMode = GENERIC_READ, shareMode = FILE_SHARE_READ, createType = OPEN_EXISTING;
+ DWORD accessMode = GENERIC_READ, createType = OPEN_EXISTING;
DWORD protect = PAGE_READONLY, access = FILE_MAP_READ;
if (mode == readWrite)
@@ -252841,6 +252864,897 @@ void QuickTimeMovieComponent::setBoundsWithCorrectAspectRatio (const Rectangle graph;
+ return SUCCEEDED (graph.CoCreateInstance (CLSID_FilterGraph));
+ }
+
+ class VideoRenderer
+ {
+ public:
+ VideoRenderer() {}
+ virtual ~VideoRenderer() {}
+
+ virtual HRESULT create (ComSmartPtr & graphBuilder,
+ ComSmartPtr & baseFilter, HWND hwnd) = 0;
+
+ virtual void setVideoWindow (HWND hwnd) = 0;
+ virtual void setVideoPosition (HWND hwnd, long videoWidth, long videoHeight) = 0;
+ virtual void repaintVideo (HWND hwnd, HDC hdc) = 0;
+ virtual void displayModeChanged() = 0;
+ virtual HRESULT getVideoSize (long& videoWidth, long& videoHeight) = 0;
+ };
+
+ class VMR7 : public VideoRenderer
+ {
+ public:
+ VMR7() {}
+
+ HRESULT create (ComSmartPtr & graphBuilder,
+ ComSmartPtr & baseFilter, HWND hwnd)
+ {
+ ComSmartPtr filterConfig;
+
+ HRESULT hr = baseFilter.CoCreateInstance (CLSID_VideoMixingRenderer);
+
+ if (SUCCEEDED (hr))
+ hr = graphBuilder->AddFilter (baseFilter, L"VMR-7");
+
+ if (SUCCEEDED (hr))
+ hr = baseFilter.QueryInterface (IID_IVMRFilterConfig, filterConfig);
+
+ if (SUCCEEDED (hr))
+ hr = filterConfig->SetRenderingMode (VMRMode_Windowless);
+
+ if (SUCCEEDED (hr))
+ hr = baseFilter.QueryInterface (IID_IVMRWindowlessControl, windowlessControl);
+
+ if (SUCCEEDED (hr))
+ hr = windowlessControl->SetVideoClippingWindow (hwnd);
+
+ if (SUCCEEDED (hr))
+ hr = windowlessControl->SetAspectRatioMode (VMR_ARMODE_LETTER_BOX);
+
+ return hr;
+ }
+
+ void setVideoWindow (HWND hwnd)
+ {
+ windowlessControl->SetVideoClippingWindow (hwnd);
+ }
+
+ void setVideoPosition (HWND hwnd, long videoWidth, long videoHeight)
+ {
+ RECT src, dest;
+
+ SetRect (&src, 0, 0, videoWidth, videoHeight);
+ GetClientRect (hwnd, &dest);
+
+ windowlessControl->SetVideoPosition (&src, &dest);
+ }
+
+ void repaintVideo (HWND hwnd, HDC hdc)
+ {
+ windowlessControl->RepaintVideo (hwnd, hdc);
+ }
+
+ void displayModeChanged()
+ {
+ windowlessControl->DisplayModeChanged();
+ }
+
+ HRESULT getVideoSize (long& videoWidth, long& videoHeight)
+ {
+ return windowlessControl->GetNativeVideoSize (&videoWidth, &videoHeight, nullptr, nullptr);
+ }
+
+ private:
+ ComSmartPtr windowlessControl;
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VMR7);
+ };
+
+#if JUCE_MEDIAFOUNDATION
+ class EVR : public VideoRenderer
+ {
+ public:
+ EVR() {}
+
+ HRESULT create (ComSmartPtr & graphBuilder,
+ ComSmartPtr & baseFilter, HWND hwnd)
+ {
+ ComSmartPtr getService;
+
+ HRESULT hr = baseFilter.CoCreateInstance (CLSID_EnhancedVideoRenderer);
+
+ if (SUCCEEDED (hr))
+ hr = graphBuilder->AddFilter (baseFilter, L"EVR");
+
+ if (SUCCEEDED (hr))
+ hr = baseFilter.QueryInterface (IID_IMFGetService, getService);
+
+ if (SUCCEEDED (hr))
+ hr = getService->GetService (MR_VIDEO_RENDER_SERVICE, IID_IMFVideoDisplayControl,
+ (LPVOID*) videoDisplayControl.resetAndGetPointerAddress());
+
+ if (SUCCEEDED (hr))
+ hr = videoDisplayControl->SetVideoWindow (hwnd);
+
+ if (SUCCEEDED (hr))
+ hr = videoDisplayControl->SetAspectRatioMode (MFVideoARMode_PreservePicture);
+
+ return hr;
+ }
+
+ void setVideoWindow (HWND hwnd)
+ {
+ videoDisplayControl->SetVideoWindow (hwnd);
+ }
+
+ void setVideoPosition (HWND hwnd, long /*videoWidth*/, long /*videoHeight*/)
+ {
+ const MFVideoNormalizedRect src = { 0.0f, 0.0f, 1.0f, 1.0f };
+
+ RECT dest;
+ GetClientRect (hwnd, &dest);
+
+ videoDisplayControl->SetVideoPosition (&src, &dest);
+ }
+
+ void repaintVideo (HWND /*hwnd*/, HDC /*hdc*/)
+ {
+ videoDisplayControl->RepaintVideo();
+ }
+
+ void displayModeChanged() {}
+
+ HRESULT getVideoSize (long& videoWidth, long& videoHeight)
+ {
+ SIZE sz;
+ HRESULT hr = videoDisplayControl->GetNativeVideoSize (&sz, nullptr);
+ videoWidth = sz.cx;
+ videoHeight = sz.cy;
+ return hr;
+ }
+
+ private:
+ ComSmartPtr videoDisplayControl;
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EVR);
+ };
+#endif
+}
+
+class DirectShowComponent::DirectShowContext
+{
+public:
+ DirectShowContext (DirectShowComponent& component_, VideoRendererType type_)
+ : component (component_),
+ hwnd (0),
+ hdc (0),
+ state (uninitializedState),
+ hasVideo (false),
+ videoWidth (0),
+ videoHeight (0),
+ type (type_)
+ {
+ CoInitialize (0);
+
+ if (type == dshowDefault)
+ {
+ type = dshowVMR7;
+
+ #if JUCE_MEDIAFOUNDATION
+ if (SystemStats::getOperatingSystemType() >= SystemStats::WinVista)
+ type = dshowEVR;
+ #endif
+ }
+ }
+
+ ~DirectShowContext()
+ {
+ release();
+ CoUninitialize();
+ }
+
+ HWND getNativeWindowHandle() const
+ {
+ return nativeWindow != nullptr ? nativeWindow->getHandle() : 0;
+ }
+
+ void updateWindowPosition (const Rectangle& newBounds)
+ {
+ nativeWindow->setWindowPosition (newBounds);
+ }
+
+ void showWindow (bool shouldBeVisible)
+ {
+ nativeWindow->showWindow (shouldBeVisible);
+ }
+
+ void repaint()
+ {
+ if (hasVideo)
+ videoRenderer->repaintVideo (nativeWindow->getHandle(), nativeWindow->getContext());
+ }
+
+ void updateVideoPosition()
+ {
+ if (hasVideo)
+ videoRenderer->setVideoPosition (nativeWindow->getHandle(), videoWidth, videoHeight);
+ }
+
+ void displayResolutionChanged()
+ {
+ if (hasVideo)
+ videoRenderer->displayModeChanged();
+ }
+
+ void peerChanged()
+ {
+ deleteNativeWindow();
+
+ mediaEvent->SetNotifyWindow (0, 0, 0);
+ if (videoRenderer != nullptr)
+ videoRenderer->setVideoWindow (nullptr);
+
+ createNativeWindow();
+
+ mediaEvent->SetNotifyWindow ((OAHWND) hwnd, graphEventID, 0);
+ if (videoRenderer != nullptr)
+ videoRenderer->setVideoWindow (hwnd);
+ }
+
+ bool loadFile (const String& fileOrURLPath)
+ {
+ jassert (state == uninitializedState);
+
+ if (! createNativeWindow())
+ return false;
+
+ HRESULT hr = graphBuilder.CoCreateInstance (CLSID_FilterGraph);
+
+ // basic playback interfaces
+ if (SUCCEEDED (hr)) hr = graphBuilder.QueryInterface (IID_IMediaControl, mediaControl);
+ if (SUCCEEDED (hr)) hr = graphBuilder.QueryInterface (IID_IMediaPosition, mediaPosition);
+ if (SUCCEEDED (hr)) hr = graphBuilder.QueryInterface (IID_IMediaEventEx, mediaEvent);
+ if (SUCCEEDED (hr)) hr = graphBuilder.QueryInterface (IID_IBasicAudio, basicAudio);
+
+ // video renderer interface
+ if (SUCCEEDED (hr))
+ {
+ #if JUCE_MEDIAFOUNDATION
+ if (type == dshowEVR)
+ videoRenderer = new DirectShowHelpers::EVR();
+ else
+ #endif
+ videoRenderer = new DirectShowHelpers::VMR7();
+
+ hr = videoRenderer->create (graphBuilder, baseFilter, hwnd);
+ }
+
+ // build filter graph
+ if (SUCCEEDED (hr))
+ hr = graphBuilder->RenderFile (fileOrURLPath.toWideCharPointer(), nullptr);
+
+ // remove video renderer if not connected (no video)
+ if (SUCCEEDED (hr))
+ {
+ if (isRendererConnected())
+ {
+ hasVideo = true;
+ hr = videoRenderer->getVideoSize (videoWidth, videoHeight);
+ }
+ else
+ {
+ hasVideo = false;
+ graphBuilder->RemoveFilter (baseFilter);
+ videoRenderer = nullptr;
+ baseFilter = nullptr;
+ }
+ }
+
+ // set window to receive events
+ if (SUCCEEDED (hr))
+ hr = mediaEvent->SetNotifyWindow ((OAHWND) hwnd, graphEventID, 0);
+
+ if (SUCCEEDED (hr))
+ {
+ state = stoppedState;
+ return true;
+ }
+
+ release();
+ return false;
+ }
+
+ void release()
+ {
+ if (mediaControl != nullptr)
+ mediaControl->Stop();
+
+ if (mediaEvent != nullptr)
+ mediaEvent->SetNotifyWindow (0, 0, 0);
+
+ if (videoRenderer != nullptr)
+ videoRenderer->setVideoWindow (0);
+
+ hasVideo = false;
+ videoRenderer = nullptr;
+
+ baseFilter = nullptr;
+ basicAudio = nullptr;
+ mediaEvent = nullptr;
+ mediaPosition = nullptr;
+ mediaControl = nullptr;
+ graphBuilder = nullptr;
+
+ state = uninitializedState;
+
+ videoWidth = 0;
+ videoHeight = 0;
+
+ if (nativeWindow != nullptr)
+ deleteNativeWindow();
+ }
+
+ void graphEventProc()
+ {
+ LONG ec;
+ LONG_PTR p1, p2;
+
+ jassert (mediaEvent != nullptr);
+
+ while (SUCCEEDED (mediaEvent->GetEvent (&ec, &p1, &p2, 0)))
+ {
+ switch (ec)
+ {
+ case EC_REPAINT:
+ component.repaint();
+ break;
+
+ case EC_COMPLETE:
+ if (component.isLooping())
+ component.goToStart();
+ else
+ component.stop();
+ break;
+
+ case EC_USERABORT:
+ case EC_ERRORABORT:
+ case EC_ERRORABORTEX:
+ component.closeMovie();
+ break;
+
+ default:
+ break;
+ }
+
+ mediaEvent->FreeEventParams (ec, p1, p2);
+ }
+ }
+
+ void run()
+ {
+ mediaControl->Run();
+ state = runningState;
+ }
+
+ void stop()
+ {
+ mediaControl->Stop();
+ state = stoppedState;
+ }
+
+ void pause()
+ {
+ mediaControl->Pause();
+ state = pausedState;
+ }
+
+ bool isInitialised() const noexcept { return state != uninitializedState; }
+ bool isRunning() const noexcept { return state == runningState; }
+ bool isPaused() const noexcept { return state == pausedState; }
+ bool isStopped() const noexcept { return state == stoppedState; }
+ bool containsVideo() const noexcept { return hasVideo; }
+ int getVideoWidth() const noexcept { return (int) videoWidth; }
+ int getVideoHeight() const noexcept { return (int) videoHeight; }
+
+ double getDuration() const
+ {
+ REFTIME duration;
+ mediaPosition->get_Duration (&duration);
+ return duration;
+ }
+
+ double getPosition() const
+ {
+ REFTIME seconds;
+ mediaPosition->get_CurrentPosition (&seconds);
+ return seconds;
+ }
+
+ void setSpeed (const float newSpeed) { mediaPosition->put_Rate (newSpeed); }
+ void setPosition (const double seconds) { mediaPosition->put_CurrentPosition (seconds); }
+ void setVolume (const float newVolume) { basicAudio->put_Volume (convertToDShowVolume (newVolume)); }
+
+ // in DirectShow, full volume is 0, silence is -10000
+ static long convertToDShowVolume (const float vol) noexcept
+ {
+ if (vol >= 1.0f) return 0;
+ if (vol <= 0.0f) return -10000;
+
+ return roundToInt ((vol * 10000.0f) - 10000.0f);
+ }
+
+ float getVolume() const
+ {
+ long volume;
+ basicAudio->get_Volume (&volume);
+ return (volume + 10000) / 10000.0f;
+ }
+
+private:
+
+ enum { graphEventID = WM_APP + 0x43f0 };
+
+ DirectShowComponent& component;
+ HWND hwnd;
+ HDC hdc;
+
+ enum State { uninitializedState, runningState, pausedState, stoppedState };
+ State state;
+
+ bool hasVideo;
+ long videoWidth, videoHeight;
+
+ VideoRendererType type;
+
+ ComSmartPtr graphBuilder;
+ ComSmartPtr mediaControl;
+ ComSmartPtr mediaPosition;
+ ComSmartPtr mediaEvent;
+ ComSmartPtr basicAudio;
+ ComSmartPtr baseFilter;
+
+ ScopedPointer videoRenderer;
+
+ class NativeWindowClass : public DeletedAtShutdown
+ {
+ private:
+ NativeWindowClass()
+ : atom (0)
+ {
+ String windowClassName ("JUCE_DIRECTSHOW_");
+ windowClassName << (int) (Time::currentTimeMillis() & 0x7fffffff);
+
+ HINSTANCE moduleHandle = (HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle();
+
+ TCHAR moduleFile [1024] = { 0 };
+ GetModuleFileName (moduleHandle, moduleFile, 1024);
+
+ WNDCLASSEX wcex = { 0 };
+ wcex.cbSize = sizeof (wcex);
+ wcex.style = CS_OWNDC;
+ wcex.lpfnWndProc = (WNDPROC) wndProc;
+ wcex.lpszClassName = windowClassName.toWideCharPointer();
+ wcex.hInstance = moduleHandle;
+
+ atom = RegisterClassEx (&wcex);
+ jassert (atom != 0);
+ }
+
+ ~NativeWindowClass()
+ {
+ if (atom != 0)
+ UnregisterClass (getWindowClassName(), (HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle());
+
+ clearSingletonInstance();
+ }
+
+ static LRESULT CALLBACK wndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+ {
+ DirectShowContext* c = (DirectShowContext*) GetWindowLongPtr (hwnd, GWLP_USERDATA);
+
+ if (c != nullptr)
+ {
+ jassert (c->getNativeWindowHandle() == hwnd);
+
+ switch (msg)
+ {
+ case WM_ERASEBKGND: return 1;
+ case WM_DISPLAYCHANGE: c->displayResolutionChanged(); break;
+ case graphEventID: c->graphEventProc(); return 0;
+ default: break;
+ }
+ }
+
+ return DefWindowProc (hwnd, msg, wParam, lParam);
+ }
+
+ public:
+ bool isRegistered() const noexcept { return atom != 0; }
+ LPCTSTR getWindowClassName() const noexcept { return (LPCTSTR) MAKELONG (atom, 0); }
+
+ juce_DeclareSingleton_SingleThreaded_Minimal (NativeWindowClass);
+
+ private:
+ ATOM atom;
+
+ JUCE_DECLARE_NON_COPYABLE (NativeWindowClass);
+ };
+
+ class NativeWindow
+ {
+ public:
+ NativeWindow (HWND parentToAddTo, void* const userData)
+ : hwnd (0), hdc (0)
+ {
+ NativeWindowClass* const wc = NativeWindowClass::getInstance();
+
+ if (wc->isRegistered())
+ {
+ DWORD exstyle = 0;
+ DWORD type = WS_CHILD;
+
+ hwnd = CreateWindowEx (exstyle, wc->getWindowClassName(),
+ L"", type, 0, 0, 0, 0, parentToAddTo, 0,
+ (HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle(), 0);
+
+ if (hwnd != 0)
+ {
+ hdc = GetDC (hwnd);
+ SetWindowLongPtr (hwnd, GWLP_USERDATA, (LONG_PTR) userData);
+ }
+ }
+
+ jassert (hwnd != 0);
+ }
+
+ ~NativeWindow()
+ {
+ if (hwnd != 0)
+ {
+ SetWindowLongPtr (hwnd, GWLP_USERDATA, (LONG_PTR) 0);
+ DestroyWindow (hwnd);
+ }
+ }
+
+ HWND getHandle() const noexcept { return hwnd; }
+ HDC getContext() const noexcept { return hdc; }
+
+ void setWindowPosition (const Rectangle& newBounds)
+ {
+ SetWindowPos (hwnd, 0, newBounds.getX(), newBounds.getY(),
+ newBounds.getWidth(), newBounds.getHeight(),
+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER);
+ }
+
+ void showWindow (const bool shouldBeVisible)
+ {
+ ShowWindow (hwnd, shouldBeVisible ? SW_SHOWNA : SW_HIDE);
+ }
+
+ private:
+ HWND hwnd;
+ HDC hdc;
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeWindow);
+ };
+
+ ScopedPointer nativeWindow;
+
+ bool createNativeWindow()
+ {
+ jassert (nativeWindow == nullptr);
+
+ ComponentPeer* topLevelPeer = component.getTopLevelComponent()->getPeer();
+
+ jassert (topLevelPeer != nullptr);
+
+ if (topLevelPeer != nullptr)
+ {
+ nativeWindow = new NativeWindow ((HWND) topLevelPeer->getNativeHandle(), this);
+
+ hwnd = nativeWindow->getHandle();
+
+ if (hwnd != 0)
+ {
+ hdc = GetDC (hwnd);
+ component.updateContextPosition();
+ component.showContext (component.isShowing());
+ return true;
+ }
+ else
+ {
+ nativeWindow = nullptr;
+ }
+ }
+
+ return false;
+ }
+
+ void deleteNativeWindow()
+ {
+ jassert (nativeWindow != nullptr);
+ ReleaseDC (hwnd, hdc);
+ hwnd = 0;
+ hdc = 0;
+ nativeWindow = nullptr;
+ }
+
+ bool isRendererConnected()
+ {
+ ComSmartPtr enumPins;
+
+ HRESULT hr = baseFilter->EnumPins (enumPins.resetAndGetPointerAddress());
+
+ if (SUCCEEDED (hr))
+ hr = enumPins->Reset();
+
+ ComSmartPtr pin;
+
+ while (SUCCEEDED (hr)
+ && enumPins->Next (1, pin.resetAndGetPointerAddress(), nullptr) == S_OK)
+ {
+ ComSmartPtr otherPin;
+
+ hr = pin->ConnectedTo (otherPin.resetAndGetPointerAddress());
+
+ if (SUCCEEDED (hr))
+ {
+ PIN_DIRECTION direction;
+ hr = pin->QueryDirection (&direction);
+
+ if (SUCCEEDED (hr) && direction == PINDIR_INPUT)
+ return true;
+ }
+ else if (hr == VFW_E_NOT_CONNECTED)
+ {
+ hr = S_OK;
+ }
+ }
+
+ return false;
+ }
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectShowContext);
+};
+
+juce_ImplementSingleton_SingleThreaded (DirectShowComponent::DirectShowContext::NativeWindowClass);
+
+class DirectShowComponent::DirectShowComponentWatcher : public ComponentMovementWatcher
+{
+public:
+ DirectShowComponentWatcher (DirectShowComponent* const owner_)
+ : ComponentMovementWatcher (owner_),
+ owner (owner_)
+ {
+ }
+
+ void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/)
+ {
+ if (owner->videoLoaded)
+ owner->updateContextPosition();
+ }
+
+ void componentPeerChanged()
+ {
+ if (owner->videoLoaded)
+ owner->recreateNativeWindowAsync();
+ }
+
+ void componentVisibilityChanged()
+ {
+ if (owner->videoLoaded)
+ owner->showContext (owner->isShowing());
+ }
+
+private:
+ DirectShowComponent* const owner;
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectShowComponentWatcher);
+};
+
+DirectShowComponent::DirectShowComponent (VideoRendererType type)
+ : videoLoaded (false),
+ looping (false),
+ needToUpdateViewport (true),
+ needToRecreateNativeWindow (false)
+{
+ setOpaque (true);
+ context = new DirectShowContext (*this, type);
+ componentWatcher = new DirectShowComponentWatcher (this);
+}
+
+DirectShowComponent::~DirectShowComponent()
+{
+ componentWatcher = nullptr;
+}
+
+bool DirectShowComponent::isDirectShowAvailable()
+{
+ static bool isDSAvailable = DirectShowHelpers::checkDShowAvailability();
+ return isDSAvailable;
+}
+
+void DirectShowComponent::recreateNativeWindowAsync()
+{
+ needToRecreateNativeWindow = true;
+ repaint();
+}
+
+void DirectShowComponent::updateContextPosition()
+{
+ needToUpdateViewport = true;
+
+ if (getWidth() > 0 && getHeight() > 0)
+ {
+ Component* const topComp = getTopLevelComponent();
+
+ if (topComp->getPeer() != nullptr)
+ context->updateWindowPosition (topComp->getLocalArea (this, getLocalBounds()));
+ }
+}
+
+void DirectShowComponent::showContext (const bool shouldBeVisible)
+{
+ context->showWindow (shouldBeVisible);
+}
+
+void DirectShowComponent::paint (Graphics& g)
+{
+ if (videoLoaded)
+ {
+ if (needToRecreateNativeWindow)
+ {
+ context->peerChanged();
+ needToRecreateNativeWindow = false;
+ }
+
+ if (needToUpdateViewport)
+ {
+ context->updateVideoPosition();
+ needToUpdateViewport = false;
+ }
+
+ context->repaint();
+
+ ComponentPeer* const peer = getPeer();
+
+ if (peer != nullptr)
+ {
+ const Point topLeft (getScreenPosition() - peer->getScreenPosition());
+ peer->addMaskedRegion (topLeft.getX(), topLeft.getY(), getWidth(), getHeight());
+ }
+ }
+ else
+ {
+ g.fillAll (Colours::grey);
+ }
+}
+
+bool DirectShowComponent::loadMovie (const String& fileOrURLPath)
+{
+ closeMovie();
+
+ videoLoaded = context->loadFile (fileOrURLPath);
+
+ if (videoLoaded)
+ {
+ videoPath = fileOrURLPath;
+ context->updateVideoPosition();
+ }
+
+ return videoLoaded;
+}
+
+bool DirectShowComponent::loadMovie (const File& videoFile)
+{
+ return loadMovie (videoFile.getFullPathName());
+}
+
+bool DirectShowComponent::loadMovie (const URL& videoURL)
+{
+ return loadMovie (videoURL.toString (false));
+}
+
+void DirectShowComponent::closeMovie()
+{
+ if (videoLoaded)
+ context->release();
+
+ videoLoaded = false;
+ videoPath = String::empty;
+}
+
+const File DirectShowComponent::getCurrentMoviePath() const { return videoPath; }
+bool DirectShowComponent::isMovieOpen() const { return videoLoaded; }
+double DirectShowComponent::getMovieDuration() const { return videoLoaded ? context->getDuration() : 0.0; }
+void DirectShowComponent::setLooping (const bool shouldLoop) { looping = shouldLoop; }
+bool DirectShowComponent::isLooping() const { return looping; }
+
+void DirectShowComponent::getMovieNormalSize (int &width, int &height) const
+{
+ width = context->getVideoWidth();
+ height = context->getVideoHeight();
+}
+
+void DirectShowComponent::setBoundsWithCorrectAspectRatio (const Rectangle& spaceToFitWithin,
+ const RectanglePlacement& placement)
+{
+ int normalWidth, normalHeight;
+ getMovieNormalSize (normalWidth, normalHeight);
+
+ const Rectangle normalSize (0, 0, normalWidth, normalHeight);
+
+ if (! (spaceToFitWithin.isEmpty() || normalSize.isEmpty()))
+ setBounds (placement.appliedTo (normalSize, spaceToFitWithin));
+ else
+ setBounds (spaceToFitWithin);
+}
+
+void DirectShowComponent::play()
+{
+ if (videoLoaded)
+ context->run();
+}
+
+void DirectShowComponent::stop()
+{
+ if (videoLoaded)
+ context->stop();
+}
+
+bool DirectShowComponent::isPlaying() const
+{
+ return context->isRunning();
+}
+
+void DirectShowComponent::goToStart()
+{
+ setPosition (0.0);
+}
+
+void DirectShowComponent::setPosition (const double seconds)
+{
+ if (videoLoaded)
+ context->setPosition (seconds);
+}
+
+double DirectShowComponent::getPosition() const
+{
+ return videoLoaded ? context->getPosition() : 0.0;
+}
+
+void DirectShowComponent::setSpeed (const float newSpeed)
+{
+ if (videoLoaded)
+ context->setSpeed (newSpeed);
+}
+
+void DirectShowComponent::setMovieVolume (const float newVolume)
+{
+ if (videoLoaded)
+ context->setVolume (newVolume);
+}
+
+float DirectShowComponent::getMovieVolume() const
+{
+ return videoLoaded ? context->getVolume() : 0.0f;
+}
+
+#endif
+
+/*** End of inlined file: juce_win32_DirectShowComponent.cpp ***/
+
+
/*** Start of inlined file: juce_win32_WebBrowserComponent.cpp ***/
// (This file gets included by juce_win32_NativeCode.cpp, rather than being
// compiled on its own).
@@ -253397,10 +254311,10 @@ public:
return false;
}
- void updateWindowPosition (int x, int y, int w, int h, int)
+ void updateWindowPosition (const Rectangle& bounds)
{
SetWindowPos ((HWND) nativeWindow->getNativeHandle(), 0,
- x, y, w, h,
+ bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(),
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER);
}
@@ -260934,6 +261848,14 @@ CameraDevice* CameraDevice::openDevice (int index,
#pragma comment (lib, "D2d1.lib")
#endif
+#if JUCE_DIRECTSHOW
+ #pragma comment (lib, "strmiids.lib")
+#endif
+
+#if JUCE_MEDIAFOUNDATION
+ #pragma comment (lib, "mfuuid.lib")
+#endif
+
/*** End of inlined file: juce_win32_AutoLinkLibraries.h ***/
@@ -267409,11 +268331,11 @@ public:
return renderContext;
}
- void updateWindowPosition (int x, int y, int w, int h, int)
+ void updateWindowPosition (const Rectangle& bounds)
{
ScopedXLock xlock;
XMoveResizeWindow (display, embeddedWindow,
- x, y, jmax (1, w), jmax (1, h));
+ bounds.getX(), bounds.getY(), jmax (1, bounds.getWidth()), jmax (1, bounds.getHeight()));
}
void swapBuffers()
@@ -276123,9 +277045,7 @@ public:
const OpenGLPixelFormat getPixelFormat() const { return pixelFormat; }
void* getRawContext() const noexcept { return renderContext; }
- void updateWindowPosition (int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*outerWindowHeight*/)
- {
- }
+ void updateWindowPosition (const Rectangle&) {}
void swapBuffers()
{
@@ -276327,9 +277247,10 @@ public:
const OpenGLPixelFormat getPixelFormat() const { return pixelFormat; }
void* getRawContext() const noexcept { return glLayer; }
- void updateWindowPosition (int x, int y, int w, int h, int outerWindowHeight)
+ void updateWindowPosition (const Rectangle& bounds)
{
- view.frame = CGRectMake ((CGFloat) x, (CGFloat) y, (CGFloat) w, (CGFloat) h);
+ view.frame = CGRectMake ((CGFloat) bounds.getX(), (CGFloat) bounds.getY(),
+ (CGFloat) bounds.getWidth(), (CGFloat) bounds.getHeight());
if (lastWidth != w || lastHeight != h)
{
@@ -282037,9 +282958,7 @@ public:
const OpenGLPixelFormat getPixelFormat() const { return pixelFormat; }
void* getRawContext() const noexcept { return renderContext; }
- void updateWindowPosition (int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*outerWindowHeight*/)
- {
- }
+ void updateWindowPosition (const Rectangle&) {}
void swapBuffers()
{
@@ -282241,9 +283160,10 @@ public:
const OpenGLPixelFormat getPixelFormat() const { return pixelFormat; }
void* getRawContext() const noexcept { return glLayer; }
- void updateWindowPosition (int x, int y, int w, int h, int outerWindowHeight)
+ void updateWindowPosition (const Rectangle& bounds)
{
- view.frame = CGRectMake ((CGFloat) x, (CGFloat) y, (CGFloat) w, (CGFloat) h);
+ view.frame = CGRectMake ((CGFloat) bounds.getX(), (CGFloat) bounds.getY(),
+ (CGFloat) bounds.getWidth(), (CGFloat) bounds.getHeight());
if (lastWidth != w || lastHeight != h)
{
diff --git a/juce_amalgamated.h b/juce_amalgamated.h
index b30c2a3083..7093485eca 100644
--- a/juce_amalgamated.h
+++ b/juce_amalgamated.h
@@ -73,7 +73,7 @@ namespace JuceDummyNamespace {}
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 53
-#define JUCE_BUILDNUMBER 99
+#define JUCE_BUILDNUMBER 100
/** Current Juce version number.
@@ -305,6 +305,25 @@ namespace JuceDummyNamespace {}
#define JUCE_DIRECTSOUND 1
#endif
+/** JUCE_DIRECTSHOW: Enables DirectShow media-streaming architecture
+ (MS Windows only).
+*/
+#ifndef JUCE_DIRECTSHOW
+ #define JUCE_DIRECTSHOW 1
+#endif
+
+/** JUCE_MEDIAFOUNDATION: Enables Media Foundation multimedia platform
+ (Windows Vista and above).
+*/
+#ifndef JUCE_MEDIAFOUNDATION
+ #define JUCE_MEDIAFOUNDATION 1
+#endif
+
+#if ! JUCE_WINDOWS
+ #undef JUCE_DIRECTSHOW
+ #undef JUCE_MEDIAFOUNDATION
+#endif
+
/** JUCE_ALSA: Enables ALSA audio devices (Linux only). */
#ifndef JUCE_ALSA
#define JUCE_ALSA 1
@@ -64223,6 +64242,202 @@ private:
/*** End of inlined file: juce_ColourSelector.h ***/
+#endif
+#ifndef __JUCE_DIRECTSHOWCOMPONENT_JUCEHEADER__
+
+/*** Start of inlined file: juce_DirectShowComponent.h ***/
+#ifndef __JUCE_DIRECTSHOWCOMPONENT_JUCEHEADER__
+#define __JUCE_DIRECTSHOWCOMPONENT_JUCEHEADER__
+
+#if JUCE_DIRECTSHOW || DOXYGEN
+
+/**
+ A window that can play back a DirectShow video.
+
+ @note Controller is not implemented
+*/
+class JUCE_API DirectShowComponent : public Component
+{
+public:
+
+ /** DirectShow video renderer type.
+
+ See MSDN for adivce about choosing the right renderer.
+ */
+ enum VideoRendererType
+ {
+ dshowDefault, /**< VMR7 for Windows XP, EVR for Windows Vista and later */
+ dshowVMR7, /**< Video Mixing Renderer 7 */
+ dshowEVR /**< Enhanced Video Renderer */
+ };
+
+ /** Creates a DirectShowComponent, initially blank.
+
+ Use the loadMovie() method to load a video once you've added the
+ component to a window, (or put it on the desktop as a heavyweight window).
+ Loading a video when the component isn't visible can cause problems, as
+ DirectShow needs a window handle to initialise properly.
+
+ @see VideoRendererType
+ */
+ DirectShowComponent (VideoRendererType type = dshowDefault);
+
+ /** Destructor. */
+ ~DirectShowComponent();
+
+ /** Returns true if DirectShow is installed and working on this machine. */
+ static bool isDirectShowAvailable();
+
+ /** Tries to load a DirectShow video from a file or URL into the player.
+
+ It's best to call this function once you've added the component to a window,
+ (or put it on the desktop as a heavyweight window). Loading a video when the
+ component isn't visible can cause problems, because DirectShow needs a window
+ handle to do its stuff.
+
+ @param fileOrURLPath the file or URL path to open
+ @returns true if the video opens successfully
+ */
+ bool loadMovie (const String& fileOrURLPath);
+
+ /** Tries to load a DirectShow video from a file into the player.
+
+ It's best to call this function once you've added the component to a window,
+ (or put it on the desktop as a heavyweight window). Loading a video when the
+ component isn't visible can cause problems, because DirectShow needs a window
+ handle to do its stuff.
+
+ @param videoFile the video file to open
+ @returns true if the video opens successfully
+ */
+ bool loadMovie (const File& videoFile);
+
+ /** Tries to load a DirectShow video from a URL into the player.
+
+ It's best to call this function once you've added the component to a window,
+ (or put it on the desktop as a heavyweight window). Loading a video when the
+ component isn't visible can cause problems, because DirectShow needs a window
+ handle to do its stuff.
+
+ @param videoURL the video URL to open
+ @returns true if the video opens successfully
+ */
+ bool loadMovie (const URL& videoURL);
+
+ /** Closes the video, if one is open. */
+ void closeMovie();
+
+ /** Returns the file path or URL from which the video file was loaded.
+ If there isn't one, this returns an empty string.
+ */
+ const File getCurrentMoviePath() const;
+
+ /** Returns true if there's currently a video open. */
+ bool isMovieOpen() const;
+
+ /** Returns the length of the video, in seconds. */
+ double getMovieDuration() const;
+
+ /** Returns the video's natural size, in pixels.
+
+ You can use this to resize the component to show the video at its preferred
+ scale.
+
+ If no video is loaded, the size returned will be 0 x 0.
+ */
+ void getMovieNormalSize (int& width, int& height) const;
+
+ /** This will position the component within a given area, keeping its aspect
+ ratio correct according to the video's normal size.
+
+ The component will be made as large as it can go within the space, and will
+ be aligned according to the justification value if this means there are gaps at
+ the top or sides.
+
+ @note Not implemented
+ */
+ void setBoundsWithCorrectAspectRatio (const Rectangle& spaceToFitWithin,
+ const RectanglePlacement& placement);
+
+ /** Starts the video playing. */
+ void play();
+
+ /** Stops the video playing. */
+ void stop();
+
+ /** Returns true if the video is currently playing. */
+ bool isPlaying() const;
+
+ /** Moves the video's position back to the start. */
+ void goToStart();
+
+ /** Sets the video's position to a given time. */
+ void setPosition (double seconds);
+
+ /** Returns the current play position of the video. */
+ double getPosition() const;
+
+ /** Changes the video playback rate.
+
+ A value of 1 is normal speed, greater values play it proportionately faster,
+ smaller values play it slower.
+ */
+ void setSpeed (float newSpeed);
+
+ /** Changes the video's playback volume.
+
+ @param newVolume the volume in the range 0 (silent) to 1.0 (full)
+ */
+ void setMovieVolume (float newVolume);
+
+ /** Returns the video's playback volume.
+
+ @returns the volume in the range 0 (silent) to 1.0 (full)
+ */
+ float getMovieVolume() const;
+
+ /** Tells the video whether it should loop. */
+ void setLooping (bool shouldLoop);
+
+ /** Returns true if the video is currently looping.
+
+ @see setLooping
+ */
+ bool isLooping() const;
+
+ /** @internal */
+ void paint (Graphics& g);
+
+private:
+
+ String videoPath;
+ bool videoLoaded, looping;
+
+ class DirectShowContext;
+ friend class DirectShowContext;
+ friend class ScopedPointer ;
+ ScopedPointer context;
+
+ class DirectShowComponentWatcher;
+ friend class DirectShowComponentWatcher;
+ friend class ScopedPointer ;
+ ScopedPointer componentWatcher;
+
+ bool needToUpdateViewport, needToRecreateNativeWindow;
+
+ void updateContextPosition();
+ void showContext (bool shouldBeVisible);
+ void recreateNativeWindowAsync();
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectShowComponent);
+};
+
+#endif
+#endif // __JUCE_DIRECTSHOWCOMPONENT_JUCEHEADER__
+
+/*** End of inlined file: juce_DirectShowComponent.h ***/
+
+
#endif
#ifndef __JUCE_DROPSHADOWER_JUCEHEADER__
@@ -64786,7 +65001,7 @@ public:
/** For windowed contexts, this moves the context within the bounds of
its parent window.
*/
- virtual void updateWindowPosition (int x, int y, int w, int h, int outerWindowHeight) = 0;
+ virtual void updateWindowPosition (const Rectangle& bounds) = 0;
/** For windowed contexts, this triggers a repaint of the window.
@@ -69544,6 +69759,14 @@ END_JUCE_NAMESPACE
#pragma comment (lib, "D2d1.lib")
#endif
+#if JUCE_DIRECTSHOW
+ #pragma comment (lib, "strmiids.lib")
+#endif
+
+#if JUCE_MEDIAFOUNDATION
+ #pragma comment (lib, "mfuuid.lib")
+#endif
+
/*** End of inlined file: juce_win32_AutoLinkLibraries.h ***/
diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h
index 83fdf0d9da..88557a4285 100644
--- a/src/core/juce_StandardHeader.h
+++ b/src/core/juce_StandardHeader.h
@@ -33,7 +33,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 53
-#define JUCE_BUILDNUMBER 99
+#define JUCE_BUILDNUMBER 100
/** Current Juce version number.
diff --git a/src/gui/components/special/juce_DirectShowComponent.h b/src/gui/components/special/juce_DirectShowComponent.h
new file mode 100644
index 0000000000..3fcf7249b1
--- /dev/null
+++ b/src/gui/components/special/juce_DirectShowComponent.h
@@ -0,0 +1,221 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE library - "Jules' Utility Class Extensions"
+ Copyright 2004-11 by Raw Material Software Ltd.
+
+ ------------------------------------------------------------------------------
+
+ JUCE can be redistributed and/or modified under the terms of the GNU General
+ Public License (Version 2), as published by the Free Software Foundation.
+ A copy of the license is included in the JUCE distribution, or can be found
+ online at www.gnu.org/licenses.
+
+ JUCE 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.
+
+ ------------------------------------------------------------------------------
+
+ To release a closed-source product which uses JUCE, commercial licenses are
+ available: visit www.rawmaterialsoftware.com/juce for more information.
+
+ ==============================================================================
+*/
+
+#ifndef __JUCE_DIRECTSHOWCOMPONENT_JUCEHEADER__
+#define __JUCE_DIRECTSHOWCOMPONENT_JUCEHEADER__
+
+#include "../juce_Component.h"
+
+#if JUCE_DIRECTSHOW || DOXYGEN
+
+//==============================================================================
+/**
+ A window that can play back a DirectShow video.
+
+ @note Controller is not implemented
+*/
+class JUCE_API DirectShowComponent : public Component
+{
+public:
+ //==============================================================================
+ /** DirectShow video renderer type.
+
+ See MSDN for adivce about choosing the right renderer.
+ */
+ enum VideoRendererType
+ {
+ dshowDefault, /**< VMR7 for Windows XP, EVR for Windows Vista and later */
+ dshowVMR7, /**< Video Mixing Renderer 7 */
+ dshowEVR /**< Enhanced Video Renderer */
+ };
+
+ /** Creates a DirectShowComponent, initially blank.
+
+ Use the loadMovie() method to load a video once you've added the
+ component to a window, (or put it on the desktop as a heavyweight window).
+ Loading a video when the component isn't visible can cause problems, as
+ DirectShow needs a window handle to initialise properly.
+
+ @see VideoRendererType
+ */
+ DirectShowComponent (VideoRendererType type = dshowDefault);
+
+ /** Destructor. */
+ ~DirectShowComponent();
+
+ /** Returns true if DirectShow is installed and working on this machine. */
+ static bool isDirectShowAvailable();
+
+ //==============================================================================
+ /** Tries to load a DirectShow video from a file or URL into the player.
+
+ It's best to call this function once you've added the component to a window,
+ (or put it on the desktop as a heavyweight window). Loading a video when the
+ component isn't visible can cause problems, because DirectShow needs a window
+ handle to do its stuff.
+
+ @param fileOrURLPath the file or URL path to open
+ @returns true if the video opens successfully
+ */
+ bool loadMovie (const String& fileOrURLPath);
+
+ /** Tries to load a DirectShow video from a file into the player.
+
+ It's best to call this function once you've added the component to a window,
+ (or put it on the desktop as a heavyweight window). Loading a video when the
+ component isn't visible can cause problems, because DirectShow needs a window
+ handle to do its stuff.
+
+ @param videoFile the video file to open
+ @returns true if the video opens successfully
+ */
+ bool loadMovie (const File& videoFile);
+
+ /** Tries to load a DirectShow video from a URL into the player.
+
+ It's best to call this function once you've added the component to a window,
+ (or put it on the desktop as a heavyweight window). Loading a video when the
+ component isn't visible can cause problems, because DirectShow needs a window
+ handle to do its stuff.
+
+ @param videoURL the video URL to open
+ @returns true if the video opens successfully
+ */
+ bool loadMovie (const URL& videoURL);
+
+ /** Closes the video, if one is open. */
+ void closeMovie();
+
+ /** Returns the file path or URL from which the video file was loaded.
+ If there isn't one, this returns an empty string.
+ */
+ const File getCurrentMoviePath() const;
+
+ /** Returns true if there's currently a video open. */
+ bool isMovieOpen() const;
+
+ /** Returns the length of the video, in seconds. */
+ double getMovieDuration() const;
+
+ /** Returns the video's natural size, in pixels.
+
+ You can use this to resize the component to show the video at its preferred
+ scale.
+
+ If no video is loaded, the size returned will be 0 x 0.
+ */
+ void getMovieNormalSize (int& width, int& height) const;
+
+ /** This will position the component within a given area, keeping its aspect
+ ratio correct according to the video's normal size.
+
+ The component will be made as large as it can go within the space, and will
+ be aligned according to the justification value if this means there are gaps at
+ the top or sides.
+
+ @note Not implemented
+ */
+ void setBoundsWithCorrectAspectRatio (const Rectangle& spaceToFitWithin,
+ const RectanglePlacement& placement);
+
+ /** Starts the video playing. */
+ void play();
+
+ /** Stops the video playing. */
+ void stop();
+
+ /** Returns true if the video is currently playing. */
+ bool isPlaying() const;
+
+ /** Moves the video's position back to the start. */
+ void goToStart();
+
+ /** Sets the video's position to a given time. */
+ void setPosition (double seconds);
+
+ /** Returns the current play position of the video. */
+ double getPosition() const;
+
+ /** Changes the video playback rate.
+
+ A value of 1 is normal speed, greater values play it proportionately faster,
+ smaller values play it slower.
+ */
+ void setSpeed (float newSpeed);
+
+ /** Changes the video's playback volume.
+
+ @param newVolume the volume in the range 0 (silent) to 1.0 (full)
+ */
+ void setMovieVolume (float newVolume);
+
+ /** Returns the video's playback volume.
+
+ @returns the volume in the range 0 (silent) to 1.0 (full)
+ */
+ float getMovieVolume() const;
+
+ /** Tells the video whether it should loop. */
+ void setLooping (bool shouldLoop);
+
+ /** Returns true if the video is currently looping.
+
+ @see setLooping
+ */
+ bool isLooping() const;
+
+
+ //==============================================================================
+ /** @internal */
+ void paint (Graphics& g);
+
+private:
+ //==============================================================================
+ String videoPath;
+ bool videoLoaded, looping;
+
+ class DirectShowContext;
+ friend class DirectShowContext;
+ friend class ScopedPointer ;
+ ScopedPointer context;
+
+ class DirectShowComponentWatcher;
+ friend class DirectShowComponentWatcher;
+ friend class ScopedPointer ;
+ ScopedPointer componentWatcher;
+
+ bool needToUpdateViewport, needToRecreateNativeWindow;
+
+ //==============================================================================
+ void updateContextPosition();
+ void showContext (bool shouldBeVisible);
+ void recreateNativeWindowAsync();
+
+ //==============================================================================
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectShowComponent);
+};
+
+#endif
+#endif // __JUCE_DIRECTSHOWCOMPONENT_JUCEHEADER__
diff --git a/src/gui/components/special/juce_OpenGLComponent.cpp b/src/gui/components/special/juce_OpenGLComponent.cpp
index 02dfa413a3..7afbdcd281 100644
--- a/src/gui/components/special/juce_OpenGLComponent.cpp
+++ b/src/gui/components/special/juce_OpenGLComponent.cpp
@@ -359,11 +359,7 @@ void OpenGLComponent::updateContextPosition()
const ScopedLock sl (contextLock);
if (context != nullptr)
- context->updateWindowPosition (getScreenX() - topComp->getScreenX(),
- getScreenY() - topComp->getScreenY(),
- getWidth(),
- getHeight(),
- topComp->getHeight());
+ context->updateWindowPosition (topComp->getLocalArea (this, getLocalBounds()));
}
}
}
diff --git a/src/gui/components/special/juce_OpenGLComponent.h b/src/gui/components/special/juce_OpenGLComponent.h
index c3c051f381..673b430cef 100644
--- a/src/gui/components/special/juce_OpenGLComponent.h
+++ b/src/gui/components/special/juce_OpenGLComponent.h
@@ -132,7 +132,7 @@ public:
/** For windowed contexts, this moves the context within the bounds of
its parent window.
*/
- virtual void updateWindowPosition (int x, int y, int w, int h, int outerWindowHeight) = 0;
+ virtual void updateWindowPosition (const Rectangle& bounds) = 0;
/** For windowed contexts, this triggers a repaint of the window.
diff --git a/src/juce_app_includes.h b/src/juce_app_includes.h
index 45d44478e9..5407cf8759 100644
--- a/src/juce_app_includes.h
+++ b/src/juce_app_includes.h
@@ -587,6 +587,9 @@
#ifndef __JUCE_COLOURSELECTOR_JUCEHEADER__
#include "gui/components/special/juce_ColourSelector.h"
#endif
+#ifndef __JUCE_DIRECTSHOWCOMPONENT_JUCEHEADER__
+ #include "gui/components/special/juce_DirectShowComponent.h"
+#endif
#ifndef __JUCE_DROPSHADOWER_JUCEHEADER__
#include "gui/components/special/juce_DropShadower.h"
#endif
diff --git a/src/native/linux/juce_linux_Windowing.cpp b/src/native/linux/juce_linux_Windowing.cpp
index 6c4dd90eeb..a22a917002 100644
--- a/src/native/linux/juce_linux_Windowing.cpp
+++ b/src/native/linux/juce_linux_Windowing.cpp
@@ -3213,11 +3213,11 @@ public:
return renderContext;
}
- void updateWindowPosition (int x, int y, int w, int h, int)
+ void updateWindowPosition (const Rectangle& bounds)
{
ScopedXLock xlock;
XMoveResizeWindow (display, embeddedWindow,
- x, y, jmax (1, w), jmax (1, h));
+ bounds.getX(), bounds.getY(), jmax (1, bounds.getWidth()), jmax (1, bounds.getHeight()));
}
void swapBuffers()
diff --git a/src/native/mac/juce_mac_OpenGLComponent.mm b/src/native/mac/juce_mac_OpenGLComponent.mm
index afcd096d94..18acd5b8bc 100644
--- a/src/native/mac/juce_mac_OpenGLComponent.mm
+++ b/src/native/mac/juce_mac_OpenGLComponent.mm
@@ -215,9 +215,7 @@ public:
const OpenGLPixelFormat getPixelFormat() const { return pixelFormat; }
void* getRawContext() const noexcept { return renderContext; }
- void updateWindowPosition (int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*outerWindowHeight*/)
- {
- }
+ void updateWindowPosition (const Rectangle&) {}
void swapBuffers()
{
@@ -424,9 +422,10 @@ public:
const OpenGLPixelFormat getPixelFormat() const { return pixelFormat; }
void* getRawContext() const noexcept { return glLayer; }
- void updateWindowPosition (int x, int y, int w, int h, int outerWindowHeight)
+ void updateWindowPosition (const Rectangle& bounds)
{
- view.frame = CGRectMake ((CGFloat) x, (CGFloat) y, (CGFloat) w, (CGFloat) h);
+ view.frame = CGRectMake ((CGFloat) bounds.getX(), (CGFloat) bounds.getY(),
+ (CGFloat) bounds.getWidth(), (CGFloat) bounds.getHeight());
if (lastWidth != w || lastHeight != h)
{
diff --git a/src/native/windows/juce_win32_AutoLinkLibraries.h b/src/native/windows/juce_win32_AutoLinkLibraries.h
index a3b4ebb632..18bb4fca64 100644
--- a/src/native/windows/juce_win32_AutoLinkLibraries.h
+++ b/src/native/windows/juce_win32_AutoLinkLibraries.h
@@ -48,3 +48,11 @@
#pragma comment (lib, "Dwrite.lib")
#pragma comment (lib, "D2d1.lib")
#endif
+
+#if JUCE_DIRECTSHOW
+ #pragma comment (lib, "strmiids.lib")
+#endif
+
+#if JUCE_MEDIAFOUNDATION
+ #pragma comment (lib, "mfuuid.lib")
+#endif
diff --git a/src/native/windows/juce_win32_DirectShowComponent.cpp b/src/native/windows/juce_win32_DirectShowComponent.cpp
new file mode 100644
index 0000000000..7c98a2c511
--- /dev/null
+++ b/src/native/windows/juce_win32_DirectShowComponent.cpp
@@ -0,0 +1,941 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE library - "Jules' Utility Class Extensions"
+ Copyright 2004-11 by Raw Material Software Ltd.
+
+ ------------------------------------------------------------------------------
+
+ JUCE can be redistributed and/or modified under the terms of the GNU General
+ Public License (Version 2), as published by the Free Software Foundation.
+ A copy of the license is included in the JUCE distribution, or can be found
+ online at www.gnu.org/licenses.
+
+ JUCE 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.
+
+ ------------------------------------------------------------------------------
+
+ To release a closed-source product which uses JUCE, commercial licenses are
+ available: visit www.rawmaterialsoftware.com/juce for more information.
+
+ ==============================================================================
+*/
+
+#if JUCE_INCLUDED_FILE
+
+
+//======================================================================
+namespace DirectShowHelpers
+{
+ bool checkDShowAvailability()
+ {
+ ComSmartPtr graph;
+ return SUCCEEDED (graph.CoCreateInstance (CLSID_FilterGraph));
+ }
+
+ //======================================================================
+ class VideoRenderer
+ {
+ public:
+ VideoRenderer() {}
+ virtual ~VideoRenderer() {}
+
+ virtual HRESULT create (ComSmartPtr & graphBuilder,
+ ComSmartPtr & baseFilter, HWND hwnd) = 0;
+
+ virtual void setVideoWindow (HWND hwnd) = 0;
+ virtual void setVideoPosition (HWND hwnd, long videoWidth, long videoHeight) = 0;
+ virtual void repaintVideo (HWND hwnd, HDC hdc) = 0;
+ virtual void displayModeChanged() = 0;
+ virtual HRESULT getVideoSize (long& videoWidth, long& videoHeight) = 0;
+ };
+
+ //======================================================================
+ class VMR7 : public VideoRenderer
+ {
+ public:
+ VMR7() {}
+
+ HRESULT create (ComSmartPtr & graphBuilder,
+ ComSmartPtr & baseFilter, HWND hwnd)
+ {
+ ComSmartPtr filterConfig;
+
+ HRESULT hr = baseFilter.CoCreateInstance (CLSID_VideoMixingRenderer);
+
+ if (SUCCEEDED (hr))
+ hr = graphBuilder->AddFilter (baseFilter, L"VMR-7");
+
+ if (SUCCEEDED (hr))
+ hr = baseFilter.QueryInterface (IID_IVMRFilterConfig, filterConfig);
+
+ if (SUCCEEDED (hr))
+ hr = filterConfig->SetRenderingMode (VMRMode_Windowless);
+
+ if (SUCCEEDED (hr))
+ hr = baseFilter.QueryInterface (IID_IVMRWindowlessControl, windowlessControl);
+
+ if (SUCCEEDED (hr))
+ hr = windowlessControl->SetVideoClippingWindow (hwnd);
+
+ if (SUCCEEDED (hr))
+ hr = windowlessControl->SetAspectRatioMode (VMR_ARMODE_LETTER_BOX);
+
+ return hr;
+ }
+
+ void setVideoWindow (HWND hwnd)
+ {
+ windowlessControl->SetVideoClippingWindow (hwnd);
+ }
+
+ void setVideoPosition (HWND hwnd, long videoWidth, long videoHeight)
+ {
+ RECT src, dest;
+
+ SetRect (&src, 0, 0, videoWidth, videoHeight);
+ GetClientRect (hwnd, &dest);
+
+ windowlessControl->SetVideoPosition (&src, &dest);
+ }
+
+ void repaintVideo (HWND hwnd, HDC hdc)
+ {
+ windowlessControl->RepaintVideo (hwnd, hdc);
+ }
+
+ void displayModeChanged()
+ {
+ windowlessControl->DisplayModeChanged();
+ }
+
+ HRESULT getVideoSize (long& videoWidth, long& videoHeight)
+ {
+ return windowlessControl->GetNativeVideoSize (&videoWidth, &videoHeight, nullptr, nullptr);
+ }
+
+ private:
+ ComSmartPtr windowlessControl;
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VMR7);
+ };
+
+
+ //======================================================================
+#if JUCE_MEDIAFOUNDATION
+ class EVR : public VideoRenderer
+ {
+ public:
+ EVR() {}
+
+ HRESULT create (ComSmartPtr & graphBuilder,
+ ComSmartPtr & baseFilter, HWND hwnd)
+ {
+ ComSmartPtr getService;
+
+ HRESULT hr = baseFilter.CoCreateInstance (CLSID_EnhancedVideoRenderer);
+
+ if (SUCCEEDED (hr))
+ hr = graphBuilder->AddFilter (baseFilter, L"EVR");
+
+ if (SUCCEEDED (hr))
+ hr = baseFilter.QueryInterface (IID_IMFGetService, getService);
+
+ if (SUCCEEDED (hr))
+ hr = getService->GetService (MR_VIDEO_RENDER_SERVICE, IID_IMFVideoDisplayControl,
+ (LPVOID*) videoDisplayControl.resetAndGetPointerAddress());
+
+ if (SUCCEEDED (hr))
+ hr = videoDisplayControl->SetVideoWindow (hwnd);
+
+ if (SUCCEEDED (hr))
+ hr = videoDisplayControl->SetAspectRatioMode (MFVideoARMode_PreservePicture);
+
+ return hr;
+ }
+
+ void setVideoWindow (HWND hwnd)
+ {
+ videoDisplayControl->SetVideoWindow (hwnd);
+ }
+
+ void setVideoPosition (HWND hwnd, long /*videoWidth*/, long /*videoHeight*/)
+ {
+ const MFVideoNormalizedRect src = { 0.0f, 0.0f, 1.0f, 1.0f };
+
+ RECT dest;
+ GetClientRect (hwnd, &dest);
+
+ videoDisplayControl->SetVideoPosition (&src, &dest);
+ }
+
+ void repaintVideo (HWND /*hwnd*/, HDC /*hdc*/)
+ {
+ videoDisplayControl->RepaintVideo();
+ }
+
+ void displayModeChanged() {}
+
+ HRESULT getVideoSize (long& videoWidth, long& videoHeight)
+ {
+ SIZE sz;
+ HRESULT hr = videoDisplayControl->GetNativeVideoSize (&sz, nullptr);
+ videoWidth = sz.cx;
+ videoHeight = sz.cy;
+ return hr;
+ }
+
+ private:
+ ComSmartPtr videoDisplayControl;
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EVR);
+ };
+#endif
+}
+
+
+//======================================================================
+class DirectShowComponent::DirectShowContext
+{
+public:
+ DirectShowContext (DirectShowComponent& component_, VideoRendererType type_)
+ : component (component_),
+ hwnd (0),
+ hdc (0),
+ state (uninitializedState),
+ hasVideo (false),
+ videoWidth (0),
+ videoHeight (0),
+ type (type_)
+ {
+ CoInitialize (0);
+
+ if (type == dshowDefault)
+ {
+ type = dshowVMR7;
+
+ #if JUCE_MEDIAFOUNDATION
+ if (SystemStats::getOperatingSystemType() >= SystemStats::WinVista)
+ type = dshowEVR;
+ #endif
+ }
+ }
+
+ ~DirectShowContext()
+ {
+ release();
+ CoUninitialize();
+ }
+
+ //======================================================================
+ HWND getNativeWindowHandle() const
+ {
+ return nativeWindow != nullptr ? nativeWindow->getHandle() : 0;
+ }
+
+ //======================================================================
+ void updateWindowPosition (const Rectangle& newBounds)
+ {
+ nativeWindow->setWindowPosition (newBounds);
+ }
+
+ void showWindow (bool shouldBeVisible)
+ {
+ nativeWindow->showWindow (shouldBeVisible);
+ }
+
+ //======================================================================
+ void repaint()
+ {
+ if (hasVideo)
+ videoRenderer->repaintVideo (nativeWindow->getHandle(), nativeWindow->getContext());
+ }
+
+ void updateVideoPosition()
+ {
+ if (hasVideo)
+ videoRenderer->setVideoPosition (nativeWindow->getHandle(), videoWidth, videoHeight);
+ }
+
+ void displayResolutionChanged()
+ {
+ if (hasVideo)
+ videoRenderer->displayModeChanged();
+ }
+
+ //======================================================================
+ void peerChanged()
+ {
+ deleteNativeWindow();
+
+ mediaEvent->SetNotifyWindow (0, 0, 0);
+ if (videoRenderer != nullptr)
+ videoRenderer->setVideoWindow (nullptr);
+
+ createNativeWindow();
+
+ mediaEvent->SetNotifyWindow ((OAHWND) hwnd, graphEventID, 0);
+ if (videoRenderer != nullptr)
+ videoRenderer->setVideoWindow (hwnd);
+ }
+
+ //======================================================================
+ bool loadFile (const String& fileOrURLPath)
+ {
+ jassert (state == uninitializedState);
+
+ if (! createNativeWindow())
+ return false;
+
+ HRESULT hr = graphBuilder.CoCreateInstance (CLSID_FilterGraph);
+
+ // basic playback interfaces
+ if (SUCCEEDED (hr)) hr = graphBuilder.QueryInterface (IID_IMediaControl, mediaControl);
+ if (SUCCEEDED (hr)) hr = graphBuilder.QueryInterface (IID_IMediaPosition, mediaPosition);
+ if (SUCCEEDED (hr)) hr = graphBuilder.QueryInterface (IID_IMediaEventEx, mediaEvent);
+ if (SUCCEEDED (hr)) hr = graphBuilder.QueryInterface (IID_IBasicAudio, basicAudio);
+
+ // video renderer interface
+ if (SUCCEEDED (hr))
+ {
+ #if JUCE_MEDIAFOUNDATION
+ if (type == dshowEVR)
+ videoRenderer = new DirectShowHelpers::EVR();
+ else
+ #endif
+ videoRenderer = new DirectShowHelpers::VMR7();
+
+ hr = videoRenderer->create (graphBuilder, baseFilter, hwnd);
+ }
+
+ // build filter graph
+ if (SUCCEEDED (hr))
+ hr = graphBuilder->RenderFile (fileOrURLPath.toWideCharPointer(), nullptr);
+
+ // remove video renderer if not connected (no video)
+ if (SUCCEEDED (hr))
+ {
+ if (isRendererConnected())
+ {
+ hasVideo = true;
+ hr = videoRenderer->getVideoSize (videoWidth, videoHeight);
+ }
+ else
+ {
+ hasVideo = false;
+ graphBuilder->RemoveFilter (baseFilter);
+ videoRenderer = nullptr;
+ baseFilter = nullptr;
+ }
+ }
+
+ // set window to receive events
+ if (SUCCEEDED (hr))
+ hr = mediaEvent->SetNotifyWindow ((OAHWND) hwnd, graphEventID, 0);
+
+ if (SUCCEEDED (hr))
+ {
+ state = stoppedState;
+ return true;
+ }
+
+ release();
+ return false;
+ }
+
+ void release()
+ {
+ if (mediaControl != nullptr)
+ mediaControl->Stop();
+
+ if (mediaEvent != nullptr)
+ mediaEvent->SetNotifyWindow (0, 0, 0);
+
+ if (videoRenderer != nullptr)
+ videoRenderer->setVideoWindow (0);
+
+ hasVideo = false;
+ videoRenderer = nullptr;
+
+ baseFilter = nullptr;
+ basicAudio = nullptr;
+ mediaEvent = nullptr;
+ mediaPosition = nullptr;
+ mediaControl = nullptr;
+ graphBuilder = nullptr;
+
+ state = uninitializedState;
+
+ videoWidth = 0;
+ videoHeight = 0;
+
+ if (nativeWindow != nullptr)
+ deleteNativeWindow();
+ }
+
+ void graphEventProc()
+ {
+ LONG ec;
+ LONG_PTR p1, p2;
+
+ jassert (mediaEvent != nullptr);
+
+ while (SUCCEEDED (mediaEvent->GetEvent (&ec, &p1, &p2, 0)))
+ {
+ switch (ec)
+ {
+ case EC_REPAINT:
+ component.repaint();
+ break;
+
+ case EC_COMPLETE:
+ if (component.isLooping())
+ component.goToStart();
+ else
+ component.stop();
+ break;
+
+ case EC_USERABORT:
+ case EC_ERRORABORT:
+ case EC_ERRORABORTEX:
+ component.closeMovie();
+ break;
+
+ default:
+ break;
+ }
+
+ mediaEvent->FreeEventParams (ec, p1, p2);
+ }
+ }
+
+ //======================================================================
+ void run()
+ {
+ mediaControl->Run();
+ state = runningState;
+ }
+
+ void stop()
+ {
+ mediaControl->Stop();
+ state = stoppedState;
+ }
+
+ void pause()
+ {
+ mediaControl->Pause();
+ state = pausedState;
+ }
+
+ //======================================================================
+ bool isInitialised() const noexcept { return state != uninitializedState; }
+ bool isRunning() const noexcept { return state == runningState; }
+ bool isPaused() const noexcept { return state == pausedState; }
+ bool isStopped() const noexcept { return state == stoppedState; }
+ bool containsVideo() const noexcept { return hasVideo; }
+ int getVideoWidth() const noexcept { return (int) videoWidth; }
+ int getVideoHeight() const noexcept { return (int) videoHeight; }
+
+ //======================================================================
+ double getDuration() const
+ {
+ REFTIME duration;
+ mediaPosition->get_Duration (&duration);
+ return duration;
+ }
+
+ double getPosition() const
+ {
+ REFTIME seconds;
+ mediaPosition->get_CurrentPosition (&seconds);
+ return seconds;
+ }
+
+ //======================================================================
+ void setSpeed (const float newSpeed) { mediaPosition->put_Rate (newSpeed); }
+ void setPosition (const double seconds) { mediaPosition->put_CurrentPosition (seconds); }
+ void setVolume (const float newVolume) { basicAudio->put_Volume (convertToDShowVolume (newVolume)); }
+
+ // in DirectShow, full volume is 0, silence is -10000
+ static long convertToDShowVolume (const float vol) noexcept
+ {
+ if (vol >= 1.0f) return 0;
+ if (vol <= 0.0f) return -10000;
+
+ return roundToInt ((vol * 10000.0f) - 10000.0f);
+ }
+
+ float getVolume() const
+ {
+ long volume;
+ basicAudio->get_Volume (&volume);
+ return (volume + 10000) / 10000.0f;
+ }
+
+private:
+ //======================================================================
+ enum { graphEventID = WM_APP + 0x43f0 };
+
+ DirectShowComponent& component;
+ HWND hwnd;
+ HDC hdc;
+
+ enum State { uninitializedState, runningState, pausedState, stoppedState };
+ State state;
+
+ bool hasVideo;
+ long videoWidth, videoHeight;
+
+ VideoRendererType type;
+
+ ComSmartPtr graphBuilder;
+ ComSmartPtr mediaControl;
+ ComSmartPtr mediaPosition;
+ ComSmartPtr mediaEvent;
+ ComSmartPtr basicAudio;
+ ComSmartPtr baseFilter;
+
+ ScopedPointer videoRenderer;
+
+ //======================================================================
+ class NativeWindowClass : public DeletedAtShutdown
+ {
+ private:
+ NativeWindowClass()
+ : atom (0)
+ {
+ String windowClassName ("JUCE_DIRECTSHOW_");
+ windowClassName << (int) (Time::currentTimeMillis() & 0x7fffffff);
+
+ HINSTANCE moduleHandle = (HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle();
+
+ TCHAR moduleFile [1024] = { 0 };
+ GetModuleFileName (moduleHandle, moduleFile, 1024);
+
+ WNDCLASSEX wcex = { 0 };
+ wcex.cbSize = sizeof (wcex);
+ wcex.style = CS_OWNDC;
+ wcex.lpfnWndProc = (WNDPROC) wndProc;
+ wcex.lpszClassName = windowClassName.toWideCharPointer();
+ wcex.hInstance = moduleHandle;
+
+ atom = RegisterClassEx (&wcex);
+ jassert (atom != 0);
+ }
+
+ ~NativeWindowClass()
+ {
+ if (atom != 0)
+ UnregisterClass (getWindowClassName(), (HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle());
+
+ clearSingletonInstance();
+ }
+
+ static LRESULT CALLBACK wndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+ {
+ DirectShowContext* c = (DirectShowContext*) GetWindowLongPtr (hwnd, GWLP_USERDATA);
+
+ if (c != nullptr)
+ {
+ jassert (c->getNativeWindowHandle() == hwnd);
+
+ switch (msg)
+ {
+ case WM_ERASEBKGND: return 1;
+ case WM_DISPLAYCHANGE: c->displayResolutionChanged(); break;
+ case graphEventID: c->graphEventProc(); return 0;
+ default: break;
+ }
+ }
+
+ return DefWindowProc (hwnd, msg, wParam, lParam);
+ }
+
+ public:
+ bool isRegistered() const noexcept { return atom != 0; }
+ LPCTSTR getWindowClassName() const noexcept { return (LPCTSTR) MAKELONG (atom, 0); }
+
+ juce_DeclareSingleton_SingleThreaded_Minimal (NativeWindowClass);
+
+ private:
+ ATOM atom;
+
+ JUCE_DECLARE_NON_COPYABLE (NativeWindowClass);
+ };
+
+ //======================================================================
+ class NativeWindow
+ {
+ public:
+ NativeWindow (HWND parentToAddTo, void* const userData)
+ : hwnd (0), hdc (0)
+ {
+ NativeWindowClass* const wc = NativeWindowClass::getInstance();
+
+ if (wc->isRegistered())
+ {
+ DWORD exstyle = 0;
+ DWORD type = WS_CHILD;
+
+ hwnd = CreateWindowEx (exstyle, wc->getWindowClassName(),
+ L"", type, 0, 0, 0, 0, parentToAddTo, 0,
+ (HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle(), 0);
+
+ if (hwnd != 0)
+ {
+ hdc = GetDC (hwnd);
+ SetWindowLongPtr (hwnd, GWLP_USERDATA, (LONG_PTR) userData);
+ }
+ }
+
+ jassert (hwnd != 0);
+ }
+
+ ~NativeWindow()
+ {
+ if (hwnd != 0)
+ {
+ SetWindowLongPtr (hwnd, GWLP_USERDATA, (LONG_PTR) 0);
+ DestroyWindow (hwnd);
+ }
+ }
+
+ HWND getHandle() const noexcept { return hwnd; }
+ HDC getContext() const noexcept { return hdc; }
+
+ void setWindowPosition (const Rectangle& newBounds)
+ {
+ SetWindowPos (hwnd, 0, newBounds.getX(), newBounds.getY(),
+ newBounds.getWidth(), newBounds.getHeight(),
+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER);
+ }
+
+ void showWindow (const bool shouldBeVisible)
+ {
+ ShowWindow (hwnd, shouldBeVisible ? SW_SHOWNA : SW_HIDE);
+ }
+
+ private:
+ HWND hwnd;
+ HDC hdc;
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeWindow);
+ };
+
+ ScopedPointer nativeWindow;
+
+ //======================================================================
+ bool createNativeWindow()
+ {
+ jassert (nativeWindow == nullptr);
+
+ ComponentPeer* topLevelPeer = component.getTopLevelComponent()->getPeer();
+
+ jassert (topLevelPeer != nullptr);
+
+ if (topLevelPeer != nullptr)
+ {
+ nativeWindow = new NativeWindow ((HWND) topLevelPeer->getNativeHandle(), this);
+
+ hwnd = nativeWindow->getHandle();
+
+ if (hwnd != 0)
+ {
+ hdc = GetDC (hwnd);
+ component.updateContextPosition();
+ component.showContext (component.isShowing());
+ return true;
+ }
+ else
+ {
+ nativeWindow = nullptr;
+ }
+ }
+
+ return false;
+ }
+
+ void deleteNativeWindow()
+ {
+ jassert (nativeWindow != nullptr);
+ ReleaseDC (hwnd, hdc);
+ hwnd = 0;
+ hdc = 0;
+ nativeWindow = nullptr;
+ }
+
+ bool isRendererConnected()
+ {
+ ComSmartPtr enumPins;
+
+ HRESULT hr = baseFilter->EnumPins (enumPins.resetAndGetPointerAddress());
+
+ if (SUCCEEDED (hr))
+ hr = enumPins->Reset();
+
+ ComSmartPtr pin;
+
+ while (SUCCEEDED (hr)
+ && enumPins->Next (1, pin.resetAndGetPointerAddress(), nullptr) == S_OK)
+ {
+ ComSmartPtr otherPin;
+
+ hr = pin->ConnectedTo (otherPin.resetAndGetPointerAddress());
+
+ if (SUCCEEDED (hr))
+ {
+ PIN_DIRECTION direction;
+ hr = pin->QueryDirection (&direction);
+
+ if (SUCCEEDED (hr) && direction == PINDIR_INPUT)
+ return true;
+ }
+ else if (hr == VFW_E_NOT_CONNECTED)
+ {
+ hr = S_OK;
+ }
+ }
+
+ return false;
+ }
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectShowContext);
+};
+
+juce_ImplementSingleton_SingleThreaded (DirectShowComponent::DirectShowContext::NativeWindowClass);
+
+
+//======================================================================
+class DirectShowComponent::DirectShowComponentWatcher : public ComponentMovementWatcher
+{
+public:
+ DirectShowComponentWatcher (DirectShowComponent* const owner_)
+ : ComponentMovementWatcher (owner_),
+ owner (owner_)
+ {
+ }
+
+ void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/)
+ {
+ if (owner->videoLoaded)
+ owner->updateContextPosition();
+ }
+
+ void componentPeerChanged()
+ {
+ if (owner->videoLoaded)
+ owner->recreateNativeWindowAsync();
+ }
+
+ void componentVisibilityChanged()
+ {
+ if (owner->videoLoaded)
+ owner->showContext (owner->isShowing());
+ }
+
+ //======================================================================
+private:
+ DirectShowComponent* const owner;
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectShowComponentWatcher);
+};
+
+
+//======================================================================
+DirectShowComponent::DirectShowComponent (VideoRendererType type)
+ : videoLoaded (false),
+ looping (false),
+ needToUpdateViewport (true),
+ needToRecreateNativeWindow (false)
+{
+ setOpaque (true);
+ context = new DirectShowContext (*this, type);
+ componentWatcher = new DirectShowComponentWatcher (this);
+}
+
+DirectShowComponent::~DirectShowComponent()
+{
+ componentWatcher = nullptr;
+}
+
+bool DirectShowComponent::isDirectShowAvailable()
+{
+ static bool isDSAvailable = DirectShowHelpers::checkDShowAvailability();
+ return isDSAvailable;
+}
+
+void DirectShowComponent::recreateNativeWindowAsync()
+{
+ needToRecreateNativeWindow = true;
+ repaint();
+}
+
+void DirectShowComponent::updateContextPosition()
+{
+ needToUpdateViewport = true;
+
+ if (getWidth() > 0 && getHeight() > 0)
+ {
+ Component* const topComp = getTopLevelComponent();
+
+ if (topComp->getPeer() != nullptr)
+ context->updateWindowPosition (topComp->getLocalArea (this, getLocalBounds()));
+ }
+}
+
+void DirectShowComponent::showContext (const bool shouldBeVisible)
+{
+ context->showWindow (shouldBeVisible);
+}
+
+void DirectShowComponent::paint (Graphics& g)
+{
+ if (videoLoaded)
+ {
+ if (needToRecreateNativeWindow)
+ {
+ context->peerChanged();
+ needToRecreateNativeWindow = false;
+ }
+
+ if (needToUpdateViewport)
+ {
+ context->updateVideoPosition();
+ needToUpdateViewport = false;
+ }
+
+ context->repaint();
+
+ ComponentPeer* const peer = getPeer();
+
+ if (peer != nullptr)
+ {
+ const Point topLeft (getScreenPosition() - peer->getScreenPosition());
+ peer->addMaskedRegion (topLeft.getX(), topLeft.getY(), getWidth(), getHeight());
+ }
+ }
+ else
+ {
+ g.fillAll (Colours::grey);
+ }
+}
+
+//======================================================================
+bool DirectShowComponent::loadMovie (const String& fileOrURLPath)
+{
+ closeMovie();
+
+ videoLoaded = context->loadFile (fileOrURLPath);
+
+ if (videoLoaded)
+ {
+ videoPath = fileOrURLPath;
+ context->updateVideoPosition();
+ }
+
+ return videoLoaded;
+}
+
+bool DirectShowComponent::loadMovie (const File& videoFile)
+{
+ return loadMovie (videoFile.getFullPathName());
+}
+
+bool DirectShowComponent::loadMovie (const URL& videoURL)
+{
+ return loadMovie (videoURL.toString (false));
+}
+
+void DirectShowComponent::closeMovie()
+{
+ if (videoLoaded)
+ context->release();
+
+ videoLoaded = false;
+ videoPath = String::empty;
+}
+
+//======================================================================
+const File DirectShowComponent::getCurrentMoviePath() const { return videoPath; }
+bool DirectShowComponent::isMovieOpen() const { return videoLoaded; }
+double DirectShowComponent::getMovieDuration() const { return videoLoaded ? context->getDuration() : 0.0; }
+void DirectShowComponent::setLooping (const bool shouldLoop) { looping = shouldLoop; }
+bool DirectShowComponent::isLooping() const { return looping; }
+
+void DirectShowComponent::getMovieNormalSize (int &width, int &height) const
+{
+ width = context->getVideoWidth();
+ height = context->getVideoHeight();
+}
+
+//======================================================================
+void DirectShowComponent::setBoundsWithCorrectAspectRatio (const Rectangle& spaceToFitWithin,
+ const RectanglePlacement& placement)
+{
+ int normalWidth, normalHeight;
+ getMovieNormalSize (normalWidth, normalHeight);
+
+ const Rectangle normalSize (0, 0, normalWidth, normalHeight);
+
+ if (! (spaceToFitWithin.isEmpty() || normalSize.isEmpty()))
+ setBounds (placement.appliedTo (normalSize, spaceToFitWithin));
+ else
+ setBounds (spaceToFitWithin);
+}
+
+//======================================================================
+void DirectShowComponent::play()
+{
+ if (videoLoaded)
+ context->run();
+}
+
+void DirectShowComponent::stop()
+{
+ if (videoLoaded)
+ context->stop();
+}
+
+bool DirectShowComponent::isPlaying() const
+{
+ return context->isRunning();
+}
+
+void DirectShowComponent::goToStart()
+{
+ setPosition (0.0);
+}
+
+void DirectShowComponent::setPosition (const double seconds)
+{
+ if (videoLoaded)
+ context->setPosition (seconds);
+}
+
+double DirectShowComponent::getPosition() const
+{
+ return videoLoaded ? context->getPosition() : 0.0;
+}
+
+void DirectShowComponent::setSpeed (const float newSpeed)
+{
+ if (videoLoaded)
+ context->setSpeed (newSpeed);
+}
+
+void DirectShowComponent::setMovieVolume (const float newVolume)
+{
+ if (videoLoaded)
+ context->setVolume (newVolume);
+}
+
+float DirectShowComponent::getMovieVolume() const
+{
+ return videoLoaded ? context->getVolume() : 0.0f;
+}
+
+
+#endif
diff --git a/src/native/windows/juce_win32_Files.cpp b/src/native/windows/juce_win32_Files.cpp
index 572e51055c..84247764cc 100644
--- a/src/native/windows/juce_win32_Files.cpp
+++ b/src/native/windows/juce_win32_Files.cpp
@@ -307,7 +307,7 @@ MemoryMappedFile::MemoryMappedFile (const File& file, MemoryMappedFile::AccessMo
{
jassert (mode == readOnly || mode == readWrite);
- DWORD accessMode = GENERIC_READ, shareMode = FILE_SHARE_READ, createType = OPEN_EXISTING;
+ DWORD accessMode = GENERIC_READ, createType = OPEN_EXISTING;
DWORD protect = PAGE_READONLY, access = FILE_MAP_READ;
if (mode == readWrite)
diff --git a/src/native/windows/juce_win32_NativeCode.cpp b/src/native/windows/juce_win32_NativeCode.cpp
index 5b57974fe5..e6c4627c75 100644
--- a/src/native/windows/juce_win32_NativeCode.cpp
+++ b/src/native/windows/juce_win32_NativeCode.cpp
@@ -74,6 +74,7 @@ BEGIN_JUCE_NAMESPACE
#include "../../gui/components/menus/juce_MenuBarModel.h"
#include "../../gui/components/special/juce_OpenGLComponent.h"
#include "../../gui/components/special/juce_QuickTimeMovieComponent.h"
+#include "../../gui/components/special/juce_DirectShowComponent.h"
#include "../../gui/components/mouse/juce_DragAndDropContainer.h"
#include "../../gui/components/mouse/juce_MouseInputSource.h"
#include "../../gui/components/keyboard/juce_KeyPressMappingSet.h"
@@ -114,6 +115,7 @@ BEGIN_JUCE_NAMESPACE
#include "juce_win32_Misc.cpp"
#include "juce_win32_ActiveXComponent.cpp"
#include "juce_win32_QuickTimeMovieComponent.cpp"
+ #include "juce_win32_DirectShowComponent.cpp"
#include "juce_win32_WebBrowserComponent.cpp"
#include "juce_win32_OpenGLComponent.cpp"
#include "juce_win32_AudioCDReader.cpp"
diff --git a/src/native/windows/juce_win32_NativeIncludes.h b/src/native/windows/juce_win32_NativeIncludes.h
index 520c4823f7..30fe9ea2ac 100644
--- a/src/native/windows/juce_win32_NativeIncludes.h
+++ b/src/native/windows/juce_win32_NativeIncludes.h
@@ -183,6 +183,14 @@
#import
#endif
+#if JUCE_DIRECTSHOW && JUCE_BUILD_NATIVE
+ #include
+#endif
+
+#if JUCE_MEDIAFOUNDATION && JUCE_BUILD_NATIVE
+ #include
+#endif
+
//==============================================================================
#if JUCE_MSVC
#pragma warning (pop)
diff --git a/src/native/windows/juce_win32_OpenGLComponent.cpp b/src/native/windows/juce_win32_OpenGLComponent.cpp
index bee75c7d01..9ac80d944d 100644
--- a/src/native/windows/juce_win32_OpenGLComponent.cpp
+++ b/src/native/windows/juce_win32_OpenGLComponent.cpp
@@ -287,10 +287,10 @@ public:
return false;
}
- void updateWindowPosition (int x, int y, int w, int h, int)
+ void updateWindowPosition (const Rectangle& bounds)
{
SetWindowPos ((HWND) nativeWindow->getNativeHandle(), 0,
- x, y, w, h,
+ bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(),
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER);
}