adding file source with IFileSourceFilter - c++

I am writing a Directshow application which connects a file source to a MPEG4s DMO.
The graph looks like:
File Source -> DMO Wrapper Filter -> Video Renderer.
Here are my questions:
1. How can I add a file source filter in the graph ? I got this piece of code which graphedit plus generated. Is this piece of code correct ? I see that it uses "CComPtr" which needs "atlbase.h". With VS2010 Express edition I don't have the atl headers.
LPCOLESTR srcFile1 = L"C:\\Users\shyam\\Downloads\\sample.avi";
CComPtr<IBaseFilter> pBaseFilter;
hr = pBaseFilter.CoCreateInstance(CLSID_AsyncReader);
CComQIPtr<IFileSourceFilter> pFileSourceFilter = pBaseFilter;
ATLASSERT(pFileSourceFilter);
pFileSourceFilter->Load(srcFile1, NULL);
hr = pGB->AddFilter(pBaseFilter, L"File Source (Async.)");
2. I manually downloaded "atlbase.h" from net and I am encountering several build errors. What can be done in this case.
Please help me in moving in the right direction !!
Thanks,
Shyam

The code generated above is correct. For getting rid of your compilation error, download and install the latest windows sdk. It should have the correct atl headers.

It's possible to write C++ code for Directshow without ATL, but I strongly wouldn't recommend it unless you like spagetti with leaks. Here's what your code would look like
IBaseFilter* pBaseFilter;
CoCreateInstance(CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pBaseFilter);
IFileSourceFilter* pFileSourceFilter = NULL;
hr = pBaseFilter->QueryInterface(IID_IFileSourceFilter, (void**)&pFileSourceFilter);
ASSERT(pFileSourceFilter != NULL);
hr = pFileSourceFilter->Load(L"C:\\Users\shyam\\Downloads\\sample.avi", NULL);
if (pFileSourceFilter)
pFileSourceFilter->Release();
hr = pFileSourceFilter->AddFilter(pBaseFilter, L"AsyncReader");
You also need to check hr for errors at every step.
The latest Windows SDK may not have all the Directshow interfaces, so I suggest Microsoft Windows SDK Update for Windows Vista (for qedit.h). But seriously please don't write Directshow or COM code without ATL, even DirectshowLib in c# would be easier for a simple app.

Related

DirectX11 E_INVALIDARG One or more arguments are invalid

When I am trying to load a Shader result from memory the compiler says: one or more arguments are invalid. Shader compiling successfully but it seems after D3DCompileFromFile() command in memory is something not correct and ID3DBlob interface does not get correct values for some reason.
ID3DBlob* pBlobFX = NULL;
ID3DBlob* pErrorBlob = NULL;
hr = D3DCompileFromFile(str, NULL, NULL, NULL, "fx_5_0", NULL, NULL, &pBlobFX, &pErrorBlob); // OK
if (FAILED(hr))
{
if (pErrorBlob != NULL)
OutputDebugStringA((char *)pErrorBlob->GetBufferPointer());
SAFE_RELEASE(pErrorBlob);
return hr;
}
// Create the effect
hr = D3DX11CreateEffectFromMemory(pBlobFX->GetBufferPointer(), pBlobFX->GetBufferSize(), 0, pd3dDevice, ppEffect); // Error: E_INVALIDARG One or more arguments are invalid
The legacy DirectX SDK version of Effects for Direct3D 11 only included D3DX11CreateEffectFromMemory for creating effects which required using a compiled shader binary blob loaded by the application.
The latest GitHub version includes the other expected functions:
D3DX11CreateEffectFromFile which loads a compiled binary blob from disk and then creates an effect from it.
D3DX11CompileEffectFromMemory which uses the D3DCompile API to compile a fx file in memory and then create an effect from it.
D3DX11CompileEffectFromFile which uses the D3DCompile API to compile a provided fx file and then create an effect from it.
Using D3DX11CompileEffectFromFile instead of trying to do it manually as the original poster tried is the easiest solution here.
The original library wanted to strongly encourage using build-time rather than run-time compilation of effects. Given that the primary use of Effects 11 today is developer education, this was unnecessarily difficult for new developers to use so the GitHub version now includes all four possible options for creating effects.
Note: The fx_5_0 profile in the HLSL compiler is deprecated, and is required to use Effects 11.

VP8-DirectShowFilter: QueryInterface results in E_NOINTERFACE (C++)

I am new in Directshow and C++. I try to capture Video from a Source and encode this with VP8. To accomplish this I'm using the DirectShow-Filters from https://code.google.com/p/webm/downloads/list
My Filtergraph is working and consists of these four filters:
recorder -> WebM VP8 Encoder Filter -> WebM Muxer Filter -> FileWriter
The Problem is, that I need to change the properties from the VP8 Encoder Filter. With GraphEdit I can change for example the Targed Bitrate, but I don't know how to do this programmatically in C++ (I don't want to use the PropertyPage).
I also downloaded the source code and found and included the file vp8encoder\vp8encoderfilter.hpp. This lead to the problem that I needed to include the vp8encoderidl.h file. At first I did not found this file in the soure folder, so I downloaded it from somewhere in the internet. Later I saw the IDL folder containing a vp8encoder.idl file, which I add to my project, compiled it and included the resulting vp8encoder_h.h file. In both cases (with the code from the Internet or from the header file) I can compile my project and record the video. So I tried to get the IVP8Encoder Interface from the DirectShow Filter:
//Instanziate Encoder-Filter
hr = CoCreateInstance(__uuidof(IVP8Encoder), NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pVideoEncoder);
//Get Interface
IVP8Encoder *iEncoder = NULL;
hr = pVideoEncoder->QueryInterface(__uuidof(IVP8Encoder), (void**)&iEncoder);
The QueryInterface()-method returns E_NOINTERFACE. So I think, that probably the first parameter is not correct, but I don't have an idea which parameter is needed instead.
I appreciate your help and thanks in advance!
You instantiate classes (CLSID_VP8Encoder) and classes implement interfaces (IBaseFilter, IVP8Encoder).
Your code should be:
IBaseFilter* pVideoEncoder;
hr = CoCreateInstance(CLSID_VP8Encoder, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void**) &pVideoEncoder);
IVP8Encoder *iEncoder = NULL;
hr = pVideoEncoder->QueryInterface(__uuidof(IVP8Encoder), (void**) &iEncoder);

DirectShow Filter error "Class is not registered"

Using the following code under my cpp/win32 project I get error "class is not registered"
hr = CoCreateInstance(CLSID_PIAsyncFile, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void**) &ppF);
if (SUCCEEDED(hr)) {
hr = pGraph->AddFilter(ppF, L"My Async Source (File)");
}
This is not true,since my filter works just fine under GraphEdit and I can also find it using IFilterMapper2 enumerating monikers. I can also bind to object from the direct show filters successfully.
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&ppF);
So, what's wrong with the CoCreateInstance ?
PS:This is a 32bit filter that registered under a 64Bit Windows 7 system. In the registry I can also find the filter under sysWOW3264 (a mirror registry for 32-bit windows apps running on 64bit windows).
You can also refer and find the source code to my codeproject post at http://www.codeproject.com/Messages/4603967/Class-not-registered-error.aspx
Thanks to Roman R, the problem was the wrong CLSID declaration in my code.

TTS C++ program can only run on developing PC

I followed the instructions given by the SAPI 5.1 “Text-to-Speech Tutorial”, compiled the sample code given by the tutorial(The instructions and the sample code are the same as those given by SAPI 5.3 TTS Tutorial! and SAPI 5.4 TTS Tutorial!). The compiled program works fine on the XP PC where it was built, but it will not work on other XP and Win 7 PCs. The other 2 PCs have no Speech SDK installed. But the SAPI 5.1 demo program TTSApp and MS Excel 2003 Text-to-Speech function work very well on these 2 PCs.
Why the tutorial program can only run on the development PC and other 2 programs can run on all PCs?
The development PC has XP sp3, Visual Studio 2008 and SAPI 5.1 installed. When I build the project I selected pre-compiled header. In step 1 below, there is no “#endif” in the stdafx.h file so these lines are inserted after "#include ".
Error message from the XP PC: this application failed to start because the application configuration is incorrect. Reinstall the application may fix this problem.
Error message from Win7 PC: The application has failed to start because its side-by-side configuration is incorrect. Please see the application event log or use the command-line sxstrace.exe tool for more detail
Below is the tutorial.
Microsoft Speech SDK
SAPI 5.1
Text-to-Speech Tutorial
This tutorial covers a very basic text-to-speech (TTS) example. The console application is one of the simplest demonstrations of speech. It is the "Hello World" equivalent for TTS. An equivalent sample for a Windows application using a graphical interface (and event pump) is available in Using Events with TTS.
The sample builds up from the simplest (though nonfunctional) COM framework to speaking a sentence. Steps are provided for each new function. The sample even goes one step beyond demonstrating the use XML tags to modify speech. The Complete Sample Application is at the bottom of the page.
Step 1: Setting Up The Project
Step 2: Initialize COM
Step 3: Setting Up Voices
Step 4: Speak!
Step 5: Modifying Speech
Step 1: Setting up the project
While it is possible to write an application from scratch, it is easier to start from an existing project. In this case, use Visual Studio's application wizard to create a Win32 console application. Choose "Hello, world" as the sample when asked during the wizard set up. After generating it, open the STDAfx.h file and paste the following code after "#include " but before the "#endif" statement. This sets up the additional dependencies SAPI requires.
#define _ATL_APARTMENT_THREADED
#include <atlbase.h>
//You may derive a class from CComModule and use it if you want to override something,
//but do not change the name of _Module
extern CComModule _Module;
#include <atlcom.h>
Code Listing 1
Next add the paths to SAPI.h and SAPI.lib files. The paths shown are for a standard SAPI SDK install. If the compiler is unable to locate either file, or if a nonstandard install was performed, use the new path to the files. Change the project settings to reflect the paths. Using the Project->Settings. menu item, set the SAPI.h path. Click the C/C++ tab and select Preprocessor from the Category drop-down list. Enter the following in the "Additional include directories": C:\Program Files\Microsoft Speech SDK 5.1\Include.
To set the SAPI.lib path:
1. Select the Link tab from the Same Settings dialog box.
2. Choose Input from the Category drop-down list.
3. Add the following path to the "Additional library path":
C:\Program Files\Microsoft Speech SDK 5.1\Lib\i386.
4. Also add "sapi.lib" to the "Object/library modules" line. Be sure that the name is separated by a space.
Step 2: Initialize COM
SAPI is a COM-based application, and COM must be initialized both before use and during the time SAPI is active. In most cases, this is for the lifetime of the host application. The following code (from Listing 2) initializes COM. Of course, the application does not do anything beyond initialization, but it does ensure that COM is successfully started.
#include <stdafx.h>
#include <sapi.h>
int main(int argc, char* argv[])
{
if (FAILED(::CoInitialize(NULL)))
return FALSE;
::CoUninitialize();
return TRUE;
}
Code Listing 2
Step 3: Setting up voices
Once COM is running, the next step is to create the voice. A voice is simply a COM object. Additionally, SAPI uses intelligent defaults. During initialization of the object, SAPI assigns most values automatically so that the object may be used immediately afterward. This represents an important improvement from earlier versions. The defaults are retrieved from Speech properties in Control Panel and include such information as the voice (if more than one is available on your system), and the language (English, Japanese, etc.). While some defaults are obvious, others are not (speaking rate, pitch, etc.). Nevertheless, all defaults may be changed either programmatically or in Speech properties in Control Panel.
Setting the pVoice pointer to NULL is not required but is useful for checking errors; this ensures an invalid pointer is not reused, or as a reminder that the pointer has already been allocated or deallocated
#include <stdafx.h>
#include <sapi.h>
int main(int argc, char* argv[])
{
ISpVoice * pVoice = NULL;
if (FAILED(::CoInitialize(NULL)))
return FALSE;
HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);
if( SUCCEEDED( hr ) )
{
pVoice->Release();
pVoice = NULL;
}
::CoUninitialize();
return TRUE;
}
Code Listing 3. Bold text represents new code for this example.
Step 4: Speak!
The actual speaking of the phrase is an equally simple task: one line calling the Speak function. When the instance of the voice is no longer needed, you can release the object.
#include <stdafx.h>
#include <sapi.h>
int main(int argc, char* argv[])
{
ISpVoice * pVoice = NULL;
if (FAILED(::CoInitialize(NULL)))
return FALSE;
HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);
if( SUCCEEDED( hr ) )
{
hr = pVoice->Speak(L"Hello world", 0, NULL);
pVoice->Release();
pVoice = NULL;
}
::CoUninitialize();
return TRUE;
}
Code Listing 4. Bold text represents new code for this example.
Step 5: Modifying Speech
Voices may be modified using a variety of methods. The most direct way is to apply XML commands directly to the stream. The commands are outlined in XML Schema. In this case, a relative rating of 10 will lower the pitch of the voice.
#include <stdafx.h>
#include <sapi.h>
int main(int argc, char* argv[])
{
ISpVoice * pVoice = NULL;
if (FAILED(::CoInitialize(NULL)))
return FALSE;
HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);
if( SUCCEEDED( hr ) )
{
hr = pVoice->Speak(L"Hello world", 0, NULL);
// Change pitch
hr = pVoice->Speak(L"This sounds normal <pitch middle = '-10'/> but the pitch drops half way through", SPF_IS_XML, NULL );
pVoice->Release();
pVoice = NULL;
}
::CoUninitialize();
return TRUE;
}
Code Listing 5. Bold text represents new code for this example. This is the complete code sample.
You have to install the C++ runtime which comes with an installer (redist).
VC++ 2008 redist
VC++ 2008 SP1 redist
Which one to install depends on the VS service pack - if SP1 then SP1 if not the not.
EDIT: A second way is to link the runtime libraries static. This increases the size of the executable but you don't need additional requirements on the target machine.

Why does my code fail to create a directory in "C:\Program Files" under Windows 7?

I am using Windows 7 and I have to run one program in that windows but that program working in Windows XP. This is a Visual C++ program and I am using Visual Studio 2008 for this. When I am running my application, it does not throw any errors, but it does not create a directory in "c:\program files\". So can anyone help me to create directory and exe file?
This is the code I am using:
char szAppPath[MAX_PATH];
char szFileName[MAX_PATH];
DWORD dwResult;
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
dwResult = ExpandEnvironmentStrings( NULL, szAppPath, MAX_PATH); // "%ProgramFiles%"
// do same for NSim directory
strcat(szAppPath,"\\NSim");
hFind = FindFirstFile(szAppPath, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{
//Directory Does't Exists create New
if(!CreateDirectory(szAppPath,NULL)) //Throw Error
{
MessageBox("Unable to Create N-SIM directory","NSim Installer");
return ;
}
}
else
{
//check if is directory or not
if(!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
MessageBox("Can't Create N-SIM directory\n Another file with same name exists","NSim Installer");
return ;
}
FindClose(hFind);
}
//***************************************N-SIM Application****************************
strcpy(szFileName, szAppPath);
HRSRC hRes;
if( bRegister == FALSE)
{
strcat(szFileName,"\\NSim.exe"); //make same name of the Client & Server in program file
hRes = FindResource(NULL, MAKEINTRESOURCE(IDR_LANSIMSERVER),RT_RCDATA);
if(flagUpgrade ==0)
{
CString trial = installationDate(); //----- Detemine Expiry Date -----
setRegistry(trial);
}
}
It's a file permissions issue, plain and simple. Programs can't just go rooting around system directories in Windows 7. That's why it works "properly" in Windows XP, but not in newer versions.
I can't tell for sure, but it looks like you're trying to write an installer. If so, why are you reinventing the wheel? There are tons of great setup utilities available—Visual Studio provides a setup project that you can customize to your needs, or look into Inno Setup, my personal favorite. A Google search will turn up plenty of other options that have already solved this problem for you, and innumerable others.
If this isn't an installer, and you're just trying to store application and/or user data in the Program Files folder, I highly recommend that you look elsewhere. You weren't supposed to shove data into the app folder under earlier versions of Windows, and Windows 7 just cuts you off at the knees if you do this. Your best bet is to follow the recommendations that existed from the beginning: Investigate the user and common Application Data folders carefully. Use the SHGetKnownFolderPath function to retrieve the full path to a known folder using its KNOWNFOLDERID. A couple of suggestions:
FOLDERID_ProgramData (a shared program data directory for all users)
FOLDERID_LocalAppData (a per-user program data directory, non-roaming)
FOLDERID_RoamingAppData (a per-user program data directory, roaming)
Alternatively, you can try running the application as an Administrator. You might want to look into creating a manifest that indicates the application requires administrator-level permissions to execute.
[edit] I edited the code in the question for readability and removed the commented out code (to see the wood for the trees). It is now obvious that nothing initialises szAppPath before calling strcat(), and calling ExpandEnvironmentStrings with NULL as the first argument is undefined (and certainly useless). Calling strcat() on an unitialised string is not likely to have the desired result. This may be an artefact of not posting the real code, or even of other peoples edits (including mine).
CreateDirectory sets the system error code on error; if you want to know what went wrong, check it! Any answer you get here will be an educated guess.
if(!CreateDirectory(szAppPath,NULL)) //Throw Error
{
DWORD errorcode = GetLastError();
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorcode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL );
MessageBox(NULL, (LPCTSTR)lpMsgBuf, TEXT("Error"), MB_OK);
return ;
}
If you just want to get the error code and look it up manually, then a complete directory of codes is available on MSDN, here, I would guess that ERROR_ACCESS_DENIED
(5) is most probable. A more elaborate example of error code display is given here.
windows7?
Ok, the problem is not with your program. Its with the file system permissions in Windows 7. User programs cannot create files there.
I think the problem is lack of privileges. You can debug your project to see whether the CreateDirectory function sets an error as ERROR_ACCESS_DENIED, if it does, you should make your program run with an administrator privilege. Add manifest in your project to do so.
It is intended to protect your computer against attack. Well maybe. Or Microsoft deciding to tell you what you are and not allowed to do on your own computer.
In any case you can change your UAC settings if you really have to write there in that way although that obviously exposes you to risk.
Otherwise play nice and do things the Microsoft way, using a proper installer.