Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial checkin: current state of kkapture 0.08

  • Loading branch information...
commit 1b22ed8f8cd6ffd1df9bf34ce2a156549a304d17 0 parents
@rygorous authored
Showing with 9,212 additions and 0 deletions.
  1. +11 −0 CONTRIBUTORS.txt
  2. +213 −0 LICENSE.txt
  3. +99 −0 changelog.txt
  4. +25 −0 kkapture.sln
  5. +714 −0 kkapture/kkapture.cpp
  6. +175 −0 kkapture/kkapture.rc
  7. +238 −0 kkapture/kkapture.vcproj
  8. +65 −0 kkapture/kkapture.vcproj.RYG.fg.user
  9. +36 −0 kkapture/resource.h
  10. +23 −0 kkapture/stdafx.cpp
  11. +29 −0 kkapture/stdafx.h
  12. +288 −0 kkapturedll/audio_resample.cpp
  13. +59 −0 kkapturedll/audio_resample.h
  14. +875 −0 kkapturedll/avi_videoencoder_dshow.cpp
  15. +60 −0 kkapturedll/avi_videoencoder_dshow.h
  16. +391 −0 kkapturedll/avi_videoencoder_vfw.cpp
  17. +57 −0 kkapturedll/avi_videoencoder_vfw.h
  18. +157 −0 kkapturedll/bmp_videoencoder.cpp
  19. +51 −0 kkapturedll/bmp_videoencoder.h
  20. +342 −0 kkapturedll/kkapturedll.vcproj
  21. +65 −0 kkapturedll/kkapturedll.vcproj.RYG.fg.user
  22. +279 −0 kkapturedll/main.cpp
  23. +80 −0 kkapturedll/main.h
  24. +223 −0 kkapturedll/mt_proxy_videoencoder.cpp
  25. +54 −0 kkapturedll/mt_proxy_videoencoder.h
  26. +1,392 −0 kkapturedll/sound.cpp
  27. +33 −0 kkapturedll/sound.h
  28. +23 −0 kkapturedll/stdafx.cpp
  29. +44 −0 kkapturedll/stdafx.h
  30. +546 −0 kkapturedll/timing.cpp
  31. +35 −0 kkapturedll/timing.h
  32. +105 −0 kkapturedll/util.cpp
  33. +59 −0 kkapturedll/util.h
  34. +342 −0 kkapturedll/video.cpp
  35. +64 −0 kkapturedll/video.h
  36. +266 −0 kkapturedll/video_direct3d8.cpp
  37. +302 −0 kkapturedll/video_direct3d9.cpp
  38. +888 −0 kkapturedll/video_directdraw.cpp
  39. +248 −0 kkapturedll/video_opengl.cpp
  40. +48 −0 kkapturedll/videocapturetimer.h
  41. +59 −0 kkapturedll/videoencoder.cpp
  42. +55 −0 kkapturedll/videoencoder.h
  43. +94 −0 working_demos.txt
11 CONTRIBUTORS.txt
@@ -0,0 +1,11 @@
+OFFICIAL PROJECT HOMEPAGE:
+ http://www.farbrausch.de/~fg/kkapture
+
+MAINTAINER AND PROJECT LEAD:
+ Fabian "ryg/farbrausch" Giesen
+ http://www.farbrausch.de/~fg
+
+CONTRIBUTORS:
+ Tammo "kb" Hinrichs Parts of the D3D8 code in v0.02
+ Bernhard "bartman" Wodok AVI splitting, resolution bugfix in v0.04
+ Joern "manx" Heusipp waveout-bugfix in v0.04
213 LICENSE.txt
@@ -0,0 +1,213 @@
+ The Artistic License
+ Version 2.0beta5, October 2001
+
+ Copyright (C) 2000, 2001 Larry Wall, Bradley M. Kuhn.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+This copyright license states the terms under which a given free software
+Package may be copied, modified and/or redistributed, while the
+Originator(s) maintain some artistic control over the future development of
+that Package (at least as much artistic control as can be given under
+copyright law while still making the Package open source and free software).
+
+This license is bound by copyright law, and thus it legally applies only to
+works which the copyright holder has permitted copying, distribution or
+modification under the terms of the Artistic License, Version 2.0.
+
+You are reminded that You are always permitted to make arrangements wholly
+outside of a given copyright license directly with the copyright holder(s)
+of a given Package. If the terms of this license impede your ability to
+make full use of the Package, You are encouraged to contact the copyright
+holder(s) and seek a different licensing arrangement.
+
+
+ Definitions
+
+"Package" refers to the collection of files distributed by the
+ Originator(s), and derivatives of that collection of files created
+ through textual modification.
+
+"Standard Version" refers to the Package if it has not been modified, or has
+ been modified only in ways suggested by the
+ Originator(s).
+
+"Modified Version" refers to the Package, if it has been changed by You via
+ textual modification of the source code, and such changes
+ were not suggested by the Originator(s).
+
+"Originator" refers to the author(s) and/or copyright holder(s) of the
+ Standard Version of the Package.
+
+"You" and "Your" refers to any person who would like to copy, distribute, or
+ modify the Package.
+
+"Distribution Fee" is any fee that You charge for providing a copy of this
+ Package to another party. It does not refer to licensing
+ fees.
+
+"Freely Available" means that:
+
+ (a) no fee is charged for the right to use the item (though a
+ Distribution Fee may be charged).
+
+ (b) recipients of the item may redistribute it under the same
+ conditions they received it.
+
+ (c) If the item is a binary, object code, bytecode, the complete
+ corresponding machine-readable source code is included with the
+ item.
+
+
+ Permission for Use and Modification Without Redistribution
+
+ (1) You are permitted to use the Standard Version and create and use
+ Modified Versions for any purpose without restriction, provided that
+ you do not redistribute the Modified Version to others outside of your
+ company or organization.
+
+
+ Permissions for Redistribution of the Standard Version
+
+ (2) You may make available verbatim copies of the source code of the
+ Standard Version of this Package in any medium without restriction,
+ either gratis or for a Distribution Fee, provided that you duplicate
+ all of the original copyright notices and associated disclaimers. At
+ Your discretion, such verbatim copies may or may not include compiled
+ bytecode, object code or binary versions of the corresponding source
+ code in the same medium.
+
+ (3) You may apply any bug fixes, portability changes, and other
+ modifications made available from any of the Originator(s). The
+ resulting modified Package will still be considered the Standard
+ Version, and may be copied, modified and redistributed under the terms
+ of the original license of the Standard Version as if it were the
+ Standard Version.
+
+
+ Permissions for Redistribution of Modified Versions of the Package as Source
+
+ (4) You may modify your copy of the source code of this Package in any way
+ and distribute that Modified Version (either gratis or for a
+ Distribution Fee, and with or without a corresponding binary, bytecode
+ or object code version of the Modified Version) provided that You
+ clearly indicate what changes You made to the Package, and provided
+ that You do at least ONE of the following:
+
+ (a) make the Modified Version available to the Originator(s) of the
+ Standard Version, under the exact license of the Standard
+ Version, so that the Originator(s) may include your modifications
+ into the Standard Version (at their discretion).
+
+ (b) modify any installation scripts and procedures so that
+ installation of the Modified Version will never conflict with an
+ installation of the Standard Version, include for each program
+ installed by the Modified Version clear documentation describing
+ how it differs from the Standard Version, and rename your
+ Modified Version so that the name is substantially different from
+ the Standard Version.
+
+ (c) permit and encourage anyone who receives a copy of the Modified
+ Version to make your modifications Freely Available in some
+ specific way.
+
+ If Your Modified Version is in turn derived from a Modified Version
+ made by a third party, then You are still required to ensure that Your
+ Modified Version complies with the requirements of this license.
+
+
+ Permissions for Redistribution of Non-Source Versions of Package
+
+ (5) You may distribute binary, object code, bytecode or other non-source
+ versions of the Standard Version of the Package, provided that you
+ include complete instructions on where to get the source code of the
+ Standard Version. Such instructions must be valid at the time of Your
+ distribution. If these instructions, at any time while You are
+ carrying our such distribution, become invalid, you must provide new
+ instructions on demand or cease further distribution. If You cease
+ distribution within thirty days after You become aware that the
+ instructions are invalid, then You do not forfeit any of Your rights
+ under this license.
+
+ (6) You may distribute binary, object code, bytecode or other non-source
+ versions of a Modified Version provided that You do at least ONE of
+ the following:
+
+ (a) include a copy of the corresponding source code for the Modified
+ Version under the terms indicated in (4).
+
+ (b) ensure that the installation of Your non-source Modified Version
+ does not conflict in any way with an installation of the Standard
+ Version, include for each program installed by the Modified
+ Version clear documentation describing how it differs from the
+ Standard Version, and rename your Modified Version so that the
+ name is substantially different from the Standard Version.
+
+ (c) ensure that the Modified Version includes notification of the
+ changes made from the Standard Version, and offer to provide
+ machine-readable source code (under a license that permits making
+ that source code Freely Available) of the Modified Version via
+ mail order.
+
+
+ Permissions for Inclusion of the Package in Aggregate Works
+
+ (7) You may aggregate this Package (either the Standard Version or
+ Modified Version) with other packages and distribute the resulting
+ aggregation provided that You do not charge a licensing fee for the
+ Package. Distribution Fees are permitted, and licensing fees for
+ other packages in the aggregation are permitted. Your permission to
+ distribute Standard or Modified Versions of the Package is still
+ subject to the other terms set forth in other sections of this
+ license.
+
+ (8) In addition to the permissions given elsewhere by this license, You
+ are also permitted to link Modified and Standard Versions of this
+ Package with other works and distribute the result without
+ restriction, provided You have produced binary program(s) that do not
+ overtly expose the interfaces of the Package. This includes
+ permission to embed the Package in a larger work of your own without
+ exposing a direct interface to the Package. This also includes
+ permission to build stand-alone binary or bytecode versions of your
+ scripts that require the Package, but do not otherwise give the casual
+ user direct access to the Package itself.
+
+
+ Items That are Never Considered Part of a Modified Version Package
+
+ (9) Works (including, but not limited to, subroutines and scripts) that
+ you have linked or aggregated with the Package that merely extend or
+ make use of the Package, but are not intended to cause the Package to
+ operate differently from the Standard Version, do not, by themselves,
+ cause the Package to be a Modified Version. In addition, such works
+ are not considered parts of the Package itself, and are not bound by
+ the terms of the Package's license.
+
+
+ Acceptance of License and Disclaimer of Warranty
+
+ (10) You are not required to accept this License, since you have not signed
+ it. However, nothing else grants you permission to copy, modify or
+ distribute the Standard or Modified Versions of the Package. These
+ actions are prohibited by copyright law if you do not accept this
+ License. Therefore, by copying, modifying or distributing Standard
+ and Modified Versions of the Package, you indicate your acceptance of
+ the license of the Package.
+
+
+ (11) Disclaimer of Warranty:
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT UNLESS REQUIRED BY
+ LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER OR CONTRIBUTOR
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
99 changelog.txt
@@ -0,0 +1,99 @@
+version 0.08:
+* "frame rate" edit control now supports arbitrary positive decimal ("12.3456") and fractional ("60000/1001") framerates
+
+version 0.07:
+* "frame timed out" now mentions *which* frame was skipped (if you want to check whether the video is fine or if it causes problems)
+* if kkapture is being debugged, main.cpp now gives you time to attach the debugger to the target demo aswell.
+ (this is the deluxe version of a hack i've been using for ages - thought it might be useful for others trying to debug, too :)
+* fixed some bugs in the cleanup code that may have caused crashes after recording was complete.
+* waveOutGetPosition now even accepts wrong size specifications for MMTIME struct as long as they're big enough (helps candystall)
+* ddraw code temp surface handling should now be more stable (helps with moral hard candy)
+* seeding of all timers now synchronized. helps with demos that mix timing values returned from independent sources (not a good idea!!!).
+ in any case, fixes problems with ante dominum.
+* "power down after completion" switch
+
+version 0.06b:
+* now default to vfw video encoder on new installations.
+* "fairlight hack" switch now explicit due to request - turn it on for track one and possibly other flt demos, otherwise leave it off.
+ (was implicitly on in all versions from 0.05 upwards)
+* more new startup instrumentation fixes (yaay!)
+
+version 0.06:
+* magic exit key (ctrl+break) improved: now uses lowlevel hook, should always work now.
+* d3d8 capture fixes: r08028, nature v2.0 work now.
+* vfw .avi writer can now also handle format changes while the demo is running
+* should now work with demos that use FMODEx: at least first offence works fine now.
+* now automatically advances time if frames take too long.
+ fixes a LOT of demos that do busy waits somewhere, including:
+ - frameskool by equinox
+ - mupe by playpsyco
+ - abstinens by keyboards
+ - noumenon by andromeda
+ and probably a lot of other demos too.
+
+ how to use: check "Enable automatic frameskip on timeout".
+ the two timeout values define how much time the application has to render
+ the first/subsequent frames; if it takes longer, kkapture will skip a
+ frame and write a log message. lower timeouts mean faster kkapturing for
+ apps that explicitly perform waits every frame, but the lower you set those
+ values, the higher the risk that kkapture will drop a frame just because
+ rendering took a tad longer than expected. so be careful!
+
+version 0.05b:
+* IDirectSoundBuffer::SetFrequency handling fixed (affects onwards, 2^5 by traction)
+* debug force-windowed code for d3d9 removed :)
+
+version 0.05:
+* small bugfix in dshow video encoder (thanks malc)
+* "new startup instrumentation" button now actually does something :)
+* startup instrumentation code now less picky about executable files
+* startup instrumentation now works when first instr. is call/jmp (helps with several demos)
+* added dc/rendering context tracking for opengl (fixes problem with animal attraction)
+* synchronization policy changed in dsound code (fixes problems with mega hilter expansion pack, maybe some threading issues too?)
+* old fallback gdi capture code removed (not required anymore and it never worked properly anyway)
+
+version 0.04:
+* switched to visual c++ 2005 express edition
+* "new startup interception" that works on 64bit host machines (always on on 64bit, default off on 32bit)
+* kkapturing on 64bit host machines works now
+* kkapture is now under the artistic license v2.0beta5
+* small waveout code fix by manx included (thanks)
+* automatic segmenting code for avi-vfw encoder by bartman included (thanks to you too :)
+* automatically disables VSync during recording for most supported APIs (improves capturing speed somewhat)
+* basic SetTimer support (i'm not particularly happy with it)
+* improved resolution determination for opengl demos
+* magic exit key: press ctrl+break to safely abort a capture.
+* writes (approximate) capturing frame rate on exit
+* small fix in doneTiming() to make sure no waits are currently active when timing is deinitialized
+* improvements in d3d8/9 reference handling code
+* support for demos that initialize/deinitialize the graphics API several times
+
+version 0.04alpha:
+* some performance improvements for directdraw capturing
+* several bugfixes
+* new directshow-based avi writer, currently the only one available (0.04 final will have both the old and new avi writer)
+* automatic audio resampling (required for dshow, currently converts everything to 16bit 44.1kHz stereo)
+
+version 0.03:
+* waveout capturing finally works (now that was one stupid bug)
+* directdraw/old d3d support (both software and hardware)
+* kkapture now sets the executables' directory as current working dir before starting
+* "skip silence" option added (required for e.g. fr-08); currently only works for
+ directsound
+* "make sleeps last one frame" option added (required for some old BASS and FMOD
+ versions to work correctly)
+* the .bmp/.wav writer now compensates for frames at the beginning without sound
+* capture audio/capture video flags
+
+version 0.02:
+* direct xvid/divx encoding works now.
+* windowed capture support for both opengl and d3d - beware, some demos do not use correct window sizes in windowed mode, so you get e.g. a 630x472 capture for a 640x480 demo - most video codecs don't like sizes that aren't multiples of 4.
+* opengl capturing bugfix - on swapbuffers(), frames were accidentially advanced twice.
+* some QueryPerformanceCounter-related fixes.
+* vastly improved Direct3D9 capture speed.
+* Direct3D8 support (co-written by kb/farbrausch).
+* .bmp/.wav output added (uncompressed highres captures easily hit the avifile 4gb limit).
+* lots of tiny fixes here and there.
+
+version 0.01:
+* initial release; still missing d3d8, ddraw support, waveout completely untested.
25 kkapture.sln
@@ -0,0 +1,25 @@
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual C++ Express 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kkapturedll", "kkapturedll\kkapturedll.vcproj", "{8212119F-DBE1-4DA5-80A9-67FDE9A4CBD3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kkapture", "kkapture\kkapture.vcproj", "{DBA35513-DE77-4FE9-8B71-C483946E76FF}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {8212119F-DBE1-4DA5-80A9-67FDE9A4CBD3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8212119F-DBE1-4DA5-80A9-67FDE9A4CBD3}.Debug|Win32.Build.0 = Debug|Win32
+ {8212119F-DBE1-4DA5-80A9-67FDE9A4CBD3}.Release|Win32.ActiveCfg = Release|Win32
+ {8212119F-DBE1-4DA5-80A9-67FDE9A4CBD3}.Release|Win32.Build.0 = Release|Win32
+ {DBA35513-DE77-4FE9-8B71-C483946E76FF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {DBA35513-DE77-4FE9-8B71-C483946E76FF}.Debug|Win32.Build.0 = Debug|Win32
+ {DBA35513-DE77-4FE9-8B71-C483946E76FF}.Release|Win32.ActiveCfg = Release|Win32
+ {DBA35513-DE77-4FE9-8B71-C483946E76FF}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
714 kkapture/kkapture.cpp
@@ -0,0 +1,714 @@
+/* kkapture: intrusive demo video capturing.
+ * Copyright (c) 2005-2006 Fabian "ryg/farbrausch" Giesen.
+ *
+ * This program is free software; you can redistribute and/or modify it under
+ * the terms of the Artistic License, Version 2.0beta5, or (at your opinion)
+ * any later version; all distributions of this program should contain this
+ * license in a file named "LICENSE.txt".
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT UNLESS REQUIRED BY
+ * LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER OR CONTRIBUTOR
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "stdafx.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <assert.h>
+#include <tchar.h>
+#include "../kkapturedll/main.h"
+#include "resource.h"
+
+#pragma comment(lib,"vfw32.lib")
+#pragma comment(lib,"msacm32.lib")
+
+static const TCHAR RegistryKeyName[] = _T("Software\\Farbrausch\\kkapture");
+static const int MAX_ARGS = _MAX_PATH*2;
+
+// global vars for parameter passing (yes this sucks...)
+static TCHAR ExeName[_MAX_PATH];
+static TCHAR Arguments[MAX_ARGS];
+static ParameterBlock Params;
+
+// some dialog helpers
+static BOOL EnableDlgItem(HWND hWnd,int id,BOOL bEnable)
+{
+ HWND hCtrlWnd = GetDlgItem(hWnd,id);
+ return EnableWindow(hCtrlWnd,bEnable);
+}
+
+static BOOL IsWow64()
+{
+ typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
+ LPFN_ISWOW64PROCESS IsWow64Process = (LPFN_ISWOW64PROCESS)
+ GetProcAddress(GetModuleHandle(_T("kernel32")),_T("IsWow64Process"));
+
+ if(IsWow64Process)
+ {
+ BOOL result;
+ if(!IsWow64Process(GetCurrentProcess(),&result))
+ result = FALSE;
+
+ return result;
+ }
+ else
+ return FALSE;
+}
+
+static void SetVideoCodecInfo(HWND hWndDlg,HIC codec)
+{
+ TCHAR buffer[256];
+
+ if(codec)
+ {
+ ICINFO info;
+ ZeroMemory(&info,sizeof(info));
+ ICGetInfo(codec,&info,sizeof(info));
+
+ _sntprintf(buffer,sizeof(buffer)/sizeof(*buffer),_T("Video codec: %S"),info.szDescription);
+ buffer[255] = 0;
+ }
+ else
+ _tcscpy(buffer,_T("Video codec: (uncompressed)"));
+
+ SetDlgItemText(hWndDlg,IDC_VIDEOCODEC,buffer);
+}
+
+static DWORD RegQueryDWord(HKEY hk,LPCTSTR name,DWORD defValue)
+{
+ DWORD value,typeCode,size=sizeof(DWORD);
+
+ if(!hk || !RegQueryValueEx(hk,name,0,&typeCode,(LPBYTE) &value,&size) == ERROR_SUCCESS
+ || typeCode != REG_DWORD && size != sizeof(DWORD))
+ value = defValue;
+
+ return value;
+}
+
+static void RegSetDWord(HKEY hk,LPCTSTR name,DWORD value)
+{
+ RegSetValueEx(hk,name,0,REG_DWORD,(LPBYTE) &value,sizeof(DWORD));
+}
+
+static void LoadSettingsFromRegistry()
+{
+ HKEY hk = 0;
+
+ if(RegOpenKeyEx(HKEY_CURRENT_USER,RegistryKeyName,0,KEY_READ,&hk) != ERROR_SUCCESS)
+ hk = 0;
+
+ Params.FrameRateNum = RegQueryDWord(hk,_T("FrameRate"),6000);
+ Params.FrameRateDenom = RegQueryDWord(hk,_T("FrameRateDenom"),100);
+ Params.Encoder = (EncoderType) RegQueryDWord(hk,_T("VideoEncoder"),AVIEncoderVFW);
+ Params.VideoCodec = RegQueryDWord(hk,_T("AVIVideoCodec"),mmioFOURCC('D','I','B',' '));
+ Params.VideoQuality = RegQueryDWord(hk,_T("AVIVideoQuality"),ICQUALITY_DEFAULT);
+ Params.NewIntercept = RegQueryDWord(hk,_T("NewIntercept"),0);
+ Params.FairlightHack = RegQueryDWord(hk,_T("FairlightHack"),0);
+ Params.EnableAutoSkip = RegQueryDWord(hk,_T("EnableAutoSkip"),0);
+ Params.FirstFrameTimeout = RegQueryDWord(hk,_T("FirstFrameTimeout"),1000);
+ Params.FrameTimeout = RegQueryDWord(hk,_T("FrameTimeout"),500);
+ Params.UseEncoderThread = RegQueryDWord(hk,_T("UseEncoderThread"),0);
+
+ if(hk)
+ RegCloseKey(hk);
+}
+
+static void SaveSettingsToRegistry()
+{
+ HKEY hk;
+
+ if(RegCreateKeyEx(HKEY_CURRENT_USER,RegistryKeyName,0,0,0,KEY_ALL_ACCESS,0,&hk,0) == ERROR_SUCCESS)
+ {
+ RegSetDWord(hk,_T("FrameRate"),Params.FrameRateNum);
+ RegSetDWord(hk,_T("FrameRateDenom"),Params.FrameRateDenom);
+ RegSetDWord(hk,_T("VideoEncoder"),Params.Encoder);
+ RegSetDWord(hk,_T("AVIVideoCodec"),Params.VideoCodec);
+ RegSetDWord(hk,_T("AVIVideoQuality"),Params.VideoQuality);
+ RegSetDWord(hk,_T("NewIntercept"),Params.NewIntercept);
+ RegSetDWord(hk,_T("FairlightHack"),Params.FairlightHack);
+ RegSetDWord(hk,_T("EnableAutoSkip"),Params.EnableAutoSkip);
+ RegSetDWord(hk,_T("FirstFrameTimeout"),Params.FirstFrameTimeout);
+ RegSetDWord(hk,_T("FrameTimeout"),Params.FrameTimeout);
+ RegSetDWord(hk,_T("UseEncoderThread"),Params.UseEncoderThread);
+ RegCloseKey(hk);
+ }
+}
+
+static int IntPow(int a,int b)
+{
+ int x = 1;
+ while(b-- > 0)
+ x *= a;
+
+ return x;
+}
+
+// log10(x) if x is a nonnegative power of 10, -1 otherwise
+static int GetPowerOf10(int x)
+{
+ int power = 0;
+ while((x % 10) == 0)
+ {
+ power++;
+ x /= 10;
+ }
+
+ return (x == 1) ? power : -1;
+}
+
+static void FormatRational(TCHAR *buffer,int nChars,int num,int denom)
+{
+ int d10 = GetPowerOf10(denom);
+ if(d10 != -1) // decimal power
+ _sntprintf(buffer,nChars,"%d.%0*d",num/denom,d10,num%denom);
+ else // general rational
+ _sntprintf(buffer,nChars,"%d/%d",num,denom);
+
+ buffer[nChars-1] = 0;
+}
+
+static bool ParsePositiveRational(const TCHAR *buffer,int &num,int &denom)
+{
+ TCHAR *end;
+ long intPart = _tcstol(buffer,&end,10);
+ if(intPart < 0 || end == buffer)
+ return false;
+
+ if(*end == 0)
+ {
+ num = intPart;
+ denom = 1;
+ return num > 0;
+ }
+ else if(*end == '.') // decimal notation
+ {
+ end++;
+ int digits = 0;
+ while(end[digits] >= '0' && end[digits] <= '9')
+ digits++;
+
+ if(!digits || end[digits] != 0) // invalid character in digit string
+ return false;
+
+ denom = IntPow(10,digits);
+ long fracPart = _tcstol(end,&end,10);
+ if(intPart > (LONG_MAX - fracPart) / denom) // overflow
+ return false;
+
+ num = intPart * denom + fracPart;
+ return true;
+ }
+ else if(*end == '/') // rational number
+ {
+ const TCHAR *rest = end + 1;
+ num = intPart;
+ denom = _tcstol(rest,&end,10);
+ return (denom > 0) && (end != rest) && *end == 0;
+ }
+ else // invalid character
+ return false;
+}
+
+static INT_PTR CALLBACK MainDialogProc(HWND hWndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ // center this window
+ RECT rcWork,rcDlg;
+ SystemParametersInfo(SPI_GETWORKAREA,0,&rcWork,0);
+ GetWindowRect(hWndDlg,&rcDlg);
+ SetWindowPos(hWndDlg,0,(rcWork.left+rcWork.right-rcDlg.right+rcDlg.left)/2,
+ (rcWork.top+rcWork.bottom-rcDlg.bottom+rcDlg.top)/2,-1,-1,SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+ // load settings from registry (or get default settings)
+ LoadSettingsFromRegistry();
+
+ // set gui values
+ TCHAR buffer[32];
+ FormatRational(buffer,32,Params.FrameRateNum,Params.FrameRateDenom);
+ //_stprintf(buffer,"%d.%02d",Params.FrameRate/100,Params.FrameRate%100);
+ SetDlgItemText(hWndDlg,IDC_FRAMERATE,buffer);
+
+ _stprintf(buffer,"%d.%02d",Params.FirstFrameTimeout/1000,(Params.FirstFrameTimeout/10)%100);
+ SetDlgItemText(hWndDlg,IDC_FIRSTFRAMETIMEOUT,buffer);
+
+ _stprintf(buffer,"%d.%02d",Params.FrameTimeout/1000,(Params.FrameTimeout/10)%100);
+ SetDlgItemText(hWndDlg,IDC_OTHERFRAMETIMEOUT,buffer);
+
+ SendDlgItemMessage(hWndDlg,IDC_ENCODER,CB_ADDSTRING,0,(LPARAM) ".BMP/.WAV writer");
+ SendDlgItemMessage(hWndDlg,IDC_ENCODER,CB_ADDSTRING,0,(LPARAM) ".AVI (VfW, segmented)");
+ SendDlgItemMessage(hWndDlg,IDC_ENCODER,CB_ADDSTRING,0,(LPARAM) ".AVI (DirectShow, *unstable*)");
+ SendDlgItemMessage(hWndDlg,IDC_ENCODER,CB_SETCURSEL,Params.Encoder - 1,0);
+
+ EnableDlgItem(hWndDlg,IDC_VIDEOCODEC,Params.Encoder != BMPEncoder);
+ EnableDlgItem(hWndDlg,IDC_VCPICK,Params.Encoder != BMPEncoder);
+
+ if(IsWow64())
+ {
+ CheckDlgButton(hWndDlg,IDC_NEWINTERCEPT,BST_CHECKED);
+ EnableDlgItem(hWndDlg,IDC_NEWINTERCEPT,FALSE);
+ }
+ else
+ CheckDlgButton(hWndDlg,IDC_NEWINTERCEPT,Params.NewIntercept ? BST_CHECKED : BST_UNCHECKED);
+
+ if(Params.EnableAutoSkip)
+ CheckDlgButton(hWndDlg,IDC_AUTOSKIP,BST_CHECKED);
+ else
+ {
+ EnableDlgItem(hWndDlg,IDC_FIRSTFRAMETIMEOUT,FALSE);
+ EnableDlgItem(hWndDlg,IDC_OTHERFRAMETIMEOUT,FALSE);
+ }
+
+ CheckDlgButton(hWndDlg,IDC_FAIRLIGHTHACK,Params.FairlightHack ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hWndDlg,IDC_ENCODERTHREAD,Params.UseEncoderThread ? BST_CHECKED : BST_UNCHECKED);
+
+ HIC codec = ICOpen(ICTYPE_VIDEO,Params.VideoCodec,ICMODE_QUERY);
+ SetVideoCodecInfo(hWndDlg,codec);
+ ICClose(codec);
+
+ // gui stuff not read from registry
+ CheckDlgButton(hWndDlg,IDC_VCAPTURE,BST_CHECKED);
+ CheckDlgButton(hWndDlg,IDC_ACAPTURE,BST_CHECKED);
+ CheckDlgButton(hWndDlg,IDC_SLEEPLAST,BST_CHECKED);
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case IDCANCEL:
+ EndDialog(hWndDlg,0);
+ return TRUE;
+
+ case IDOK:
+ {
+ TCHAR frameRateStr[64];
+ TCHAR firstFrameTimeout[64];
+ TCHAR otherFrameTimeout[64];
+
+ Params.VersionTag = PARAMVERSION;
+
+ // get values
+ GetDlgItemText(hWndDlg,IDC_DEMO,ExeName,_MAX_PATH);
+ GetDlgItemText(hWndDlg,IDC_ARGUMENTS,Arguments,MAX_ARGS);
+ GetDlgItemText(hWndDlg,IDC_TARGET,Params.FileName,_MAX_PATH);
+ GetDlgItemText(hWndDlg,IDC_FRAMERATE,frameRateStr,sizeof(frameRateStr)/sizeof(*frameRateStr));
+ GetDlgItemText(hWndDlg,IDC_FIRSTFRAMETIMEOUT,firstFrameTimeout,sizeof(firstFrameTimeout)/sizeof(*firstFrameTimeout));
+ GetDlgItemText(hWndDlg,IDC_OTHERFRAMETIMEOUT,otherFrameTimeout,sizeof(otherFrameTimeout)/sizeof(*otherFrameTimeout));
+
+ BOOL autoSkip = IsDlgButtonChecked(hWndDlg,IDC_AUTOSKIP) == BST_CHECKED;
+
+ // validate everything and fill out parameter block
+ HANDLE hFile = CreateFile(ExeName,GENERIC_READ,0,0,OPEN_EXISTING,0,0);
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ MessageBox(hWndDlg,_T("You need to specify a valid executable in the 'demo' field."),
+ _T(".kkapture"),MB_ICONERROR|MB_OK);
+ return TRUE;
+ }
+ else
+ CloseHandle(hFile);
+
+ int frameRateNum,frameRateDenom;
+ if(!ParsePositiveRational(frameRateStr,frameRateNum,frameRateDenom)
+ || frameRateNum < 0 || frameRateNum / frameRateDenom >= 1000)
+ {
+ MessageBox(hWndDlg,_T("Please enter a valid frame rate between 0 and 1000 "
+ "(either as decimal or rational)."),_T(".kkapture"),MB_ICONERROR|MB_OK);
+ return TRUE;
+ }
+ /*double frameRate = atof(frameRateStr);
+ if(frameRate <= 0.0 || frameRate >= 1000.0)
+ {
+ MessageBox(hWndDlg,_T("Please enter a valid frame rate."),
+ _T(".kkapture"),MB_ICONERROR|MB_OK);
+ return TRUE;
+ }*/
+
+ if(autoSkip)
+ {
+ double fft = atof(firstFrameTimeout);
+ if(fft <= 0.0 || fft >= 3600.0)
+ {
+ MessageBox(hWndDlg,_T("'Initial frame timeout' must be between 0 and 3600 seconds."),
+ _T(".kkapture"),MB_ICONERROR|MB_OK);
+ return TRUE;
+ }
+
+ double oft = atof(otherFrameTimeout);
+ if(oft <= 0.0 || oft >= 3600.0)
+ {
+ MessageBox(hWndDlg,_T("'Other frames timeout' must be between 0 and 3600 seconds."),
+ _T(".kkapture"),MB_ICONERROR|MB_OK);
+ return TRUE;
+ }
+
+ Params.FirstFrameTimeout = DWORD(fft*1000);
+ Params.FrameTimeout = DWORD(oft*1000);
+ }
+
+ Params.FrameRateNum = frameRateNum;
+ Params.FrameRateDenom = frameRateDenom;
+ //Params.FrameRate = int(frameRate * 100);
+ Params.Encoder = (EncoderType) (1 + SendDlgItemMessage(hWndDlg,IDC_ENCODER,CB_GETCURSEL,0,0));
+
+ Params.CaptureVideo = IsDlgButtonChecked(hWndDlg,IDC_VCAPTURE) == BST_CHECKED;
+ Params.CaptureAudio = IsDlgButtonChecked(hWndDlg,IDC_ACAPTURE) == BST_CHECKED;
+ Params.SoundMaxSkip = IsDlgButtonChecked(hWndDlg,IDC_SKIPSILENCE) == BST_CHECKED ? 10 : 0;
+ Params.MakeSleepsLastOneFrame = IsDlgButtonChecked(hWndDlg,IDC_SLEEPLAST) == BST_CHECKED;
+ Params.SleepTimeout = 2500; // yeah, this should be configurable
+ Params.NewIntercept = IsDlgButtonChecked(hWndDlg,IDC_NEWINTERCEPT) == BST_CHECKED;
+ Params.FairlightHack = IsDlgButtonChecked(hWndDlg,IDC_FAIRLIGHTHACK) == BST_CHECKED;
+ Params.EnableAutoSkip = autoSkip;
+ Params.PowerDownAfterwards = IsDlgButtonChecked(hWndDlg,IDC_POWERDOWN) == BST_CHECKED;
+ Params.UseEncoderThread = IsDlgButtonChecked(hWndDlg,IDC_ENCODERTHREAD) == BST_CHECKED;
+
+ // save settings for next time
+ SaveSettingsToRegistry();
+
+ // that's it.
+ EndDialog(hWndDlg,1);
+ }
+ return TRUE;
+
+ case IDC_BDEMO:
+ {
+ OPENFILENAME ofn;
+ TCHAR filename[_MAX_PATH];
+
+ GetDlgItemText(hWndDlg,IDC_DEMO,filename,_MAX_PATH);
+
+ ZeroMemory(&ofn,sizeof(ofn));
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = hWndDlg;
+ ofn.hInstance = GetModuleHandle(0);
+ ofn.lpstrFilter = _T("Executable files (*.exe)\0*.exe\0");
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFile = filename;
+ ofn.nMaxFile = sizeof(filename)/sizeof(*filename);
+ ofn.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
+ if(GetOpenFileName(&ofn))
+ {
+ SetDlgItemText(hWndDlg,IDC_DEMO,ofn.lpstrFile);
+
+ // also set demo .avi file name if not yet set
+ TCHAR drive[_MAX_DRIVE],dir[_MAX_DIR],fname[_MAX_FNAME],ext[_MAX_EXT],path[_MAX_PATH];
+ int nChars = GetDlgItemText(hWndDlg,IDC_TARGET,fname,_MAX_FNAME);
+ if(!nChars)
+ {
+ _tsplitpath(ofn.lpstrFile,drive,dir,fname,ext);
+ _tmakepath(path,drive,dir,fname,_T(".avi"));
+ SetDlgItemText(hWndDlg,IDC_TARGET,path);
+ }
+ }
+ }
+ return TRUE;
+
+ case IDC_BTARGET:
+ {
+ OPENFILENAME ofn;
+ TCHAR filename[_MAX_PATH];
+
+ GetDlgItemText(hWndDlg,IDC_TARGET,filename,_MAX_PATH);
+
+ ZeroMemory(&ofn,sizeof(ofn));
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = hWndDlg;
+ ofn.hInstance = GetModuleHandle(0);
+ ofn.lpstrFilter = _T("AVI files (*.avi)\0*.avi\0");
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFile = filename;
+ ofn.nMaxFile = sizeof(filename)/sizeof(*filename);
+ ofn.Flags = OFN_HIDEREADONLY|OFN_PATHMUSTEXIST|OFN_OVERWRITEPROMPT;
+ if(GetSaveFileName(&ofn))
+ SetDlgItemText(hWndDlg,IDC_TARGET,ofn.lpstrFile);
+ }
+ return TRUE;
+
+ case IDC_ENCODER:
+ if(HIWORD(wParam) == CBN_SELCHANGE)
+ {
+ LRESULT selection = SendDlgItemMessage(hWndDlg,IDC_ENCODER,CB_GETCURSEL,0,0);
+ BOOL allowCodecSelect = selection != 0;
+
+ EnableDlgItem(hWndDlg,IDC_VIDEOCODEC,allowCodecSelect);
+ EnableDlgItem(hWndDlg,IDC_VCPICK,allowCodecSelect);
+ }
+ return TRUE;
+
+ case IDC_VCPICK:
+ {
+ COMPVARS cv;
+ ZeroMemory(&cv,sizeof(cv));
+
+ cv.cbSize = sizeof(cv);
+ cv.dwFlags = ICMF_COMPVARS_VALID;
+ cv.fccType = ICTYPE_VIDEO;
+ cv.fccHandler = Params.VideoCodec;
+ cv.lQ = Params.VideoQuality;
+ if(ICCompressorChoose(hWndDlg,0,0,0,&cv,0))
+ {
+ Params.VideoCodec = cv.fccHandler;
+ Params.VideoQuality = cv.lQ;
+ SetVideoCodecInfo(hWndDlg,cv.hic);
+
+ if(cv.cbState <= sizeof(Params.CodecSpecificData))
+ {
+ Params.CodecDataSize = cv.cbState;
+ memcpy(Params.CodecSpecificData, cv.lpState, cv.cbState);
+ }
+ else
+ Params.CodecDataSize = 0;
+
+ ICCompressorFree(&cv);
+ }
+ }
+ return TRUE;
+
+ case IDC_AUTOSKIP:
+ {
+ BOOL enable = IsDlgButtonChecked(hWndDlg,IDC_AUTOSKIP) == BST_CHECKED;
+ EnableDlgItem(hWndDlg,IDC_FIRSTFRAMETIMEOUT,enable);
+ EnableDlgItem(hWndDlg,IDC_OTHERFRAMETIMEOUT,enable);
+ }
+ return TRUE;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+// ----
+
+static DWORD GetEntryPoint(TCHAR *fileName)
+{
+ IMAGE_DOS_HEADER doshdr;
+ IMAGE_NT_HEADERS32 nthdr;
+ DWORD read;
+
+ HANDLE hFile = CreateFile(fileName,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
+ if(hFile == INVALID_HANDLE_VALUE)
+ return 0;
+
+ if(!ReadFile(hFile,&doshdr,sizeof(doshdr),&read,0) || read != sizeof(doshdr))
+ {
+ CloseHandle(hFile);
+ return 0;
+ }
+
+ if(doshdr.e_magic != IMAGE_DOS_SIGNATURE)
+ {
+ CloseHandle(hFile);
+ return 0;
+ }
+
+ if(SetFilePointer(hFile,doshdr.e_lfanew,0,FILE_BEGIN) == INVALID_SET_FILE_POINTER)
+ {
+ CloseHandle(hFile);
+ return 0;
+ }
+
+ if(!ReadFile(hFile,&nthdr,sizeof(nthdr),&read,0) || read != sizeof(nthdr))
+ {
+ CloseHandle(hFile);
+ return 0;
+ }
+
+ CloseHandle(hFile);
+
+ if(nthdr.Signature != IMAGE_NT_SIGNATURE
+ || nthdr.FileHeader.Machine != IMAGE_FILE_MACHINE_I386
+ /*|| nthdr.FileHeader.SizeOfOptionalHeader != IMAGE_SIZEOF_NT_OPTIONAL32_HEADER*/
+ || nthdr.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC
+ || !nthdr.OptionalHeader.AddressOfEntryPoint)
+ return 0;
+
+ return nthdr.OptionalHeader.ImageBase + nthdr.OptionalHeader.AddressOfEntryPoint;
+}
+
+static bool PrepareInstrumentation(HANDLE hProcess,BYTE *workArea,TCHAR *dllName,DWORD entryPointAddr)
+{
+ BYTE origCode[24];
+ struct bufferType
+ {
+ BYTE code[2048]; // code must be first field
+ BYTE data[2048];
+ } buffer;
+ BYTE jumpCode[5];
+
+ DWORD offsWorkArea = (DWORD) workArea;
+ BYTE *code = buffer.code;
+ BYTE *loadLibrary = (BYTE *) GetProcAddress(GetModuleHandle(_T("kernel32.dll")),"LoadLibraryA");
+ BYTE *entryPoint = (BYTE *) entryPointAddr;
+
+ // Read original startup code
+ if(!ReadProcessMemory(hProcess,entryPoint,origCode,sizeof(origCode),0))
+ return false;
+
+ // Generate Initialization hook
+ code = DetourGenPushad(code);
+ _tcscpy((TCHAR *) buffer.data,dllName);
+ code = DetourGenPush(code,offsWorkArea + offsetof(bufferType,data));
+ code = DetourGenCall(code,loadLibrary,workArea + (code - buffer.code));
+ code = DetourGenPopad(code);
+
+ // Check whether startup code begins with a call or jump
+ BYTE *sourcePtr = origCode;
+
+ if(sourcePtr[0] == 0xe8 || sourcePtr[0] == 0xe9) // Yes, we can jump/call there too
+ {
+ // Copy the opcode
+ *code++ = *sourcePtr++;
+
+ // Copy target address, compensating for offset
+ *((DWORD *) code) = *((DWORD *) sourcePtr)
+ + entryPoint + (sourcePtr - origCode) + 4 // add back original position
+ - (workArea + (code - buffer.code) + 4); // subtract new position
+
+ code += 4;
+ sourcePtr += 4;
+ }
+ else // No, we have to copy instructions
+ {
+ // Copy over first few bytes from startup code
+ while((sourcePtr - origCode) < sizeof(jumpCode))
+ sourcePtr = DetourCopyInstruction(code + (sourcePtr - origCode),sourcePtr,0);
+
+ code += sourcePtr - origCode;
+ }
+
+ // Jump to rest
+ code = DetourGenJmp(code,entryPoint + (sourcePtr - origCode),workArea + (code - buffer.code));
+
+ // And prepare jump to init hook from original entry point
+ DetourGenJmp(jumpCode,workArea,entryPoint);
+
+ // Finally, write everything into process memory
+ DWORD oldProtect;
+
+ if(!VirtualProtectEx(hProcess,workArea,sizeof(buffer),PAGE_EXECUTE_READWRITE,&oldProtect))
+ return false;
+
+ if(!WriteProcessMemory(hProcess,workArea,&buffer,sizeof(buffer),0))
+ return false;
+
+ if(!VirtualProtectEx(hProcess,entryPoint,sizeof(jumpCode),PAGE_EXECUTE_READWRITE,&oldProtect))
+ return false;
+
+ if(!WriteProcessMemory(hProcess,entryPoint,jumpCode,sizeof(jumpCode),0))
+ return false;
+
+ if(!FlushInstructionCache(hProcess,entryPoint,sizeof(jumpCode)))
+ return false;
+
+ return true;
+}
+
+// ----
+
+int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
+{
+ if(DialogBox(hInstance,MAKEINTRESOURCE(IDD_MAINWIN),0,MainDialogProc))
+ {
+ Params.IsDebugged = IsDebuggerPresent() != 0;
+
+ // create file mapping object with parameter block
+ HANDLE hParamMapping = CreateFileMapping(INVALID_HANDLE_VALUE,0,PAGE_READWRITE,
+ 0,sizeof(ParameterBlock),_T("__kkapture_parameter_block"));
+
+ // copy parameters
+ LPVOID ParamBlock = MapViewOfFile(hParamMapping,FILE_MAP_WRITE,0,0,sizeof(ParameterBlock));
+ if(ParamBlock)
+ {
+ memcpy(ParamBlock,&Params,sizeof(ParameterBlock));
+ UnmapViewOfFile(ParamBlock);
+ }
+
+ // prepare command line
+ TCHAR commandLine[_MAX_PATH+MAX_ARGS+4];
+ _tcscpy(commandLine,_T("\""));
+ _tcscat(commandLine,ExeName);
+ _tcscat(commandLine,_T("\" "));
+ _tcscat(commandLine,Arguments);
+
+ // determine kkapture dll path
+ TCHAR mypath[_MAX_PATH],dllpath[_MAX_PATH],exepath[_MAX_PATH];
+ TCHAR drive[_MAX_DRIVE],dir[_MAX_DIR],fname[_MAX_FNAME],ext[_MAX_EXT];
+ GetModuleFileName(0,mypath,_MAX_PATH);
+ _tsplitpath(mypath,drive,dir,fname,ext);
+ _tmakepath(dllpath,drive,dir,"kkapturedll","dll");
+
+ // create process
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ ZeroMemory(&si,sizeof(si));
+ ZeroMemory(&pi,sizeof(pi));
+ si.cb = sizeof(si);
+
+ _tsplitpath(ExeName,drive,dir,fname,ext);
+ _tmakepath(exepath,drive,dir,_T(""),_T(""));
+ SetCurrentDirectory(exepath);
+
+ if(!Params.NewIntercept)
+ {
+ if(DetourCreateProcessWithDll(ExeName,commandLine,0,0,TRUE,
+ CREATE_DEFAULT_ERROR_MODE,0,0,&si,&pi,dllpath,0))
+ {
+ // wait for target process to finish
+ WaitForSingleObject(pi.hProcess,INFINITE);
+ CloseHandle(pi.hProcess);
+ }
+ else
+ MessageBox(0,_T("Couldn't execute target process"),
+ _T(".kkapture"),MB_ICONERROR|MB_OK);
+ }
+ else
+ {
+ DWORD entryPoint = GetEntryPoint(ExeName);
+ if(!entryPoint)
+ MessageBox(0,_T("Not a supported executable format."),
+ _T(".kkapture"),MB_ICONERROR|MB_OK);
+ else if(CreateProcess(ExeName,commandLine,0,0,TRUE,
+ CREATE_DEFAULT_ERROR_MODE|CREATE_SUSPENDED,0,0,&si,&pi))
+ {
+ // get some memory in the target processes' space for us to work with
+ void *workMem = VirtualAllocEx(pi.hProcess,0,4096,MEM_COMMIT,
+ PAGE_EXECUTE_READWRITE);
+
+ // do all the mean initialization faking code here
+ if(PrepareInstrumentation(pi.hProcess,(BYTE *) workMem,dllpath,entryPoint))
+ {
+ // we're done with our evil machinations, so rock on
+ ResumeThread(pi.hThread);
+
+ // wait for target process to finish
+ WaitForSingleObject(pi.hProcess,INFINITE);
+ CloseHandle(pi.hProcess);
+ }
+ else
+ MessageBox(0,_T("Startup instrumentation failed"),
+ _T(".kkapture"),MB_ICONERROR|MB_OK);
+ }
+ else
+ MessageBox(0,_T("Couldn't execute target process"),
+ _T(".kkapture"),MB_ICONERROR|MB_OK);
+ }
+
+ // cleanup
+ CloseHandle(hParamMapping);
+ }
+}
175 kkapture/kkapture.rc
@@ -0,0 +1,175 @@
+/* kkapture: intrusive demo video capturing.
+ * Copyright (c) 2005-2006 Fabian "ryg/farbrausch" Giesen.
+ *
+ * This program is free software; you can redistribute and/or modify it under
+ * the terms of the Artistic License, Version 2.0beta5, or (at your opinion)
+ * any later version; all distributions of this program should contain this
+ * license in a file named "LICENSE.txt".
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT UNLESS REQUIRED BY
+ * LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER OR CONTRIBUTOR
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "windows.h"
+
+#define IDC_STATIC (-1) // all static controls
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Neutral (Sys. Default) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD)
+#ifdef _WIN32
+LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_MAINWIN DIALOGEX 0, 0, 258, 251
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION |
+ WS_SYSMENU
+CAPTION ".kkapture 0.08 beta"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "kkapture!",IDOK,149,230,50,14
+ PUSHBUTTON "Exit",IDCANCEL,201,230,50,14
+ EDITTEXT IDC_DEMO,51,7,146,13,ES_AUTOHSCROLL
+ LTEXT "Demo:",IDC_STATIC,9,9,22,8
+ PUSHBUTTON "Browse...",IDC_BDEMO,201,7,50,13
+ EDITTEXT IDC_ARGUMENTS,51,23,146,13,ES_AUTOHSCROLL
+ LTEXT "Arguments:",IDC_STATIC,9,25,38,8
+ EDITTEXT IDC_TARGET,51,39,146,13,ES_AUTOHSCROLL
+ LTEXT "Target:",IDC_STATIC,9,41,25,8
+ PUSHBUTTON "Browse...",IDC_BTARGET,201,39,50,13
+ LTEXT "Frame rate:",IDC_STATIC,10,57,39,8
+ EDITTEXT IDC_FRAMERATE,51,55,31,13,ES_AUTOHSCROLL
+ LTEXT "Encoder:",IDC_STATIC,95,57,28,8
+ COMBOBOX IDC_ENCODER,130,55,121,100,CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_TABSTOP
+ GROUPBOX "AVI Encoding Options",IDC_STATIC,7,73,244,26
+ LTEXT "Video Codec:",IDC_VIDEOCODEC,14,84,176,8
+ PUSHBUTTON "Pick...",IDC_VCPICK,214,82,30,12
+ GROUPBOX "Tweaking",IDC_STATIC,7,103,244,61
+ CONTROL "Capture Video",IDC_VCAPTURE,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,14,114,61,10
+ CONTROL "Capture Audio",IDC_ACAPTURE,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,14,126,62,10
+ CONTROL "Skip digital silence at start",IDC_SKIPSILENCE,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,121,114,99,10
+ CONTROL "Make Sleep() last one frame",IDC_SLEEPLAST,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,121,126,105,10
+ CONTROL "New startup interception",IDC_NEWINTERCEPT,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,14,138,95,10
+ CONTROL "BASS latency (aka Fairlight) hack",IDC_FAIRLIGHTHACK,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,121,138,120,10
+ CONTROL "Power down on completion",IDC_POWERDOWN,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,14,150,120,10
+ CONTROL "Separate encoder thread (BETA)",IDC_ENCODERTHREAD,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,121,150,120,10
+ GROUPBOX "Auto-skip",IDC_STATIC,7,167,244,57
+ CONTROL "Enable automatic frameskip on timeout",IDC_AUTOSKIP,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,178,150,10
+ LTEXT "Initial frame timeout (seconds):",IDC_STATIC,
+ 14,192,140,8
+ EDITTEXT IDC_FIRSTFRAMETIMEOUT,130,190,31,13,ES_AUTOHSCROLL
+ LTEXT "Other frames timeout (seconds):",IDC_STATIC,
+ 14,208,140,8
+ EDITTEXT IDC_OTHERFRAMETIMEOUT,130,206,31,13,ES_AUTOHSCROLL
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_MAINWIN, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 251
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 160
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // Neutral (Sys. Default) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
238 kkapture/kkapture.vcproj
@@ -0,0 +1,238 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="kkapture"
+ ProjectGUID="{DBA35513-DE77-4FE9-8B71-C483946E76FF}"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="2"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="kernel32.lib user32.lib gdi32.lib advapi32.lib comdlg32.lib"
+ OutputFile="$(OutDir)/kkapture.exe"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="..\lib"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/kkapture.pdb"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/kkapture.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ BaseAddress="0x410000"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\kkapture.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\stdafx.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\stdafx.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath=".\kkapture.rc"
+ >
+ </File>
+ </Filter>
+ <File
+ RelativePath="..\changelog.txt"
+ >
+ </File>
+ <File
+ RelativePath="..\CONTRIBUTORS.txt"
+ >
+ </File>
+ <File
+ RelativePath="..\LICENSE.txt"
+ >
+ </File>
+ <File
+ RelativePath=".\resource.h"
+ >
+ </File>
+ <File
+ RelativePath="..\working_demos.txt"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
65 kkapture/kkapture.vcproj.RYG.fg.user
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioUserFile
+ ProjectType="Visual C++"
+ Version="8,00"
+ ShowAllFiles="false"
+ >
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ >
+ <DebugSettings
+ Command="$(TargetPath)"
+ WorkingDirectory=""
+ CommandArguments=""
+ Attach="false"
+ DebuggerType="3"
+ Remote="1"
+ RemoteMachine="RYG"
+ RemoteCommand=""
+ HttpUrl=""
+ PDBPath=""
+ SQLDebugging=""
+ Environment=""
+ EnvironmentMerge="true"
+ DebuggerFlavor=""
+ MPIRunCommand=""
+ MPIRunArguments=""
+ MPIRunWorkingDirectory=""
+ ApplicationCommand=""
+ ApplicationArguments=""
+ ShimCommand=""
+ MPIAcceptMode=""
+ MPIAcceptFilter=""
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ >
+ <DebugSettings
+ Command="$(TargetPath)"
+ WorkingDirectory=""
+ CommandArguments=""
+ Attach="false"
+ DebuggerType="3"
+ Remote="1"
+ RemoteMachine="RYG"
+ RemoteCommand=""
+ HttpUrl=""
+ PDBPath=""
+ SQLDebugging=""
+ Environment=""
+ EnvironmentMerge="true"
+ DebuggerFlavor=""
+ MPIRunCommand=""
+ MPIRunArguments=""
+ MPIRunWorkingDirectory=""
+ ApplicationCommand=""
+ ApplicationArguments=""
+ ShimCommand=""
+ MPIAcceptMode=""
+ MPIAcceptFilter=""
+ />
+ </Configuration>
+ </Configurations>
+</VisualStudioUserFile>
36 kkapture/resource.h
@@ -0,0 +1,36 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by kkapture.rc
+//
+#define IDD_MAINWIN 101
+#define IDC_DEMO 1001
+#define IDC_BDEMO 1002
+#define IDC_ARGUMENTS 1003
+#define IDC_TARGET 1004
+#define IDC_BTARGET 1005
+#define IDC_FRAMERATE 1008
+#define IDC_ENCODER 1010
+#define IDC_VIDEOCODEC 1014
+#define IDC_VCPICK 1015
+#define IDC_VCAPTURE 1016
+#define IDC_ACAPTURE 1017
+#define IDC_SKIPSILENCE 1018
+#define IDC_SLEEPLAST 1019
+#define IDC_NEWINTERCEPT 1020
+#define IDC_AUTOSKIP 1021
+#define IDC_FIRSTFRAMETIMEOUT 1022
+#define IDC_OTHERFRAMETIMEOUT 1023
+#define IDC_FAIRLIGHTHACK 1024
+#define IDC_POWERDOWN 1025
+#define IDC_ENCODERTHREAD 1026
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 103
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1022
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
23 kkapture/stdafx.cpp
@@ -0,0 +1,23 @@
+/* kkapture: intrusive demo video capturing.
+ * Copyright (c) 2005-2006 Fabian "ryg/farbrausch" Giesen.
+ *
+ * This program is free software; you can redistribute and/or modify it under
+ * the terms of the Artistic License, Version 2.0beta5, or (at your opinion)
+ * any later version; all distributions of this program should contain this
+ * license in a file named "LICENSE.txt".
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT UNLESS REQUIRED BY
+ * LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER OR CONTRIBUTOR
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "stdafx.h"
29 kkapture/stdafx.h
@@ -0,0 +1,29 @@
+/* kkapture: intrusive demo video capturing.
+ * Copyright (c) 2005-2006 Fabian "ryg/farbrausch" Giesen.
+ *
+ * This program is free software; you can redistribute and/or modify it under
+ * the terms of the Artistic License, Version 2.0beta5, or (at your opinion)
+ * any later version; all distributions of this program should contain this
+ * license in a file named "LICENSE.txt".
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT UNLESS REQUIRED BY
+ * LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER OR CONTRIBUTOR
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#define _WIN32_WINNT 0x0400
+#include <windows.h>
+#include <vfw.h>
+#define DETOURS_INTERNAL
+#include "detours.h"
288 kkapturedll/audio_resample.cpp
@@ -0,0 +1,288 @@
+/* kkapture: intrusive demo video capturing.
+ * Copyright (c) 2005-2006 Fabian "ryg/farbrausch" Giesen.
+ *
+ * This program is free software; you can redistribute and/or modify it under
+ * the terms of the Artistic License, Version 2.0beta5, or (at your opinion)
+ * any later version; all distributions of this program should contain this
+ * license in a file named "LICENSE.txt".
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT UNLESS REQUIRED BY
+ * LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER OR CONTRIBUTOR
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// note this is by no means a general audio resampler, it's only meant
+// for the purposes of kkapture... so no really good resampling routines,
+// only cubic spline (catmull-rom) interpolation.
+//
+// i'll gladly take any improved resampling code provided it uses the same
+// (or a similar) interface.
+
+#include "stdafx.h"
+#include "audio_resample.h"
+
+// ----
+
+// evaluates Catmull-Rom spline with x_0,x_1,x_2,x_3 as given at time
+// t (in [0,1]) - note index shift, x_0 should be x_-1.
+static float catmullRom(float x0,float x1,float x2,float x3,float t)
+{
+ float a = 1.5f * (x1 - x2) + 0.5f * (x3 - x0);
+ float b = x0 - 2.5f * x1 + 2.0f * x2 - 0.5f * x3;
+ float c = 0.5f * (x2 - x0);
+ float d = x1;
+
+ return ((a*t+b)*t+c)*t+d;
+}
+
+// clamp to 16bit signed range
+static int clamp(int x)
+{
+ return (x < -32768) ? -32768 : (x > 32767) ? 32767 : x;
+}
+
+// read 8-bit unsigned samples
+float getSample(unsigned char *in)
+{
+ return (*in - 128.0f) * 256.0f;
+}
+
+// read 16-bit signed samples
+float getSample(short *in)
+{
+ return *in;
+}
+
+// ----
+
+// resampling main function for 16bit input data
+template<class T> int AudioResampler::ResampleChan(T *in,short *out,int nInSamples,float *chanBuf)
+{
+ int outSamples = 0;
+ float x0,x1,x2,x3;
+
+ // get current state
+ x0 = chanBuf[0];
+ x1 = chanBuf[1];
+ x2 = chanBuf[2];
+ x3 = chanBuf[3];
+
+ // resample
+ while(nInSamples)
+ {
+ if(tFrac >= OutRate) // we need to advance by one input sample
+ {
+ x0 = x1;
+ x1 = x2;
+ x2 = x3;
+ x3 = getSample(in);
+ in += InChans;
+ tFrac -= OutRate;
+ nInSamples--;
+ }
+ else // generate output samples
+ {
+ // evaluate
+ *out = clamp((int) catmullRom(x0,x1,x2,x3,tFrac * invScale));
+ out += 2;
+ outSamples++;
+
+ // advance input time
+ tFrac += dStep;
+ }
+ }
+
+ // store current state
+ chanBuf[0] = x0;
+ chanBuf[1] = x1;
+ chanBuf[2] = x2;
+ chanBuf[3] = x3;
+
+ return outSamples;
+}
+
+// initialize resampling
+template<class T> int AudioResampler::ResampleInit(T *in,int nInSamples,float *chanBuf)
+{
+ int processed = 0;
+
+ if(InitSamples == 0 && nInSamples > processed)
+ {
+ chanBuf[1] = getSample(in);
+ in += InChans;
+ processed++;
+ InitSamples++;
+ }
+
+ if(InitSamples == 1 && nInSamples > processed)
+ {
+ chanBuf[2] = getSample(in);
+ chanBuf[0] = 2*chanBuf[1] - chanBuf[2]; // symmetric extension
+ in += InChans;
+ processed++;
+ InitSamples++;
+ }
+
+ if(InitSamples == 2 && nInSamples > processed)
+ {
+ chanBuf[3] = getSample(in);
+ in += InChans;
+ processed++;
+ InitSamples++;
+ }
+
+ return processed;
+}
+
+// block processing
+template<class T> int AudioResampler::ResampleBlock(T *in,short *out,int nInSamples)
+{
+ int count;
+
+ // if we're not completely initialized, continue
+ if(InitSamples < 3)
+ {
+ count = ResampleInit(in,nInSamples,ChannelBuf[0]);
+ if(InChans == 2) // stereo
+ ResampleInit(in+1,nInSamples,ChannelBuf[1]);
+
+ in += count * InChans;
+ nInSamples -= count;
+ }
+
+ // process the sample block
+ count = 0;
+
+ if(nInSamples)
+ {
+ int tOrig = tFrac;
+
+ count = ResampleChan(in,out,nInSamples,ChannelBuf[0]);
+ if(InChans == 2) // stereo input
+ {
+ tFrac = tOrig;
+ ResampleChan(in+1,out+1,nInSamples,ChannelBuf[1]);
+ }
+ else // plain channel doubling
+ {
+ for(int i=0;i<count*2;i+=2)
+ out[i+1] = out[i];
+ }
+ }
+
+ return count;
+}
+
+// ----
+
+AudioResampler::AudioResampler()
+{
+ Initialized = false;
+}
+
+AudioResampler::~AudioResampler()
+{
+}
+
+bool AudioResampler::Init(const tWAVEFORMATEX *srcFormat,const tWAVEFORMATEX *dstFormat)
+{
+ // some sanity checks: first of all, we only support PCM formats
+ if(srcFormat->wFormatTag != WAVE_FORMAT_PCM || dstFormat->wFormatTag != WAVE_FORMAT_PCM)
+ return false;
+
+ // only 8 or 16 bit input and only 16 bit output
+ if((srcFormat->wBitsPerSample != 8 && srcFormat->wBitsPerSample != 16)
+ || dstFormat->wBitsPerSample != 16)
+ return false;
+
+ // only mono or stereo input and stereo output
+ if((srcFormat->nChannels != 1 && srcFormat->nChannels != 2)
+ || dstFormat->nChannels != 2)
+ return false;
+
+ // reasonable sample rate bounds
+ if(srcFormat->nSamplesPerSec < 4000 || srcFormat->nSamplesPerSec > 48000
+ || dstFormat->nSamplesPerSec < 4000 || dstFormat->nSamplesPerSec > 48000)
+ return false;
+
+ // plus some consistency checks
+ if(srcFormat->nBlockAlign != srcFormat->nChannels * srcFormat->wBitsPerSample / 8)
+ return false;
+
+ if(dstFormat->nBlockAlign != dstFormat->nChannels * dstFormat->wBitsPerSample / 8)
+ return false;
+
+ if(srcFormat->cbSize != 0 || dstFormat->cbSize != 0)
+ return false;
+
+ // everything seems to be ok, set up conversion...
+ Initialized = true;
+ In8Bit = srcFormat->wBitsPerSample == 8;
+ InChans = srcFormat->nChannels;
+ InRate = srcFormat->nSamplesPerSec;
+ OutRate = dstFormat->nSamplesPerSec;
+
+ Identical = !In8Bit && InChans == 2 && InRate == OutRate;
+ if(!Identical)
+ printLog("audio_resample: converting from %d Hz %d bits %s to %d Hz %d bits %s\n",
+ InRate,In8Bit ? 8 : 16,InChans == 1 ? "mono" : "stereo",
+ OutRate,16,"stereo");
+
+ // setup resampling state
+ tFrac = 0;
+ dStep = InRate;
+ invScale = 1.0f / OutRate;
+ InitSamples = 0;
+
+ // all ok.
+ return true;
+}
+
+// upper bound for maximum number of output samples generated in one step
+int AudioResampler::MaxOutputSamples(int nInSamples) const
+{
+ // 3 additional input samples for last sample (catmull-rom tail),
+ // 1 for safety
+ return MulDiv(nInSamples+3+1,OutRate,InRate);
+}
+
+// main resampling function
+int AudioResampler::Resample(const void *src,short *out,int nInSamples,bool last)
+{
+ int count;
+ unsigned char zero[3*2*2]; // enough space for 3 16bit stereo samples
+
+ memset(zero,0,sizeof(zero));
+
+ // in identical resampling mode, just copy
+ if(Identical)
+ {
+ memcpy(out,src,nInSamples * 4);
+ return nInSamples;
+ }
+
+ // else we have some more work to do
+ if(In8Bit)
+ {
+ count = ResampleBlock((unsigned char *) src,out,nInSamples);
+ if(last)
+ count += ResampleBlock((unsigned char *) zero,out + count*2,3);
+ }
+ else
+ {
+ count = ResampleBlock((short *) src,out,nInSamples);
+ if(last)
+ count += ResampleBlock((short *) zero,out + count*2,3);
+ }
+
+ return count;
+}
59 kkapturedll/audio_resample.h
@@ -0,0 +1,59 @@
+/* kkapture: intrusive demo video capturing.
+ * Copyright (c) 2005-2006 Fabian "ryg/farbrausch" Giesen.
+ *
+ * This program is free software; you can redistribute and/or modify it under
+ * the terms of the Artistic License, Version 2.0beta5, or (at your opinion)
+ * any later version; all distributions of this program should contain this
+ * license in a file named "LICENSE.txt".
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT UNLESS REQUIRED BY
+ * LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER OR CONTRIBUTOR
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// note this is by no means a general audio resampler, it's only meant
+// for the purposes of kkapture... so no really good resampling routines,
+// only cubic spline (catmull-rom) interpolation
+
+#ifndef __AUDIO_RESAMPLE_H__
+#define __AUDIO_RESAMPLE_H__
+
+struct tWAVEFORMATEX;
+
+class AudioResampler
+{
+ bool Initialized;
+ bool In8Bit;
+ int InChans;
+ int InRate,OutRate;
+ bool Identical;
+
+ int tFrac;
+ int dStep;
+ float invScale;
+ int InitSamples;
+ float ChannelBuf[2][4];
+
+ template<class T> int ResampleChan(T *in,short *out,int nInSamples,float *chanBuf);
+ template<class T> int ResampleInit(T *in,int nInSamples,float *chanBuf);
+ template<class T> int ResampleBlock(T *in,short *out,int nInSamples);
+
+public:
+ AudioResampler();
+ ~AudioResampler();
+
+ bool Init(const tWAVEFORMATEX *srcFormat,const tWAVEFORMATEX *dstFormat);
+ int MaxOutputSamples(int nInSamples) const;
+ int Resample(const void *src,short *out,int nInSamples,bool last);
+};
+
+#endif
875 kkapturedll/avi_videoencoder_dshow.cpp
@@ -0,0 +1,875 @@
+/* kkapture: intrusive demo video capturing.
+ * Copyright (c) 2005-2006 Fabian "ryg/farbrausch" Giesen.
+ *
+ * This program is free software; you can redistribute and/or modify it under
+ * the terms of the Artistic License, Version 2.0beta5, or (at your opinion)
+ * any later version; all distributions of this program should contain this
+ * license in a file named "LICENSE.txt".
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT UNLESS REQUIRED BY
+ * LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER OR CONTRIBUTOR
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "stdafx.h"
+#include "avi_videoencoder_dshow.h"
+#include "video.h"
+#include "audio_resample.h"
+#include "videocapturetimer.h"
+
+#if USE_DSHOW_AVI_WRITER
+
+// okay, so why is this only enabled on a define?
+// why you would want to enable it:
+// - it allows kkapture to write avi files >2gb without indexing problems
+//
+// why you wouldn't want to enable it:
+// - it requires directshow and the directshow base classes, which is a
+// pretty big bunch of code most people don't have installed and
+// probably don't *want* to install.
+//
+// if you want it enabled, copy over the base classes header files into
+// the dshow_base/ subdirectory of the solution dir.
+//
+// you also need to make the stream base classes libraries (release/debug
+// builds) available as strmbase_r.lib and strmbase_d.lib in the same
+// directory.
+
+#pragma comment(lib,"vfw32.lib")
+
+#ifdef NDEBUG
+#pragma comment(lib,"../dshow_base/strmbase_r.lib")
+#else
+#pragma comment(lib,"../dshow_base/strmbase_d.lib")
+#endif
+
+// ---- dshow filters (aaargh!!)
+
+// {D4176A5A-B1CA-4c9e-A4A5-1BEDB9E281A8}
+static const GUID CLSID_VideoSource =
+{ 0xd4176a5a, 0xb1ca, 0x4c9e, { 0xa4, 0xa5, 0x1b, 0xed, 0xb9, 0xe2, 0x81, 0xa8 } };
+// {C8F8DD64-223D-4d2f-A240-FF437137CF1B}
+static const GUID CLSID_AudioSource =
+{ 0xc8f8dd64, 0x223d, 0x4d2f, { 0xa2, 0x40, 0xff, 0x43, 0x71, 0x37, 0xcf, 0x1b } };
+
+class VideoSourcePin : public CSourceStream
+{
+ enum { BufferCount = 4 };
+
+ CSource *Filter;
+ REFERENCE_TIME TimePerFrame;
+
+ unsigned char *Buffers[BufferCount];
+ CAMEvent BufferReadChange,BufferWriteChange;
+ int BufferReadPtr,BufferWritePtr;
+
+ int XRes,YRes;
+ int Frames;
+ bool Terminating;
+
+public:
+ VideoSourcePin(HRESULT *hr,CSource *filter,int fpsNum,int fpsDenom,int xRes,int yRes)
+ : CSourceStream(NAME("kkapture video source"),hr,filter,L"Out"),
+ Filter(filter),XRes(xRes),YRes(yRes)
+ {
+ // time per frame is in units of 100 nanoseconds
+ TimePerFrame = ULongMulDiv(10*1000*1000,fpsDenom,fpsNum);
+ Frames = 0;
+ Terminating = false;
+
+ // allocate buffers
+ for(int i=0;i<BufferCount;i++)
+ Buffers[i] = new unsigned char[xRes*yRes*3];
+
+ BufferReadPtr = 0;
+ BufferWritePtr = 0;
+ }
+
+ ~VideoSourcePin()
+ {
+ // free buffers
+ for(int i=0;i<BufferCount;i++)
+ delete[] Buffers[i];
+ }
+
+ HRESULT GetMediaType(CMediaType *mediaType)
+ {
+ CAutoLock autolock(Filter->pStateLock());
+
+ CheckPointer(mediaType,E_POINTER);
+
+ // allocate memory for the VIDEOINFOHEADER
+ VIDEOINFOHEADER *vi = (VIDEOINFOHEADER *) mediaType->AllocFormatBuffer(SIZE_PREHEADER + sizeof(BITMAPINFOHEADER));
+ if(!vi)
+ return E_OUTOFMEMORY;
+
+ ZeroMemory(vi,mediaType->cbFormat);
+ vi->AvgTimePerFrame = TimePerFrame;
+
+ // set stream format
+ vi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ vi->bmiHeader.biWidth = XRes;
+ vi->bmiHeader.biHeight = YRes;
+ vi->bmiHeader.biPlanes = 1;
+ vi->bmiHeader.biBitCount = 24;
+ vi->bmiHeader.biCompression = BI_RGB;
+ vi->bmiHeader.biSizeImage = XRes * YRes * 3;
+
+ // clear source&target rectangles
+ SetRectEmpty(&vi->rcSource);
+ SetRectEmpty(&vi->rcTarget);
+
+ // setup media type
+ mediaType->SetType(&MEDIATYPE_Video);
+ mediaType->SetFormatType(&FORMAT_VideoInfo);
+ mediaType->SetTemporalCompression(FALSE);
+
+ const GUID subtypeGUID = GetBitmapSubtype(&vi->bmiHeader);
+ mediaType->SetSubtype(&subtypeGUID);
+ mediaType->SetSampleSize(vi->bmiHeader.biSizeImage);
+
+ return S_OK;
+ }
+
+ HRESULT DecideBufferSize(IMemAllocator *alloc,ALLOCATOR_PROPERTIES *request)
+ {
+ HRESULT hr;
+ CAutoLock autolock(Filter->pStateLock());
+
+ CheckPointer(alloc,E_POINTER);
+ CheckPointer(request,E_POINTER);
+
+ // setup buffer count+size
+ VIDEOINFOHEADER *vi = (VIDEOINFOHEADER *) m_mt.Format();
+ if(!request->cBuffers)
+ request->cBuffers = 2;
+
+ request->cbBuffer = vi->bmiHeader.biSizeImage;
+
+ // setup allocator
+ ALLOCATOR_PROPERTIES actual;
+ hr = alloc->SetProperties(request,&actual);
+ if(FAILED(hr))
+ return hr;
+
+ // if he doesn't want to give us enough memory, ditch him
+ if(actual.cbBuffer < request->cbBuffer)
+ return E_FAIL;
+
+ return S_OK;
+ }
+
+ HRESULT FillBuffer(IMediaSample *sample)
+ {
+ CheckPointer(sample,E_POINTER);
+
+ // synchronize
+ unsigned char *sourceData = 0;
+ do
+ {
+ if(Terminating)
+ {
+ BufferWriteChange.Set();
+ return S_FALSE;
+ }
+
+ if(BufferReadPtr != BufferWritePtr)
+ {
+ sourceData = Buffers[BufferReadPtr];
+ BufferReadPtr = (BufferReadPtr + 1) % BufferCount;
+ BufferReadChange.Set();
+ }
+ else
+ BufferWriteChange.Wait();
+ }
+ while(!sourceData);
+
+ // copy over
+ BYTE *dataPtr;
+ VIDEOINFOHEADER *vi = (VIDEOINFOHEADER *) m_mt.Format();
+ sample->GetPointer(&dataPtr);
+
+ memcpy(dataPtr,sourceData,min(sample->GetSize(),vi->bmiHeader.biSizeImage));
+
+ // set time and sync point
+ REFERENCE_TIME start,end;
+ start = Frames * TimePerFrame;
+ end = start + TimePerFrame;
+
+ sample->SetTime(&start,&end);
+ sample->SetSyncPoint(TRUE);
+
+ // re-sync
+ return S_OK;
+ }
+
+ // we don't implement quality control
+ STDMETHODIMP Notify(IBaseFilter *self,Quality q)
+ {
+ return E_FAIL;
+ }
+
+ // use this to submit frames.
+ void PushData(const unsigned char *buffer)
+ {
+ unsigned char *destBuffer = 0;
+
+ do
+ {
+ int ReadPrev = (BufferReadPtr + BufferCount - 1) % BufferCount;
+
+ if(ReadPrev != BufferWritePtr)
+ {
+ destBuffer = Buffers[BufferWritePtr];
+ memcpy(destBuffer,buffer,XRes * YRes * 3);
+ BufferWritePtr = (BufferWritePtr + 1) % BufferCount;
+ BufferWriteChange.Set();
+ }
+ else
+ BufferReadChange.Wait();
+ }
+ while(!destBuffer);
+ }
+
+ void Terminate()
+ {
+ Terminating = true;
+ BufferWriteChange.Set();
+ }
+};
+
+class VideoSourceFilter : public CSource
+{
+ VideoSourcePin *pin;
+
+public:
+ VideoSourceFilter(int fpsNum,int fpsDenom,int xRes,int yRes)
+ : CSource(NAME("kkapture video source"),0,CLSID_VideoSource)
+ {
+ HRESULT hr;
+
+ pin = new VideoSourcePin(&hr,this,fpsNum,fpsDenom,xRes,yRes);
+ }
+
+ ~VideoSourceFilter()
+ {
+ delete pin;
+ }
+
+ void PushData(const unsigned char *buffer)
+ {
+ pin->PushData(buffer);
+ }
+
+ void Terminate()
+ {
+ pin->Terminate();
+ }
+};
+
+class AudioSourcePin : public CSourceStream
+{
+ enum { BufferCount = 4*4 };
+
+ struct Buffer
+ {