/* * 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.Collections.Generic; using System.Diagnostics; using System.Linq; using static Interop; namespace Tizen.Multimedia { /// /// Provides the ability to push packets as the source of . /// /// The source must be set as a source to a player before pushing. /// /// 3 public sealed class MediaStreamSource : MediaSource { private readonly MediaFormat _audioMediaFormat; private readonly MediaFormat _videoMediaFormat; private static List _supportedAudioFormats; private static List _supportedVideoFormats; /// /// Gets all supported audio types. /// /// 3 public static IEnumerable SupportedAudioTypes { get { GetSupportedTypes(); return _supportedAudioFormats.AsReadOnly(); } } /// /// Gets all supported video types. /// /// 3 public static IEnumerable SupportedVideoTypes { get { GetSupportedTypes(); return _supportedVideoFormats.AsReadOnly(); } } private static void GetSupportedTypes() { if (_supportedAudioFormats == null && _supportedVideoFormats == null) { PlayerHandle _playerHandle; IntPtr _handle; NativePlayer.Create(out _playerHandle).ThrowIfFailed(null, "Failed to create player"); _handle = _playerHandle.DangerousGetHandle(); Debug.Assert(_handle != IntPtr.Zero); try { _supportedAudioFormats = new List(); _supportedVideoFormats = new List(); NativePlayer.SupportedMediaFormatCallback callback = (int format, IntPtr userData) => { if (Enum.IsDefined(typeof(MediaFormatAudioMimeType), format)) { Log.Debug(PlayerLog.Tag, "supported audio : " + ((MediaFormatAudioMimeType)format).ToString()); _supportedAudioFormats.Add((MediaFormatAudioMimeType)format); } else if (Enum.IsDefined(typeof(MediaFormatVideoMimeType), format)) { Log.Debug(PlayerLog.Tag, "supported video : " + ((MediaFormatVideoMimeType)format).ToString()); _supportedVideoFormats.Add((MediaFormatVideoMimeType)format); } else { Log.Debug(PlayerLog.Tag, "skipped : " + format.ToString()); } return true; }; NativePlayer.SupportedMediaStreamFormat(_handle, callback, IntPtr.Zero). ThrowIfFailed(null, "Failed to get the list"); } finally { _playerHandle.Dispose(); } } } private Player _player; private MediaStreamConfiguration CreateAudioConfiguration(AudioMediaFormat format) { if (format == null) { return null; } if (!SupportedAudioTypes.Contains(format.MimeType)) { Log.Error(PlayerLog.Tag, "The audio format is not supported : " + format.MimeType); throw new ArgumentException($"The audio format is not supported, Type : {format.MimeType}."); } return new MediaStreamConfiguration(this, StreamType.Audio); } private MediaStreamConfiguration CreateVideoConfiguration(VideoMediaFormat format) { if (format == null) { return null; } if (!SupportedVideoTypes.Contains(format.MimeType)) { Log.Error(PlayerLog.Tag, "The video format is not supported : " + format.MimeType); throw new ArgumentException($"The video format is not supported, Type : {format.MimeType}."); } return new MediaStreamConfiguration(this, StreamType.Video); } /// /// Initializes a new instance of the MediaStreamSource class /// with the specified and . /// /// The for this source. /// The for this source. /// AAC and H.264 are supported. /// Both and are null. /// /// is not supported.
/// -or-
/// is not supported. ///
/// /// /// 3 public MediaStreamSource(AudioMediaFormat audioMediaFormat, VideoMediaFormat videoMediaFormat) { if (audioMediaFormat == null && videoMediaFormat == null) { throw new ArgumentNullException(string.Concat(nameof(_audioMediaFormat), " and ", nameof(_videoMediaFormat))); } _audioMediaFormat = audioMediaFormat; _videoMediaFormat = videoMediaFormat; AudioConfiguration = CreateAudioConfiguration(audioMediaFormat); VideoConfiguration = CreateVideoConfiguration(videoMediaFormat); } /// /// Initializes a new instance of the MediaStreamSource class with the specified . /// /// The for this source. /// AAC is supported. /// is null. /// is not supported. /// /// 3 public MediaStreamSource(AudioMediaFormat audioMediaFormat) { _audioMediaFormat = audioMediaFormat ?? throw new ArgumentNullException(nameof(audioMediaFormat)); AudioConfiguration = CreateAudioConfiguration(audioMediaFormat); } /// /// Initializes a new instance of the MediaStreamSource class with the specified . /// /// H.264 is supported. /// The for this source. /// is null. /// is not supported. /// /// 3 public MediaStreamSource(VideoMediaFormat videoMediaFormat) { _videoMediaFormat = videoMediaFormat ?? throw new ArgumentNullException(nameof(videoMediaFormat)); VideoConfiguration = CreateVideoConfiguration(videoMediaFormat); } /// /// Gets the audio configuration, or null if no AudioMediaFormat is specified in the constructor. /// /// 3 public MediaStreamConfiguration AudioConfiguration { get; } /// /// Gets the video configuration, or null if no VideoMediaFormat is specified in the constructor. /// /// 3 public MediaStreamConfiguration VideoConfiguration { get; } /// /// Pushes elementary stream to decode audio or video. /// /// This source must be set as a source to a player and the player must be in the , /// , or state. /// The to decode. /// /// This source is not set as a source to a player.
/// -or-
/// The player is not in the valid state. ///
/// is null. /// has been disposed of. /// /// is neither video nor audio type.
/// -or-
/// The format of packet is not matched with the specified format in the constructor. ///
/// The internal buffer has reached its limits. /// /// /// /// 3 public void Push(MediaPacket packet) { if (_player == null) { Log.Error(PlayerLog.Tag, "The source is not set as a source to a player yet."); throw new InvalidOperationException("The source is not set as a source to a player yet."); } if (packet == null) { Log.Error(PlayerLog.Tag, "packet is null"); throw new ArgumentNullException(nameof(packet)); } if (packet.IsDisposed) { Log.Error(PlayerLog.Tag, "packet is disposed"); throw new ObjectDisposedException(nameof(packet)); } if (packet.Format.Type == MediaFormatType.Text || packet.Format.Type == MediaFormatType.Container) { Log.Error(PlayerLog.Tag, "The format of the packet is invalid : " + packet.Format.Type); throw new ArgumentException($"The format of the packet is invalid : { packet.Format.Type }."); } if (!packet.Format.Equals(_audioMediaFormat) && !packet.Format.Equals(_videoMediaFormat)) { Log.Error(PlayerLog.Tag, "The format of the packet is invalid : Unmatched format."); throw new ArgumentException($"The format of the packet is invalid : Unmatched format."); } if (packet.Format.Type == MediaFormatType.Video && _videoMediaFormat == null) { Log.Error(PlayerLog.Tag, "Video is not configured with the current source."); throw new ArgumentException("Video is not configured with the current source."); } if (packet.Format.Type == MediaFormatType.Audio && _audioMediaFormat == null) { Log.Error(PlayerLog.Tag, "Audio is not configured with the current source."); throw new ArgumentException("Audio is not configured with the current source."); } _player.ValidatePlayerState(PlayerState.Paused, PlayerState.Playing, PlayerState.Ready); NativePlayer.PushMediaStream(_player.Handle, packet.GetHandle()). ThrowIfFailed(_player, "Failed to push the packet to the player"); } private void SetMediaStreamInfo(StreamType streamType, MediaFormat mediaFormat) { if (mediaFormat == null) { Log.Warn(PlayerLog.Tag, "invalid media format"); return; } IntPtr ptr = IntPtr.Zero; try { ptr = mediaFormat.AsNativeHandle(); NativePlayer.SetMediaStreamInfo(_player.Handle, streamType, ptr). ThrowIfFailed(_player, "Failed to set the media stream info"); } finally { MediaFormat.ReleaseNativeHandle(ptr); } } internal override void OnAttached(Player player) { Debug.Assert(player != null); if (_player != null) { Log.Error(PlayerLog.Tag, "The source is has already been assigned to another player."); throw new InvalidOperationException("The source is has already been assigned to another player."); } AudioConfiguration?.OnPlayerSet(player); VideoConfiguration?.OnPlayerSet(player); _player = player; SetMediaStreamInfo(StreamType.Audio, _audioMediaFormat); SetMediaStreamInfo(StreamType.Video, _videoMediaFormat); } internal override void OnDetached(Player player) { base.OnDetached(player); AudioConfiguration?.OnPlayerUnset(player); VideoConfiguration?.OnPlayerUnset(player); _player = null; } /// /// Gets the that this source is assigned to as a source, or null if this source is not assigned. /// /// /// 3 public Player Player => _player; } }