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 a native handle.
57 /// <param name="handle">The native handle to be used.</param>
58 internal MediaPacket(IntPtr handle)
62 int ret = Native.GetFormat(handle, out IntPtr formatHandle);
64 MultimediaDebug.AssertNoError(ret);
68 if (formatHandle != IntPtr.Zero)
70 _format = MediaFormat.FromHandle(formatHandle);
75 NativeFormat.Unref(formatHandle);
80 /// Finalizes an instance of the MediaPacket class.
88 /// Creates and initializes a native handle for the current object.
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)
94 if (format.Type == MediaFormatType.Container)
96 throw new ArgumentException("Container format can't be used to create a new packet.",
100 IntPtr formatHandle = IntPtr.Zero;
104 formatHandle = format.AsNativeHandle();
106 int ret = Native.Create(formatHandle, IntPtr.Zero, IntPtr.Zero, out _handle);
107 MultimediaDebug.AssertNoError(ret);
109 Debug.Assert(_handle != IntPtr.Zero, "Created handle must not be null");
115 if (_handle != IntPtr.Zero)
117 Native.Destroy(_handle);
118 _handle = IntPtr.Zero;
125 if (formatHandle != IntPtr.Zero)
127 NativeFormat.Unref(formatHandle);
133 /// Allocates internal buffer.
135 /// <exception cref="InvalidOperationException">Operation failed.</exception>
138 ErrorCode ret = (ErrorCode)Native.Alloc(_handle);
139 if (ret == ErrorCode.None)
144 _handle = IntPtr.Zero;
148 case ErrorCode.OutOfMemory:
149 throw new OutOfMemoryException("Failed to allocate buffer for the packet.");
152 throw new InvalidOperationException("Failed to create a packet.");
157 private readonly MediaFormat _format;
160 /// Gets the media format of the current packet.
162 /// <since_tizen> 3 </since_tizen>
163 public MediaFormat Format
167 ValidateNotDisposed();
173 /// Gets or sets the PTS(Presentation Time Stamp) value of the current packet.
175 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
176 /// <exception cref="InvalidOperationException">
177 /// The MediaPacket is not in the writable state, which means it is being used by another module.
179 /// <since_tizen> 3 </since_tizen>
184 ValidateNotDisposed();
186 int ret = Native.GetPts(_handle, out var value);
188 MultimediaDebug.AssertNoError(ret);
194 ValidateNotDisposed();
197 int ret = Native.SetPts(_handle, value);
199 MultimediaDebug.AssertNoError(ret);
204 /// Gets or sets the DTS(Decoding Time Stamp) value of the current packet.
206 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
207 /// <exception cref="InvalidOperationException">
208 /// The MediaPacket is not in the writable state, which means it is being used by another module.
210 /// <since_tizen> 3 </since_tizen>
215 ValidateNotDisposed();
217 int ret = Native.GetDts(_handle, out var value);
218 MultimediaDebug.AssertNoError(ret);
224 ValidateNotDisposed();
227 int ret = Native.SetDts(_handle, value);
228 MultimediaDebug.AssertNoError(ret);
233 /// Gets or sets the duration value of the current packet.
235 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
236 /// <exception cref="InvalidOperationException">
237 /// The MediaPacket is not in the writable state, which means it is being used by another module.
239 /// <since_tizen> 6 </since_tizen>
240 public ulong Duration
244 ValidateNotDisposed();
246 int ret = Native.GetDuration(_handle, out var value);
247 MultimediaDebug.AssertNoError(ret);
253 ValidateNotDisposed();
256 int ret = Native.SetDuration(_handle, value);
257 MultimediaDebug.AssertNoError(ret);
262 /// Gets a value indicating whether the packet is the encoded type.
264 /// <value>true if the packet is the encoded type; otherwise, false.</value>
265 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
266 /// <since_tizen> 3 </since_tizen>
267 public bool IsEncoded
271 ValidateNotDisposed();
273 int ret = Native.IsEncoded(_handle, out var value);
274 MultimediaDebug.AssertNoError(ret);
281 /// Gets or sets the rotation value of the current packet.
283 /// <exception cref="ArgumentException">The specified value to set is invalid.</exception>
284 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
285 /// <exception cref="InvalidOperationException">
286 /// The MediaPacket is not in the writable state, which means it is being used by another module.
288 /// <since_tizen> 5 </since_tizen>
289 public Rotation Rotation
293 ValidateNotDisposed();
295 int ret = Native.GetRotation(_handle, out var value);
296 MultimediaDebug.AssertNoError(ret);
298 var rotation = value < RotationFlip.HorizontalFlip ? (Rotation)value : Rotation.Rotate0;
304 ValidateNotDisposed();
306 ValidationUtil.ValidateEnum(typeof(Rotation), value, nameof(value));
308 int ret = Native.SetRotation(_handle, (RotationFlip)value);
309 MultimediaDebug.AssertNoError(ret);
314 /// Gets or sets the flip value of the current packet.
317 /// <see cref="Flips.None"/> will be ignored in set case. It's not supported in Native FW.
319 /// <exception cref="ArgumentException">The specified value to set is invalid.</exception>
320 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
321 /// <exception cref="InvalidOperationException">
322 /// The MediaPacket is not in the writable state, which means it is being used by another module.
324 /// <since_tizen> 5 </since_tizen>
329 ValidateNotDisposed();
331 int ret = Native.GetRotation(_handle, out var value);
332 MultimediaDebug.AssertNoError(ret);
334 var flip = (value < RotationFlip.HorizontalFlip) ? Flips.None :
335 (value == RotationFlip.HorizontalFlip ? Flips.Horizontal : Flips.Vertical);
341 ValidateNotDisposed();
343 ValidationUtil.ValidateEnum(typeof(Flips), value, nameof(value));
345 if (value == Flips.None)
350 var flip = value == Flips.Horizontal ? RotationFlip.HorizontalFlip : RotationFlip.VerticalFlip;
352 int ret = Native.SetRotation(_handle, flip);
353 MultimediaDebug.AssertNoError(ret);
357 private Lazy<IMediaBuffer> _buffer;
360 /// Gets the buffer of the packet.
363 /// The <see cref="IMediaBuffer"/> allocated to the packet.
364 /// This property will return null if the packet is in the raw video format.
366 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
367 /// <seealso cref="IsEncoded"/>
368 /// <seealso cref="VideoPlanes"/>
369 /// <since_tizen> 3 </since_tizen>
370 public IMediaBuffer Buffer
374 ValidateNotDisposed();
376 if (IsVideoPlaneSupported)
381 return _buffer.Value;
386 /// Gets or sets a length of data written in the <see cref="Buffer"/>.
388 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
389 /// <exception cref="ArgumentOutOfRangeException">
390 /// The value specified for this property is less than zero or greater than the length of the <see cref="Buffer"/>.</exception>
391 /// <exception cref="InvalidOperationException">
392 /// The MediaPacket has <see cref="VideoPlanes"/> instead of <see cref="Buffer"/>.<br/>
394 /// The MediaPacket is not in the writable state, which means it is being used by another module.
396 /// <since_tizen> 3 </since_tizen>
397 public int BufferWrittenLength
401 ValidateNotDisposed();
403 int ret = Native.GetBufferSize(_handle, out var value);
404 MultimediaDebug.AssertNoError(ret);
406 Debug.Assert(value < int.MaxValue);
412 ValidateNotDisposed();
415 if (IsVideoPlaneSupported)
417 throw new InvalidOperationException(
418 "This packet uses VideoPlanes instead of Buffer.");
421 Debug.Assert(Buffer != null);
423 if (value < 0 || value >= Buffer.Length)
425 throw new ArgumentOutOfRangeException(nameof(value), value,
426 "value must be less than Buffer.Size.");
429 int ret = Native.SetBufferSize(_handle, (ulong)value);
430 MultimediaDebug.AssertNoError(ret);
434 private MediaPacketVideoPlane[] _videoPlanes;
437 /// Gets the video planes of the packet.
439 /// <value>The <see cref="MediaPacketVideoPlane"/>s allocated to the packet.
440 /// This property will return null if the packet is not in the raw video format.</value>
441 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
442 /// <seealso cref="IsEncoded"/>
443 /// <seealso cref="Buffer"/>
444 /// <since_tizen> 3 </since_tizen>
445 public MediaPacketVideoPlane[] VideoPlanes
449 ValidateNotDisposed();
451 if (!IsVideoPlaneSupported)
456 if (_videoPlanes == null)
458 _videoPlanes = GetVideoPlanes();
466 /// Gets or sets the buffer flags of the packet.
468 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
469 /// <exception cref="InvalidOperationException">
470 /// The MediaPacket is not in the writable state, which means it is being used by another module.
472 /// <since_tizen> 3 </since_tizen>
473 public MediaPacketBufferFlags BufferFlags
477 ValidateNotDisposed();
479 int ret = Native.GetBufferFlags(_handle, out var value);
481 MultimediaDebug.AssertNoError(ret);
488 ValidateNotDisposed();
491 int ret = Native.ResetBufferFlags(_handle);
493 MultimediaDebug.AssertNoError(ret);
495 ret = Native.SetBufferFlags(_handle, (int)value);
497 MultimediaDebug.AssertNoError(ret);
501 #region Dispose support
503 /// Gets a value indicating whether the packet has been disposed of.
505 /// <value>true if the packet has been disposed of; otherwise, false.</value>
506 /// <since_tizen> 3 </since_tizen>
507 public bool IsDisposed => _isDisposed;
509 private bool _isDisposed = false;
512 /// Releases all resources used by the <see cref="MediaPacket"/> object.
514 /// <exception cref="InvalidOperationException">
515 /// The MediaPacket can not be disposed, which means it is being used by another module.
517 /// <since_tizen> 3 </since_tizen>
518 public void Dispose()
527 GC.SuppressFinalize(this);
531 /// Releases the resources used by the <see cref="MediaPacket"/> object.
533 /// <param name="disposing">
534 /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
536 /// <since_tizen> 3 </since_tizen>
537 protected virtual void Dispose(bool disposing)
544 if (_handle != IntPtr.Zero)
546 Native.Destroy(_handle);
547 _handle = IntPtr.Zero;
554 /// Validates the current object has not been disposed of.
556 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
557 private void ValidateNotDisposed()
561 throw new ObjectDisposedException("This packet has already been disposed of.");
566 internal IntPtr GetHandle()
568 ValidateNotDisposed();
570 Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!");
576 /// Ensures whether the packet is writable.
578 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
579 /// <exception cref="InvalidOperationException">The MediaPacket is being used by another module.</exception>
580 internal void EnsureWritableState()
582 ValidateNotDisposed();
587 /// Ensures whether the packet is readable.
589 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
590 internal void EnsureReadableState()
592 ValidateNotDisposed();
596 /// Gets a value indicating whether the packet is in the raw video format.
598 /// <value>true if the packet is in the raw video format; otherwise, false.</value>
599 private bool IsVideoPlaneSupported => !IsEncoded && Format.Type == MediaFormatType.Video;
602 /// Retrieves video planes of the current packet.
604 /// <returns>The <see cref="MediaPacketVideoPlane"/>s allocated to the current MediaPacket.</returns>
605 private MediaPacketVideoPlane[] GetVideoPlanes()
607 Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!");
609 int ret = Native.GetNumberOfVideoPlanes(_handle, out var numberOfPlanes);
611 MultimediaDebug.AssertNoError(ret);
613 MediaPacketVideoPlane[] planes = new MediaPacketVideoPlane[numberOfPlanes];
615 for (int i = 0; i < numberOfPlanes; ++i)
617 planes[i] = new MediaPacketVideoPlane(this, i);
624 /// Retrieves the buffer of the current packet.
626 /// <returns>The <see cref="IMediaBuffer"/> allocated to the current MediaPacket.</returns>
627 private IMediaBuffer GetBuffer()
629 Debug.Assert(!IsDisposed, "Packet is already disposed!");
631 Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!");
633 int ret = Native.GetBufferData(_handle, out var dataHandle);
634 MultimediaDebug.AssertNoError(ret);
636 Debug.Assert(dataHandle != IntPtr.Zero, "Data handle is invalid!");
638 ret = Native.GetAllocatedBufferSize(_handle, out var size);
639 MultimediaDebug.AssertNoError(ret);
641 Debug.Assert(size >= 0, "size must not be negative!");
643 return new DependentMediaBuffer(this, dataHandle, size);
647 /// Creates an object of the MediaPacket with the specified <see cref="MediaFormat"/>.
649 /// <param name="format">The media format for the new packet.</param>
650 /// <returns>A new MediaPacket object.</returns>
651 /// <since_tizen> 3 </since_tizen>
652 public static MediaPacket Create(MediaFormat format)
654 return new SimpleMediaPacket(format);
657 internal static MediaPacket From(IntPtr handle)
659 return new SimpleMediaPacket(handle);
662 bool IBufferOwner.IsDisposed => IsDisposed;
664 bool IBufferOwner.IsBufferAccessible(object buffer, MediaBufferAccessMode accessMode) => true;
667 internal class SimpleMediaPacket : MediaPacket
669 internal SimpleMediaPacket(MediaFormat format) : base(format)
673 internal SimpleMediaPacket(IntPtr handle) : base(handle)