[Camera] Fix preview gc issue (#3883)
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia.Camera / Camera / PreviewFrame.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 using System;
18 using System.Diagnostics;
19 using System.Runtime.InteropServices;
20 using static Interop.Camera;
21
22 namespace Tizen.Multimedia
23 {
24     /// <summary>
25     /// The class containing the preview image data.
26     /// </summary>
27     /// <since_tizen> 4 </since_tizen>
28     public class PreviewFrame
29     {
30         internal PreviewFrame(IntPtr ptr, ref PinnedPreviewBuffer<byte> buffers)
31         {
32             var unmanagedStruct = Marshal.PtrToStructure<CameraPreviewDataStruct>(ptr);
33
34             Format = unmanagedStruct.Format;
35             Resolution = new Size(unmanagedStruct.Width, unmanagedStruct.Height);
36             TimeStamp = unmanagedStruct.TimeStamp;
37             PlaneType = GetPlaneType(unmanagedStruct);
38             CreatePlane(unmanagedStruct, ref buffers);
39         }
40
41         private static PlaneType GetPlaneType(CameraPreviewDataStruct unmanagedStruct)
42         {
43             if (unmanagedStruct.NumOfPlanes == 1)
44             {
45                 switch (unmanagedStruct.Format)
46                 {
47                     case CameraPixelFormat.H264:
48                     case CameraPixelFormat.Jpeg:
49                     case CameraPixelFormat.Mjpeg:
50                     case CameraPixelFormat.Vp8:
51                     case CameraPixelFormat.Vp9:
52                         return PlaneType.EncodedPlane;
53                     case CameraPixelFormat.Invz:
54                         return PlaneType.DepthPlane;
55                     case CameraPixelFormat.Rgba:
56                     case CameraPixelFormat.Argb:
57                         return PlaneType.RgbPlane;
58                     default:
59                         return PlaneType.SinglePlane;
60                 }
61             }
62             else if (unmanagedStruct.NumOfPlanes == 2)
63             {
64                 return PlaneType.DoublePlane;
65             }
66
67             return PlaneType.TriplePlane;
68         }
69
70         internal void CreatePlane(CameraPreviewDataStruct unmanagedStruct, ref PinnedPreviewBuffer<byte> buffers)
71         {
72             Log.Info(CameraLog.Tag, "Enter");
73             switch (PlaneType)
74             {
75                 case PlaneType.SinglePlane:
76                     Log.Info(CameraLog.Tag, "SinglePlane - START");
77                     var singlePlane = unmanagedStruct.Plane.SinglePlane;
78
79                     if (buffers == null)
80                     {
81                         Log.Info(CameraLog.Tag, "SinglePlane - Alloc buffer");
82                         buffers = new PinnedPreviewBuffer<byte>(singlePlane.DataLength);
83                     }
84                     Log.Info(CameraLog.Tag, "SinglePlane - Marshal copy");
85                     Marshal.Copy(singlePlane.Data, buffers[0], 0, (int)singlePlane.DataLength);
86
87                     Log.Info(CameraLog.Tag, "SinglePlane - Create SinglePlane instance");
88                     Plane = new SinglePlane(buffers[0]);
89                     Log.Info(CameraLog.Tag, "SinglePlane - DONE");
90                     break;
91                 case PlaneType.DoublePlane:
92                     Log.Info(CameraLog.Tag, "DoublePlane - START");
93                     var doublePlane = unmanagedStruct.Plane.DoublePlane;
94
95                     doublePlane.YLength = (uint)(Resolution.Width * Resolution.Height);
96                     doublePlane.UVLength = (uint)(Resolution.Width * Resolution.Height) / 2;
97
98                     if (buffers == null)
99                     {
100                         Log.Info(CameraLog.Tag, "DoublePlane - Alloc buffer");
101                         buffers = new PinnedPreviewBuffer<byte>(doublePlane.YLength, doublePlane.UVLength);
102                     }
103
104                     Log.Info(CameraLog.Tag, $"DoublePlane - Marshal copy");
105                     Marshal.Copy(doublePlane.Y, buffers[0], 0, (int)doublePlane.YLength);
106                     Marshal.Copy(doublePlane.UV, buffers[1], 0, (int)doublePlane.UVLength);
107
108                     Log.Info(CameraLog.Tag, "DoublePlane - Create DoublePlane instance");
109                     Plane =  new DoublePlane(buffers[0], buffers[1]);
110                     Log.Info(CameraLog.Tag, "DoublePlane - DONE");
111                     break;
112                 case PlaneType.TriplePlane:
113                     Log.Info(CameraLog.Tag, "TriplePlane - START");
114                     var triplePlane = unmanagedStruct.Plane.TriplePlane;
115
116                     if (buffers == null)
117                     {
118                         Log.Info(CameraLog.Tag, "TriplePlane - Alloc buffer");
119                         buffers = new PinnedPreviewBuffer<byte>(triplePlane.YLength, triplePlane.ULength, triplePlane.VLength);
120                     }
121                     Log.Info(CameraLog.Tag, "TriplePlane - Marshal copy");
122                     Marshal.Copy(triplePlane.Y, buffers[0], 0, (int)triplePlane.YLength);
123                     Marshal.Copy(triplePlane.U, buffers[1], 0, (int)triplePlane.ULength);
124                     Marshal.Copy(triplePlane.V, buffers[2], 0, (int)triplePlane.VLength);
125
126                     Log.Info(CameraLog.Tag, "TriplePlane - Create TriplePlane instance");
127                     Plane =  new TriplePlane(buffers[0], buffers[1], buffers[2]);
128                     Log.Info(CameraLog.Tag, "TriplePlane - DONE");
129                     break;
130                 case PlaneType.EncodedPlane:
131                     Log.Info(CameraLog.Tag, "EncodedPlane - START");
132                     var encodedPlane = unmanagedStruct.Plane.EncodedPlane;
133
134                     if (buffers == null)
135                     {
136                         Log.Info(CameraLog.Tag, "EncodedPlane - Alloc buffer");
137                         buffers = new PinnedPreviewBuffer<byte>(encodedPlane.DataLength * 2);
138                     }
139                     Log.Info(CameraLog.Tag, "EncodedPlane - Marshal copy");
140                     Marshal.Copy(encodedPlane.Data, buffers[0], 0, (int)encodedPlane.DataLength);
141
142                     Log.Info(CameraLog.Tag, "EncodedPlane - Create EncodedPlane instance");
143                     Plane = new EncodedPlane(buffers[0], encodedPlane.IsDeltaFrame);
144                     Log.Info(CameraLog.Tag, "EncodedPlane - DONE");
145                     break;
146                 case PlaneType.DepthPlane:
147                     Log.Info(CameraLog.Tag, "DepthPlane - START");
148                     var depthPlane = unmanagedStruct.Plane.DepthPlane;
149
150                     if (buffers == null)
151                     {
152                         Log.Info(CameraLog.Tag, "DepthPlane - Alloc buffer");
153                         buffers = new PinnedPreviewBuffer<byte>(depthPlane.DataLength);
154                     }
155                     Log.Info(CameraLog.Tag, "DepthPlane - Marshal copy");
156                     Marshal.Copy(depthPlane.Data, buffers[0], 0, (int)depthPlane.DataLength);
157
158                     Log.Info(CameraLog.Tag, "DepthPlane - Create DepthPlane instance");
159                     Plane = new DepthPlane(buffers[0]);
160                     Log.Info(CameraLog.Tag, "DepthPlane - DONE");
161                     break;
162                 case PlaneType.RgbPlane:
163                     var rgbPlane = unmanagedStruct.Plane.RgbPlane;
164
165                     if (buffers == null)
166                     {
167                         Log.Info(CameraLog.Tag, "RgbPlane - Alloc buffer");
168                         buffers = new PinnedPreviewBuffer<byte>(rgbPlane.DataLength);
169                     }
170                     Marshal.Copy(rgbPlane.Data, buffers[0], 0, (int)rgbPlane.DataLength);
171
172                     Plane = new RgbPlane(buffers[0]);
173                     break;
174                 default:
175                     Debug.Fail("Unknown preview data!");
176                     break;
177             }
178             Log.Info(CameraLog.Tag, "Leave");
179         }
180
181         internal static uint GetMaxPreviewPlaneSize(IntPtr ptr)
182         {
183             uint size = 0;
184             var unmanagedStruct = Marshal.PtrToStructure<CameraPreviewDataStruct>(ptr);
185
186             switch (GetPlaneType(unmanagedStruct))
187             {
188                 case PlaneType.SinglePlane:
189                     size = unmanagedStruct.Plane.SinglePlane.DataLength;
190                     break;
191                 case PlaneType.DoublePlane:
192                     size = unmanagedStruct.Plane.DoublePlane.UVLength;
193                     Log.Info(CameraLog.Tag, $"Size : {size}");
194                     break;
195                 case PlaneType.TriplePlane:
196                     size = unmanagedStruct.Plane.TriplePlane.YLength;
197                     break;
198                 case PlaneType.EncodedPlane:
199                     size = unmanagedStruct.Plane.EncodedPlane.DataLength;
200                     break;
201                 case PlaneType.DepthPlane:
202                     size = unmanagedStruct.Plane.DepthPlane.DataLength;
203                     break;
204                 case PlaneType.RgbPlane:
205                     size = unmanagedStruct.Plane.RgbPlane.DataLength;
206                     break;
207                 default:
208                     Debug.Fail("Unknown preview data!");
209                     break;
210             }
211
212             return size;
213         }
214
215         /// <summary>
216         /// The pixel format of the image.
217         /// </summary>
218         /// <since_tizen> 4 </since_tizen>
219         public CameraPixelFormat Format { get; }
220
221         /// <summary>
222         /// The resolution of the preview image.
223         /// </summary>
224         /// <since_tizen> 4 </since_tizen>
225         public Size Resolution { get; }
226
227         /// <summary>
228         /// The time stamp of the preview frame.
229         /// </summary>
230         /// <since_tizen> 4 </since_tizen>
231         public uint TimeStamp { get; }
232
233         /// <summary>
234         /// The type of the preview plane. <see cref="Tizen.Multimedia.PlaneType"/>
235         /// </summary>
236         /// <since_tizen> 4 </since_tizen>
237         public PlaneType PlaneType { get; }
238
239         /// <summary>
240         /// The buffer including the preview frame.
241         /// </summary>
242         /// <since_tizen> 4 </since_tizen>
243         public IPreviewPlane Plane { get; private set;}
244     }
245 }