/* * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Diagnostics; using Tizen.Internals.Errors; using Native = Tizen.Multimedia.Interop.MediaPacket; using NativeFormat = Tizen.Multimedia.Interop.MediaFormat; namespace Tizen.Multimedia { /// /// Represents a packet for multimedia. /// public abstract partial class MediaPacket : IBufferOwner, IDisposable { private IntPtr _handle = IntPtr.Zero; /// /// Initializes a new instance of the MediaPacket class with the specified media format. /// /// The media format containing properties for the packet. /// is null. /// /// The of the specified format is . /// /// Operation failed. internal MediaPacket(MediaFormat format) { if (format == null) { throw new ArgumentNullException(nameof(format)); } Initialize(format); _format = format; _buffer = new Lazy(GetBuffer); } /// /// Initializes a new instance of the MediaPacket class from a native handle. /// /// The native handle to be used. internal MediaPacket(IntPtr handle) { _handle = handle; int ret = Native.GetFormat(handle, out IntPtr formatHandle); MultimediaDebug.AssertNoError(ret); try { if (formatHandle != IntPtr.Zero) { _format = MediaFormat.FromHandle(formatHandle); } } finally { NativeFormat.Unref(formatHandle); } } /// /// Finalizes an instance of the MediaPacket class. /// ~MediaPacket() { Dispose(false); } /// /// Creates and initializes a native handle for the current object. /// /// The format to be set to the media format. /// Operation failed. private void Initialize(MediaFormat format) { if (format.Type == MediaFormatType.Container) { throw new ArgumentException("Container format can't be used to create a new packet.", nameof(format)); } IntPtr formatHandle = IntPtr.Zero; try { formatHandle = format.AsNativeHandle(); int ret = Native.Create(formatHandle, IntPtr.Zero, IntPtr.Zero, out _handle); MultimediaDebug.AssertNoError(ret); Debug.Assert(_handle != IntPtr.Zero, "Created handle must not be null"); Alloc(); } catch (Exception) { if (_handle != IntPtr.Zero) { Native.Destroy(_handle); _handle = IntPtr.Zero; } throw; } finally { if (formatHandle != IntPtr.Zero) { NativeFormat.Unref(formatHandle); } } } /// /// Allocates internal buffer. /// /// Operation failed. private void Alloc() { ErrorCode ret = (ErrorCode)Native.Alloc(_handle); if (ret == ErrorCode.None) { return; } _handle = IntPtr.Zero; switch (ret) { case ErrorCode.OutOfMemory: throw new OutOfMemoryException("Failed to allocate buffer for the packet."); default: throw new InvalidOperationException("Failed to create a packet."); } } private readonly MediaFormat _format; /// /// Gets the media format of the current packet. /// /// 3 public MediaFormat Format { get { ValidateNotDisposed(); return _format; } } /// /// Gets or sets the PTS(Presentation Time Stamp) value of the current packet. /// /// The MediaPacket has already been disposed of. /// /// The MediaPacket is not in the writable state, which means it is being used by another module. /// /// 3 public ulong Pts { get { ValidateNotDisposed(); int ret = Native.GetPts(_handle, out var value); MultimediaDebug.AssertNoError(ret); return value; } set { ValidateNotDisposed(); ValidateNotLocked(); int ret = Native.SetPts(_handle, value); MultimediaDebug.AssertNoError(ret); } } /// /// Gets or sets the DTS(Decoding Time Stamp) value of the current packet. /// /// The MediaPacket has already been disposed of. /// /// The MediaPacket is not in the writable state, which means it is being used by another module. /// /// 3 public ulong Dts { get { ValidateNotDisposed(); int ret = Native.GetDts(_handle, out var value); MultimediaDebug.AssertNoError(ret); return value; } set { ValidateNotDisposed(); ValidateNotLocked(); int ret = Native.SetDts(_handle, value); MultimediaDebug.AssertNoError(ret); } } /// /// Gets or sets the duration value of the current packet. /// /// The MediaPacket has already been disposed of. /// /// The MediaPacket is not in the writable state, which means it is being used by another module. /// /// 6 public ulong Duration { get { ValidateNotDisposed(); int ret = Native.GetDuration(_handle, out var value); MultimediaDebug.AssertNoError(ret); return value; } set { ValidateNotDisposed(); ValidateNotLocked(); int ret = Native.SetDuration(_handle, value); MultimediaDebug.AssertNoError(ret); } } /// /// Gets a value indicating whether the packet is the encoded type. /// /// true if the packet is the encoded type; otherwise, false. /// The MediaPacket has already been disposed of. /// 3 public bool IsEncoded { get { ValidateNotDisposed(); int ret = Native.IsEncoded(_handle, out var value); MultimediaDebug.AssertNoError(ret); return value; } } /// /// Gets or sets the rotation value of the current packet. /// /// The specified value to set is invalid. /// The MediaPacket has already been disposed of. /// /// The MediaPacket is not in the writable state, which means it is being used by another module. /// /// 5 public Rotation Rotation { get { ValidateNotDisposed(); int ret = Native.GetRotation(_handle, out var value); MultimediaDebug.AssertNoError(ret); var rotation = value < RotationFlip.HorizontalFlip ? (Rotation)value : Rotation.Rotate0; return rotation; } set { ValidateNotDisposed(); ValidateNotLocked(); ValidationUtil.ValidateEnum(typeof(Rotation), value, nameof(value)); int ret = Native.SetRotation(_handle, (RotationFlip)value); MultimediaDebug.AssertNoError(ret); } } /// /// Gets or sets the flip value of the current packet. /// /// /// will be ignored in set case. It's not supported in Native FW. /// /// The specified value to set is invalid. /// The MediaPacket has already been disposed of. /// /// The MediaPacket is not in the writable state, which means it is being used by another module. /// /// 5 public Flips Flip { get { ValidateNotDisposed(); int ret = Native.GetRotation(_handle, out var value); MultimediaDebug.AssertNoError(ret); var flip = (value < RotationFlip.HorizontalFlip) ? Flips.None : (value == RotationFlip.HorizontalFlip ? Flips.Horizontal : Flips.Vertical); return flip; } set { ValidateNotDisposed(); ValidateNotLocked(); ValidationUtil.ValidateEnum(typeof(Flips), value, nameof(value)); if (value == Flips.None) { return; } var flip = value == Flips.Horizontal ? RotationFlip.HorizontalFlip : RotationFlip.VerticalFlip; int ret = Native.SetRotation(_handle, flip); MultimediaDebug.AssertNoError(ret); } } private Lazy _buffer; /// /// Gets the buffer of the packet. /// /// /// The allocated to the packet. /// This property will return null if the packet is in the raw video format. /// /// The MediaPacket has already been disposed of. /// /// /// 3 public IMediaBuffer Buffer { get { ValidateNotDisposed(); if (IsVideoPlaneSupported) { return null; } return _buffer.Value; } } /// /// Gets or sets a length of data written in the . /// /// The MediaPacket has already been disposed of. /// /// The value specified for this property is less than zero or greater than the length of the . /// /// The MediaPacket has instead of .
/// -or-
/// The MediaPacket is not in the writable state, which means it is being used by another module. ///
/// 3 public int BufferWrittenLength { get { ValidateNotDisposed(); int ret = Native.GetBufferSize(_handle, out var value); MultimediaDebug.AssertNoError(ret); Debug.Assert(value < int.MaxValue); return (int)value; } set { ValidateNotDisposed(); ValidateNotLocked(); if (IsVideoPlaneSupported) { throw new InvalidOperationException( "This packet uses VideoPlanes instead of Buffer."); } Debug.Assert(Buffer != null); if (value < 0 || value >= Buffer.Length) { throw new ArgumentOutOfRangeException(nameof(value), value, "value must be less than Buffer.Size."); } int ret = Native.SetBufferSize(_handle, (ulong)value); MultimediaDebug.AssertNoError(ret); } } private MediaPacketVideoPlane[] _videoPlanes; /// /// Gets the video planes of the packet. /// /// The s allocated to the packet. /// This property will return null if the packet is not in the raw video format. /// The MediaPacket has already been disposed of. /// /// /// 3 public MediaPacketVideoPlane[] VideoPlanes { get { ValidateNotDisposed(); if (!IsVideoPlaneSupported) { return null; } if (_videoPlanes == null) { _videoPlanes = GetVideoPlanes(); } return _videoPlanes; } } /// /// Gets or sets the buffer flags of the packet. /// /// The MediaPacket has already been disposed of. /// /// The MediaPacket is not in the writable state, which means it is being used by another module. /// /// 3 public MediaPacketBufferFlags BufferFlags { get { ValidateNotDisposed(); int ret = Native.GetBufferFlags(_handle, out var value); MultimediaDebug.AssertNoError(ret); return value; } set { ValidateNotDisposed(); ValidateNotLocked(); int ret = Native.ResetBufferFlags(_handle); MultimediaDebug.AssertNoError(ret); ret = Native.SetBufferFlags(_handle, (int)value); MultimediaDebug.AssertNoError(ret); } } #region Dispose support /// /// Gets a value indicating whether the packet has been disposed of. /// /// true if the packet has been disposed of; otherwise, false. /// 3 public bool IsDisposed => _isDisposed; private bool _isDisposed = false; /// /// Releases all resources used by the object. /// /// /// The MediaPacket can not be disposed, which means it is being used by another module. /// /// 3 public void Dispose() { if (_isDisposed) { return; } ValidateNotLocked(); Dispose(true); GC.SuppressFinalize(this); } /// /// Releases the resources used by the object. /// /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. /// /// 3 protected virtual void Dispose(bool disposing) { if (_isDisposed) { return; } if (_handle != IntPtr.Zero) { Native.Destroy(_handle); _handle = IntPtr.Zero; } _isDisposed = true; } /// /// Validates the current object has not been disposed of. /// /// The MediaPacket has already been disposed of. private void ValidateNotDisposed() { if (_isDisposed) { throw new ObjectDisposedException("This packet has already been disposed of."); } } #endregion internal IntPtr GetHandle() { ValidateNotDisposed(); Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!"); return _handle; } /// /// Ensures whether the packet is writable. /// /// The MediaPacket has already been disposed of. /// The MediaPacket is being used by another module. internal void EnsureWritableState() { ValidateNotDisposed(); ValidateNotLocked(); } /// /// Ensures whether the packet is readable. /// /// The MediaPacket has already been disposed of. internal void EnsureReadableState() { ValidateNotDisposed(); } /// /// Gets a value indicating whether the packet is in the raw video format. /// /// true if the packet is in the raw video format; otherwise, false. private bool IsVideoPlaneSupported => !IsEncoded && Format.Type == MediaFormatType.Video; /// /// Retrieves video planes of the current packet. /// /// The s allocated to the current MediaPacket. private MediaPacketVideoPlane[] GetVideoPlanes() { Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!"); int ret = Native.GetNumberOfVideoPlanes(_handle, out var numberOfPlanes); MultimediaDebug.AssertNoError(ret); MediaPacketVideoPlane[] planes = new MediaPacketVideoPlane[numberOfPlanes]; for (int i = 0; i < numberOfPlanes; ++i) { planes[i] = new MediaPacketVideoPlane(this, i); } return planes; } /// /// Retrieves the buffer of the current packet. /// /// The allocated to the current MediaPacket. private IMediaBuffer GetBuffer() { Debug.Assert(!IsDisposed, "Packet is already disposed!"); Debug.Assert(_handle != IntPtr.Zero, "The handle is invalid!"); int ret = Native.GetBufferData(_handle, out var dataHandle); MultimediaDebug.AssertNoError(ret); Debug.Assert(dataHandle != IntPtr.Zero, "Data handle is invalid!"); ret = Native.GetAllocatedBufferSize(_handle, out var size); MultimediaDebug.AssertNoError(ret); Debug.Assert(size >= 0, "size must not be negative!"); return new DependentMediaBuffer(this, dataHandle, size); } /// /// Creates an object of the MediaPacket with the specified . /// /// The media format for the new packet. /// A new MediaPacket object. /// 3 public static MediaPacket Create(MediaFormat format) { return new SimpleMediaPacket(format); } internal static MediaPacket From(IntPtr handle) { return new SimpleMediaPacket(handle); } bool IBufferOwner.IsDisposed => IsDisposed; bool IBufferOwner.IsBufferAccessible(object buffer, MediaBufferAccessMode accessMode) => true; } internal class SimpleMediaPacket : MediaPacket { internal SimpleMediaPacket(MediaFormat format) : base(format) { } internal SimpleMediaPacket(IntPtr handle) : base(handle) { } } }