/* * 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. /// public sealed class MediaStreamSource : MediaSource { private readonly MediaFormat _audioMediaFormat; private readonly MediaFormat _videoMediaFormat; /// /// Gets all supported audio types. /// public static IEnumerable SupportedAudioTypes { get { yield return MediaFormatAudioMimeType.Aac; } } /// /// Gets all supported video types. /// public static IEnumerable SupportedVideoTypes { get { yield return MediaFormatVideoMimeType.H264SP; } } 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. ///
/// /// public MediaStreamSource(AudioMediaFormat audioMediaFormat, VideoMediaFormat videoMediaFormat) { if (audioMediaFormat == null && videoMediaFormat == null) { throw new ArgumentNullException(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. /// public MediaStreamSource(AudioMediaFormat audioMediaFormat) { if (audioMediaFormat == null) { throw new ArgumentNullException(nameof(audioMediaFormat)); } _audioMediaFormat = 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. /// public MediaStreamSource(VideoMediaFormat videoMediaFormat) { if (videoMediaFormat == null) { throw new ArgumentNullException(nameof(videoMediaFormat)); } _videoMediaFormat = videoMediaFormat; VideoConfiguration = CreateVideoConfiguration(videoMediaFormat); } /// /// Gets the audio configuration, or null if no AudioMediaFormat is specified in the constructor. /// public MediaStreamConfiguration AudioConfiguration { get; } /// /// Gets the video configuration, or null if no VideoMediaFormat is specified in the constructor. /// 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. /// /// /// 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("Failed to push the packet to the player"); } private void SetMediaStreamInfo(StreamType streamType, MediaFormat mediaFormat) { if (mediaFormat == null) { Log.Error(PlayerLog.Tag, "invalid media format"); return; } IntPtr ptr = IntPtr.Zero; try { ptr = mediaFormat.AsNativeHandle(); NativePlayer.SetMediaStreamInfo(_player.Handle, (int)streamType, ptr). ThrowIfFailed("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. /// /// public Player Player => _player; } }