MediaEngine audio playback on WinRT - mp3

I'm trying to add music to my game that runs on WinRT. The music should be in an encoded format (mp3, ogg, etc.) and should be streamable and be decoded by the hardware (for performance reasons).
I've looked through the samples, and found out that MediaEngine can do something like this (I hope).
However, I'm having problems making it work. I keep getting ComExceptions everytime I try to create IMFByteStream from IRandomAccessStream via MFCreateMFByteStreamOnStreamEx().
It might be that I'm not handling tasks correctly, since they are a new paradigm for me.
Here's some code (pretty similar to the sample I mentioned before):
void MyMedia::PlayMusic ()
{
try
{
StorageFolder^ installedLocation = Windows::ApplicationModel::Package::Current->InstalledLocation;
Concurrency::task<StorageFile^> m_pickFileTask = Concurrency::task<StorageFile^>(installedLocation->GetFileAsync("music.mp3"), m_tcs.get_token());
SetURL(StringHelper::toString("music.mp3"));
auto player = this;
m_pickFileTask.then([&player](StorageFile^ fileHandle)
{
Concurrency::task<IRandomAccessStream^> fOpenStreamTask = Concurrency::task<IRandomAccessStream^> (fileHandle->OpenAsync(Windows::Storage::FileAccessMode::Read));
fOpenStreamTask.then([&player](IRandomAccessStream^ streamHandle)
{
try
{
player->SetBytestream(streamHandle);
if (player->m_spMediaEngine)
{
MEDIA::ThrowIfFailed(
player->m_spMediaEngine->Play()
);
}
} catch(Platform::Exception^)
{
MEDIA::ThrowIfFailed(E_UNEXPECTED);
}
}
);
}
);
} catch(Platform::Exception^ ex)
{
Printf("error: %s", ex->Message);
}
}
void MyMedia::SetBytestream(IRandomAccessStream^ streamHandle)
{
HRESULT hr = S_OK;
ComPtr<IMFByteStream> spMFByteStream = nullptr;
//The following line always throws a ComException
MEDIA::ThrowIfFailed(
MFCreateMFByteStreamOnStreamEx((IUnknown*)streamHandle, &spMFByteStream)
);
MEDIA::ThrowIfFailed(
m_spEngineEx->SetSourceFromByteStream(spMFByteStream.Get(), m_bstrURL)
);
return;
}
Bonus: If you know a better solution to my audio needs, please leave a comment.

I managed to fix this. There was two problems I found.
Media Foundation was not initialized
MFStartup(MF_VERSION); needs to be called before Media Foundation can be used. I added this code just before creating the media engine.
Referencing a pointer.
Line m_pickFileTask.then([&player](StorageFile^ fileHandle) should be m_pickFileTask.then([player](StorageFile^ fileHandle). This is already a pointer to the current class, and & provides the address of variable, so I was actually passing the pointer's pointer.

Related

Where does MFC COleControl::DoPropExchange store persistent properties?

I have taken over maintenance of a legacy MFC OCX control in C++. The project is now in VS2013. I'm trying to understand the functioning of the DoPropExchange method. This method appears to be calling PX_?????(member) for nearly all the data members in the control where ???? is the type (Bool, Short, Long ...) My understanding is these are called for the purpose of providing persistent storage of properties. But from my understanding of the operation of the OCX control there are no persistent properties. Would there be any other reason to be calling PX_???? for all data members in DoPropExchange other than to support persistent properties? I'm also trying to understand where these persistent properties are loaded/stored. Where is the serialized file for loading/storing persistent property values specified?
Here is the source for DoPropExchange
// CSigPlusCtrl::DoPropExchange - Persistence support
void CSigPlusCtrl::DoPropExchange(CPropExchange* pPX)
{
DWORD Version;
long BaudRate;
short ComPort;
BOOL Rv;
LOG(("DoPropExchange Entry"));
ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
COleControl::DoPropExchange(pPX);
Version = pPX->GetVersion();
if (pPX->IsLoading())
{
LoadDefaultProperties();
LoadIniParameters();
}
if ((Version & 0xFFFF0000) == (DWORD)MAKELONG(0, _wVerMajor))
{
Rv = PX_Short(pPX, _T("ImageFileFormat"), ImageFileFormat, 0);
Rv = PX_Short(pPX, _T("ImageXSize"), ImageXSize, 0);
Rv = PX_Short(pPX, _T("ImageYSize"), ImageYSize, 0);
Rv = PX_Short(pPX, _T("ImagePenWidth"), ImagePenWidth, 1);
. . .
Rv = PX_Short(pPX, _T("ZoomY"), ZoomY, 0);
Rv = PX_Short(pPX, _T("ZoomPower"), ZoomPower, 1);
if (pPX->IsLoading())
{
if (SigBlob != NULL)
{
GlobalFree(SigBlob);
SigBlob = NULL;
}
}
else
{
if (SigBlob == NULL)
{
SigBlobType* SigBlobPtr;
SigBlob = GlobalAlloc(GMEM_MOVEABLE, sizeof(DWORD));
SigBlobPtr = (SigBlobType*)GlobalLock(SigBlob);
SigBlobPtr->Size = 0;
GlobalUnlock(SigBlob);
}
}
if ((Version & 0xFFFF) == Version223)
{
Rv = PX_Blob(pPX, _T("SigBlob"), SigBlob, NULL);
}
if ((Version & 0xFFFF) >= Version224)
{
CString SigStr;
if (!pPX->IsLoading())
{
SigStr = BlobToString();
}
Rv = PX_String(pPX, _T("SigStringStored"), SigStr, _T(""));
if (pPX->IsLoading())
{
BlobFromString(SigStr);
}
}
}
else
{
SigMessageBox("Warning Incompatable Versions of SigPlus Control");
}
LoadTabletParameters();
LOG(("DoPropExchange Exit"));
}
EDIT Added 6-21-2018
Running in the debugger I observe that when DoPropExchange is called, VS2013 shows the stack with a message that stack frames below may be incorrect. And the one frame just above, that calls DoPropExchange, is from mfc120d.dll which does not have symbol file available mfc120d.i386.pdb.
This Microsoft Forum Post seems to indicate that the symbol file is not available for VS2015 and I'm wondering if that is also the case for VS2013. So far I have not been able to find place to download MFC120 symbols for debug.
Starting a bounty today to find someone who can explain how and where properties are normally serialized for OLE controls and what methods are used to specify the serialized data storage location/media. This is of concern because this control runs in a Citrix ZenDesk network environment in a Terminal Aware program and if properties are being stored somewhere then each client needs to specify a location unique to that client.
The DoPropExchange is used to implement control attribute persistence mainly between design and run-time. The actual destination sink is passed by the client of the OCX.
In VC the the settings are stored in RC file while in VB in frm and frx files. If you open FRM in notepad you would probably see the section with the properties of this control.
As a side note, there is a similar implementation in case the control is used in HTML with inline settings in he html itself.
Unless your VB clients saves the settings externally via direct calls to Property bag function it is not likely you have a issue here since the above properties are not stored at runtime.

C++ Legacy Driver mongoDB Replicaset in Class of a DLL

I have built a dll which includes a class implementing the mongoDB replicaset operations. Here is a summary of the class.
#include "mongo/client/dbclient.h"
mongoimp::mongoimp() {
mongo::client::initialize();
}
mongoimp::~mongoimp() {
mongo::client::shutdown();
}
int mongoimp::queryTRecords() {
string errmsg;
vector<mongo::HostAndPort> hosts = { mongo::HostAndPort("xx-a0.yyyy.com:xxxxx"), mongo::HostAndPort("xx-a1.yyyy.com:xxxxx") };
static mongo::DBClientReplicaSet con("xx", hosts, 0);
con.connect();
con.auth("dbname", "username", "password", errmsg);
auto_ptr<DBClientCursor> cursor = con.query("dbname.t", BSONObj());
BSONObj response;
con.logout("xx", response);
if (cursor->more()) {
BSONObj recordnm = cursor->nextSafe();
return(recordnm.getIntField("lastid"));
} else return(-1);
}
The above code is working. But here are my questions:
1) With the above setting, I can do normal mongoDB operations with the dll but since my application needs to constantly update mongoDB data (close to real-time, up to hundreds a second), I am getting error (No valid replicaset instance servers found) when updating data.
2) Only the server needs to talk to the mongoDB database. So basically I just need one connection to the database. So I want to declare the mongo::DBClientReplicaSet con as a static global variable and connect to it in the class construct function. But it seemed I cannot do it. My application cannot run at all. With that, I constantly get the following error.
Assertion failed: px != 0, file C:\Boost\include\boost-1_62\boost/smart_ptr/scoped_ptr.hpp, line 105
Does anybody know how to solve the problem?
Below is the code I tried:
static mongo::DBClientReplicaSet con("xx", { mongo::HostAndPort("xx-a0.yyyy.com:xxxxx"), mongo::HostAndPort("xx-a1.yyyy.com:xxxxx") }, 0);
mongoimp::mongoimp() {
mongo::client::initialize();
string errmsg;
con.connect();
con.auth("dbname", "username", "password", errmsg);
}
mongoimp::~mongoimp() {
BSONObj response;
con.logout("xx", response);
mongo::client::shutdown();
}
int mongoimp::queryTRecords() {
auto_ptr<DBClientCursor> cursor = con.query("dbname.t", BSONObj());
if (cursor->more()) {
BSONObj recordnm = cursor->nextSafe();
return(recordnm.getIntField("lastid"));
} else return(-1);
}
3) Last question, I noticed there is mongo/client/dbclient_rs.h" file for replicaset. But it seemed I cannot use it. With that, I am getting error for initialize() and auto_ptr cursor. How can I use the file and take full advantage of replicaset features? How can I initialize the relica set if I can use "dbclient_rs.h"? How do I do query and fetch data in that case?
Thanks a lot in advance!
For question No. 2, I remembered the reason for the error:
You need to call mongo::client::initialize before you construct any driver objects, or BSON for that matter.
But how to make that global definition possible, I still need a solution.

How to get Game Controller name (Windows 10 / C++)

I've seen lots of info on how to read game controller input using XInput but I really want to know the name of the controller that is connected.
How can I find out the name of connected controllers on a PC or more specifically the name of the controller I am reading XInput from?
You can do this by calling the joyGetDevCaps function which returns a JOYCAPS structure containing all information (including name) of the connected controller.
You can use DirectInput to get the name of the device. You need to do that using a callback:
pDirectInput->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoystickCallbackStatus, &joynum, DIEDFL_ATTACHEDONLY);
Then you have to be a bit creative: on Startup detect all devices using the callback and store their name/GUID... and then when a device is hot-plugged (which you detect with XInputGetState) look for the device which you don't know about yet, with a modified version of that earlier callback, something similar to this:
BOOL CALLBACK EnumJoystickCallbackStatus(LPCDIDEVICEINSTANCE pdevinst, LPVOID pref)
{
DWORD devtype = GET_DIDEVICE_TYPE(pdevinst->dwDevType);
DWORD subtype = GET_DIDEVICE_SUBTYPE(pdevinst->dwDevType);
if (devtype == DI8DEVTYPE_KEYBOARD || (devtype == DI8DEVTYPE_SUPPLEMENTAL && subtype == DI8DEVTYPESUPPLEMENTAL_UNKNOWN)) {
return DIENUM_CONTINUE;
}
ULONG* pjoynum = reinterpret_cast<ULONG*>(pref);
if (IsXInputDevice(&pdevinst->guidProduct)) {
// loop through your known devices and see if this GUI already exists
// we are looking for one which we don't know about yet.
if (!found) {
// store GUI / Name / ... in some global controllers-array
return DIENUM_STOP; // done
}
}
DEBUG_INFO(Debug::XDF_General, "continue");
return DIENUM_CONTINUE;
}
Note that if you have multiple xbox-controllers, you'll get a callback for each one separately.
Implementation of IsXInputDevice can be found in the MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/ee417014(v=vs.85).aspx

How create a DICOM image from byte (DCMTK)

I want to use the DCMTK 3.6.1 library in an existing project that can create DICOM image. I want to use this library because I want to make the compression of the DICOM images. In a new solution (Visual Studio 2013/C++) Following the example in the DCMTK official documentation, I have this code, that works properly.
using namespace std;
int main()
{
DJEncoderRegistration::registerCodecs();
DcmFileFormat fileformat;
/**** MONO FILE ******/
if (fileformat.loadFile("Files/test.dcm").good())
{
DcmDataset *dataset = fileformat.getDataset();
DcmItem *metaInfo = fileformat.getMetaInfo();
DJ_RPLossless params; // codec parameters, we use the defaults
// this causes the lossless JPEG version of the dataset
//to be created EXS_JPEGProcess14SV1
dataset->chooseRepresentation(EXS_JPEGProcess14SV1, &params);
// check if everything went well
if (dataset->canWriteXfer(EXS_JPEGProcess14SV1))
{
// force the meta-header UIDs to be re-generated when storing the file
// since the UIDs in the data set may have changed
delete metaInfo->remove(DCM_MediaStorageSOPClassUID);
delete metaInfo->remove(DCM_MediaStorageSOPInstanceUID);
metaInfo->putAndInsertString(DCM_ImplementationVersionName, "New Implementation Version Name");
//delete metaInfo->remove(DCM_ImplementationVersionName);
//dataset->remove(DCM_ImplementationVersionName);
// store in lossless JPEG format
fileformat.saveFile("Files/carrellata_esami_compresso.dcm", EXS_JPEGProcess14SV1);
}
}
DJEncoderRegistration::cleanup();
return 0;
}
Now I want to use the same code in an existing C++ application where
if (infoDicom.arrayImgDicom.GetSize() != 0) //Things of existing previous code
{
//I have added here the registration
DJEncoderRegistration::registerCodecs(); // register JPEG codecs
DcmFileFormat fileformat;
DcmDataset *dataset = fileformat.getDataset();
DJ_RPLossless params;
dataset->putAndInsertUint16(DCM_Rows, infoDicom.rows);
dataset->putAndInsertUint16(DCM_Columns, infoDicom.columns,);
dataset->putAndInsertUint16(DCM_BitsStored, infoDicom.m_bitstor);
dataset->putAndInsertUint16(DCM_HighBit, infoDicom.highbit);
dataset->putAndInsertUint16(DCM_PixelRepresentation, infoDicom.pixelrapresentation);
dataset->putAndInsertUint16(DCM_RescaleIntercept, infoDicom.rescaleintercept);
dataset->putAndInsertString(DCM_PhotometricInterpretation,"MONOCHROME2");
dataset->putAndInsertString(DCM_PixelSpacing, "0.086\\0.086");
dataset->putAndInsertString(DCM_ImagerPixelSpacing, "0.096\\0.096");
BYTE* pData = new BYTE[sizeBuffer];
LPBYTE pSorg;
for (int nf=0; nf<iNumberFrames; nf++)
{
//this contains all the PixelData and I put it into the dataset
pSorg = (BYTE*)infoDicom.arrayImgDicom.GetAt(nf);
dataset->putAndInsertUint8Array(DCM_PixelData, pSorg, sizeBuffer);
dataset->chooseRepresentation(EXS_JPEGProcess14SV1, &params);
//and I put it in my data set
//but this IF return false so che canWriteXfer fails...
if (dataset->canWriteXfer(EXS_JPEGProcess14SV1))
{
dataset->remove(DCM_MediaStorageSOPClassUID);
dataset->remove(DCM_MediaStorageSOPInstanceUID);
}
//the saveFile fails too, and the error is "Pixel
//rappresentation non found" but I have set the Pixel rep with
//dataset->putAndInsertUint16(DCM_PixelRepresentation, infoDicom.pixelrapresentation);
OFCondition status = fileformat.saveFile("test1.dcm", EXS_JPEGProcess14SV1);
DJEncoderRegistration::cleanup();
if (status.bad())
{
int error = 0; //only for test
}
thefile.Write(pSorg, sizeBuffer); //previous code
}
Actually I made test with image that have on one frame, so the for cycle is done only one time. I don't understand why if I choose dataset->chooseRepresentation(EXS_LittleEndianImplicit, &params); or dataset->chooseRepresentation(EXS_LittleEndianEXplicit, &params); works perfectly but not when I choose dataset->chooseRepresentation(EXS_JPEGProcess14SV1, &params);
If I use the same image in the first application, I can compress the image without problems...
EDIT: I think the main problem to solve is the status = dataset->chooseRepresentation(EXS_JPEGProcess14SV1, &rp_lossless) that return "Tag not found". How can I know wich tag is missed?
EDIT2: As suggest in the DCMTK forum I have added the tag about the Bits Allocated and now works for few images, but non for all. For some images I have again "Tag not found": how can I know wich one of tags is missing? As a rule it's better insert all the tags?
I solve the problem adding the tags DCM_BitsAllocated and DCM_PlanarConfiguration. This are the tags that are missed. I hope that is useful for someone.
At least you should call the function chooseRepresentation, after you have applied the data.
**dataset->putAndInsertUint8Array(DCM_PixelData, pSorg, sizeBuffer);**
dataset->chooseRepresentation(EXS_JPEGProcess14SV1, &params);

Address COM in OS X via FireMonkey/C++

The COM-based Blackmagic DeckLink API is available for both Windows and OS X. I wish to address it in OS X but using FireMonkey (FMX) in C++. The problem is that their sample code* is written for Cocoa and I have no idea how to rewrite it for FireMonkey. Does anyone have any experience with this, is it even possible.
Or, is there a generic way in which libraries with a COM interface can be addressed in FireMonkey/OS X?
Here's part of the code for Cocoa, per request.
void InitDeckLinkAPI (void)
{
CFURLRef bundleURL;
bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR(kDeckLinkAPI_BundlePath), kCFURLPOSIXPathStyle, true);
if (bundleURL != NULL)
{
gDeckLinkAPIBundleRef = CFBundleCreate(kCFAllocatorDefault, bundleURL);
if (gDeckLinkAPIBundleRef != NULL)
{
gCreateIteratorFunc = (CreateIteratorFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateDeckLinkIteratorInstance_0002"));
gCreateAPIInformationFunc = (CreateAPIInformationFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateDeckLinkAPIInformationInstance_0001"));
gCreateOpenGLPreviewFunc = (CreateOpenGLScreenPreviewHelperFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateOpenGLScreenPreviewHelper_0001"));
gCreateCocoaPreviewFunc = (CreateCocoaScreenPreviewFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateCocoaScreenPreview_0001"));
gCreateVideoConversionFunc = (CreateVideoConversionInstanceFunc)CFBundleGetFunctionPointerForName(gDeckLinkAPIBundleRef, CFSTR("CreateVideoConversionInstance_0001"));
}
CFRelease(bundleURL);
}
}
bool IsDeckLinkAPIPresent (void)
{
// If the DeckLink API bundle was successfully loaded, return this knowledge to the caller
if (gDeckLinkAPIBundleRef != NULL)
return true;
return false;
}
IDeckLinkIterator* CreateDeckLinkIteratorInstance (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateIteratorFunc == NULL)
return NULL;
return gCreateIteratorFunc();
}
*Too long to include here but you can download it here.
On platforms without native COM support (such as OS X) a C entry point should be provided to access an Interface and in DeckLink API there is such factory methods :
IDeckLinkIterator *deckLinkIterator = CreateDeckLinkIteratorInstance();
Thus you can simply use DeckLink API in C++Builder. But there is a problem, C++Builder has defined some COM types such as IUnknown in sysmac.h (is included by System.hpp) which conflicts with same types have been defined in CFPluginCOM.h, If your project includes System.hpp such as all firemonkey projects the compiler displays an error:
[bccosx Error] sysmac.h(287): E2238 Multiple declaration for 'IUnknown'
There is a sample named DeckControl in samples directory of DeckLink API which is a console program and you can compile it by C++Builder:
Create a console project and specify main.cpp as project source.
Select "None" as Target Framework
Add "OSX" Platform
The project is compiled successfuly.
And what about Fmx project (uses System.hpp) ?
Create a wrapper unit (For example bcb_deck) put needed APIs in it. Note that do not include "DeckLinkAPI.h" in unit header, this causes same problems described above, but put it in cpp (bcb_deck.cpp), for example:
bcb_deck.cpp:
void* createDeckLinkIteratorInstance() // use camel case to prevent conflict
{
return (void*) CreateDeckLinkIteratorInstance();
}
bool deckLinkIteratorNext(void *hDeckLinkIterator, void *hDeckLink)
{
IDeckLinkIterator *deckLinkIterator = (IDeckLinkIterator*) hDeckLinkIterator;
IDeckLink *deckLink = (IDeckLink*) hDeckLink;
return deckLinkIterator->Next(&deckLink) == S_OK;
}
Usage:
#include "bcb_deck.h"
void *hDeckLinkIterator, *hDeckLink;
hDeckLinkIterator = createDeckLinkIteratorInstance();
if (hDeckLinkIterator)
{
// Enumerate all cards in this system
while (deckLinkIteratorNext(hDeckLinkIterator, hDeckLink))
{
// ...
}
}