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 System.Runtime.InteropServices;
20 using System.Threading;
21 using Tizen.Internals.Errors;
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));
48 if (format.Type == MediaFormatType.Container)
50 throw new ArgumentException("Container format can't be used to create a new packet.");
55 _buffer = new Lazy<IMediaBuffer>(GetBuffer);
59 /// Initializes a new instance of the MediaPacket class from a native handle.
61 /// <param name="handle">The native handle to be used.</param>
62 internal MediaPacket(IntPtr handle)
67 int ret = Interop.MediaPacket.GetFormat(handle, out formatHandle);
69 MultimediaDebug.AssertNoError(ret);
73 if (formatHandle != IntPtr.Zero)
75 _format = MediaFormat.FromHandle(formatHandle);
80 Interop.MediaFormat.Unref(formatHandle);
90 /// Creates and initializes a native handle for the current object.
92 /// <param name="format">The format to be set to the media format.</param>
93 /// <exception cref="InvalidOperationException">Operation failed.</exception>
94 private void Initialize(MediaFormat format)
96 if (format.Type == MediaFormatType.Container)
98 throw new ArgumentException("Creating a packet for container is not supported.");
101 IntPtr formatHandle = IntPtr.Zero;
105 formatHandle = format.AsNativeHandle();
107 int ret = Interop.MediaPacket.Create(formatHandle, IntPtr.Zero, IntPtr.Zero, out _handle);
108 MultimediaDebug.AssertNoError(ret);
110 Debug.Assert(_handle != IntPtr.Zero, "Created handle must not be null");
116 if (_handle != IntPtr.Zero)
118 Interop.MediaPacket.Destroy(_handle);
119 _handle = IntPtr.Zero;
126 if (formatHandle != IntPtr.Zero)
128 Interop.MediaFormat.Unref(formatHandle);
134 /// Allocates internal buffer.
136 /// <exception cref="InvalidOperationException">Operation failed.</exception>
139 ErrorCode ret = (ErrorCode)Interop.MediaPacket.Alloc(_handle);
140 if (ret == ErrorCode.None)
145 _handle = IntPtr.Zero;
149 case ErrorCode.OutOfMemory:
150 throw new OutOfMemoryException("Failed to allocate buffer for the packet.");
153 throw new InvalidOperationException("Failed to create a packet.");
158 private readonly MediaFormat _format;
161 /// Gets the media format of the current packet.
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.
183 ValidateNotDisposed();
186 int ret = Interop.MediaPacket.GetPts(_handle, out value);
188 MultimediaDebug.AssertNoError(ret);
194 ValidateNotDisposed();
197 int ret = Interop.MediaPacket.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.
214 ValidateNotDisposed();
217 int ret = Interop.MediaPacket.GetDts(_handle, out value);
219 MultimediaDebug.AssertNoError(ret);
225 ValidateNotDisposed();
228 int ret = Interop.MediaPacket.SetDts(_handle, value);
230 MultimediaDebug.AssertNoError(ret);
235 /// Gets a value indicating whether the packet is the encoded type.
237 /// <value>true if the packet is the encoded type; otherwise, false.</value>
238 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
239 public bool IsEncoded
243 ValidateNotDisposed();
246 int ret = Interop.MediaPacket.IsEncoded(_handle, out value);
248 MultimediaDebug.AssertNoError(ret);
254 private Lazy<IMediaBuffer> _buffer;
257 /// Gets the buffer of the packet.
260 /// The <see cref="IMediaBuffer"/> allocated to the packet.
261 /// This property will return null if the packet is in the raw video format.
263 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
264 /// <seealso cref="IsEncoded"/>
265 /// <seealso cref="VideoPlanes"/>
266 public IMediaBuffer Buffer
270 ValidateNotDisposed();
272 if (IsVideoPlaneSupported)
277 return _buffer.Value;
282 /// Gets or sets a length of data written in the <see cref="Buffer"/>.
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 the length of the <see cref="Buffer"/>.</exception>
287 /// <exception cref="InvalidOperationException">
288 /// The MediaPacket has <see cref="VideoPlanes"/> instead of <see cref="Buffer"/>.\n
290 /// The MediaPacket is not in the writable state, which means it is being used by another module.
292 public int BufferWrittenLength
296 ValidateNotDisposed();
299 int ret = Interop.MediaPacket.GetBufferSize(_handle, out value);
300 MultimediaDebug.AssertNoError(ret);
302 Debug.Assert(value < int.MaxValue);
308 ValidateNotDisposed();
311 if (IsVideoPlaneSupported)
313 throw new InvalidOperationException(
314 "This packet uses VideoPlanes instead of Buffer.");
317 Debug.Assert(Buffer != null);
319 if (value < 0 || value >= Buffer.Length)
321 throw new ArgumentOutOfRangeException("value must be less than Buffer.Size.");
324 int ret = Interop.MediaPacket.SetBufferSize(_handle, (ulong)value);
325 MultimediaDebug.AssertNoError(ret);
329 private MediaPacketVideoPlane[] _videoPlanes;
332 /// Gets the video planes of the packet.
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
343 ValidateNotDisposed();
345 if (!IsVideoPlaneSupported)
350 if (_videoPlanes == null)
352 _videoPlanes = GetVideoPlanes();
360 /// Gets or sets the buffer flags of the packet.
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.
366 public MediaPacketBufferFlags BufferFlags
370 ValidateNotDisposed();
372 int ret = Interop.MediaPacket.GetBufferFlags(_handle, out var value);
374 MultimediaDebug.AssertNoError(ret);
381 ValidateNotDisposed();
384 int ret = Interop.MediaPacket.ResetBufferFlags(_handle);
386 MultimediaDebug.AssertNoError(ret);
388 ret = Interop.MediaPacket.SetBufferFlags(_handle, (int)value);
390 MultimediaDebug.AssertNoError(ret);
395 /// Gets a value indicating whether the packet has been disposed of.
397 /// <value>true if the packet has been disposed of; otherwise, false.</value>
398 public bool IsDisposed => _isDisposed;
400 private bool _isDisposed = false;
404 /// Releases all resources used by the <see cref="MediaPacket"/> object.
406 /// <exception cref="InvalidOperationException">
407 /// The MediaPacket can not be disposed, which means it is being used by another module.
409 public void Dispose()
418 GC.SuppressFinalize(this);
422 /// Releases the resources used by the <see cref="MediaPacket"/> object.
424 /// <param name="disposing">
425 /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
427 protected virtual void Dispose(bool disposing)
434 if (_handle != IntPtr.Zero)
436 Interop.MediaPacket.Destroy(_handle);
437 _handle = IntPtr.Zero;
443 internal IntPtr GetHandle()
445 ValidateNotDisposed();
447 Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!");
453 /// Validates the current object has not been disposed of.
455 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
456 private void ValidateNotDisposed()
460 throw new ObjectDisposedException("This packet has already been disposed of.");
465 /// Ensures whether the packet is writable.
467 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
468 /// <exception cref="InvalidOperationException">The MediaPacket is being used by another module.</exception>
469 internal void EnsureWritableState()
471 ValidateNotDisposed();
476 /// Ensures whether the packet is readable.
478 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
479 internal void EnsureReadableState()
481 ValidateNotDisposed();
485 /// Gets a value indicating whether the packet is in the raw video format.
487 /// <value>true if the packet is in the raw video format; otherwise, false.</value>
488 private bool IsVideoPlaneSupported
492 return !IsEncoded && Format.Type == MediaFormatType.Video;
497 /// Retrieves video planes of the current packet.
499 /// <returns>The <see cref="MediaPacketVideoPlane"/>s allocated to the current MediaPacket.</returns>
500 private MediaPacketVideoPlane[] GetVideoPlanes()
502 Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!");
504 uint numberOfPlanes = 0;
505 int ret = Interop.MediaPacket.GetNumberOfVideoPlanes(_handle, out numberOfPlanes);
507 MultimediaDebug.AssertNoError(ret);
509 MediaPacketVideoPlane[] planes = new MediaPacketVideoPlane[numberOfPlanes];
511 for (int i = 0; i < numberOfPlanes; ++i)
513 planes[i] = new MediaPacketVideoPlane(this, i);
520 /// Retrieves the buffer of the current packet.
522 /// <returns>The <see cref="IMediaBuffer"/> allocated to the current MediaPacket.</returns>
523 private IMediaBuffer GetBuffer()
525 Debug.Assert(!IsDisposed, "Packet is already disposed!");
527 Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!");
531 int ret = Interop.MediaPacket.GetBufferData(_handle, out dataHandle);
532 MultimediaDebug.AssertNoError(ret);
534 Debug.Assert(dataHandle != IntPtr.Zero, "Data handle is invalid!");
537 ret = Interop.MediaPacket.GetAllocatedBufferSize(_handle, out size);
538 MultimediaDebug.AssertNoError(ret);
540 Debug.Assert(size >= 0, "size must not be negative!");
542 return new DependentMediaBuffer(this, dataHandle, size);
546 /// Creates an object of the MediaPacket with the specified <see cref="MediaFormat"/>.
548 /// <param name="format">The media format for the new packet.</param>
549 /// <returns>A new MediaPacket object.</returns>
550 public static MediaPacket Create(MediaFormat format)
552 return new SimpleMediaPacket(format);
555 internal static MediaPacket From(IntPtr handle)
557 return new SimpleMediaPacket(handle);
560 bool IBufferOwner.IsDisposed => IsDisposed;
562 bool IBufferOwner.IsBufferAccessible(object buffer, MediaBufferAccessMode accessMode) => true;
565 internal class SimpleMediaPacket : MediaPacket
567 internal SimpleMediaPacket(MediaFormat format) : base(format)
571 internal SimpleMediaPacket(IntPtr handle) : base(handle)