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