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