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);
85 /// Finalizes an instance of the MediaPacket class.
93 /// Creates and initializes a native handle for the current object.
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)
99 if (format.Type == MediaFormatType.Container)
101 throw new ArgumentException("Creating a packet for container is not supported.");
104 IntPtr formatHandle = IntPtr.Zero;
108 formatHandle = format.AsNativeHandle();
110 int ret = Interop.MediaPacket.Create(formatHandle, IntPtr.Zero, IntPtr.Zero, out _handle);
111 MultimediaDebug.AssertNoError(ret);
113 Debug.Assert(_handle != IntPtr.Zero, "Created handle must not be null");
119 if (_handle != IntPtr.Zero)
121 Interop.MediaPacket.Destroy(_handle);
122 _handle = IntPtr.Zero;
129 if (formatHandle != IntPtr.Zero)
131 Interop.MediaFormat.Unref(formatHandle);
137 /// Allocates internal buffer.
139 /// <exception cref="InvalidOperationException">Operation failed.</exception>
142 ErrorCode ret = (ErrorCode)Interop.MediaPacket.Alloc(_handle);
143 if (ret == ErrorCode.None)
148 _handle = IntPtr.Zero;
152 case ErrorCode.OutOfMemory:
153 throw new OutOfMemoryException("Failed to allocate buffer for the packet.");
156 throw new InvalidOperationException("Failed to create a packet.");
161 private readonly MediaFormat _format;
164 /// Gets the media format of the current packet.
166 public MediaFormat Format
170 ValidateNotDisposed();
176 /// Gets or sets the PTS(Presentation Time Stamp) value of the current packet.
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.
186 ValidateNotDisposed();
189 int ret = Interop.MediaPacket.GetPts(_handle, out value);
191 MultimediaDebug.AssertNoError(ret);
197 ValidateNotDisposed();
200 int ret = Interop.MediaPacket.SetPts(_handle, value);
202 MultimediaDebug.AssertNoError(ret);
207 /// Gets or sets the DTS(Decoding Time Stamp) value of the current packet.
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.
217 ValidateNotDisposed();
220 int ret = Interop.MediaPacket.GetDts(_handle, out value);
222 MultimediaDebug.AssertNoError(ret);
228 ValidateNotDisposed();
231 int ret = Interop.MediaPacket.SetDts(_handle, value);
233 MultimediaDebug.AssertNoError(ret);
238 /// Gets a value indicating whether the packet is the encoded type.
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
246 ValidateNotDisposed();
249 int ret = Interop.MediaPacket.IsEncoded(_handle, out value);
251 MultimediaDebug.AssertNoError(ret);
257 private Lazy<IMediaBuffer> _buffer;
260 /// Gets the buffer of the packet.
263 /// The <see cref="IMediaBuffer"/> allocated to the packet.
264 /// This property will return null if the packet is in the raw video format.
266 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
267 /// <seealso cref="IsEncoded"/>
268 /// <seealso cref="VideoPlanes"/>
269 public IMediaBuffer Buffer
273 ValidateNotDisposed();
275 if (IsVideoPlaneSupported)
280 return _buffer.Value;
285 /// Gets or sets a length of data written in the <see cref="Buffer"/>.
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"/>.<br/>
293 /// The MediaPacket is not in the writable state, which means it is being used by another module.
295 public int BufferWrittenLength
299 ValidateNotDisposed();
302 int ret = Interop.MediaPacket.GetBufferSize(_handle, out value);
303 MultimediaDebug.AssertNoError(ret);
305 Debug.Assert(value < int.MaxValue);
311 ValidateNotDisposed();
314 if (IsVideoPlaneSupported)
316 throw new InvalidOperationException(
317 "This packet uses VideoPlanes instead of Buffer.");
320 Debug.Assert(Buffer != null);
322 if (value < 0 || value >= Buffer.Length)
324 throw new ArgumentOutOfRangeException("value must be less than Buffer.Size.");
327 int ret = Interop.MediaPacket.SetBufferSize(_handle, (ulong)value);
328 MultimediaDebug.AssertNoError(ret);
332 private MediaPacketVideoPlane[] _videoPlanes;
335 /// Gets the video planes of the packet.
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
346 ValidateNotDisposed();
348 if (!IsVideoPlaneSupported)
353 if (_videoPlanes == null)
355 _videoPlanes = GetVideoPlanes();
363 /// Gets or sets the buffer flags of the packet.
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.
369 public MediaPacketBufferFlags BufferFlags
373 ValidateNotDisposed();
375 int ret = Interop.MediaPacket.GetBufferFlags(_handle, out var value);
377 MultimediaDebug.AssertNoError(ret);
384 ValidateNotDisposed();
387 int ret = Interop.MediaPacket.ResetBufferFlags(_handle);
389 MultimediaDebug.AssertNoError(ret);
391 ret = Interop.MediaPacket.SetBufferFlags(_handle, (int)value);
393 MultimediaDebug.AssertNoError(ret);
398 /// Gets a value indicating whether the packet has been disposed of.
400 /// <value>true if the packet has been disposed of; otherwise, false.</value>
401 public bool IsDisposed => _isDisposed;
403 private bool _isDisposed = false;
407 /// Releases all resources used by the <see cref="MediaPacket"/> object.
409 /// <exception cref="InvalidOperationException">
410 /// The MediaPacket can not be disposed, which means it is being used by another module.
412 public void Dispose()
421 GC.SuppressFinalize(this);
425 /// Releases the resources used by the <see cref="MediaPacket"/> object.
427 /// <param name="disposing">
428 /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
430 protected virtual void Dispose(bool disposing)
437 if (_handle != IntPtr.Zero)
439 Interop.MediaPacket.Destroy(_handle);
440 _handle = IntPtr.Zero;
446 internal IntPtr GetHandle()
448 ValidateNotDisposed();
450 Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!");
456 /// Validates the current object has not been disposed of.
458 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
459 private void ValidateNotDisposed()
463 throw new ObjectDisposedException("This packet has already been disposed of.");
468 /// Ensures whether the packet is writable.
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()
474 ValidateNotDisposed();
479 /// Ensures whether the packet is readable.
481 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
482 internal void EnsureReadableState()
484 ValidateNotDisposed();
488 /// Gets a value indicating whether the packet is in the raw video format.
490 /// <value>true if the packet is in the raw video format; otherwise, false.</value>
491 private bool IsVideoPlaneSupported
495 return !IsEncoded && Format.Type == MediaFormatType.Video;
500 /// Retrieves video planes of the current packet.
502 /// <returns>The <see cref="MediaPacketVideoPlane"/>s allocated to the current MediaPacket.</returns>
503 private MediaPacketVideoPlane[] GetVideoPlanes()
505 Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!");
507 uint numberOfPlanes = 0;
508 int ret = Interop.MediaPacket.GetNumberOfVideoPlanes(_handle, out numberOfPlanes);
510 MultimediaDebug.AssertNoError(ret);
512 MediaPacketVideoPlane[] planes = new MediaPacketVideoPlane[numberOfPlanes];
514 for (int i = 0; i < numberOfPlanes; ++i)
516 planes[i] = new MediaPacketVideoPlane(this, i);
523 /// Retrieves the buffer of the current packet.
525 /// <returns>The <see cref="IMediaBuffer"/> allocated to the current MediaPacket.</returns>
526 private IMediaBuffer GetBuffer()
528 Debug.Assert(!IsDisposed, "Packet is already disposed!");
530 Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!");
534 int ret = Interop.MediaPacket.GetBufferData(_handle, out dataHandle);
535 MultimediaDebug.AssertNoError(ret);
537 Debug.Assert(dataHandle != IntPtr.Zero, "Data handle is invalid!");
540 ret = Interop.MediaPacket.GetAllocatedBufferSize(_handle, out size);
541 MultimediaDebug.AssertNoError(ret);
543 Debug.Assert(size >= 0, "size must not be negative!");
545 return new DependentMediaBuffer(this, dataHandle, size);
549 /// Creates an object of the MediaPacket with the specified <see cref="MediaFormat"/>.
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)
555 return new SimpleMediaPacket(format);
558 internal static MediaPacket From(IntPtr handle)
560 return new SimpleMediaPacket(handle);
563 bool IBufferOwner.IsDisposed => IsDisposed;
565 bool IBufferOwner.IsBufferAccessible(object buffer, MediaBufferAccessMode accessMode) => true;
568 internal class SimpleMediaPacket : MediaPacket
570 internal SimpleMediaPacket(MediaFormat format) : base(format)
574 internal SimpleMediaPacket(IntPtr handle) : base(handle)