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 /// <since_tizen> 3 </since_tizen>
167 public MediaFormat Format
171 ValidateNotDisposed();
177 /// Gets or sets the PTS(Presentation Time Stamp) value of the current packet.
179 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
180 /// <exception cref="InvalidOperationException">
181 /// The MediaPacket is not in the writable state, which means it is being used by another module.
183 /// <since_tizen> 3 </since_tizen>
188 ValidateNotDisposed();
191 int ret = Interop.MediaPacket.GetPts(_handle, out value);
193 MultimediaDebug.AssertNoError(ret);
199 ValidateNotDisposed();
202 int ret = Interop.MediaPacket.SetPts(_handle, value);
204 MultimediaDebug.AssertNoError(ret);
209 /// Gets or sets the DTS(Decoding Time Stamp) value of the current packet.
211 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
212 /// <exception cref="InvalidOperationException">
213 /// The MediaPacket is not in the writable state, which means it is being used by another module.
215 /// <since_tizen> 3 </since_tizen>
220 ValidateNotDisposed();
223 int ret = Interop.MediaPacket.GetDts(_handle, out value);
225 MultimediaDebug.AssertNoError(ret);
231 ValidateNotDisposed();
234 int ret = Interop.MediaPacket.SetDts(_handle, value);
236 MultimediaDebug.AssertNoError(ret);
241 /// Gets a value indicating whether the packet is the encoded type.
243 /// <value>true if the packet is the encoded type; otherwise, false.</value>
244 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
245 /// <since_tizen> 3 </since_tizen>
246 public bool IsEncoded
250 ValidateNotDisposed();
253 int ret = Interop.MediaPacket.IsEncoded(_handle, out value);
255 MultimediaDebug.AssertNoError(ret);
261 private Lazy<IMediaBuffer> _buffer;
264 /// Gets the buffer of the packet.
267 /// The <see cref="IMediaBuffer"/> allocated to the packet.
268 /// This property will return null if the packet is in the raw video format.
270 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
271 /// <seealso cref="IsEncoded"/>
272 /// <seealso cref="VideoPlanes"/>
273 /// <since_tizen> 3 </since_tizen>
274 public IMediaBuffer Buffer
278 ValidateNotDisposed();
280 if (IsVideoPlaneSupported)
285 return _buffer.Value;
290 /// Gets or sets a length of data written in the <see cref="Buffer"/>.
292 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
293 /// <exception cref="ArgumentOutOfRangeException">
294 /// The value specified for this property is less than zero or greater than the length of the <see cref="Buffer"/>.</exception>
295 /// <exception cref="InvalidOperationException">
296 /// The MediaPacket has <see cref="VideoPlanes"/> instead of <see cref="Buffer"/>.<br/>
298 /// The MediaPacket is not in the writable state, which means it is being used by another module.
300 /// <since_tizen> 3 </since_tizen>
301 public int BufferWrittenLength
305 ValidateNotDisposed();
308 int ret = Interop.MediaPacket.GetBufferSize(_handle, out value);
309 MultimediaDebug.AssertNoError(ret);
311 Debug.Assert(value < int.MaxValue);
317 ValidateNotDisposed();
320 if (IsVideoPlaneSupported)
322 throw new InvalidOperationException(
323 "This packet uses VideoPlanes instead of Buffer.");
326 Debug.Assert(Buffer != null);
328 if (value < 0 || value >= Buffer.Length)
330 throw new ArgumentOutOfRangeException("value must be less than Buffer.Size.");
333 int ret = Interop.MediaPacket.SetBufferSize(_handle, (ulong)value);
334 MultimediaDebug.AssertNoError(ret);
338 private MediaPacketVideoPlane[] _videoPlanes;
341 /// Gets the video planes of the packet.
343 /// <value>The <see cref="MediaPacketVideoPlane"/>s allocated to the packet.
344 /// This property will return null if the packet is not in the raw video format.</value>
345 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
346 /// <seealso cref="IsEncoded"/>
347 /// <seealso cref="Buffer"/>
348 /// <since_tizen> 3 </since_tizen>
349 public MediaPacketVideoPlane[] VideoPlanes
353 ValidateNotDisposed();
355 if (!IsVideoPlaneSupported)
360 if (_videoPlanes == null)
362 _videoPlanes = GetVideoPlanes();
370 /// Gets or sets the buffer flags of the packet.
372 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
373 /// <exception cref="InvalidOperationException">
374 /// The MediaPacket is not in the writable state, which means it is being used by another module.
376 /// <since_tizen> 3 </since_tizen>
377 public MediaPacketBufferFlags BufferFlags
381 ValidateNotDisposed();
383 int ret = Interop.MediaPacket.GetBufferFlags(_handle, out var value);
385 MultimediaDebug.AssertNoError(ret);
392 ValidateNotDisposed();
395 int ret = Interop.MediaPacket.ResetBufferFlags(_handle);
397 MultimediaDebug.AssertNoError(ret);
399 ret = Interop.MediaPacket.SetBufferFlags(_handle, (int)value);
401 MultimediaDebug.AssertNoError(ret);
406 /// Gets a value indicating whether the packet has been disposed of.
408 /// <value>true if the packet has been disposed of; otherwise, false.</value>
409 /// <since_tizen> 3 </since_tizen>
410 public bool IsDisposed => _isDisposed;
412 private bool _isDisposed = false;
416 /// Releases all resources used by the <see cref="MediaPacket"/> object.
418 /// <exception cref="InvalidOperationException">
419 /// The MediaPacket can not be disposed, which means it is being used by another module.
421 /// <since_tizen> 3 </since_tizen>
422 public void Dispose()
431 GC.SuppressFinalize(this);
435 /// Releases the resources used by the <see cref="MediaPacket"/> object.
437 /// <param name="disposing">
438 /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
440 /// <since_tizen> 3 </since_tizen>
441 protected virtual void Dispose(bool disposing)
448 if (_handle != IntPtr.Zero)
450 Interop.MediaPacket.Destroy(_handle);
451 _handle = IntPtr.Zero;
457 internal IntPtr GetHandle()
459 ValidateNotDisposed();
461 Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!");
467 /// Validates the current object has not been disposed of.
469 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
470 private void ValidateNotDisposed()
474 throw new ObjectDisposedException("This packet has already been disposed of.");
479 /// Ensures whether the packet is writable.
481 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
482 /// <exception cref="InvalidOperationException">The MediaPacket is being used by another module.</exception>
483 internal void EnsureWritableState()
485 ValidateNotDisposed();
490 /// Ensures whether the packet is readable.
492 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
493 internal void EnsureReadableState()
495 ValidateNotDisposed();
499 /// Gets a value indicating whether the packet is in the raw video format.
501 /// <value>true if the packet is in the raw video format; otherwise, false.</value>
502 private bool IsVideoPlaneSupported
506 return !IsEncoded && Format.Type == MediaFormatType.Video;
511 /// Retrieves video planes of the current packet.
513 /// <returns>The <see cref="MediaPacketVideoPlane"/>s allocated to the current MediaPacket.</returns>
514 private MediaPacketVideoPlane[] GetVideoPlanes()
516 Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!");
518 uint numberOfPlanes = 0;
519 int ret = Interop.MediaPacket.GetNumberOfVideoPlanes(_handle, out numberOfPlanes);
521 MultimediaDebug.AssertNoError(ret);
523 MediaPacketVideoPlane[] planes = new MediaPacketVideoPlane[numberOfPlanes];
525 for (int i = 0; i < numberOfPlanes; ++i)
527 planes[i] = new MediaPacketVideoPlane(this, i);
534 /// Retrieves the buffer of the current packet.
536 /// <returns>The <see cref="IMediaBuffer"/> allocated to the current MediaPacket.</returns>
537 private IMediaBuffer GetBuffer()
539 Debug.Assert(!IsDisposed, "Packet is already disposed!");
541 Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!");
545 int ret = Interop.MediaPacket.GetBufferData(_handle, out dataHandle);
546 MultimediaDebug.AssertNoError(ret);
548 Debug.Assert(dataHandle != IntPtr.Zero, "Data handle is invalid!");
551 ret = Interop.MediaPacket.GetAllocatedBufferSize(_handle, out size);
552 MultimediaDebug.AssertNoError(ret);
554 Debug.Assert(size >= 0, "size must not be negative!");
556 return new DependentMediaBuffer(this, dataHandle, size);
560 /// Creates an object of the MediaPacket with the specified <see cref="MediaFormat"/>.
562 /// <param name="format">The media format for the new packet.</param>
563 /// <returns>A new MediaPacket object.</returns>
564 /// <since_tizen> 3 </since_tizen>
565 public static MediaPacket Create(MediaFormat format)
567 return new SimpleMediaPacket(format);
570 internal static MediaPacket From(IntPtr handle)
572 return new SimpleMediaPacket(handle);
575 bool IBufferOwner.IsDisposed => IsDisposed;
577 bool IBufferOwner.IsBufferAccessible(object buffer, MediaBufferAccessMode accessMode) => true;
580 internal class SimpleMediaPacket : MediaPacket
582 internal SimpleMediaPacket(MediaFormat format) : base(format)
586 internal SimpleMediaPacket(IntPtr handle) : base(handle)