黄学彪
2020-09-22 ade5917841b0fdcb1df7353ef7c56b1a1bdc9282
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// <copyright company="APX Labs, Inc.">
//     Copyright (c) APX Labs, Inc. All rights reserved.
// </copyright>
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//
// Many thanks to Jonathan Pryor from Xamarin for his assistance
 
using System;
using Android.Hardware;
using Android.Runtime;
 
namespace ApxLabs.FastAndroidCamera
{
    /// <summary>
    /// Extends the <see cref="Android.Hardware.Camera"/> class with methods that take <see cref="FastJavaByteArray"/>
    /// instances as parameters instead of raw <see cref="IntPtr"/> values.
    /// </summary>
    public static class CameraExtensions
    {
        static IntPtr id_addCallbackBuffer_arrayB;
        /// <summary>
        /// Adds a pre-allocated buffer to the preview callback buffer queue. Applications can add one or more buffers
        /// to the queue. When a preview frame arrives and there is still at least one available buffer, the buffer will
        /// be used and removed from the queue. Then preview callback is invoked with the buffer. If a frame arrives and
        /// there is no buffer left, the frame is discarded. Applications should add buffers back when they finish
        /// processing the data in them.
        /// </summary>
        /// <param name="self">Camera object.</param>
        /// <param name="callbackBuffer">The buffer to add to the queue.</param>
        public static void AddCallbackBuffer(this Camera self, FastJavaByteArray callbackBuffer)
        {
            if (id_addCallbackBuffer_arrayB == IntPtr.Zero)
                id_addCallbackBuffer_arrayB = JNIEnv.GetMethodID(self.Class.Handle, "addCallbackBuffer", "([B)V");
            JNIEnv.CallVoidMethod(self.Handle, id_addCallbackBuffer_arrayB, new JValue(callbackBuffer.Handle));
        }
 
        static IntPtr id_setPreviewCallback_Landroid_hardware_Camera_PreviewCallback_;
        /// <summary>
        /// Installs a callback to be invoked for every preview frame in addition to displaying them on the screen. The
        /// callback will provide a reference to the Java array instead of copying it into a new CLR array. The callback
        /// will be repeatedly called for as long as preview is active. This method can be called at any time,
        /// even while preview is live. Any other preview callbacks are overridden.
        /// </summary>
        /// <param name="self">Camera object.</param>
        /// <param name="cb">A callback object that receives a copy of each preview frame, or null to stop receiving callbacks.</param>
        public static void SetNonMarshalingPreviewCallback(this Camera self, INonMarshalingPreviewCallback cb)
        {
            if (id_setPreviewCallback_Landroid_hardware_Camera_PreviewCallback_ == IntPtr.Zero)
                id_setPreviewCallback_Landroid_hardware_Camera_PreviewCallback_ = JNIEnv.GetMethodID(self.Class.Handle, "setPreviewCallbackWithBuffer", "(Landroid/hardware/Camera$PreviewCallback;)V");
            JNIEnv.CallVoidMethod(self.Handle, id_setPreviewCallback_Landroid_hardware_Camera_PreviewCallback_, new JValue(cb));
        }
 
        static IntPtr id_setOneShotPreviewCallback_Landroid_hardware_Camera_PreviewCallback_;
        /// <summary>
        /// <para>
        /// Installs a callback to be invoked for every preview frame, using buffers supplied with
        /// <see cref="AddCallbackBuffer"/>(FastJavaByteArray), in addition to displaying them on the screen. The
        /// callback will be repeatedly called for as long as preview is active and buffers are available. Any other
        /// preview callbacks are overridden.
        /// </para>
        /// <para>
        /// The purpose of this method is to improve preview efficiency and frame rate by allowing preview frame memory
        /// reuse.You must call <see cref="AddCallbackBuffer"/>(FastJavaByteArray) at some point -- before or after
        /// calling this method -- or no callbacks will received.
        /// </para>
        /// <para>
        /// The buffer queue will be cleared if this method is called with a null callback, or if
        /// <see cref="Camera.SetPreviewCallback"/>(Camera.PreviewCallback),
        /// <see cref="SetNonMarshalingPreviewCallback"/>(INonMarshalingPreviewCallback),
        /// <see cref="Camera.SetOneShotPreviewCallback"/>(Camera.PreviewCallback), or
        /// <see cref="SetNonMarshalingOneShotPreviewCallback"/> is called.
        /// </para>
        /// </summary>
        /// <param name="self">Camera object.</param>
        /// <param name="cb">A callback object that receives a copy of the preview frame, or null to stop receiving callbacks and clear the buffer queue.</param>
        public static void SetNonMarshalingOneShotPreviewCallback(this Camera self, INonMarshalingPreviewCallback cb)
        {
            if (id_setOneShotPreviewCallback_Landroid_hardware_Camera_PreviewCallback_ == IntPtr.Zero)
                id_setOneShotPreviewCallback_Landroid_hardware_Camera_PreviewCallback_ = JNIEnv.GetMethodID(self.Class.Handle, "setOneShotPreviewCallback", "(Landroid/hardware/Camera$PreviewCallback;)V");
            JNIEnv.CallVoidMethod(self.Handle, id_setOneShotPreviewCallback_Landroid_hardware_Camera_PreviewCallback_, new JValue(cb));
        }
    }
 
    /// <summary>
    /// Callback interface used to deliver references to Java arrays containing preview frames as they are displayed.
    /// </summary>
    // Metadata.xml XPath interface reference: path="/api/package[@name='android.hardware']/interface[@name='Camera.PreviewCallback']"
    [Register("android/hardware/Camera$PreviewCallback", "", "ApxLabs.FastAndroidCamera.INonMarshalingPreviewCallbackInvoker")]
    public interface INonMarshalingPreviewCallback : IJavaObject
    {
        /// <summary>
        /// Called as preview frames are displayed. This callback is invoked on the event thread <see cref="Camera.Open(int)"/> was called from.
        /// </summary>
        /// <param name="data">
        /// The contents of the preview frame in the format defined by <see cref="Android.Graphics.ImageFormat"/>, which
        /// can be queried with <see cref="Camera.Parameters.PreviewFormat"/>. If
        /// <see cref="Camera.Parameters.PreviewFormat"/> is never set, the default will be the YCbCr_420_SP (NV21) format.
        /// </param>
        /// <param name="camera">The Camera service object.</param>
        // Metadata.xml XPath method reference: path="/api/package[@name='android.hardware']/interface[@name='Camera.PreviewCallback']/method[@name='onPreviewFrame' and count(parameter)=2 and parameter[1][@type='byte[]'] and parameter[2][@type='android.hardware.Camera']]"
        [Register("onPreviewFrame", "([BLandroid/hardware/Camera;)V", "GetOnPreviewFrame_arrayBLandroid_hardware_Camera_Handler:ApxLabs.FastAndroidCamera.INonMarshalingPreviewCallbackInvoker, FastAndroidCamera, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")]
        void OnPreviewFrame(IntPtr data, Camera camera);
    }
 
    [Register("android/hardware/Camera$PreviewCallback", DoNotGenerateAcw = true)]
    internal class INonMarshalingPreviewCallbackInvoker : Java.Lang.Object, INonMarshalingPreviewCallback
    {
 
        static IntPtr java_class_ref = JNIEnv.FindClass("android/hardware/Camera$PreviewCallback");
        IntPtr class_ref;
 
        public static INonMarshalingPreviewCallback GetObject(IntPtr handle, JniHandleOwnership transfer)
        {
            return GetObject<INonMarshalingPreviewCallback>(handle, transfer);
        }
 
        static IntPtr Validate(IntPtr handle)
        {
            if (!JNIEnv.IsInstanceOf(handle, java_class_ref))
                throw new InvalidCastException(string.Format("Unable to convert instance of type '{0}' to type '{1}'.",
                                                               JNIEnv.GetClassNameFromInstance(handle), "android.hardware.Camera.PreviewCallback"));
            return handle;
        }
 
        protected override void Dispose(bool disposing)
        {
            if (class_ref != IntPtr.Zero)
                JNIEnv.DeleteGlobalRef(class_ref);
            class_ref = IntPtr.Zero;
            base.Dispose(disposing);
        }
 
        public INonMarshalingPreviewCallbackInvoker(IntPtr handle, JniHandleOwnership transfer)
            : base(Validate(handle), transfer)
        {
            IntPtr local_ref = JNIEnv.GetObjectClass(Handle);
            class_ref = JNIEnv.NewGlobalRef(local_ref);
            JNIEnv.DeleteLocalRef(local_ref);
        }
 
        protected override IntPtr ThresholdClass
        {
            get { return class_ref; }
        }
 
        protected override Type ThresholdType
        {
            get { return typeof(INonMarshalingPreviewCallbackInvoker); }
        }
 
        static Delegate cb_onPreviewFrame_arrayBLandroid_hardware_Camera_;
        #pragma warning disable 0169
        static Delegate GetOnPreviewFrame_arrayBLandroid_hardware_Camera_Handler()
        {
            if (cb_onPreviewFrame_arrayBLandroid_hardware_Camera_ == null)
                cb_onPreviewFrame_arrayBLandroid_hardware_Camera_ = JNINativeWrapper.CreateDelegate((Action<IntPtr, IntPtr, IntPtr, IntPtr>)n_OnPreviewFrame_arrayBLandroid_hardware_Camera_);
            return cb_onPreviewFrame_arrayBLandroid_hardware_Camera_;
        }
 
        static void n_OnPreviewFrame_arrayBLandroid_hardware_Camera_(IntPtr jnienv, IntPtr native__this, IntPtr native_data, IntPtr native_camera)
        {
            INonMarshalingPreviewCallback __this = GetObject<INonMarshalingPreviewCallback>(native__this, JniHandleOwnership.DoNotTransfer);
            Camera camera = GetObject<Camera>(native_camera, JniHandleOwnership.DoNotTransfer);
            __this.OnPreviewFrame(native_data, camera);
        }
        #pragma warning restore 0169
 
        IntPtr id_onPreviewFrame_arrayBLandroid_hardware_Camera_;
        public void OnPreviewFrame(IntPtr data, Camera camera)
        {
            if (id_onPreviewFrame_arrayBLandroid_hardware_Camera_ == IntPtr.Zero)
                id_onPreviewFrame_arrayBLandroid_hardware_Camera_ = JNIEnv.GetMethodID(class_ref, "onPreviewFrame", "([BLandroid/hardware/Camera;)V");
            JNIEnv.CallVoidMethod(Handle, id_onPreviewFrame_arrayBLandroid_hardware_Camera_, new JValue(data), new JValue(camera));
        }
    }
}