IImage* from IBitmapImage* - com

I'm using the Imaging API to basically write a rescaling function using the Imaging built-in Resize function.
I need to feed a custom UBitmap class that it's constructed with an Image* pointer with the resized function, so here's the Rescale function proto:
int Rescale(const UBitmap* src, UBitmap* dst, UINT w, UINT h)
My function allocates heap for the dst pointer (caller does need to free it only).
What I've done so far:
// Get the IImage ptr from the source
HRESULT hr;
CoInitializeEx(NULL, COINIT_MULTITHREADED);
IImage* img_in = src->GetIImage();
if (img_in)
{
IImagingFactory* pImgf = NULL;
hr = CoCreateInstance(CLSID_ImagingFactory, 0, CLSCTX_ALL,
IID_IImagingFactory, void**)&pImgf);
assert(SUCCEEDED(hr));
IBitmapImage* pIResBmp = NULL;
hr = pImgf->CreateBitmapFromImage(img_in,w,h, PixelFormatDontCare,
InterpolationHintBilinear, &pIResBmp);
assert(SUCCEEDED(hr));
IImage* pImgOut = NULL; // How to obtain IImage pointer from pIResBmp?
bmpOut = new UBitmap(dst);
pImgf->Release();
}
CoUninitialize();
So I've successfully rescaled the image with the pImg->CreateBitmapFromImage call, but I don't know how to obtain IImage* to feed the UBitmap constructor.
THanks in advance.

To obtain IImage* object simply use IImagingFactory::CreateImageFromFile.
See http://msdn.microsoft.com/en-us/library/aa918650.aspx

Related

EDSDK Live view problems using canon example

I need to make a function for live view image in canon camera, but when I try to use the example code provided from canon I got some errors in variables. So I modified the code so that it could work. But the function EDSDK.EdsGetPropertyData returns the error code 98 (in hex 62) which represents the error EDS_ERR_INVALID_POINTER. I would like to know what is wrong in my code, and how can I proceed it.
IntPtr outData;
public void startLiveview(IntPtr camera)
{
uint err = EDSDK.EDS_ERR_OK;
EDSDK.EdsDataType device = new EDSDK.EdsDataType();
int size;
EDSDK.EdsOpenSession(camera);
// Get the output device for the live view image EdsUInt32 device; err = EdsGetPropertyData(camera, kEdsPropID_Evf_OutputDevice, 0 , , sizeof(device), &device );
// PC live view starts by setting the PC as the output device for the live view image. if(err == EDS_ERR_OK) { device |= kEdsEvfOutputDevice_PC;
err = EDSDK.EdsGetPropertySize(camera, EDSDK.PropID_Evf_OutputDevice, 0,out device, out size);
MessageBox.Show("Error result:"+err.ToString());
MessageBox.Show(device.ToString());
MessageBox.Show(size.ToString());
err = EDSDK.EdsGetPropertyData(camera, EDSDK.PropID_Evf_OutputDevice, 0, size, outData);
MessageBox.Show(outData.ToString());
if (err == EDSDK.EDS_ERR_OK)
{
//type2.GetType();
//device |= EDSDK.PropID_Evf_OutputDevice;
// err = EDSDK.EdsSetPropertyData(camera, EDSDK.PropID_Evf_OutputDevice, 0, sizeof(device), &device);
}
else
{
MessageBox.Show("Error result:" + err.ToString());
}
EDSDK.EdsCloseSession(camera);
}
EdsGetPropertyData expects the outData pointer to have a value but you are passing a zero pointer.
You need to allocate memory first and then call EdsGetPropertyData, i.e. something like this:
outData = System.Runtime.InteropServices.Marshal.AllocHGlobal(size);
err = EDSDK.EdsGetPropertyData(camera, EDSDK.PropID_Evf_OutputDevice, 0, size, outData);
Once you are done, you must release that allocated memory or you'll have a memory leak:
System.Runtime.InteropServices.Marshal.FreeHGlobal(outData);
In the C# examples of the Canon SDK (since version 13.x, I believe) you should find methods that already implement EdsGetPropertyData methods for several data types. Why not use those instead of writing it yourself?

Problems connecting to the input pins of GMFBridge Sink Filter

I am experiencing a strange problem when trying to use the GMFBridge filter with the output of an Euresys UxH264 card.
I am trying to integrate this card into our solution, that relies on GMFBridge to handle the ability of continuous capture to multiple files, performing muxing and file-splitting without having to stop the capture graph.
This card captures video and audio from analog inputs. It provides a DirectShow filter exposing both a raw stream of the video input and a hardware-encoded H.264 stream. The audio stream is provided as an uncompressed stream only.
When I attempt to directly connect any of the output pins of the Euresys source filters to the input pins of the GMFBridge Sink, they get rejected, with the code VFW_E_NO_ALLOCATOR. (In the past I have successfully connected both H.264 and raw audio streams to the bridge).
Grasping at straws, I plugged in a pair of SampleGrabber filters between the Euresys card filters and the bridge sink filter, and -just like that- the connections between sample grabbers and sink were accepted.
However, I am not getting any packets on the other side of the bridge (the muxing graph). I inspected the running capture graph with GraphStudioNext and somehow the sample grabbers appear detached from my graph, even though I got successful confirmations when I connected them to the source filter!.
Here's the source code creating the graph.
void EuresysSourceBox::BuildGraph() {
HRESULT hRes;
CComPtr<IGraphBuilder> pGraph;
COM_CALL(pGraph.CoCreateInstance(CLSID_FilterGraph));
#ifdef REGISTER_IN_ROT
_rotEntry1 = FilterTools::RegisterGraphInROT(IntPtr(pGraph), "euresys graph");
#endif
// [*Video Source*]
String^ filterName = "Ux H.264 Visual Source";
Guid category = _GUIDToGuid((GUID)AM_KSCATEGORY_CAPTURE);
FilterMonikerList^ videoSourceList = FilterTools::GetFilterMonikersByName(category, filterName);
CComPtr<IBaseFilter> pVideoSource;
int monikerIndex = config->BoardIndex; // a filter instance will be retrieved for every installed board
clr_scoped_ptr<CComPtr<IMoniker>>^ ppVideoSourceMoniker = videoSourceList[monikerIndex];
COM_CALL((*ppVideoSourceMoniker->get())->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pVideoSource));
COM_CALL(pGraph->AddFilter(pVideoSource, L"VideoSource"));
// [Video Source]
//
// [*Audio Source*]
filterName = "Ux H.264 Audio Encoder";
FilterMonikerList^ audioSourceList = FilterTools::GetFilterMonikersByName(category, filterName);
CComPtr<IBaseFilter> pAudioSource;
clr_scoped_ptr<CComPtr<IMoniker>>^ ppAudioSourceMoniker = audioSourceList[monikerIndex];
COM_CALL((*ppAudioSourceMoniker->get())->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pAudioSource));
COM_CALL(pGraph->AddFilter(pAudioSource, L"AudioSource"));
CComPtr<IPin> pVideoCompressedOutPin(FilterTools::GetPin(pVideoSource, "Encoded"));
CComPtr<IPin> pAudioOutPin(FilterTools::GetPin(pAudioSource, "Audio"));
CComPtr<IBaseFilter> pSampleGrabber;
COM_CALL(pSampleGrabber.CoCreateInstance(CLSID_SampleGrabber));
COM_CALL(pGraph->AddFilter(pSampleGrabber, L"SampleGrabber"));
CComPtr<IPin> pSampleGrabberInPin(FilterTools::GetPin(pSampleGrabber, "Input"));
COM_CALL(pGraph->ConnectDirect(pVideoCompressedOutPin, pSampleGrabberInPin, NULL)); // DOES NOT FAIL!!
CComPtr<IBaseFilter> pSampleGrabber2;
COM_CALL(pSampleGrabber2.CoCreateInstance(CLSID_SampleGrabber));
COM_CALL(pGraph->AddFilter(pSampleGrabber2, L"SampleGrabber2"));
CComPtr<IPin> pSampleGrabber2InPin(FilterTools::GetPin(pSampleGrabber2, "Input"));
COM_CALL(pGraph->ConnectDirect(pAudioOutPin, pSampleGrabber2InPin, NULL)); // DOES NOT FAIL!!
// [Video Source]---
// |-->[*Bridge Sink*]
// [Audio Source]---
CComPtr<IPin> pSampleGrabberOutPin(FilterTools::GetPin(pSampleGrabber, "Output"));
CComPtr<IPin> pSampleGrabber2OutPin(FilterTools::GetPin(pSampleGrabber2, "Output"));
CreateGraphBridge(
IntPtr(pGraph),
IntPtr(pSampleGrabberOutPin),
IntPtr(pSampleGrabber2OutPin)
);
// Root graph to parent object
_ppCaptureGraph.reset(new CComPtr<IGraphBuilder>(pGraph));
}
COM_CALL is my HRESULT checking macro, it will raise a managed exception if the result is other than S_OK. So the connection between pins succeeded, but here is how the graph looks disjointed when it is running:
So, I have three questions:
1) What could VFW_E_NO_ALLOCATOR mean in this instance? (the source filter can be successfully connected to other components such as LAV Video decoder or ffdshow video decoder).
2) Is there a known workaround to circumvent the VFW_E_NO_ALLOCATOR problem?
3) Is it possible that a filter gets disconnected at runtime as it seems to be happening in my case?
I found a reference by Geraint Davies giving a reason as to why the GMFBridge sink filter may be rejecting the connection.
It looks as though the parser is insisting on using its own allocator
-- this is common with parsers where the output samples are merely pointers into the input samples. However, the bridge cannot implement
suspend mode without using its own allocator, so a copy is required.
With this information, I decided to create an ultra simple CTransformFilter filter that simply accepts the allocator offered by the bridge and copies to the output sample whatever comes in from the input sample. I am not 100% sure that what I did was right, but it is working now. I could successfully plug-in the Euresys card as part of my capture infrastructure.
For reference, if anyone experiences something similar, here is the code of the filter I created:
class SampleCopyGeneratorFilter : public CTransformFilter {
protected:
HRESULT CheckInputType(const CMediaType* mtIn) override { return S_OK; }
HRESULT GetMediaType(int iPosition, CMediaType* pMediaType) override;
HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut) override { return S_OK; }
HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProp) override;
HRESULT Transform(IMediaSample *pSource, IMediaSample *pDest) override;
public:
SampleCopyGeneratorFilter();
};
//--------------------------------------------------------------------------------------------------------------------
SampleCopyGeneratorFilter::SampleCopyGeneratorFilter()
: CTransformFilter(NAME("SampleCopyGeneratorFilter"), NULL, GUID_NULL)
{
}
HRESULT SampleCopyGeneratorFilter::GetMediaType(int iPosition, CMediaType* pMediaType) {
HRESULT hRes;
ASSERT(m_pInput->IsConnected());
if( iPosition < 0 )
return E_INVALIDARG;
CComPtr<IPin> connectedTo;
COM_CALL(m_pInput->ConnectedTo(&connectedTo));
CComPtr<IEnumMediaTypes> pMTEnumerator;
COM_CALL(connectedTo->EnumMediaTypes(&pMTEnumerator));
AM_MEDIA_TYPE* pIteratedMediaType;
for( int i = 0; i <= iPosition; i++ ) {
if( pMTEnumerator->Next(1, &pIteratedMediaType, NULL) != S_OK )
return VFW_S_NO_MORE_ITEMS;
if( i == iPosition )
*pMediaType = *pIteratedMediaType;
DeleteMediaType(pIteratedMediaType);
}
return S_OK;
}
HRESULT SampleCopyGeneratorFilter::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProp) {
HRESULT hRes;
AM_MEDIA_TYPE mt;
COM_CALL(m_pInput->ConnectionMediaType(&mt));
try {
BITMAPINFOHEADER* pBMI = HEADER(mt.pbFormat);
pProp->cbBuffer = DIBSIZE(*pBMI); // format is compressed, uncompressed size should be enough
if( !pProp->cbAlign )
pProp->cbAlign = 1;
pProp->cbPrefix = 0;
pProp->cBuffers = 4;
ALLOCATOR_PROPERTIES actualProperties;
COM_CALL(pAlloc->SetProperties(pProp, &actualProperties));
if( pProp->cbBuffer > actualProperties.cbBuffer )
return E_FAIL;
return S_OK;
} finally{
FreeMediaType(mt);
}
}
HRESULT SampleCopyGeneratorFilter::Transform(IMediaSample *pSource, IMediaSample *pDest) {
HRESULT hRes;
BYTE* pBufferIn;
BYTE* pBufferOut;
long destSize = pDest->GetSize();
long dataLen = pSource->GetActualDataLength();
if( dataLen > destSize )
return VFW_E_BUFFER_OVERFLOW;
COM_CALL(pSource->GetPointer(&pBufferIn));
COM_CALL(pDest->GetPointer(&pBufferOut));
memcpy(pBufferOut, pBufferIn, dataLen);
pDest->SetActualDataLength(dataLen);
pDest->SetSyncPoint(pSource->IsSyncPoint() == S_OK);
return S_OK;
}
Here is how I inserted the filter in the capture graph:
CComPtr<IPin> pAACEncoderOutPin(FilterTools::GetPin(pAACEncoder, "XForm Out"));
CComPtr<IPin> pVideoSourceCompressedOutPin(FilterTools::GetPin(pVideoSource, "Encoded"));
CComPtr<IBaseFilter> pSampleCopier;
pSampleCopier = new SampleCopyGeneratorFilter();
COM_CALL(pGraph->AddFilter(pSampleCopier, L"SampleCopier"));
CComPtr<IPin> pSampleCopierInPin(FilterTools::GetPin(pSampleCopier, "XForm In"));
COM_CALL(pGraph->ConnectDirect(pVideoSourceCompressedOutPin, pSampleCopierInPin, NULL));
CComPtr<IPin> pSampleCopierOutPin(FilterTools::GetPin(pSampleCopier, "XForm Out"));
CreateGraphBridge(
IntPtr(pGraph),
IntPtr(pSampleCopierOutPin),
IntPtr(pAACEncoderOutPin)
);
Now, I still have no idea why inserting the sample grabber instead did not work and resulted in detached graphs. I corroborated this quirk by examining the graphs with Graphedit Plus too. If anyone can offer me an explanation, I would be very grateful indeed.

EGL: Does a FBO get created when creating a pBuffer surface?

I am working with EGL on an ARM GPU, and I am using a pbuffer to do off screen rendering. I follow the standard procedures as described in the documentation to set everything up:
EGLDisplay display;
EGLConfig config;
EGLContext context;
EGLSurface surface;
EGLint num_config;
// assume I allocated both attrib lists somewhere
attribute_list[0] = EGL_SURFACE_TYPE;
attribute_list[1] = EGL_PBUFFER_BIT;
attribute_list[2] = EGL_RENDERABLE_TYPE;
attribute_list[3] = EGL_OPENGL_ES2_BIT;
attribute_list[4] = EGL_OPENGL_RED_SIZE;
attribute_list[5] = 8;
attribute_list[6] = EGL_OPENGL_GREEN_SIZE;
attribute_list[7] = 8;
attribute_list[8] = EGL_OPENGL_BLUE_SIZE;
attribute_list[9] = 8;
attribute_list[9] = EGL_OPENGL_ALPHA_SIZE;
attribute_list[10] = 8;
attribute_list[11] = EGL_OPENGL_DEPTH_SIZE;
attribute_list[12] = 8;
attribute_list[13] = EGL_NONE;
pbuffer_attribs[0] = EGL_WIDTH;
pbuffer_attribs[1] = 512;
pbuffer_attribs[2] = EGL_HEIGHT;
pbuffer_attribs[3] = 512;
pbuffer_attribs[4] = EGL_NONE;
/* get an EGL display connection */
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
/* initialize the EGL display connection */
eglInitialize(display, NULL, NULL);
/* get an appropriate EGL frame buffer configuration */
eglChooseConfig(display, attribute_list, &config, 1, &num_config);
/* create an EGL rendering context */
context = eglCreateContext(display, config, EGL_NO_CONTEXT, NULL);
/* create the surface */
surface = eglCreatePbufferSurface(display, config, pbuffer_attribs);
/* connect the context to the surface */
eglMakeCurrent(display, surface, surface, context);
After this, my reads and writes should be associated with this offscreen pBuffer, correct? Does this pBuffer have a FBO which is distinct from the default framebuffer associated with it? The issue I am running into is I get a GL_FRAMEBUFFER_UNDEFINED error when I try to glReadPixels. This error happens when:
GL_FRAMEBUFFER_UNDEFINED is returned if target is the default framebuffer, but the default framebuffer does not exist.
My reading of this error is I am rendering to the default FBO and not to the pBuffer FBO. Is this interpretation correct? If so, what else do I need to do so I can read and write to the pBuffer FBO?
If the above sequence completes successfully (without errors), then, yes, the offscreen pBuffer becomes the default framebuffer for the OpenGL ES context and all reads and writes will be associated with the pBuffer (unless a non-default FBO is bound).
It's worth checking that eglGetError() returns EGL_SUCCESS after each EGL call. The following part of your code listing looks suspicious:
attribute_list[9] = 8;
attribute_list[9] = EGL_OPENGL_ALPHA_SIZE;

How to convert Swift array into CFArray?

I'm trying to capture a window list in a Mac OS X app using Swift. The CGWindowListCreateImageFromArray function requires a CFArray. I've tried several things and this is the closest I've got. Or is there a better way to convert the array?
import Cocoa
// Example swift array of CGWindowID's
var windowIDs = [CGWindowID]();
windowIDs.append(1);
windowIDs.append(2);
// Convert to CFArray using CFArrayCreate
let allocator = kCFAllocatorDefault
let numValues = windowIDs.count as CFIndex
let callbacks: UnsafePointer<CFArrayCallBacks> = nil
var values: UnsafeMutablePointer<UnsafePointer<Void>> = nil
/* how do I convert windowIDs to UnsafeMutablePointer<UnsafePointer<Void>> for the values? */
let windowIDsCFArray = CFArrayCreate(allocator, values, numValues, callbacks);
let capture = CGWindowListCreateImageFromArray(CGRectInfinite, windowIDsCFArray, CGWindowImageOption(kCGWindowListOptionOnScreenOnly));
You can initialize your UnsafeMutablePointer with your array so long as you set your CGWindowIDs to CFTypeRef:
var windows: [CFTypeRef] = [1, 2]
var windowsPointer = UnsafeMutablePointer<UnsafePointer<Void>>(windows)
var cfArray = CFArrayCreate(nil, windowsPointer, windows.count, nil)
Converted Ian's answer to Swift 4:
let windows = [CGWindowID(17), CGWindowID(50), CGWindowID(59)]
let pointer = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: windows.count)
for (index, window) in windows.enumerated() {
pointer[index] = UnsafeRawPointer(bitPattern: UInt(window))
}
let array: CFArray = CFArrayCreate(kCFAllocatorDefault, pointer, windows.count, nil)
let capture = CGImage(windowListFromArrayScreenBounds: CGRect.infinite, windowArray: array, imageOption: [])!
let image: NSImage = NSImage(cgImage: capture, size: NSSize.zero)
Swift.print(image)
Arrays in Swift are bridged to NSArray, given they contain objects, e.g., conform to [AnyObject] type. Since CGWindowID is a UInt32, you need to convert it to NS family, array's map() method is an elegant approach.
var windows: [CGWindowID] = [CGWindowID(1), CGWindowID(2)]
var array: CFArray = windows.map({NSNumber(unsignedInt: $0)}) as CFArray
This, however, doesn't reflect on the actual CGWindowListCreateImageFromArray problem. Here's the working solution for that:
let windows: [CGWindowID] = [CGWindowID(17), CGWindowID(50), CGWindowID(59)]
let pointer: UnsafeMutablePointer<UnsafePointer<Void>> = UnsafeMutablePointer<UnsafePointer<Void>>.alloc(windows.count)
for var i: Int = 0, n = windows.count; i < n; i++ {
pointer[i] = UnsafePointer<Void>(bitPattern: UInt(windows[i]))
}
let array: CFArray = CFArrayCreate(kCFAllocatorDefault, pointer, windows.count, nil)
let capture: CGImage = CGWindowListCreateImageFromArray(CGRectInfinite, array, CGWindowImageOption.Default)!
let image: NSImage = NSImage(CGImage: capture, size: NSZeroSize)
Swift.print(image) // <NSImage 0x7f83a3d16920 Size={1440, 900} Reps=("<NSCGImageSnapshotRep:0x7f83a3d2dea0 cgImage=<CGImage 0x7f83a3d16840>>")>
I'm not great at ObjC, please correct if wrong, but from what I understand by playing with the SonOfGrab example and particular piece of code below is that the final pointer structure contains window ids (UInt32) not inside the memory cell (memory property of UnsafePointer instance), but inside memory address (hashValue property).
const void *windowIDs[2];
windowIDs[0] = 10;
windowIDs[1] = 20;
It's interesting, since values aren't stored in the memory, but inside the address descriptors, with oldest architectures being 32-bit UInt32 values fit perfectly into address pointers. Perhaps back in the days when the memory was a limiting factor this made a lot of sense and was a great approach. Discovering this all night in Swift in 2016 made me suicidal.
What's worse it fails in Xcode 7.2 playground with certain window ids, probably because of the way it handles memory, but works in the actual app.

How do I copy writeablebitmap to clipboard from an elevated trust silverlight application using P/Invoke?

I've got a silverlight 5 application that is running elevated trust in-browser. This allows us to do things that wouldn't ordinarily be possible in silverlight like having more access to the clipboard via P/Invoke.
What I need to be able to do is copy controls to the clipboard so they could be pasted into Word or Outlook. I can convert the controls to an image via WriteableBitmap but copying the data to the clipboard is something I'm having issues with.
Calling code:
WriteableBitmap bmp = new WriteableBitmap(elements[0], new ScaleTransform() { ScaleX = 1.0, ScaleY = 1.0 });
int[] p = bmp.Pixels;
int len = p.Length * 4;
byte[] result = new byte[len];
Buffer.BlockCopy(p, 0, result, 0, len);
CopyToClipboardViaPInvoke(result, ClipboardFormat.CF_BITMAP);
Copy function:
private void CopyToClipboardViaPInvoke(byte[] data, ClipboardFormat format)
{
IntPtr p = IntPtr.Zero;
if (Native.OpenClipboard(p))
{
GCHandle pinnedArray = GCHandle.Alloc(data, GCHandleType.Pinned);
IntPtr pointer = pinnedArray.AddrOfPinnedObject();
try
{
Native.EmptyClipboard();
IntPtr result = Native.SetClipboardData(format, pointer);
}
finally
{
Native.CloseClipboard();
pinnedArray.Free();
}
}
}
The result says it's successful, but paste does nothing. IsClipboardFormatAvailable also states that the format is available on the clipboard. I've also tried various ClipboardFormat inputs and other methods of converting the control to an image without any luck.
Update 1
Thanks to suggestions from user629926 I've got what I think is a little closer but I'm still missing something.
Native.EmptyClipboard();
IntPtr bmp = IntPtr.Zero;
GCHandle pinnedArray = GCHandle.Alloc(bytes, GCHandleType.Pinned);
IntPtr bmpPointer = pinnedArray.AddrOfPinnedObject();
Native.StartupInput sin = new Native.StartupInput() { GdiplusVersion = 1 };
Native.StartupOutput sout = new Native.StartupOutput();
IntPtr gdip = IntPtr.Zero;
int startup = Native.GdiplusStartup(out gdip, ref sin, out sout);
int created = Native.GdipCreateBitmapFromScan0(width, height, width * 4, 0x0026200A, bmpPointer, out bmp);
IntPtr result = Native.SetClipboardData(format, bmp);
Native.DeleteObject(bmp);
Native.GdiplusShutdown(ref gdip);
Use GdipCreateBitmapFromScan0 to get HBitmap from you array and pass it to clipboard and the DeleteObject to free it.
[DllImport("gdiplus.dll")]
static extern int GdipCreateBitmapFromScan0(int width, int height, int stride, int format, IntPtr scan0, out IntPtr bitmap);
[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);