c2ffe336186413f98d4dd9eb24f2d4848997755c
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia / MediaTool / MediaPacket.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 System.Threading;
21 using Tizen.Internals.Errors;
22
23 namespace Tizen.Multimedia
24 {
25     /// <summary>
26     /// Represents a packet for multimedia.
27     /// </summary>
28     public abstract partial class MediaPacket : IDisposable
29     {
30         private IntPtr _handle = IntPtr.Zero;
31
32         /// <summary>
33         /// Initializes a new instance of the MediaPacket class with the specified media format.
34         /// </summary>
35         /// <param name="format">The media format containing properties for the packet.</param>
36         /// <exception cref="ArgumentNullException">format is null.</exception>
37         /// <exception cref="ArgumentException">
38         ///     <see cref="MediaFormatType"/> of the specified format is <see cref="MediaFormatType.Container"/>.</exception>
39         /// <exception cref="InvalidOperationException">Operation failed.</exception>
40         internal MediaPacket(MediaFormat format)
41         {
42             if (format == null)
43             {
44                 throw new ArgumentNullException(nameof(format));
45             }
46
47             if (format.Type == MediaFormatType.Container)
48             {
49                 throw new ArgumentException("Container format can't be used to create a new packet.");
50             }
51
52             Initialize(format);
53             _format = format;
54         }
55
56         /// <summary>
57         /// Initializes a new instance of the MediaPacket class from a native handle.
58         /// </summary>
59         /// <param name="handle">The native handle to be used.</param>
60         internal MediaPacket(IntPtr handle)
61         {
62             _handle = handle;
63
64             IntPtr formatHandle;
65             int ret = Interop.MediaPacket.GetFormat(handle, out formatHandle);
66
67             MultimediaDebug.AssertNoError(ret);
68
69             try
70             {
71                 if (formatHandle != IntPtr.Zero)
72                 {
73                     _format = MediaFormat.FromHandle(formatHandle);
74                 }
75             }
76             finally
77             {
78                 Interop.MediaFormat.Unref(formatHandle);
79             }
80         }
81
82         ~MediaPacket()
83         {
84             Dispose(false);
85         }
86
87         /// <summary>
88         /// Creates and initializes a native handle for the current object.
89         /// </summary>
90         /// <param name="format">The format to be set to the media format.</param>
91         /// <exception cref="InvalidOperationException">Operation failed.</exception>
92         private void Initialize(MediaFormat format)
93         {
94             if (format.Type == MediaFormatType.Container)
95             {
96                 throw new ArgumentException("Creating a packet for container is not supported.");
97             }
98
99             IntPtr formatHandle = IntPtr.Zero;
100
101             try
102             {
103                 formatHandle = format.AsNativeHandle();
104
105                 int ret = Interop.MediaPacket.Create(formatHandle, IntPtr.Zero, IntPtr.Zero, out _handle);
106                 MultimediaDebug.AssertNoError(ret);
107
108                 Debug.Assert(_handle != IntPtr.Zero, "Created handle must not be null");
109
110                 Alloc();
111             }
112             catch (Exception)
113             {
114                 if (_handle != IntPtr.Zero)
115                 {
116                     Interop.MediaPacket.Destroy(_handle);
117                     _handle = IntPtr.Zero;
118                 }
119
120                 throw;
121             }
122             finally
123             {
124                 if (formatHandle != IntPtr.Zero)
125                 {
126                     Interop.MediaFormat.Unref(formatHandle);
127                 }
128             }
129         }
130
131         /// <summary>
132         /// Allocates internal buffer.
133         /// </summary>
134         /// <exception cref="InvalidOperationException">Operation failed.</exception>
135         private void Alloc()
136         {
137             ErrorCode ret = (ErrorCode)Interop.MediaPacket.Alloc(_handle);
138             if (ret == ErrorCode.None)
139             {
140                 return;
141             }
142
143             switch (ret)
144             {
145                 case ErrorCode.OutOfMemory:
146                     throw new OutOfMemoryException("Failed to allocate buffer for the packet.");
147
148                 default:
149                     throw new InvalidOperationException("Failed to create a packet.");
150             }
151
152         }
153
154         private readonly MediaFormat _format;
155
156         /// <summary>
157         /// Gets the media format of the current packet.
158         /// </summary>
159         public MediaFormat Format
160         {
161             get
162             {
163                 ValidateNotDisposed();
164                 return _format;
165             }
166         }
167
168         /// <summary>
169         /// Gets or sets the PTS(Presentation Time Stamp) value of the current packet.
170         /// </summary>
171         /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
172         /// <exception cref="InvalidOperationException">
173         ///     The MediaPacket is not writable state which means it being used by another module.</exception>
174         public ulong Pts
175         {
176             get
177             {
178                 ValidateNotDisposed();
179
180                 ulong value = 0;
181                 int ret = Interop.MediaPacket.GetPts(_handle, out value);
182
183                 MultimediaDebug.AssertNoError(ret);
184
185                 return value;
186             }
187             set
188             {
189                 ValidateNotDisposed();
190                 ValidateNotLocked();
191
192                 int ret = Interop.MediaPacket.SetPts(_handle, value);
193
194                 MultimediaDebug.AssertNoError(ret);
195             }
196         }
197
198         /// <summary>
199         /// Gets or sets the DTS(Decoding Time Stamp) value of the current packet.
200         /// </summary>
201         /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
202         /// <exception cref="InvalidOperationException">
203         ///     The MediaPacket is not in writable state which means it being used by another module.</exception>
204         public ulong Dts
205         {
206             get
207             {
208                 ValidateNotDisposed();
209
210                 ulong value = 0;
211                 int ret = Interop.MediaPacket.GetDts(_handle, out value);
212
213                 MultimediaDebug.AssertNoError(ret);
214
215                 return value;
216             }
217             set
218             {
219                 ValidateNotDisposed();
220                 ValidateNotLocked();
221
222                 int ret = Interop.MediaPacket.SetDts(_handle, value);
223
224                 MultimediaDebug.AssertNoError(ret);
225             }
226         }
227
228         /// <summary>
229         /// Gets a value indicating whether the packet is encoded type.
230         /// </summary>
231         /// <value>true if the packet is encoded type; otherwise, false.</value>
232         /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
233         public bool IsEncoded
234         {
235             get
236             {
237                 ValidateNotDisposed();
238
239                 bool value = false;
240                 int ret = Interop.MediaPacket.IsEncoded(_handle, out value);
241
242                 MultimediaDebug.AssertNoError(ret);
243
244                 return value;
245             }
246         }
247
248         private MediaPacketBuffer _buffer;
249
250         /// <summary>
251         /// Gets the buffer of the packet.
252         /// </summary>
253         /// <value>The <see cref="MediaPacketBuffer"/> allocated to the packet.
254         ///     This property will return null if the packet is raw video format.</value>
255         /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
256         /// <seealso cref="IsEncoded"/>
257         /// <seealso cref="VideoPlanes"/>
258         public MediaPacketBuffer Buffer
259         {
260             get
261             {
262                 ValidateNotDisposed();
263
264                 if (IsVideoPlaneSupported)
265                 {
266                     return null;
267                 }
268
269                 if (_buffer == null)
270                 {
271                     _buffer = GetBuffer();
272                 }
273
274                 return _buffer;
275             }
276         }
277
278         /// <summary>
279         /// Gets or sets a length of data written in the <see cref="Buffer"/>.
280         /// </summary>
281         /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
282         /// <exception cref="ArgumentOutOfRangeException">
283         ///     The value specified for this property is less than zero or greater than <see cref="MediaPacketBuffer.Length"/>.</exception>
284         /// <exception cref="InvalidOperationException">
285         ///     The MediaPacket has <see cref="VideoPlanes"/> instead of <see cref="Buffer"/>.\n
286         ///     -or-\n
287         ///     The MediaPacket is not in writable state which means it being used by another module.
288         ///     </exception>
289         public int BufferWrittenLength
290         {
291             get
292             {
293                 ValidateNotDisposed();
294
295                 ulong value = 0;
296                 int ret = Interop.MediaPacket.GetBufferSize(_handle, out value);
297                 MultimediaDebug.AssertNoError(ret);
298
299                 Debug.Assert(value < int.MaxValue);
300
301                 return (int)value;
302             }
303             set
304             {
305                 ValidateNotDisposed();
306                 ValidateNotLocked();
307
308                 if (IsVideoPlaneSupported)
309                 {
310                     throw new InvalidOperationException(
311                         "This packet uses VideoPlanes instead of Buffer.");
312                 }
313
314                 Debug.Assert(Buffer != null);
315
316                 if (value < 0 || value >= Buffer.Length)
317                 {
318                     throw new ArgumentOutOfRangeException("value must be less than Buffer.Size.");
319                 }
320
321                 int ret = Interop.MediaPacket.SetBufferSize(_handle, (ulong)value);
322                 MultimediaDebug.AssertNoError(ret);
323             }
324         }
325
326         private MediaPacketVideoPlane[] _videoPlanes;
327
328         /// <summary>
329         /// Gets the video planes of the packet.
330         /// </summary>
331         /// <value>The <see cref="MediaPacketVideoPlane"/>s allocated to the packet.
332         ///     This property will return null if the packet is not raw video format.</value>
333         /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
334         /// <seealso cref="IsEncoded"/>
335         /// <seealso cref="Buffer"/>
336         public MediaPacketVideoPlane[] VideoPlanes
337         {
338             get
339             {
340                 ValidateNotDisposed();
341
342                 if (!IsVideoPlaneSupported)
343                 {
344                     return null;
345                 }
346
347                 if (_videoPlanes == null)
348                 {
349                     _videoPlanes = GetVideoPlanes();
350                 }
351
352                 return _videoPlanes;
353             }
354         }
355
356         /// <summary>
357         /// Gets or sets the buffer flags of the packet.
358         /// </summary>
359         /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
360         /// <exception cref="InvalidOperationException">
361         ///     The MediaPacket is not in writable state which means it being used by another module.
362         ///     </exception>
363         public MediaPacketBufferFlags BufferFlags
364         {
365             get
366             {
367                 ValidateNotDisposed();
368
369                 int value = 0;
370
371                 int ret = Interop.MediaPacket.GetBufferFlags(_handle, out value);
372
373                 MultimediaDebug.AssertNoError(ret);
374
375                 return (MediaPacketBufferFlags)value;
376             }
377
378             set
379             {
380                 ValidateNotDisposed();
381                 ValidateNotLocked();
382
383                 int ret = Interop.MediaPacket.ResetBufferFlags(_handle);
384
385                 MultimediaDebug.AssertNoError(ret);
386
387                 ret = Interop.MediaPacket.SetBufferFlags(_handle, (int)value);
388
389                 MultimediaDebug.AssertNoError(ret);
390             }
391         }
392
393         /// <summary>
394         /// Gets a value indicating whether the packet has been disposed of.
395         /// </summary>
396         /// <value>true if the packet has been disposed of; otherwise, false.</value>
397         public bool IsDisposed
398         {
399             get
400             {
401                 return _isDisposed;
402             }
403         }
404
405         private bool _isDisposed = false;
406
407
408         /// <summary>
409         /// Releases all resources used by the <see cref="MediaPacket"/> object.
410         /// </summary>
411         /// <exception cref="InvalidOperationException">
412         ///     The MediaPacket can not be disposed which means it being used by another module.
413         /// </exception>
414         public void Dispose()
415         {
416             if (_isDisposed)
417             {
418                 return;
419             }
420             ValidateNotLocked();
421
422             Dispose(true);
423             GC.SuppressFinalize(this);
424         }
425
426         /// <summary>
427         /// Releases the resources used by the <see cref="MediaPacket"/> object.
428         /// </summary>
429         /// <param name="disposing">
430         /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
431         /// </param>
432         protected virtual void Dispose(bool disposing)
433         {
434             if (_isDisposed)
435             {
436                 return;
437             }
438
439             if (_handle != IntPtr.Zero)
440             {
441                 Interop.MediaPacket.Destroy(_handle);
442                 _handle = IntPtr.Zero;
443             }
444
445             _isDisposed = true;
446         }
447
448         internal IntPtr GetHandle()
449         {
450             ValidateNotDisposed();
451
452             Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!");
453
454             return _handle;
455         }
456
457         /// <summary>
458         /// Validate the current object has not been disposed of.
459         /// </summary>
460         /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
461         private void ValidateNotDisposed()
462         {
463             if (_isDisposed)
464             {
465                 throw new ObjectDisposedException("This packet has already been disposed of.");
466             }
467         }
468
469         /// <summary>
470         /// Ensures whether the packet is writable.
471         /// </summary>
472         /// <exception cref="ObjectDisposedException">The MediaPacket already has been disposed of.</exception>
473         /// <exception cref="InvalidOperationException">The MediaPacket is being used by another module.</exception>
474         internal void EnsureWritableState()
475         {
476             ValidateNotDisposed();
477             ValidateNotLocked();
478         }
479
480         /// <summary>
481         /// Ensures whether the packet is readable.
482         /// </summary>
483         /// <exception cref="ObjectDisposedException">The MediaPacket already has been disposed of.</exception>
484         internal void EnsureReadableState()
485         {
486             ValidateNotDisposed();
487         }
488
489         /// <summary>
490         /// Gets a value indicating whether the packet is raw video format.
491         /// </summary>
492         /// <value>true if the packet is raw video format; otherwise, false.</value>
493         private bool IsVideoPlaneSupported
494         {
495             get
496             {
497                 return !IsEncoded && Format.Type == MediaFormatType.Video;
498             }
499         }
500
501         /// <summary>
502         /// Retrieves video planes of the current packet.
503         /// </summary>
504         /// <returns>The <see cref="MediaPacketVideoPlane"/>s allocated to the current MediaPacket.</returns>
505         private MediaPacketVideoPlane[] GetVideoPlanes()
506         {
507             Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!");
508
509             uint numberOfPlanes = 0;
510             int ret = Interop.MediaPacket.GetNumberOfVideoPlanes(_handle, out numberOfPlanes);
511
512             MultimediaDebug.AssertNoError(ret);
513
514             MediaPacketVideoPlane[] planes = new MediaPacketVideoPlane[numberOfPlanes];
515
516             for (int i = 0; i < numberOfPlanes; ++i)
517             {
518                 planes[i] = new MediaPacketVideoPlane(this, i);
519             }
520
521             return planes;
522         }
523
524         /// <summary>
525         /// Retrieves the buffer of the current packet.
526         /// </summary>
527         /// <returns>The <see cref="MediaPacketBuffer"/> allocated to the current MediaPacket.</returns>
528         private MediaPacketBuffer GetBuffer()
529         {
530             Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!");
531
532             IntPtr dataHandle;
533
534             int ret = Interop.MediaPacket.GetBufferData(_handle, out dataHandle);
535             MultimediaDebug.AssertNoError(ret);
536
537             Debug.Assert(dataHandle != IntPtr.Zero, "Data handle is invalid!");
538
539             int size = 0;
540             ret = Interop.MediaPacket.GetAllocatedBufferSize(_handle, out size);
541             MultimediaDebug.AssertNoError(ret);
542
543             return new MediaPacketBuffer(this, dataHandle, size);
544         }
545
546         /// <summary>
547         /// Creates an object of the MediaPacket with the specified <see cref="MediaFormat"/>.
548         /// </summary>
549         /// <param name="format">The media format for the new packet.</param>
550         /// <returns>A new MediaPacket object.</returns>
551         public static MediaPacket Create(MediaFormat format)
552         {
553             return new SimpleMediaPacket(format);
554         }
555
556         internal static MediaPacket From(IntPtr handle)
557         {
558             return new SimpleMediaPacket(handle);
559         }
560     }
561
562     internal class SimpleMediaPacket : MediaPacket
563     {
564         internal SimpleMediaPacket(MediaFormat format) : base(format)
565         {
566         }
567
568         internal SimpleMediaPacket(IntPtr handle) : base(handle)
569         {
570         }
571     }
572 }