如何将这个opengl代码从xcode移植到Monotouch?

时间:2012-03-07 07:11:01

标签: opengl-es xamarin.ios

我正在尝试将以下代码转换为Monotouch:

if (videoTextureCache == NULL) {
    //  Create a new CVOpenGLESTexture cache
    CVReturn err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, self.context, NULL, &videoTextureCache);
    if (err) {
        NSLog(@"Error at CVOpenGLESTextureCacheCreate %d", err);
    }
}

if (videoTextureCache) {
    CMSampleBufferRef sampleBuffer = self.videoFrameReader.sampleBuffer;
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    CVPixelBufferLockBaseAddress(imageBuffer, 0);

    // Create a CVOpenGLESTexture from the CVImageBuffer
    size_t frameWidth = CVPixelBufferGetWidth(imageBuffer);
    size_t frameHeight = CVPixelBufferGetHeight(imageBuffer);
    CVOpenGLESTextureRef texture = NULL;
    CVReturn err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
                                                                videoTextureCache,
                                                                imageBuffer,
                                                                NULL,
                                                                GL_TEXTURE_2D,
                                                                GL_RGBA,
                                                                frameWidth,
                                                                frameHeight,
                                                                GL_BGRA,
                                                                GL_UNSIGNED_BYTE,
                                                                0,
                                                                &texture);
    if (!texture || err) {
        NSLog(@"CVOpenGLESTextureCacheCreateTextureFromImage failed (error: %d)", err);
        return;
    } else {
        self.cubeTextureName = CVOpenGLESTextureGetName(texture);
    }

    // Flush the CVOpenGLESTexture cache and release the texture
    CVOpenGLESTextureCacheFlush(videoTextureCache, 0);
    CFRelease(texture);

    CVPixelBufferUnlockBaseAddress(imageBuffer, 0);

这与将视频快速渲染成opengl纹理有关。它在xCode中运行良好,具有出色的性能,但现在我需要让它在Monotouch相关项目中工作。

但是,我对如何移植此代码感到很遗憾,因为我找不到必要的Monotouch绑定,也没有关于上面使用的关键方法的Monotouch相关文档,如CVOpenGLESTextureCacheCreateTextureFromImage和CVOpenGLESTextureCacheCreate。他们是否从Monotouch中丢失了?

有没有办法可以调用它们?

2 个答案:

答案 0 :(得分:2)

我对OpenGL不是很熟悉,所以我可能会把样本弄错,但这是一个起点:

using System;
using System.Collections.Generic;
using System.Linq;

using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.CoreVideo;
using MonoTouch.CoreMedia;
using System.Runtime.InteropServices;
using MonoTouch.OpenGLES;
using OpenTK.Platform.iPhoneOS;
using OpenTK.Graphics.ES20;
using OpenTK;

namespace cv1
{
    [Register ("AppDelegate")]
    public partial class AppDelegate : UIApplicationDelegate
    {
        UIWindow window;

        [DllImport (MonoTouch.Constants.CoreVideoLibrary)]
        extern static int CVOpenGLESTextureCacheCreate (IntPtr alloc, IntPtr cache, IntPtr eaglContext, IntPtr textureAttr, out IntPtr cache);

        [DllImport (MonoTouch.Constants.CoreVideoLibrary)]
        extern static int CVOpenGLESTextureCacheCreateTextureFromImage (IntPtr alloc, IntPtr textureCache, IntPtr sourceImage, IntPtr textureAttr, EnableCap target, PixelFormat internalFormat, int width, int height, int format, DataType type, int planeIndex, out IntPtr texture);
        [DllImport (MonoTouch.Constants.CoreVideoLibrary)]
        extern static int CVOpenGLESTextureCacheFlush (IntPtr texture, int v);
        [DllImport (MonoTouch.Constants.CoreVideoLibrary)]
        extern static int CVOpenGLESTextureGetName (IntPtr texture);
        [DllImport (MonoTouch.Constants.CoreFoundationLibrary, CharSet=CharSet.Unicode)]
        internal extern static IntPtr CFRelease (IntPtr obj);

        IntPtr videoTextureCache;

        void Stuff (EAGLContext context)
        {
            int err;
            if (videoTextureCache == IntPtr.Zero) {
                err = CVOpenGLESTextureCacheCreate (IntPtr.Zero, IntPtr.Zero, context.Handle, IntPtr.Zero, out videoTextureCache);
                if (err != 0){
                    Console.WriteLine ("Error at CVOpenGLESTextureCacheCreate {0}", err);
                    return;
                }
            }
            CMSampleBuffer sampleBuffer = null; //videoFrameReader.SampleBuffer;
            CVPixelBuffer imageBuffer = (CVPixelBuffer) sampleBuffer.GetImageBuffer ();
            imageBuffer.Lock (CVOptionFlags.None);
            int frameWidth = imageBuffer.Width;
            int frameHeight = imageBuffer.Height;

            IntPtr texture = IntPtr.Zero;
            err = CVOpenGLESTextureCacheCreateTextureFromImage(IntPtr.Zero,
                                                                videoTextureCache,
                                                                imageBuffer.Handle,
                                                                IntPtr.Zero,
                                                                EnableCap.Texture2D,
                                                                PixelFormat.Rgba,
                                                                frameWidth,
                                                                frameHeight,
                                                                0x10B6,
                                                                DataType.UnsignedByte,
                                                                0,
                                                                out texture);
            if (texture == IntPtr.Zero || err != 0) {
                Console.WriteLine("CVOpenGLESTextureCacheCreateTextureFromImage failed (error: {0})", err);
                return;
            } else {
                Console.WriteLine ("Texture name: {0}", CVOpenGLESTextureGetName(texture));
            }

            CVOpenGLESTextureCacheFlush(videoTextureCache, 0);
            CFRelease(texture);

            imageBuffer.Unlock (CVOptionFlags.None);
        }

        public override bool FinishedLaunching (UIApplication app, NSDictionary options)
        {
            window = new UIWindow (UIScreen.MainScreen.Bounds);
            window.MakeKeyAndVisible ();


            return true;
        }
    }
}

由于您没有提供几个数据点,我只需将它们保留为空值或打印出值而不将其分配给任何数据点。

答案 1 :(得分:0)

非常感谢你,虽然你提供的样本不起作用,但它帮助了我很多。 :)

这是我最终编写的代码(为了清晰起见,我进行了一些编辑):

    [DllImport (MonoTouch.Constants.CoreVideoLibrary)]
    extern static int CVOpenGLESTextureCacheCreateTextureFromImage (
        IntPtr allocator,
        IntPtr textureCache,
        IntPtr sourceImage,
        IntPtr textureAttributes,
        int target,
        int internalFormat,
        int width,
        int height,
        int format,
        int type,
        int planeIndex,
        ref IntPtr textureOut);

[DllImport (MonoTouch.Constants.CoreVideoLibrary)]
extern static int CVOpenGLESTextureCacheFlush (IntPtr texture, int v);

[DllImport (MonoTouch.Constants.CoreVideoLibrary)]
extern static int CVOpenGLESTextureGetName (IntPtr texture);

[DllImport (MonoTouch.Constants.CoreFoundationLibrary, CharSet=CharSet.Unicode)]
internal extern static IntPtr CFRelease (IntPtr obj);

    private IntPtr videoTextureCache;
    unsafe public void setTexture(CVImageBuffer sampleBuffer)
    {
        int err;
    if (videoTextureCache == IntPtr.Zero) {
            EAGLContext eaglContext=Global.localScreen.view.Context;
        err = CVOpenGLESTextureCacheCreate (IntPtr.Zero, IntPtr.Zero, eaglContext.Handle, IntPtr.Zero, out videoTextureCache);
        if (err != 0){
            Console.WriteLine ("Error at CVOpenGLESTextureCacheCreate {0}", err);
            return;
        }
    }

        CVPixelBuffer pixelBuffer = (CVPixelBuffer) sampleBuffer;
    pixelBuffer.Lock (CVOptionFlags.None);
    int frameWidth = pixelBuffer.Width;
    int frameHeight = pixelBuffer.Height;

        IntPtr texture = IntPtr.Zero;
        err = CVOpenGLESTextureCacheCreateTextureFromImage(IntPtr.Zero,
                                                        videoTextureCache,
                                                        pixelBuffer.Handle,
                                                        IntPtr.Zero,
                                                        (int)All.Texture2D,
                                                        (int)All.Rgba,
                                                        frameWidth,
                                                        frameHeight,
                                                        (int)All.Bgra,
                                                        (int)All.UnsignedByte,
                                                        0,
                                                        ref texture);

    if (texture == IntPtr.Zero || err != 0) {
        Console.WriteLine("CVOpenGLESTextureCacheCreateTextureFromImage failed (error: {0})", err);
        return;
    } else {
        Console.WriteLine ("Texture name: {0}", CVOpenGLESTextureGetName(texture));
    }

    CVOpenGLESTextureCacheFlush(videoTextureCache, 0);
        CFRelease(texture);

        pixelBuffer.Unlock (CVOptionFlags.None);            

    }

我仍然有一些奇怪的问题。当播放视频并将各个帧发送到上述方法时,帧以稍微随机的顺序绘制,使视频闪烁,尽管帧确实以正确的顺序进入该方法。

基本上程序流程是这样的:

  1. 提取视频帧(我知道它们确实按照正确的顺序排列)
  2. 将帧提供给上面的方法,并创建纹理
  3. 绘制纹理(实际绘制当前帧的+/- 5帧)
  4. 非常简单,但似乎Monotouch并没有很好地发挥作用。

    这很奇怪,因为上面的代码是xCode版本的精确副本,可以正常工作。不知道发生了什么,但我怀疑它与Monotouch中的自动内存管理有关。

    此外,如果视频的分辨率不是2的幂,我会得到黑色纹理......使用Objective C时没问题。再次,不知道Monotouch在这里发生了什么...... :(