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 Tizen.Internals.Errors;
20 using Native = Tizen.Multimedia.Interop.MediaPacket;
21 using NativeFormat = Tizen.Multimedia.Interop.MediaFormat;
23 namespace Tizen.Multimedia
26 /// Represents a packet for multimedia.
28 public abstract partial class MediaPacket : IBufferOwner, IDisposable
30 private IntPtr _handle = IntPtr.Zero;
33 /// Initializes a new instance of the MediaPacket class with the specified media format.
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"/>.
40 /// <exception cref="InvalidOperationException">Operation failed.</exception>
41 internal MediaPacket(MediaFormat format)
45 throw new ArgumentNullException(nameof(format));
51 _buffer = new Lazy<IMediaBuffer>(GetBuffer);
55 /// Initializes a new instance of the MediaPacket class from an original MediaPacket.
57 /// <param name="mediaPacket">The original MediaPacket.</param>
58 internal MediaPacket(MediaPacket mediaPacket) : this(mediaPacket._handle)
60 int ret = Native.Ref(_handle);
61 MultimediaDebug.AssertNoError(ret);
65 /// Initializes a new instance of the MediaPacket class from a native handle.
67 /// <param name="handle">The native handle to be used.</param>
68 internal MediaPacket(IntPtr handle)
72 int ret = Native.GetFormat(handle, out IntPtr formatHandle);
73 MultimediaDebug.AssertNoError(ret);
77 if (formatHandle != IntPtr.Zero)
79 _format = MediaFormat.FromHandle(formatHandle);
82 _buffer = new Lazy<IMediaBuffer>(GetBuffer);
86 NativeFormat.Unref(formatHandle);
91 /// Finalizes an instance of the MediaPacket class.
99 /// Creates and initializes a native handle for the current object.
101 /// <param name="format">The format to be set to the media format.</param>
102 /// <exception cref="InvalidOperationException">Operation failed.</exception>
103 private void Initialize(MediaFormat format)
105 if (format.Type == MediaFormatType.Container)
107 throw new ArgumentException("Container format can't be used to create a new packet.",
111 IntPtr formatHandle = IntPtr.Zero;
115 formatHandle = format.AsNativeHandle();
117 int ret = Native.New(formatHandle, IntPtr.Zero, IntPtr.Zero, out _handle);
118 MultimediaDebug.AssertNoError(ret);
120 Debug.Assert(_handle != IntPtr.Zero, "Created handle must not be null");
126 if (_handle != IntPtr.Zero)
128 Native.Unref(_handle);
129 _handle = IntPtr.Zero;
136 if (formatHandle != IntPtr.Zero)
138 NativeFormat.Unref(formatHandle);
144 /// Allocates internal buffer.
146 /// <exception cref="InvalidOperationException">Operation failed.</exception>
149 ErrorCode ret = (ErrorCode)Native.Alloc(_handle);
150 if (ret == ErrorCode.None)
155 _handle = IntPtr.Zero;
159 case ErrorCode.OutOfMemory:
160 throw new OutOfMemoryException("Failed to allocate buffer for the packet.");
163 throw new InvalidOperationException("Failed to create a packet.");
167 private readonly MediaFormat _format;
170 /// Gets the media format of the current packet.
172 /// <since_tizen> 3 </since_tizen>
173 public MediaFormat Format
177 ValidateNotDisposed();
183 /// Gets or sets the PTS(Presentation Time Stamp) value of the current packet in nanoseconds.
185 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
186 /// <exception cref="InvalidOperationException">
187 /// The MediaPacket is not in the writable state, which means it is being used by another module.
189 /// <since_tizen> 3 </since_tizen>
194 ValidateNotDisposed();
196 int ret = Native.GetPts(_handle, out var value);
197 MultimediaDebug.AssertNoError(ret);
203 ValidateNotDisposed();
206 int ret = Native.SetPts(_handle, value);
207 MultimediaDebug.AssertNoError(ret);
212 /// Gets or sets the DTS(Decoding Time Stamp) value of the current packet in nanoseconds.
214 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
215 /// <exception cref="InvalidOperationException">
216 /// The MediaPacket is not in the writable state, which means it is being used by another module.
218 /// <since_tizen> 3 </since_tizen>
223 ValidateNotDisposed();
225 int ret = Native.GetDts(_handle, out var value);
226 MultimediaDebug.AssertNoError(ret);
232 ValidateNotDisposed();
235 int ret = Native.SetDts(_handle, value);
236 MultimediaDebug.AssertNoError(ret);
241 /// Gets or sets the duration value of the current packet in nanoseconds.
243 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
244 /// <exception cref="InvalidOperationException">
245 /// The MediaPacket is not in the writable state, which means it is being used by another module.
247 /// <since_tizen> 6 </since_tizen>
248 public ulong Duration
252 ValidateNotDisposed();
254 int ret = Native.GetDuration(_handle, out var value);
255 MultimediaDebug.AssertNoError(ret);
261 ValidateNotDisposed();
264 int ret = Native.SetDuration(_handle, value);
265 MultimediaDebug.AssertNoError(ret);
270 /// Gets a value indicating whether the packet is the encoded type.
272 /// <value>true if the packet is the encoded type; otherwise, false.</value>
273 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
274 /// <since_tizen> 3 </since_tizen>
275 public bool IsEncoded
279 ValidateNotDisposed();
281 int ret = Native.IsEncoded(_handle, out var value);
282 MultimediaDebug.AssertNoError(ret);
289 /// Gets or sets the rotation value of the current packet.
291 /// <exception cref="ArgumentException">The specified value to set is invalid.</exception>
292 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
293 /// <exception cref="InvalidOperationException">
294 /// The MediaPacket is not in the writable state, which means it is being used by another module.
296 /// <since_tizen> 5 </since_tizen>
297 public Rotation Rotation
301 ValidateNotDisposed();
303 int ret = Native.GetRotation(_handle, out var value);
304 MultimediaDebug.AssertNoError(ret);
306 var rotation = value < RotationFlip.HorizontalFlip ? (Rotation)value : Rotation.Rotate0;
312 ValidateNotDisposed();
314 ValidationUtil.ValidateEnum(typeof(Rotation), value, nameof(value));
316 int ret = Native.SetRotation(_handle, (RotationFlip)value);
317 MultimediaDebug.AssertNoError(ret);
322 /// Gets or sets the flip value of the current packet.
325 /// <see cref="Flips.None"/> will be ignored in set case. It's not supported in Native FW.
327 /// <exception cref="ArgumentException">The specified value to set is invalid.</exception>
328 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
329 /// <exception cref="InvalidOperationException">
330 /// The MediaPacket is not in the writable state, which means it is being used by another module.
332 /// <since_tizen> 5 </since_tizen>
337 ValidateNotDisposed();
339 int ret = Native.GetRotation(_handle, out var value);
340 MultimediaDebug.AssertNoError(ret);
342 var flip = (value < RotationFlip.HorizontalFlip) ? Flips.None :
343 (value == RotationFlip.HorizontalFlip ? Flips.Horizontal : Flips.Vertical);
349 ValidateNotDisposed();
351 ValidationUtil.ValidateEnum(typeof(Flips), value, nameof(value));
353 if (value == Flips.None)
358 var flip = value == Flips.Horizontal ? RotationFlip.HorizontalFlip : RotationFlip.VerticalFlip;
360 int ret = Native.SetRotation(_handle, flip);
361 MultimediaDebug.AssertNoError(ret);
365 private Lazy<IMediaBuffer> _buffer;
368 /// Gets the buffer of the packet.
371 /// The <see cref="IMediaBuffer"/> allocated to the packet.
372 /// This property will return null if the packet is in the raw video format.
374 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
375 /// <seealso cref="IsEncoded"/>
376 /// <seealso cref="VideoPlanes"/>
377 /// <since_tizen> 3 </since_tizen>
378 public IMediaBuffer Buffer
382 ValidateNotDisposed();
384 if (IsVideoPlaneSupported)
389 return _buffer.Value;
394 /// Gets or sets a length of data written in the <see cref="Buffer"/>.
396 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
397 /// <exception cref="ArgumentOutOfRangeException">
398 /// The value specified for this property is less than zero or greater than the length of the <see cref="Buffer"/>.</exception>
399 /// <exception cref="InvalidOperationException">
400 /// The MediaPacket has <see cref="VideoPlanes"/> instead of <see cref="Buffer"/>.<br/>
402 /// The MediaPacket is not in the writable state, which means it is being used by another module.
404 /// <since_tizen> 3 </since_tizen>
405 public int BufferWrittenLength
409 ValidateNotDisposed();
411 int ret = Native.GetBufferSize(_handle, out var value);
412 MultimediaDebug.AssertNoError(ret);
414 Debug.Assert(value < int.MaxValue);
420 ValidateNotDisposed();
423 if (IsVideoPlaneSupported)
425 throw new InvalidOperationException(
426 "This packet uses VideoPlanes instead of Buffer.");
429 Debug.Assert(Buffer != null);
431 if (value < 0 || value >= Buffer.Length)
433 throw new ArgumentOutOfRangeException(nameof(value), value,
434 "value must be less than Buffer.Size.");
437 int ret = Native.SetBufferSize(_handle, (ulong)value);
438 MultimediaDebug.AssertNoError(ret);
442 private MediaPacketVideoPlane[] _videoPlanes;
445 /// Gets the video planes of the packet.
447 /// <value>The <see cref="MediaPacketVideoPlane"/>s allocated to the packet.
448 /// This property will return null if the packet is not in the raw video format.</value>
449 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
450 /// <seealso cref="IsEncoded"/>
451 /// <seealso cref="Buffer"/>
452 /// <since_tizen> 3 </since_tizen>
453 public MediaPacketVideoPlane[] VideoPlanes
457 ValidateNotDisposed();
459 if (!IsVideoPlaneSupported)
464 if (_videoPlanes == null)
466 _videoPlanes = GetVideoPlanes();
474 /// Gets or sets the buffer flags of the packet.
476 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
477 /// <exception cref="InvalidOperationException">
478 /// The MediaPacket is not in the writable state, which means it is being used by another module.
480 /// <since_tizen> 3 </since_tizen>
481 public MediaPacketBufferFlags BufferFlags
485 ValidateNotDisposed();
487 int ret = Native.GetBufferFlags(_handle, out var value);
488 MultimediaDebug.AssertNoError(ret);
494 ValidateNotDisposed();
497 int ret = Native.ResetBufferFlags(_handle);
498 MultimediaDebug.AssertNoError(ret);
500 ret = Native.SetBufferFlags(_handle, (int)value);
501 MultimediaDebug.AssertNoError(ret);
505 #region Dispose support
507 /// Gets a value indicating whether the packet has been disposed.
509 /// <value>true if the packet has been disposed of; otherwise, false.</value>
510 /// <since_tizen> 3 </since_tizen>
511 public bool IsDisposed => _isDisposed;
513 private bool _isDisposed = false;
516 /// Releases all resources used by the <see cref="MediaPacket"/> object.
518 /// <exception cref="InvalidOperationException">
519 /// The MediaPacket can not be disposed, which means it is being used by another module.
521 /// <since_tizen> 3 </since_tizen>
522 public void Dispose()
531 GC.SuppressFinalize(this);
535 /// Releases the resources used by the <see cref="MediaPacket"/> object.
537 /// <param name="disposing">
538 /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
540 /// <since_tizen> 3 </since_tizen>
541 protected virtual void Dispose(bool disposing)
548 if (_handle != IntPtr.Zero)
550 Native.Unref(_handle);
551 _handle = IntPtr.Zero;
558 /// Validates the current object has not been disposed.
560 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
561 private void ValidateNotDisposed()
565 throw new ObjectDisposedException("This packet has already been disposed.");
570 internal IntPtr GetHandle()
572 ValidateNotDisposed();
574 Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!");
580 /// Ensures whether the packet is writable.
582 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
583 /// <exception cref="InvalidOperationException">The MediaPacket is being used by another module.</exception>
584 internal void EnsureWritableState()
586 ValidateNotDisposed();
591 /// Ensures whether the packet is readable.
593 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed.</exception>
594 internal void EnsureReadableState()
596 ValidateNotDisposed();
600 /// Gets a value indicating whether the packet is in the raw video format.
602 /// <value>true if the packet is in the raw video format; otherwise, false.</value>
603 private bool IsVideoPlaneSupported => !IsEncoded && Format.Type == MediaFormatType.Video;
606 /// Retrieves video planes of the current packet.
608 /// <returns>The <see cref="MediaPacketVideoPlane"/>s allocated to the current MediaPacket.</returns>
609 private MediaPacketVideoPlane[] GetVideoPlanes()
611 Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!");
613 int ret = Native.GetNumberOfVideoPlanes(_handle, out var numberOfPlanes);
614 MultimediaDebug.AssertNoError(ret);
616 MediaPacketVideoPlane[] planes = new MediaPacketVideoPlane[numberOfPlanes];
618 for (int i = 0; i < numberOfPlanes; ++i)
620 planes[i] = new MediaPacketVideoPlane(this, i);
627 /// Retrieves the buffer of the current packet.
629 /// <returns>The <see cref="IMediaBuffer"/> allocated to the current MediaPacket.</returns>
630 private IMediaBuffer GetBuffer()
632 Debug.Assert(!IsDisposed, "Packet is already disposed!");
634 Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!");
636 int ret = Native.GetBufferData(_handle, out var dataHandle);
637 MultimediaDebug.AssertNoError(ret);
639 Debug.Assert(dataHandle != IntPtr.Zero, "Data handle is invalid!");
641 ret = Native.GetAllocatedBufferSize(_handle, out var size);
642 MultimediaDebug.AssertNoError(ret);
644 Debug.Assert(size >= 0, "size must not be negative!");
646 return new DependentMediaBuffer(this, dataHandle, size);
650 /// Creates an object of the MediaPacket with the specified <see cref="MediaFormat"/>.
652 /// <param name="format">The media format for the new packet.</param>
653 /// <returns>A new MediaPacket object.</returns>
654 /// <since_tizen> 3 </since_tizen>
655 public static MediaPacket Create(MediaFormat format)
657 return new SimpleMediaPacket(format);
661 /// Creates an object of the MediaPacket based on the original MediaPacket and increases the internal reference(hereafter ref) count by 1.
664 /// This method can be useful when user share MediaPacket instance to other module and don't know the exact time to dispose it.\n
665 /// In this case, user creates a new instance with <see cref="Create(MediaPacket)"/> and shares it to other module.\n
666 /// And then, each MediaPacket instances can be disposed independently without concerning other instance's life cycle.
668 /// <param name="mediaPacket">The media packet to increase ref count.</param>
669 /// <returns>A MediaPacket object which is based on original MediaPacket instance.</returns>
670 /// <since_tizen> 10 </since_tizen>
671 public static MediaPacket Create(MediaPacket mediaPacket)
673 return new SimpleMediaPacket(mediaPacket);
676 internal static MediaPacket From(IntPtr handle)
678 return new SimpleMediaPacket(handle);
681 bool IBufferOwner.IsDisposed => IsDisposed;
683 bool IBufferOwner.IsBufferAccessible(object buffer, MediaBufferAccessMode accessMode) => true;
686 internal class SimpleMediaPacket : MediaPacket
688 internal SimpleMediaPacket(MediaFormat format) : base(format)
692 internal SimpleMediaPacket(IntPtr handle) : base(handle)
696 internal SimpleMediaPacket(MediaPacket mediaPacket) : base(mediaPacket)