Binding properties without public constructor

Dear all

I have successfully created a binding library for a 3rd party native iOS SDK.
However I have 1 small issue.

one of the property bindings looks like this:

// @property (readonly, nonatomic) CMSampleBufferRef sampleBuffer;
[Export ("sampleBuffer")]
CMSampleBuffer SampleBuffer { get; } 

The compiler generated code looks like this:

[CompilerGenerated]
public virtual global::CoreMedia.CMSampleBuffer SampleBuffer {
    [Export ("sampleBuffer")]
    get {
        IntPtr ret;
        if (IsDirectBinding) {
            ret = global::ApiDefinition.Messaging.IntPtr_objc_msgSend (this.Handle, Selector.GetHandle ("sampleBuffer"));
        } else {
            ret = global::ApiDefinition.Messaging.IntPtr_objc_msgSendSuper (this.SuperHandle, Selector.GetHandle ("sampleBuffer"));
        }
        return ret == IntPtr.Zero ? null : new global::CoreMedia.CMSampleBuffer (ret);
    }

}

The problem is that CMSampleBuffer has no public constructor, and this simply does not build. Is there a way to avoid generating the "new" in de compiler generated code?

Thanks in advance

Best regards
Wim

Posts

  • WimDevosWimDevos USMember

    Hi All

    I tried to solve this by just using an IntPtr and doing the conversion to the object myself:

    `
    int[] colorValues = new int[cols * rows];

            var res = Runtime.GetINativeObject<CMSampleBuffer> (IntPtr_objc_msgSend (colorFrame.Handle, Selector.GetHandle("sampleBuffer")), false);
    
    
            using (var pixelBuffer = res.GetImageBuffer () as CVPixelBuffer) {
                // Lock the base address
                pixelBuffer.Lock (0);
    
                // Get the number of bytes per row for the pixel buffer
                var baseAddress = pixelBuffer.BaseAddress;
                int bytesPerRow = (int) pixelBuffer.BytesPerRow;
                int width = (int) pixelBuffer.Width;
                int height = (int) pixelBuffer.Height;
                var flags = CGBitmapFlags.PremultipliedFirst | CGBitmapFlags.ByteOrder32Little;
                // Create a CGImage on the RGB colorspace from the configured parameter above
                using (var cs = CGColorSpace.CreateDeviceRGB ()) {
                    using (var context = new CGBitmapContext (baseAddress, width, height, 8, bytesPerRow, cs, (CGImageAlphaInfo)flags)) {
                        pixelBuffer.Unlock (0);
                        Marshal.Copy(context.Data, colorValues, 0, cols*rows);
                    }
                }
            }
    
            res.Dispose ();`
    

    [DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")] public static extern IntPtr IntPtr_objc_msgSend(IntPtr receiver, IntPtr selector);

    This however probably contains a memory leak of some sort or I am doing something I shouldn't do, because it crashes from time to times.

    I understand this is quite deep, but getting some insights/advice would really help me forward.

    Thanks in advance
    Wim

  • adamkempadamkemp USInsider, Developer Group Leader mod

    I don't see any obvious issues with this code that would lead to leaks or crashes:

    var res = Runtime.GetINativeObject<CMSampleBuffer> (IntPtr_objc_msgSend (colorFrame.Handle, Selector.GetHandle("sampleBuffer")), false);
    

    However, it shouldn't be necessary. Maybe @RolfBjarneKvinge can explain how to make your binding work.

  • RolfBjarneKvingeRolfBjarneKvinge USXamarin Team Xamurai

    That looks just fine, but maybe you need an NSAutoreleasePool surrounding your code:

    using (var pool = new NSAutoreleasePool ()) {
         var res = Runtime.GetINativeObject<CMSampleBuffer> (IntPtr_objc_msgSend (colorFrame.Handle, Selector.GetHandle("sampleBuffer")), false);
        ...
    }
    

    If that doesn't work, I'd try and use Instruments to find out exactly what's leaking.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    Rolf, why is the IntPtr constructor for CMSampleBuffer scoped in a way that makes this binding impractical?

  • NicholasTurnerNicholasTurner USMember, University ✭✭

    I would say his biggest problem is the res variable. He's holding onto a reference for no reason. delete it and add it to the using.

    I went through and optimized the same method. It's a very wasteful way of showing the camera. Switch to StillImageOutput instead

  • adamkempadamkemp USInsider, Developer Group Leader mod

    I think you're right that res should be in a using, but he is disposing it so it shouldn't be causing a leak.

  • NicholasTurnerNicholasTurner USMember, University ✭✭
    edited October 2015

    @WimDevos You should be using the Delegate instead

    ` public class OutputRecorder : AVCaptureVideoDataOutputSampleBufferDelegate {
    public override void DidOutputSampleBuffer (AVCaptureOutput captureOutput, CMSampleBuffer sampleBuffer, AVCaptureConnection connection)
    {
    try {
    connection.VideoOrientation = AVCaptureVideoOrientation.LandscapeLeft;
    var image = ImageFromSampleBuffer (sampleBuffer);

                    sampleBuffer.Dispose ();
                } catch (Exception e){
                    Console.WriteLine (e);
                }
            }
    
            UIImage ImageFromSampleBuffer (CMSampleBuffer sampleBuffer)
            {
                // Get the CoreVideo image
                using (var pixelBuffer = sampleBuffer.GetImageBuffer () as CVPixelBuffer){
                    // Lock the base address
                    pixelBuffer.Lock (0);
                    // Get the number of bytes per row for the pixel buffer
                    var baseAddress = pixelBuffer.BaseAddress;
                    int bytesPerRow = pixelBuffer.BytesPerRow;
                    int width = pixelBuffer.Width;
                    int height = pixelBuffer.Height;
                    var flags = CGBitmapFlags.PremultipliedFirst | CGBitmapFlags.ByteOrder32Little;
                    // Create a CGImage on the RGB colorspace from the configured parameter above
                    using (var cs = CGColorSpace.CreateDeviceRGB ())
                    using (var context = new CGBitmapContext (baseAddress,width, height, 8, bytesPerRow, cs, (CGImageAlphaInfo) flags))
                    using (var cgImage = context.ToImage ()){
                        pixelBuffer.Unlock (0);
                        return UIImage.FromImage (cgImage);
                    }
                }
            }
        }
    

    `

  • WimDevosWimDevos USMember
    edited October 2015

    Hi All

    Thanks for the responses! I'll give some extra info.

    • The code as in the first post is executed in an event from a library I created the binding for (Structure sensor)
      So I am already using the delegate. The delegate passes the samplebuffer to the Structure Sensor API. The Structure Sensor API uses the CMSampleBuffer to synchronize with the its depthframes (FYI the structure sensor is a 3D sensor).

    • The Structure API fires an event where I receive 2 parameters: a DepthFrame and a ColorFrame, that ColorFrame contains the original CMSampleBuffer a passed. Due to the binding problems (hence the title) it is turned into an IntPtr.

    • final goal: In the event I want to do some magic using both the DepthFrame and the ColorFrame and create a new image and show on the screen. That is the reason of the following line, because I need pixel data.

    Marshal.Copy(context.Data, colorValues, 0, cols*rows)

    EDIT: also I don't think I have a memory leak, but - according to what I am reading on the net - a null ref exception. As the crash is a SIGSEGV

    I'll try to cleanup my code and post it here.

    Thanks for your time

    Best regards
    Wim

  • RolfBjarneKvingeRolfBjarneKvinge USXamarin Team Xamurai

    @adamkemp: we made the IntPtr ctor protected in Unified because many people were using it incorrectly.

    @WimDevos: can you post the device log (in Xamarin Studio open View -> Pads -> iOS Device Log) and the crash report (which you can find in Xcode's Organizer) from the crash?

  • adamkempadamkemp USInsider, Developer Group Leader mod

    That's understandable for normal assemblies, but it seems it's a serious issue for binding projects. Maybe the generated code should change accordingly.

  • WimDevosWimDevos USMember

    @RolfBjarneKvinge The problem is I am using an external accessory: the Structure sensor. So I cannot have a cable connected to my laptop AND use the structure sensor. So the only thing I currently rely on is WIFI debugging in Xamarin (thank god for that); cause all iOS tools seem to require a cable connection

    this is de Application Output from the crash:

    `
    2015-10-02 10:12:46.386 xamarinappdemo2.ios[296:44037] critical: Stacktrace:

    2015-10-02 10:12:46.386 xamarinappdemo2.ios[296:44037] critical: at <0xffffffff>
    2015-10-02 10:12:46.386 xamarinappdemo2.ios[296:44037] critical: at (wrapper managed-to-native) UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr) <0xffffffff>
    2015-10-02 10:12:46.387 xamarinappdemo2.ios[296:44037] critical: at UIKit.UIApplication.Main (string[],intptr,intptr) [0x00005] in /Users/builder/data/lanes/2077/d8e9592a/source/maccore/src/UIKit/UIApplication.cs:74
    2015-10-02 10:12:46.387 xamarinappdemo2.ios[296:44037] critical: at UIKit.UIApplication.Main (string[],string,string) [0x0001c] in /Users/builder/data/lanes/2077/d8e9592a/source/maccore/src/UIKit/UIApplication.cs:57
    2015-10-02 10:12:46.387 xamarinappdemo2.ios[296:44037] critical: at xamarinappdemo2.ios.Application.Main (string[]) [0x00008] in /Users/FieldFox/Source/xamarinappdemo2/iOS/xamarinappdemo2.ios/Main.cs:16
    2015-10-02 10:12:46.387 xamarinappdemo2.ios[296:44037] critical: at (wrapper runtime-invoke) object.runtime_invoke_dynamic (intptr,intptr,intptr,intptr) <0xffffffff>
    2015-10-02 10:12:46.387 xamarinappdemo2.ios[296:44037] critical:
    Native stacktrace:

    2015-10-02 10:12:46.484 xamarinappdemo2.ios[296:44037] critical: 0 xamarinappdemo2.ios 0x000000010117fc54 mono_handle_native_sigsegv + 260
    2015-10-02 10:12:46.484 xamarinappdemo2.ios[296:44037] critical: 1 xamarinappdemo2.ios 0x000000010118cba0 mono_sigsegv_signal_handler + 328
    2015-10-02 10:12:46.484 xamarinappdemo2.ios[296:44037] critical: 2 libsystem_platform.dylib 0x000000019595495c _sigtramp + 68
    2015-10-02 10:12:46.485 xamarinappdemo2.ios[296:44037] critical: 3 xamarinappdemo2.ios 0x0000000101017610 main + 66640
    2015-10-02 10:12:46.485 xamarinappdemo2.ios[296:44037] critical: 4 Foundation 0x00000001844131c4 + 16
    2015-10-02 10:12:46.485 xamarinappdemo2.ios[296:44037] critical: 5 Foundation 0x0000000184364604 + 96
    2015-10-02 10:12:46.485 xamarinappdemo2.ios[296:44037] critical: 6 Foundation 0x00000001843541cc + 636
    2015-10-02 10:12:46.485 xamarinappdemo2.ios[296:44037] critical: 7 Foundation 0x0000000184415f28 + 228
    2015-10-02 10:12:46.485 xamarinappdemo2.ios[296:44037] critical: 8 libdispatch.dylib 0x0000000195779954 + 16
    2015-10-02 10:12:46.485 xamarinappdemo2.ios[296:44037] critical: 9 libdispatch.dylib 0x000000019577e20c _dispatch_main_queue_callback_4CF + 1608
    2015-10-02 10:12:46.486 xamarinappdemo2.ios[296:44037] critical: 10 CoreFoundation 0x00000001834e37f8 + 12
    2015-10-02 10:12:46.486 xamarinappdemo2.ios[296:44037] critical: 11 CoreFoundation 0x00000001834e18a0 + 1492
    2015-10-02 10:12:46.486 xamarinappdemo2.ios[296:44037] critical: 12 CoreFoundation 0x000000018340d2d4 CFRunLoopRunSpecific + 396
    2015-10-02 10:12:46.486 xamarinappdemo2.ios[296:44037] critical: 13 GraphicsServices 0x000000018cd3b6fc GSEventRunModal + 168
    2015-10-02 10:12:46.486 xamarinappdemo2.ios[296:44037] critical: 14 UIKit 0x000000018800af40 UIApplicationMain + 1488
    2015-10-02 10:12:46.487 xamarinappdemo2.ios[296:44037] critical: 15 xamarinappdemo2.ios 0x00000001002778ec wrapper_managed_to_native_UIKit_UIApplication_UIApplicationMain_int_string___intptr_intptr + 348
    2015-10-02 10:12:46.487 xamarinappdemo2.ios[296:44037] critical: 16 xamarinappdemo2.ios 0x00000001001fffbc UIKit_UIApplication_Main_string___intptr_intptr + 44
    2015-10-02 10:12:46.487 xamarinappdemo2.ios[296:44037] critical: 17 xamarinappdemo2.ios 0x00000001001fff7c UIKit_UIApplication_Main_string___string_string + 172
    2015-10-02 10:12:46.487 xamarinappdemo2.ios[296:44037] critical: 18 xamarinappdemo2.ios 0x000000010019ef0c xamarinappdemo2_ios_Application_Main_string__ + 156
    2015-10-02 10:12:46.487 xamarinappdemo2.ios[296:44037] critical: 19 xamarinappdemo2.ios 0x0000000100474664 wrapper_runtime_invoke_object_runtime_invoke_dynamic_intptr_intptr_intptr_intptr + 244
    2015-10-02 10:12:46.487 xamarinappdemo2.ios[296:44037] critical: 20 xamarinappdemo2.ios 0x000000010118ee80 mono_jit_runtime_invoke + 1264
    2015-10-02 10:12:46.488 xamarinappdemo2.ios[296:44037] critical: 21 xamarinappdemo2.ios 0x00000001011f2c00 mono_runtime_invoke + 124
    2015-10-02 10:12:46.488 xamarinappdemo2.ios[296:44037] critical: 22 xamarinappdemo2.ios 0x00000001011f7488 mono_runtime_exec_main + 400
    2015-10-02 10:12:46.488 xamarinappdemo2.ios[296:44037] critical: 23 xamarinappdemo2.ios 0x0000000101287b88 xamarin_main + 1840
    2015-10-02 10:12:46.488 xamarinappdemo2.ios[296:44037] critical: 24 xamarinappdemo2.ios 0x0000000101007220 main + 96
    2015-10-02 10:12:46.488 xamarinappdemo2.ios[296:44037] critical: 25 libdyld.dylib 0x00000001957a6a08 + 4

    2015-10-02 10:12:46.488 xamarinappdemo2.ios[296:44037] critical:

    Got a SIGSEGV while executing native code. This usually indicates
    a fatal error in the mono runtime or one of the native libraries

    used by your application.

    `

  • RolfBjarneKvingeRolfBjarneKvinge USXamarin Team Xamurai

    @WimDevos: crash reports are written to disk (on the device) when they occur, and Xcode will fetch them all once you connect the device to your Mac using the USB cable.

Sign In or Register to comment.