Perhaps the problem i have is a bit specific but I'm sure the solution would be interesting for a lot of people.
Now to the point. I have an ActiveX control that plays streaming video. My goal is to get to every frame it plays and display them in external c# application over some windows control, a panel, for instance.
Here is the sample DirectShow transform filter:
STDMETHODIMP CTransform::Transform(BSTR bsResource, struct U_VideoFrame *pInFrame, struct U_VideoFrameData **pOutFrameData)
{
//Must allocate memory this way, the output size must be equal to input size
*pOutFrameData = (U_VideoFrameData*)CoTaskMemAlloc(sizeof(U_VideoFrameData));
(*pOutFrameData)->pFrame = (BYTE*)CoTaskMemAlloc(pInFrame->Frame.nLength);
(*pOutFrameData)->nLength = pInFrame->Frame.nLength;
//Now transform data contained in (*pOutFrameData)->pFrame;
//We simply copy data here
memcpy((*pOutFrameData)->pFrame, pInFrame->Frame.pFrame, pInFrame->Frame.nLength);
return S_OK;
}
My idea is that somewhere inside this method I should place a callback function that will call my managed code and pass pInFrame to it. How can I do it? Please help
P.S. I have read the great article Howto implement callback interface from unmanaged DLL to .net app. It works as described (of course). However, when I modify the code above to this:
typedef int (__stdcall * Callback)(const char* text);
static Callback Handler = 0;
extern "C" __declspec(dllexport)
void __stdcall SetCallback(Callback handler) {
Handler = handler;
}
extern "C" __declspec(dllexport)
void __stdcall TestCallback() {
int retval = Handler("hello world");
}
// CTransform
STDMETHODIMP CTransform::Transform(BSTR bsResource, struct U_VideoFrame *pInFrame, struct U_VideoFrameData **pOutFrameData)
{
//Must allocate memory this way, the output size must be equal to input size
*pOutFrameData = (U_VideoFrameData*)CoTaskMemAlloc(sizeof(U_VideoFrameData));
(*pOutFrameData)->pFrame = (BYTE*)CoTaskMemAlloc(pInFrame->Frame.nLength);
(*pOutFrameData)->nLength = pInFrame->Frame.nLength;
//Now transform data contained in (*pOutFrameData)->pFrame;
//We simply copy data here
memcpy((*pOutFrameData)->pFrame, pInFrame->Frame.pFrame, pInFrame->Frame.nLength);
if (Handler != 0)
int retval = Handler("Transform");
return S_OK;
}
then the event does not fire from Transform method. TestCallback() method works
I'm stuck. Any help will be greatly appreciated.
Related
I'm trying to use some native functions in C# over OpenGL.
I need to draw a Sphere and I read about gluSphere and looked at it on GL\glu.h, but receives a struct object as parameter:
typedef struct GLUquadric GLUquadric;
void APIENTRY gluSphere(GLUquadric *qobj,GLdouble radius,GLint slices,GLint stacks);
I need to create a struct so I can send it to gluSphere.
Is there some place or information of how is GLUquadric defined so I can write it and send it to gluSphere ?
[StructLayout(LayoutKind.Sequential)]
struct GLUquadric{
//What's here???
}
The bigger question is, if you actually want to use GLU at all. GLU has not been maintained for decades and didn't keep up with the development of the OpenGL API. GLU is not part of OpenGL proper, it's a companion library developed by SGI alongside OpenGL and published together with the OpenGL-1.1 specification. This first and latest version of GLU still assumes the presence of a fixed function pipeline and immediate drawing modes. Both have been removed from modern OpenGL.
I need to create a struct so I can send it to gluNewQuadric.
Actually there's no need to know what's inside this struct. It's defined as a opaque pointer type. Think of it as a class instance handle to which you don't have the interface; you can still pass it into the module implementing the class and call global methods on it, but you can't look inside. From the C# perspective it's an unmanaged pointer to something.
EDIT a code example (that I hope is valid C#)
[DllImport("glu32.dll")]
static extern IntPtr gluNewQuadric();
[DllImport("glu32.dll")]
static extern void gluDeleteQuadric(IntPtr quadric);
[DllImport("glu32.dll")]
static extern void gluSphere(IntPtr quadric, double radius, int slices, int stacks);
IntPtr quadric = gluNewQuadric();
gluSphere(quadric, 1, 10, 10);
gluDeleteQuadric(quadric);
That being said if you accept these caveats I wonder if it wouldn't make more sense to port some GLU implementation over to .net/CLI so that it can be used natively from C#.
You can of course also access GLU through unmanaged interfaces. Now my personal experience with C# is little (I've got more experience with F#) and I never left the managed grounds doing unmanaged things. But from my understanding what you have to do there is just define an integer variable large enough to hold a native pointer (and if I'm not mistaken, there already should be such a integer type for holding unmanaged pointers) and use that for the GLUQuadric* type.
Looks like searching in google for
"struct GLUquadric"
didn't give any information or clue... But searching for
"struct GLUquadric{ "
took me to the place I wanted:
OGLES_GLU.h
Struct I found and used and WORKS is:
[StructLayout(LayoutKind.Sequential)]
public struct GLUquadric
{
int normals;
bool textureCoords;
int orientation;
int drawStyle;
}
So now I can use:
[DllImport("glu32.dll")]
static extern void gluSphere(ref GLUquadric qobj, double radius, int slices, int stacks);
public static void Sphere(ref GLUquadric qobject, double Radius, int Slices, int Stacks)
{
gluSphere(ref qobject, Radius, Slices, Stacks);
}
OpenGL draws spheres now.
NOTE: When drawing spheres in imported openGL function, DO NOT CALL gluDeleteQuadric();
Let GC do it's work, just declare a new GLUQuadric() and send it as a ref to gluSphere, else you will have memory problems in your program.
To compliment datenwolf's answer which is not valid in my case:
The implementation of my program is this way:
[StructLayout(LayoutKind.Sequential)]
public struct GLUquadric
{
int normals;
bool textureCoords;
int orientation;
int drawStyle;
public void Init(int norm, int draw, int orient, bool textCoor)
{
normals = norm;
drawStyle = draw;
orientation = orient;
textureCoords = textCoor;
}
}
Use is:
public static void DrawSphere(T Radius, Int32 Slices, Int32 Stacks,
GLU.QuadricDrawStyles Style, GLU.QuadricNormals Normal, Color color)
{
OpenGL.SetColor(color);
GLU.GLUquadric quadric = new GLU.GLUquadric();
quadric.Init((int)Normal, (int)Style, 0, false);
GLU.Sphere(ref quadric, (dynamic)Radius, Slices, Stacks);
}
Implementation is full OO, so every Sphere is isolated from static GL Function as gluQuadricDrawStyle and gluQuadricNormals so leaving struct empty is NOT valid since it will draw nothing.
In my code I retrieve frames from a camera with a pointer to an unmanaged object, make some calculations on it and then I make it visualized on a picturebox control.
Before I go further in this application with all the details, I want to be sure that the base code for this process is good.
In particular I would like to:
- keep execution time minimal and avoid unnecessary operations, such as
copying more images than necessary. I want to keep only essential
operations
- understand if a delay in the calculation process on every frame could have detrimental effects on the way images are shown (i.e. if it is not printed what I expect) or some image is skipped
- prevent more serious errors, such as ones due to memory or thread management, or to image display.
For this purpose, I set up a few experimental lines of code (below), but I’m not able to explain the results of what I found. If you have the executables of OpenCv you can make a try by yourself.
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;
public partial class FormX : Form
{
private delegate void setImageCallback();
Bitmap _bmp;
Bitmap _bmp_draw;
bool _exit;
double _x;
IntPtr _ImgBuffer;
bool buffercopy;
bool copyBitmap;
bool refresh;
public FormX()
{
InitializeComponent();
_x = 10.1;
// set experimemental parameters
buffercopy = false;
copyBitmap = false;
refresh = true;
}
private void buttonStart_Click(object sender, EventArgs e)
{
Thread camThread = new Thread(new ThreadStart(Cycle));
camThread.Start();
}
private void buttonStop_Click(object sender, EventArgs e)
{
_exit = true;
}
private void Cycle()
{
_ImgBuffer = IntPtr.Zero;
_exit = false;
IntPtr vcap = cvCreateCameraCapture(0);
while (!_exit)
{
IntPtr frame = cvQueryFrame(vcap);
if (buffercopy)
{
UnmanageCopy(frame);
_bmp = SharedBitmap(_ImgBuffer);
}
else
{ _bmp = SharedBitmap(frame); }
// make calculations
int N = 1000000; /*1000000*/
for (int i = 0; i < N; i++)
_x = Math.Sin(0.999999 * _x);
ShowFrame();
}
cvReleaseImage(ref _ImgBuffer);
cvReleaseCapture(ref vcap);
}
private void ShowFrame()
{
if (pbCam.InvokeRequired)
{
this.Invoke(new setImageCallback(ShowFrame));
}
else
{
Pen RectangleDtPen = new Pen(Color.Azure, 3);
if (copyBitmap)
{
if (_bmp_draw != null) _bmp_draw.Dispose();
//_bmp_draw = new Bitmap(_bmp); // deep copy
_bmp_draw = _bmp.Clone(new Rectangle(0, 0, _bmp.Width, _bmp.Height), _bmp.PixelFormat);
}
else
{
_bmp_draw = _bmp; // add reference to the same object
}
Graphics g = Graphics.FromImage(_bmp_draw);
String drawString = _x.ToString();
Font drawFont = new Font("Arial", 56);
SolidBrush drawBrush = new SolidBrush(Color.Red);
PointF drawPoint = new PointF(10.0F, 10.0F);
g.DrawString(drawString, drawFont, drawBrush, drawPoint);
drawPoint = new PointF(10.0F, 300.0F);
g.DrawString(drawString, drawFont, drawBrush, drawPoint);
g.DrawRectangle(RectangleDtPen, 12, 12, 200, 400);
g.Dispose();
pbCam.Image = _bmp_draw;
if (refresh) pbCam.Refresh();
}
}
public void UnmanageCopy(IntPtr f)
{
if (_ImgBuffer == IntPtr.Zero)
_ImgBuffer = cvCloneImage(f);
else
cvCopy(f, _ImgBuffer, IntPtr.Zero);
}
// only works with 3 channel images from camera! (to keep code minimal)
public Bitmap SharedBitmap(IntPtr ipl)
{
// gets unmanaged data from pointer to IplImage:
IntPtr scan0;
int step;
Size size;
OpenCvCall.cvGetRawData(ipl, out scan0, out step, out size);
return new Bitmap(size.Width, size.Height, step, PixelFormat.Format24bppRgb, scan0);
}
// based on older version of OpenCv. Change dll name if different
[DllImport( "opencv_highgui246", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr cvCreateCameraCapture(int index);
[DllImport("opencv_highgui246", CallingConvention = CallingConvention.Cdecl)]
public static extern void cvReleaseCapture(ref IntPtr capture);
[DllImport("opencv_highgui246", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr cvQueryFrame(IntPtr capture);
[DllImport("opencv_core246", CallingConvention = CallingConvention.Cdecl)]
public static extern void cvGetRawData(IntPtr arr, out IntPtr data, out int step, out Size roiSize);
[DllImport("opencv_core246", CallingConvention = CallingConvention.Cdecl)]
public static extern void cvCopy(IntPtr src, IntPtr dst, IntPtr mask);
[DllImport("opencv_core246", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr cvCloneImage(IntPtr src);
[DllImport("opencv_core246", CallingConvention = CallingConvention.Cdecl)]
public static extern void cvReleaseImage(ref IntPtr image);
}
results [dual core 2 Duo T6600 2.2 GHz]:
A. buffercopy = false; copyBitmap = false; refresh = false;
This is the simpler configuration. Each frame is retrieved in turn, operations are made (in the reality they are based on the same frame, here just calculations), then the result of the calculations is printed on top of the image and finally it is displayed on a picturebox.
OpenCv documentation says:
OpenCV 1.x functions cvRetrieveFrame and cv.RetrieveFrame return image
stored inside the video capturing structure. It is not allowed to
modify or release the image! You can copy the frame using
cvCloneImage() and then do whatever you want with the copy.
But this doesn’t prevent us from doing experiments.
If the calculation are not intense (low number of iterations, N), everything is just ok and the fact that we manipulate the image buffer own by the unmanaged frame retriever doesn’t pose a problem here.
The reason is that probably they advise to leave untouched the buffer, in case people would modify its structure (not its values) or do operations asynchronously without realizing it. Now we retrieve frames and modify their content in turn.
If N is increased (N=1000000 or more), when the number of frames per second is not high, for example with artificial light and low exposure, everything seems ok, but after a while the video is lagged and the graphics impressed on it are blinking. With a higher frame rate the blinking appears from the beginning, even when the video is still fluid.
Is this because the mechanism of displaying images on the control (or refreshing or whatever else) is somehow asynchronous and when the picturebox is fetching its buffer of data it is modified in the meanwhile by the camera, deleting the graphics?
Or is there some other reason?
Why is the image lagged in that way, i.e. I would expect that the delay due to calculations only had the effect of skipping the frames received by the camera when the calculation are not done yet, and de facto only reducing the frame rate; or alternatively that all frames are received and the delay due to calculations brings the system to process images gotten minutes before, because the queue of images to process rises over time.
Instead, the observed behavior seems hybrid between the two: there is a delay of a few seconds, but this seems not increased much as the capturing process goes on.
B. buffercopy = true; copyBitmap = false; refresh = false;
Here I make a deep copy of the buffer into a second buffer, following the advice of the OpenCv documentation.
Nothing changes. The second buffer doesn’t change its address in memory during the run.
C. buffercopy = false; copyBitmap = true; refresh = false;
Now the (deep) copy of the bitmap is made allocating every time a new space in memory.
The blinking effect has gone, but the lagging keep arising after a certain time.
D. buffercopy = false; copyBitmap = false; refresh = true;
As before.
Please help me explain these results!
If I may be so frank, it is a bit tedious to understand all the details of your questions, but let me make a few points to help you analyse your results.
In case A, you say you perform calculations directly on the buffer. The documentation says you shouldn't do this, so if you do, you can expect undefined results. OpenCV assumes you won't touch it, so it might do stuff like suddenly delete that part of memory, let some other app process it, etc. It might look like it works, but you can never know for sure, so don't do it *slaps your wrist* In particular, if your processing takes a long time, the camera might overwrite the buffer while you're in the middle of processing it.
The way you should do it is to copy the buffer before doing anything. This will give you a piece of memory that is yours to do with whatever you wish. You can create a Bitmap that refers to this memory, and manually free the memory when you no longer need it.
If your processing rate (frames processed per second) is less than the number of frames captured per second by the camera, you have to expect some frames will be dropped. If you want to show a live view of the processed images, it will lag and there's no simple way around it. If it is vital that your application processes a fluid video (e.g. this might be necessary if you're tracking an object), then consider storing the video to disk so you don't have to process in real-time. You can also consider multithreading to process several frames at once, but the live view would have a latency.
By the way, is there any particular reason why you're not using EmguCV? It has abstractions for the camera and a system that raises an event whenever the camera has captured a new frame. This way, you don't need to continuously call cvQueryFrame on a background thread.
I think that you still have a problem with your UnmanageCopy method in that you only clone the image the first time this is called and you subsequently copy it. I believe that you need to do a cvCloneImage(f) every time as copy performs only a shallow copy, not a deep copy as you seem to think.
I have a C# DLL, whose code derives from a base class, which is written in managed C++. (I don't have any control over the base class code)
This base class (which is in managed C++) has a member
int *buffer
is expected to be memset (filled with Zeros) by the derived class (which is in C#). The derived class knows the size of the buffer.
I am using unsafe context, to access the member "int *buffer" of the base class, in the derived class. Please let me know is there any way special way to memset the buffer in "unsafe" context in c#.
I already looked into this What is the equivalent of memset in C#? for details, but I would like to know is there something specifically for "unsafe" context.
Background : This is a conversion project, where the derived class itself was in managed c++ before. Now I am converting the derived class DLL alone to C#. Also I have no control over the base class code! The current code flow is as follows: Only the derived class knows the size of the buffer. The base class creates a memory for that particular size, by getting the size of the buffer from derived, but it doesn't zero fill. The derived class Zero fills it first and then need to appropriately fill the buffer with its contents. Though strange, that is how it is.
Thanks!
Well, there is... memset. Why settle for a replacement when you can p/invoke the real thing?
[DllImport("msvcrt.dll", EntryPoint = "memset", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
public static extern IntPtr MemSet(IntPtr dest, int c, IntPtr count);
Taken from pinvoke.net
edit
As #Hans rightfully mentions in the OP comments, this is useless if you don't already know the size of *buffer.
You can code it on your own:
void memset( byte* buffer, int value, int size )
{
for( int i = 0; i < count; i++)
{
*( buffer + i ) = value;
}
}
Or you can use an API for this. Actually RtlZeroMemory sets values to zero. It's not actually memset.
[DllImport("kernel32.dll")]
static extern void RtlZeroMemory(IntPtr dst, int length);
RtlZeroMemory(buffer, bufferLength);
RtlZeroMemory is not actually an entry point in kernel32. If yo want something like that, use this in C#
public static unsafe void ZeroMemory(IntPtr Safebuffer, int count)
{
if (count == 0) return;
byte* buffer = (byte*)Safebuffer.ToPointer();
memset(buffer, count);
}
public static unsafe void ZeroMemory(byte* buffer, int count)
{
if (count == 0) return;
while (count-- > 0)
{
buffer[count] = 0;
}
}
I have an application which uses a C++ DLL to communicate with a Canon Camera, methods in this C++ DLL are invoked from a C# application. What I've seen in the application is that when taking photos, the memory increases, of course. After I close the "Image Capture Window" the application still holds the same amount of memory as it did, when all of the images were captured.
Since my application exists of many layers of WPF UserControls, I thought that the "Image Preview UserControl" was unable to get garbage collected because of other controls subscribed to an event fired from this control. After some googling, I decided to implement the Weak Reference Pattern on the events.
//Source code found here: http://paulstovell.com/blog/weakevents
public sealed class WeakEventHandler<TEventArgs> where TEventArgs : EventArgs
{
private readonly WeakReference _targetReference;
private readonly MethodInfo _method;
public WeakEventHandler(EventHandler<TEventArgs> callback)
{
_method = callback.Method;
_targetReference = new WeakReference(callback.Target, true);
}
public void Handler(object sender, TEventArgs eventArgs)
{
var target = _targetReference.Target;
if (target != null)
{
var callback =
(Action<object, TEventArgs>)
Delegate.CreateDelegate(typeof (Action<object, TEventArgs>), target, _method, true);
if (callback != null)
{
callback(sender, eventArgs);
}
}
}
}
So, if I forget to unsubscribe some events the GC will collect them anyway. After some more testing, this approach did not work, so I decided to use the Redgate ANTS Memory Profiler
I took three snapshots:
Before taking images
After I took 4 images
After destruction of the wpf controllers
The result when comparing snapshot 1 and 3:
As you can see the amount of allocated Unmanaged Memory is the big problem here. My first thought would be that the C++ DLL isn't deallocating the allocated memory when the "Image Capture Window" is closed.
Am I correct that the problem is in the C++ plugin? Can I exclude the C# application? As far as I know, all code written in .NET is managed memory.
Based upon a comment here is how the image arrives from the C++ plugin to the C# plugin:
From the C++ plugin there is a callback like this:
_resultcallback(img->GetImageInfo().Data, img->GetImageInfo().Width, img->GetImageInfo().Height, img->GetImageInfo().BPP);
And the method which receives the image on the C# side:
private void OnResultImageCallback(IntPtr imagePtr, int width, int height, int bitsPerPixel)
{
_state = CameraState.InitializedStandby;
_cbResultData.Width = width;
_cbResultData.Height = height;
_cbResultData.BitsPerPixel = bitsPerPixel;
int memSize = bitsPerPixel * width * height / 8;
_cbResultData.data = new byte[memSize];
Marshal.Copy(imagePtr, _cbResultData.data, 0, memSize);
_deleteAllocatedImageFunction(imagePtr);
if (ImageCaptured != null)
ImageCaptured(_cbResultData.data, _cbResultData.Width, _cbResultData.Height, _cbResultData.BitsPerPixel);
_cbResultData.data = null;
}
I also have a method to clear the allocated memory in my C++ which takes in a byte-pointer like this:
BOOL CanonEDSDKWnd::ClearImageBuffer(BYTE* img) {
_debug->Write(_T("CanonEDSDKWnd::ClearImageBuffer"));
delete[] img;
return TRUE;
}
Which is called from the C# code with the IntPtr from the callback
_deleteAllocatedImageFunction(imagePtr);
I think your callback function should look like the following:
C++ side:
_resultcallback(
img // extend the signature
img->GetImageInfo().Data,
img->GetImageInfo().Width,
img->GetImageInfo().Height,
img->GetImageInfo().BPP
);
C# side:
private void OnResultImageCallback(IntPtr img, IntPtr imagePtr, int width, int height, int bitsPerPixel)
{
_state = CameraState.InitializedStandby;
_cbResultData.Width = width;
_cbResultData.Height = height;
_cbResultData.BitsPerPixel = bitsPerPixel;
int memSize = bitsPerPixel * width * height / 8;
_cbResultData.data = new byte[memSize];
Marshal.Copy(imagePtr, _cbResultData.data, 0, memSize);
_deleteAllocatedImageFunction(img);
if (ImageCaptured != null)
ImageCaptured(_cbResultData.data, _cbResultData.Width, _cbResultData.Height, _cbResultData.BitsPerPixel);
_cbResultData.data = null;
}
I have these in my c++ header file
#ifndef S2dll_H
#define S2dll_H
#ifdef S2dll_EXPORTS
#define S2dll_API __declspec(dllexport)
#else
#pragma message("automatic link to S2dll.LIB")
#pragma comment(lib, "S2dll.lib")
#define S2dll_API __declspec(dllimport)
#endif
class is declared like this
class S2dll_API Sample
{
//members here
}
a cpp file containing function definitions, constructors
void * __stdcall CreateS() //constructor
{
return new SDLL;
}
void __stdcall DestroyS(void * objPtr) //destructor
{
s* sObj = (s *) objPtr;
if (sobj)
delete sObj;
}
exporting/exposing this function
void __stdcall setvaluesDLL(void *ptr, int x, int y,int s, int p)
{
Sample *dll = (Sample *) ptr;
if (dll)
{
dll->setposition(c); //functions in the cpp file
dll->setlocation(x,y);
dll->setsize(s);
}
}
a .def file
LIBRARY BS2dll
EXPORTS
CreateS
DestroyS
setvaluesDLL
so I am trying to access it in my c# win form
made this to expose it
static internal class dllcall
{
[DllImport(#"adrress\S2dll.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void setvaluesDLL(IntPtr ptr,int x, int y, int s, int p);
}
calling it in my winform
private void Assign_Click(object sender, EventArgs e)
{
dllcall.setvaluesDLL(ptr, x, y, s, p);//all values are int
}
I get this error:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
been searching google and staring at this code for hours and every time I manage to solve a problem, a new one comes out whenever I call setvaluesDLL(//parameters)
EDITED:
IntPtr ptr is my main problem here and I have absolutely no idea how to use nor initialize it
You have to initialize first setvaluesDLL parameter value with CreateS() result. This method should be imported from the dll too. The same as DestroyS - to release memory properly
You have 5 arguments in your C++ file:
void __stdcall setvaluesDLL(void *ptr, int x, int y,int s, int p)
And only 4 in the C#:
public static extern void setvaluesDLL(int x, int y, int s, int p)
Also I don't think there's a direct equivalent to a void* pointer, so you might want to use unsafe code (you need to allow it in your project settings).
From what I know you cannot explicitly import a c++ class in C# (to initialize ptr in Assign_Click). Maybe you could write some functions in the dll to render it available to C# -- or you could delve into the assembly.