2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 using System.Diagnostics;
19 using System.Runtime.InteropServices;
20 using static Interop.Camera;
22 namespace Tizen.Multimedia
25 /// The class containing the preview image data.
27 /// <since_tizen> 4 </since_tizen>
28 public class PreviewFrame
30 private const uint _variableBufferMargin = 2;
32 internal PreviewFrame(IntPtr ptr, ref PinnedPreviewBuffer<byte> buffers)
34 var unmanagedStruct = Marshal.PtrToStructure<CameraPreviewDataStruct>(ptr);
36 Format = unmanagedStruct.Format;
37 Resolution = new Size(unmanagedStruct.Width, unmanagedStruct.Height);
38 TimeStamp = unmanagedStruct.TimeStamp;
39 PlaneType = GetPlaneType(unmanagedStruct);
40 CreatePlane(unmanagedStruct, ref buffers);
43 private static PlaneType GetPlaneType(CameraPreviewDataStruct unmanagedStruct)
45 if (unmanagedStruct.NumOfPlanes == 1)
47 switch (unmanagedStruct.Format)
49 case CameraPixelFormat.H264:
50 case CameraPixelFormat.Jpeg:
51 case CameraPixelFormat.Mjpeg:
52 case CameraPixelFormat.Vp8:
53 case CameraPixelFormat.Vp9:
54 return PlaneType.EncodedPlane;
55 case CameraPixelFormat.Invz:
56 return PlaneType.DepthPlane;
57 case CameraPixelFormat.Rgba:
58 case CameraPixelFormat.Argb:
59 return PlaneType.RgbPlane;
61 return PlaneType.SinglePlane;
64 else if (unmanagedStruct.NumOfPlanes == 2)
66 return PlaneType.DoublePlane;
69 return PlaneType.TriplePlane;
72 internal void CreatePlane(CameraPreviewDataStruct unmanagedStruct, ref PinnedPreviewBuffer<byte> buffers)
76 case PlaneType.SinglePlane:
77 var singlePlane = unmanagedStruct.Plane.SinglePlane;
79 if (buffers == null || CheckReallocation(unmanagedStruct, ref buffers))
81 buffers = new PinnedPreviewBuffer<byte>(singlePlane.DataLength);
84 Marshal.Copy(singlePlane.Data, buffers[0], 0, (int)singlePlane.DataLength);
85 Plane = new SinglePlane(buffers[0]);
88 case PlaneType.DoublePlane:
89 var doublePlane = unmanagedStruct.Plane.DoublePlane;
91 doublePlane.YLength = (uint)(Resolution.Width * Resolution.Height);
92 doublePlane.UVLength = (uint)(Resolution.Width * Resolution.Height) / 2;
94 if (buffers == null || CheckReallocation(unmanagedStruct, ref buffers))
96 buffers = new PinnedPreviewBuffer<byte>(doublePlane.YLength, doublePlane.UVLength);
99 Marshal.Copy(doublePlane.Y, buffers[0], 0, (int)doublePlane.YLength);
100 Marshal.Copy(doublePlane.UV, buffers[1], 0, (int)doublePlane.UVLength);
101 Plane = new DoublePlane(buffers[0], buffers[1]);
104 case PlaneType.TriplePlane:
105 var triplePlane = unmanagedStruct.Plane.TriplePlane;
107 if (buffers == null || CheckReallocation(unmanagedStruct, ref buffers))
109 buffers = new PinnedPreviewBuffer<byte>(triplePlane.YLength, triplePlane.ULength, triplePlane.VLength);
112 Marshal.Copy(triplePlane.Y, buffers[0], 0, (int)triplePlane.YLength);
113 Marshal.Copy(triplePlane.U, buffers[1], 0, (int)triplePlane.ULength);
114 Marshal.Copy(triplePlane.V, buffers[2], 0, (int)triplePlane.VLength);
115 Plane = new TriplePlane(buffers[0], buffers[1], buffers[2]);
118 case PlaneType.EncodedPlane:
119 var encodedPlane = unmanagedStruct.Plane.EncodedPlane;
121 if (buffers == null || CheckReallocation(unmanagedStruct, ref buffers))
123 // We take buffer margin to avoid reallocation as much as possible.
124 buffers = new PinnedPreviewBuffer<byte>(encodedPlane.DataLength * _variableBufferMargin);
127 Marshal.Copy(encodedPlane.Data, buffers[0], 0, (int)encodedPlane.DataLength);
128 Plane = new EncodedPlane(buffers[0], encodedPlane.IsDeltaFrame, encodedPlane.DataLength);
131 case PlaneType.DepthPlane:
132 var depthPlane = unmanagedStruct.Plane.DepthPlane;
134 if (buffers == null || CheckReallocation(unmanagedStruct, ref buffers))
136 buffers = new PinnedPreviewBuffer<byte>(depthPlane.DataLength);
139 Marshal.Copy(depthPlane.Data, buffers[0], 0, (int)depthPlane.DataLength);
140 Plane = new DepthPlane(buffers[0]);
143 case PlaneType.RgbPlane:
144 var rgbPlane = unmanagedStruct.Plane.RgbPlane;
146 if (buffers == null || CheckReallocation(unmanagedStruct, ref buffers))
148 buffers = new PinnedPreviewBuffer<byte>(rgbPlane.DataLength);
150 Marshal.Copy(rgbPlane.Data, buffers[0], 0, (int)rgbPlane.DataLength);
152 Plane = new RgbPlane(buffers[0]);
155 Debug.Fail("Unknown preview data!");
160 internal static uint GetMaxPreviewPlaneSize(IntPtr ptr)
163 var unmanagedStruct = Marshal.PtrToStructure<CameraPreviewDataStruct>(ptr);
165 switch (GetPlaneType(unmanagedStruct))
167 case PlaneType.SinglePlane:
168 size = unmanagedStruct.Plane.SinglePlane.DataLength;
170 case PlaneType.DoublePlane:
171 size = unmanagedStruct.Plane.DoublePlane.UVLength;
173 case PlaneType.TriplePlane:
174 size = unmanagedStruct.Plane.TriplePlane.YLength;
176 case PlaneType.EncodedPlane:
177 size = unmanagedStruct.Plane.EncodedPlane.DataLength;
179 case PlaneType.DepthPlane:
180 size = unmanagedStruct.Plane.DepthPlane.DataLength;
182 case PlaneType.RgbPlane:
183 size = unmanagedStruct.Plane.RgbPlane.DataLength;
186 Debug.Fail("Unknown preview data!");
193 internal bool CheckReallocation(CameraPreviewDataStruct unmanagedStruct, ref PinnedPreviewBuffer<byte> buffers)
195 bool isReallocation = false;
199 case PlaneType.SinglePlane:
200 var singlePlane = unmanagedStruct.Plane.SinglePlane;
202 if (buffers[0].Length < singlePlane.DataLength)
204 isReallocation = true;
208 case PlaneType.DoublePlane:
209 var doublePlane = unmanagedStruct.Plane.DoublePlane;
211 doublePlane.YLength = (uint)(Resolution.Width * Resolution.Height);
212 doublePlane.UVLength = (uint)(Resolution.Width * Resolution.Height) / 2;
214 if (buffers[0].Length < doublePlane.YLength || buffers[1].Length < doublePlane.UVLength)
216 isReallocation = true;
220 case PlaneType.TriplePlane:
221 var triplePlane = unmanagedStruct.Plane.TriplePlane;
223 if (buffers[0].Length < triplePlane.YLength || buffers[1].Length < triplePlane.ULength || buffers[2].Length < triplePlane.VLength)
225 isReallocation = true;
229 case PlaneType.EncodedPlane:
230 var encodedPlane = unmanagedStruct.Plane.EncodedPlane;
232 if (buffers[0].Length < encodedPlane.DataLength)
234 Log.Debug(CameraLog.Tag, $"Cur size:{buffers[0].Length} -> New size:{encodedPlane.DataLength * _variableBufferMargin}");
235 isReallocation = true;
239 case PlaneType.DepthPlane:
240 var depthPlane = unmanagedStruct.Plane.DepthPlane;
242 if (buffers[0].Length < depthPlane.DataLength)
244 isReallocation = true;
248 case PlaneType.RgbPlane:
249 var rgbPlane = unmanagedStruct.Plane.RgbPlane;
251 if (buffers[0].Length < rgbPlane.DataLength)
253 isReallocation = true;
258 Debug.Fail("Unknown preview data!");
264 Log.Debug(CameraLog.Tag, "Reallocate preview buffer.");
266 // Dispose current buffer to free GCHandle.
270 return isReallocation;
274 /// The pixel format of the image.
276 /// <since_tizen> 4 </since_tizen>
277 public CameraPixelFormat Format { get; }
280 /// The resolution of the preview image.
282 /// <since_tizen> 4 </since_tizen>
283 public Size Resolution { get; }
286 /// The time stamp of the preview frame.
288 /// <since_tizen> 4 </since_tizen>
289 public uint TimeStamp { get; }
292 /// The type of the preview plane. <see cref="Tizen.Multimedia.PlaneType"/>
294 /// <since_tizen> 4 </since_tizen>
295 public PlaneType PlaneType { get; }
298 /// The buffer including the preview frame.
300 /// <since_tizen> 4 </since_tizen>
301 public IPreviewPlane Plane { get; private set;}