duplicate AMMediaType - c#

I am able to copy a VideoInfoHeader which is part AMMediaType with the following lines:
AMMediaType mediaType = new AMMediaType();
VideoInfoHeader videoInfo = new VideoInfoHeader();
(pSampleGrabber as ISampleGrabber).GetConnectedMediaType(mediaType);
videoInfo = (VideoInfoHeader)Marshal.PtrToStructure(mediaType.formatPtr, typeof(VideoInfoHeader));
that I got from SampleGrabber Parameter is Incorrect and other ressources on the internet. However I am not able to copy the whole AMMediaType-Structure. The pointer to the VideoInfoHeader is lost.
So I was wondering if there exists a helper function that
copies an AMMediaType to a different location in memory, looks for pointers like VideoInfoHeader and copies the content of the VideoInfoHeader and other referenced data to a new location (including pointing formatPtr to the right location).
I am using this in the following scenario:
I retrieve all possible IPin mediatypes of a video input device and show the AMMediaTypes in a Windows.Forms - Combobox. When I read the SelectedObject from the Combobox, the pointer to the VideoInfoHeader is zero. This is where it fails to connect using my selected pin configuration when constructing the filtergraph.

The AMMediaType aka AM_MEDIA_TYPE structure consists of regular members and additionally allocated piece of memory pointed to by formatPtr. The latter is a byte array with a meaning dependent on format type. Both structure and slave memory block are typically using specific COM allocator.
Duplicating the structure is copying its members and duplicating the byte array behind formatPtr. The structure also includes pUnk member supposed to be COM interface, however it is typically null. It is valid for it to be non-null, but I cannot remember a single case over years when it was actually used, in particular with video and audio media types.

Related

Passing a C++ object pointer to a C++ class through C++/CLI

I have a particular problem which I cannot seem to reproduce in a minimal working example.
I have to deal with a large framework of legacy code and modifying all of that out of my scope. To deal with it I have to apply some particular patterns.
Overview of the codebase
I have a managed C# application (.NET 5.0). In this appliation I need to run some C++ code.
For this, there is a CLI-wrapper project. This wrapper contains most of the legacy framework which is out of my control and is why I can only transfer strings to my C++ class (more on this later). Based on config, this legacy framework uses the wrapper to instantiate C++ classes and calls methods on them, processes the results and finally, destroys all the C++ classes afterwards.
This CLI-wrapper allows me ONLY to pass strings as parameters to the C++ classes it creates.
All of my libraries are dynamically linked (using DLL's). The C# is a project which references the C++/CLI wrapper which in turn referenced the C++ project with my C++-class. This project references the external LargeLibrary (more on this later).
The root of the problem
The C++ code is called repeatedly, every few seconds. It should respond fast.
My C++ code needs to load some large file from disk (about 400 MB) and process it which takes quite some time.
Since the C++ classes are recreated each time, loading the file each time consumes so much time which is unacceptable.
As this data is essentially constant, I try to load it once during initialisation of the program. Then I pass a pointer to my C++ class which then can use the object. The object then remains in memory when the C++ class is destroyed so it can be used again later.
To complicate things, I need quite a large library to read and process my file (I reference this library here as LargeLibrary). If I make the CLI-wrapper dependent on this, it won't compile.
I can imagine this is because of the CLI stuff. Therefore, I use a void pointer, so the wrapper does not have to be aware of the actual type of behind the pointer. The actual object is created using a function inside my C++-class (so the correct destructor is linked to the shared pointer).
This all compiles fine.
My solution
I made a small extension to the CLI-wrapper to create the object which read my file from disk and keeps the information in memory.
This object is created using the method CreateInformationObject(). ptr_native is a smart pointer for using native objects in managed code. It's type is: CAutoNativePtr<std::shared_ptr<void>> ptr_native.
Creating my object inside the wrapper looks like:
// Create a shared_ptr on dynamic memory (i.e. heap).
std::shared_ptr<void>* objectPointer = new std::shared_ptr<void>();
// Load the module and store a shared pointer pointing to it in the dynamic memory.
*objectPointer = CppConsumerStuff::CppConsumer::CreateInformationObject(value);
// Load the module and store a shared pointer pointing to it in the dynamic memory.
ptr_native.Attach(objectPointer);
The CreateInformationObject() method inside my C++ class (the CppConsumerStuff::CppConsumer) is:
std::shared_ptr<void> CppConsumer::CreateInformationObject(std::string pathToFile)
{
std::shared_ptr<LargeLibrary::ActualObjectType> objectPtr = std::make_shared<LargeLibrary::ActualObjectType>();
*objectPtr = LargeLibrary::FileLoader::load(pathToFile)
return objectPtr;
}
Then, because of the legacy framework, I tried this longshot: convert the pointer address to string, pass it via the framework to my C++ class and convert it back to a pointer to the actual type of the object.
This goes like (in my CLI-wrapper extension):
//Cast void pointer to string.
String^ CliStorage::GetPointerString()
{
std::stringstream ss;
ss << (*ptr_native).get(); // Pointer to hex string.
std::string ptr_string = ss.str();
return StringToManaged(ptr_string);
}
Finally, (in my C++ class), I convert this pointer-string back to a pointer to the actual object as:
void DoWorkOnLargeObject(std::string ptr_string)
{
// Cast pointer to usable type
uint64_t raw_ptr = 0; // Define int size depending on system architecture.
std::stringstream ss;
ss << std::hex << ptr_string;
ss >> raw_ptr; //Hex string to int.
cppObjectPtr = reinterpret_cast<void*>(raw_ptr);
LargeLibrary::ActualObjectType* cppObjectPtrCasted = static_cast<LargeLibrary::ActualObjectType*>(cppObjectPtr);
// Use the object.
cppObjectPtrCasted->GetDataStuff();
// Rest of code doing work...
}
My results
I build all of this in Visual Studio 2019.
When I create a Debug build, all works :).
However, when I create a Release build, it does not work and throws the following Exception: ``
Minimal working example
I tried to create a minimal working example.
Both with and without the large external library.
However, in my minimum working Examples it always works, no matter the build type (debug / release).
My question
So my question is: Do my minimum working examples work by accident and am I relying on undefined behavior? Or should this concept (no matter how ugly it is) indeed work?
If it is undefined behavior, please explain, I want to learn. If it should work, the problem resides in the legacy framework and I will make inquiries about this.
I know these are very ugly patterns, but I try to get something working with the means I have within my scope.
Thank you
EDIT, I added CreateInformationObject() method code to my question. I think my hazard may be inside here. Maybe I do some illegal pointer stuff which results in undefined behavior?
I am not an expert on this so take my advise with a grain of salt. In my opinion directly sharing the memory address between the processes will in general fail due to memory protection (which forbids programs to just access memory that was not allocated for them).
You could used shared memory. This is memory shared between processes. Normally one would use this to share memory between concurrent processes but this is in no way necessary (and not having competing accesses is actually beneficial). Wikipedia lists boost and Qt as examples for libraries implementing cross-platform support for shared memory.
Looking into the boost documentation for sharing memory, it says "As shared memory has kernel or filesystem persistence, the user must explicitly destroy it.", which is exactly what you want, since it should persist between calls of the same program. Note that you should remove the shared memory in some other way since it will persist.
Adapting the example from the documentation, it could look something like this:
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <cstring>
#include <cstdlib>
#include <string>
constexpr auto shm_name = "SharedMemoryCLI";
using namespace boost::interprocess;
auto create_shared_memory() {
// Compute your data and calculate the size needed:
shared_memory_object shm {create_only, shm_name, read_write};
// Either use an upper bound for the size needed or compute your data before.
shm.truncate(data_size);
//Map the whole shared memory in this process
mapped_region region{shm, read_write};
// Either write your data directly to region.get_address():
compute_data_to(region.get_address());
// Or have the data already computed and memcopy it:
std::memcpy(region.get_address(), data_ptr, data_size);
return region;
}
auto obtain_memory_region() {
try {
shared_memory_object shm{open_only, shm_name, read_only};
return mapped_region {shm, read_only};
} catch(const std::exception &er) {
// One should probably check if this is the "right" exception but boost does not say what type it uses here...
return create_shared_memory();
}
}
int main(int argc, char *argv[])
{
region = obtain_memory_region();
static_cast<char*>(region.get_address()); // can be used as a to your data.
return 0;
}
Note that you maybe have to persist the exact size of your shared memory in some other way (or maybe just as the first 8 byte of the region). You can then have to somehow get the char* back to your wanted type, but I think that a reinterpret_cast should work here.
The above code is not tested and I give no guarantees but I am pretty confident that it should work roughly in this way and be about as fast as just sharing the pointer (if that would work). You really should read the entirety of https://www.boost.org/doc/libs/1_48_0/doc/html/interprocess/sharedmemorybetweenprocesses.html before applying this in any way.

What is the fundamental difference between Matrix<TDepth> and Mat in EmguCV?

Why is Mat not enough in EmguCV?
Why can't Matrix<> load an image from a file itself?
For instance,
Mat img = new Mat(path);
is a valid operation. But,
Matrix<byte> img = new Matrix<byte>(path);
or,
Matrix<byte> img = Matrix<byte>.FromFile(path);
aren't valid operations.
Based on the information from the Emgu Wiki the fundamental difference between the two types is whether the underlying data array is managed or not.
Mat is a wrapper around the C++ cv::Mat class. Generally this class acts as a smart pointer which manages the memory allocated for the data array it owns (although it's able to just observe as well -- a good example of this capability is the ability to return a Mat header for a Matrix instance in C#). This means that OpenCV is able to (re)allocate the memory as necesssary. The trade-off is that in such cases it's more difficult to access the underlying data effectively in C#.
The Matrix class uses a managed array to hold the data. That means you can easily access the underlying data array in C#.
Honestly, the best person to tell you why it's not possible to load Matrix from an image file would be the author. My guess would be that it's intended to represent other things than images. Technically this could be added in the same way as the ability to load an image file was given to the Mat wrapper (the C++ equivalent has no such feature).

encapsulate an old buffer in a new one

So I have this sort of scheme:
table Request {
a:Sample;
b:Sample;
}
Where table Sample has multiple string vectors and instances of it are pretty big.
I have a lot of files on my filesystem with Sample instances, which took me some time to create.
Now I want to take 2 files at random, read them into memory and create a new Request which encapsulates them.
I'm working with c# and this line works:
var a = Sample.GetRootAsSample(new ByteBuffer(System.IO.File.ReadAllBytes(pathToA)));
var b = Sample.GetRootAsSample(new ByteBuffer(System.IO.File.ReadAllBytes(pathTob)));
but I can't seem to find a way to just reference them in a new Request instance.
I need some way of adding those buffers as is to a new builder and then pass their Offset to the new Request all in the same builder.
Building them all over again in a new builder wouldn't be efficient.
How can I achieve this?
There's currently no way to deep-copy a table automatically in C#. Since tables may refer to all sorts of locations in the buffer, this is not a trivial operation, which requires either special purpose code generation or reflection.
There's a CopyTable in C++ using reflection. This could be ported to C# or called from C#.
An alternative is to include the existing buffers in the new table in binary form, i.e. make a and b a vector of ubytes. It means you have to call GetRootAs on them to access them, but this is all still very efficient.

How to access an array returned by a wrapped non-.net API in C#?

I have a problem with some generic C# wrappers of non-C# code. I have stumbled upon this pattern a few times while programming in windows apis. It looks like a standard pattern ported from C/C++ (pass a pointer to an allocated array, the function then fills it with data). Only in C# there is a problem - it usually only returns the first element of such array.
// some setup
var category = SharpDX.MediaFoundation.TransformCategoryGuids.VideoDecoder;
var flags = SharpDX.MediaFoundation.TransformEnumFlag.Hardware | TransformEnumFlag.Localmft | TransformEnumFlag.SortAndFilter;
var typeInfo = new SharpDX.MediaFoundation.TRegisterTypeInformation();
typeInfo.GuidMajorType = MediaTypeGuids.Video;
typeInfo.GuidSubtype = VideoFormatGuids.H264;
Guid[] guids = new Guid[50];
int someRef;
// problematic line
MediaFactory.TEnum(category, (int)flags, null, null, null, guids, out someRef);
// only first guid is filled out at this point, while I know from other sources that there are more.
This example is from SharpDX and Media Foundation, but I've had simmilar problems with other non-related wrappers. Maybe I'm not accessing the API as I should have?
I've tried with unsafe { ... }, but it did not change a thing.
If you look at the documentation of MFTEnum, the parameter ppclsidMFT is declared as a out parameter while in SharpDX the signature except an input array. If you look at the generated code in SharpDX, it passes a pointer to this copy, so the generated code in SharpDX is invalid. This particular case requires custom marshaling.
MediaFoundation in SharpDX is not a complete API and not always correctly mapped to C# due to the facts:
MediaFoundation C++ headers are not well structured and they don't contain enough annotation information like Direct3D11 to produce a more reliable generated wrapper
MediaFoundation is a huge API that can only be fixed on a per-usage basis. So far, MediaFoundation was only introduced in SharpDX to support MediaEngine for Windows Store/Phone Apps. The rest of the API could or could not work well.
Feel free to fill a bug or even better, make a PR...

How to Iterate Through Array in C# Across Multiple Calls

We have an application where we need to de-serialize some data from one stream into multiple objects.
The Data array represents a number of messages of variable length packed together. There are no message delimiting codes in the stream.
We want to do something like:
void Decode(byte[] Data)
{
Object0.ExtractMessage(Data);
Object1.ExtractMessage(Data);
Object2.ExtractMessage(Data);
...
}
where each ProcessData call knows where to start in the array. Ideally we'd do this without passing a DataIx reference in.
To do this in C++ we'd just hand around a pointer into the array, and each ProcessData function would increment it as required.
Each object class knows how its own messages are serialized and can be relied upon (in C++) to return the pointer at the beginning of the next message in the stream.
Is there some inbuilt mechanism we can use to do this (without going unsafe)? The operation is high frequency (~10kps) and very lightweight. We also don't want to go copying or trimming the array.
Thanks for your help.
Could you not just pass in and return the array index? That is basically all that a pointer is anyway, an offset from a fixed memory location.
Well this sounds like you want a simple stream (E.g. just use MemoryStream as a wrapper around your byte array: stream = new MemoryStream (data)). Just wrap the byte array into a stream and every object reads as much from the stream as it needs and then hands over the stream to the next item. It even has the benefit that you aren't forced to loading the entire byte-array at once.
Other than that you can use pointers in C# exactly the way you did in C++ (though pointers require the unsafe keyword and they are discouraged)
Alternatively you could just pass data and an index variable and then increment the index (which is, in effect, the same as using a pointer but doesn't need unsafe).
How about wrapping the data in a MemoryStream and then passing a StreamReader into the ExtractMessage method?
I guess several things come to mind.
You could simulate the action of the pointer by wrapping the byte[] in a class which also maintained the array offset. Whenever you access the array you would access it thru the class, probably via an accessor method, which returned the next byte and also incremented the offset variable. The class instance could be passed between the different ExtractMessage function calls.
How about using C++/CLI? This would allow you to use familiar C/C++ techniques, and yet be directly callable from C# without the dreaded interop.
Then of course there is the dreaded unsafe option, whereby you obtain a C# pointer to the byte[] and perform the required pointer arithmetic.
You could create a stream from the byte array.
Stream stream = new MemoryStream(data);
Then your processor's could work on streams instead.

Categories

Resources