Beispiel #1
0
 /// <summary>
 /// Initializes a new instance of the <see cref="MediaFrame" /> class.
 /// </summary>
 /// <param name="pointer">The pointer.</param>
 /// <param name="component">The component.</param>
 /// <param name="mediaType">Type of the media.</param>
 private MediaFrame(void *pointer, MediaComponent component, MediaType mediaType)
 {
     InternalPointer = new IntPtr(pointer);
     StreamTimeBase  = component.Stream->time_base;
     StreamIndex     = component.StreamIndex;
     MediaType       = mediaType;
 }
Beispiel #2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="MediaFrame"/> class.
 /// </summary>
 /// <param name="pointer">The pointer.</param>
 /// <param name="component">The component.</param>
 protected MediaFrame(AVSubtitle *pointer, MediaComponent component)
     : this(pointer, component, MediaType.Subtitle)
 {
     // TODO: Compressed size is simply an estimate
     CompressedSize   = (int)pointer->num_rects * 256;
     PresentationTime = Convert.ToInt64(pointer->start_display_time);
     DecodingTime     = pointer->pts;
 }
Beispiel #3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="MediaFrame" /> class.
        /// </summary>
        /// <param name="pointer">The pointer.</param>
        /// <param name="component">The component.</param>
        /// <param name="mediaType">Type of the media.</param>
        protected MediaFrame(AVFrame *pointer, MediaComponent component, MediaType mediaType)
            : this((void *)pointer, component, mediaType)
        {
            var packetSize = pointer->pkt_size;

            CompressedSize   = packetSize > 0 ? packetSize : 0;
            PresentationTime = pointer->pts;
            DecodingTime     = pointer->pkt_dts;
        }
Beispiel #4
0
        internal void AddComponent(MediaComponent component)
        {
            lock (ComponentSyncLock)
            {
                if (component == null)
                {
                    throw new ArgumentNullException(nameof(component));
                }

                var errorMessage = $"A component for '{component.MediaType}' is already registered.";
                switch (component.MediaType)
                {
                case MediaType.Audio:
                    if (m_Audio != null)
                    {
                        throw new ArgumentException(errorMessage);
                    }

                    m_Audio = component as AudioComponent;
                    break;

                case MediaType.Video:
                    if (m_Video != null)
                    {
                        throw new ArgumentException(errorMessage);
                    }

                    m_Video = component as VideoComponent;
                    break;

                case MediaType.Subtitle:
                    if (m_Subtitle != null)
                    {
                        throw new ArgumentException(errorMessage);
                    }

                    m_Subtitle = component as SubtitleComponent;
                    break;

                default:
                    throw new NotSupportedException($"Unable to register component with {nameof(MediaType)} '{component.MediaType}'");
                }

                UpdateComponentBackingFields();
            }
        }
Beispiel #5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="AudioFrame" /> class.
        /// </summary>
        /// <param name="frame">The frame.</param>
        /// <param name="component">The component.</param>
        internal AudioFrame(AVFrame *frame, MediaComponent component)
            : base(frame, component, MediaType.Audio)
        {
            // Compute the start time.
            frame->pts        = frame->best_effort_timestamp;
            HasValidStartTime = frame->pts != ffmpeg.AV_NOPTS_VALUE;
            StartTime         = frame->pts == ffmpeg.AV_NOPTS_VALUE ?
                                TimeSpan.FromTicks(0) :
                                TimeSpan.FromTicks(frame->pts.ToTimeSpan(StreamTimeBase).Ticks);

            // Compute the audio frame duration
            Duration = frame->pkt_duration > 0 ?
                       frame->pkt_duration.ToTimeSpan(StreamTimeBase) :
                       TimeSpan.FromTicks(Convert.ToInt64(TimeSpan.TicksPerMillisecond * 1000d * frame->nb_samples / frame->sample_rate));

            // Compute the audio frame end time
            EndTime = TimeSpan.FromTicks(StartTime.Ticks + Duration.Ticks);
        }
Beispiel #6
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SubtitleFrame" /> class.
        /// </summary>
        /// <param name="frame">The frame.</param>
        /// <param name="component">The component.</param>
        internal SubtitleFrame(AVSubtitle *frame, MediaComponent component)
            : base(frame, component)
        {
            // Extract timing information (pts for Subtitles is always in AV_TIME_BASE units)
            HasValidStartTime = frame->pts != ffmpeg.AV_NOPTS_VALUE;
            var timeOffset = frame->pts.ToTimeSpan(ffmpeg.AV_TIME_BASE);

            // start_display_time and end_display_time are relative to timeOffset
            StartTime = TimeSpan.FromMilliseconds(timeOffset.TotalMilliseconds + frame->start_display_time);
            EndTime   = TimeSpan.FromMilliseconds(timeOffset.TotalMilliseconds + frame->end_display_time);
            Duration  = TimeSpan.FromMilliseconds(frame->end_display_time - frame->start_display_time);

            // Extract text strings
            TextType = AVSubtitleType.SUBTITLE_NONE;

            for (var i = 0; i < frame->num_rects; i++)
            {
                var rect = frame->rects[i];

                if (rect->type == AVSubtitleType.SUBTITLE_TEXT)
                {
                    if (rect->text == null)
                    {
                        continue;
                    }
                    Text.Add(Utilities.PtrToStringUTF8(rect->text));
                    TextType = AVSubtitleType.SUBTITLE_TEXT;
                    break;
                }

                if (rect->type == AVSubtitleType.SUBTITLE_ASS)
                {
                    if (rect->ass == null)
                    {
                        continue;
                    }
                    Text.Add(Utilities.PtrToStringUTF8(rect->ass));
                    TextType = AVSubtitleType.SUBTITLE_ASS;
                    break;
                }

                TextType = rect->type;
            }
        }
Beispiel #7
0
        private unsafe void UpdateComponentBackingFields()
        {
            var allComponents = new List <MediaComponent>(4);
            var allMediaTypes = new List <MediaType>(4);

            // assign allMediaTypes. IMPORTANT: Order matters because this
            // establishes the priority in which playback measures are computed
            if (m_Video != null)
            {
                allComponents.Add(m_Video);
                allMediaTypes.Add(MediaType.Video);
            }

            if (m_Audio != null)
            {
                allComponents.Add(m_Audio);
                allMediaTypes.Add(MediaType.Audio);
            }

            if (m_Subtitle != null)
            {
                allComponents.Add(m_Subtitle);
                allMediaTypes.Add(MediaType.Subtitle);
            }

            m_All        = allComponents;
            m_MediaTypes = allMediaTypes;
            m_Count      = allComponents.Count;

            // Find Start time, duration and end time
            UpdatePlaybackTimingProperties();

            // Try for the main component to be the video (if it's not stuff like audio album art, that is)
            if (m_Video != null && m_Audio != null && m_Video.StreamInfo.IsAttachedPictureDisposition == false)
            {
                m_Main          = m_Video;
                m_MainMediaType = MediaType.Video;
                return;
            }

            // If it was not video, then it has to be audio (if it has audio)
            if (m_Audio != null)
            {
                m_Main          = m_Audio;
                m_MainMediaType = MediaType.Audio;
                return;
            }

            // Set it to video even if it's attached pic stuff
            if (m_Video != null)
            {
                m_Main          = m_Video;
                m_MainMediaType = MediaType.Video;
                return;
            }

            // As a last resort, set the main component to be the subtitles
            if (m_Subtitle != null)
            {
                m_Main          = m_Subtitle;
                m_MainMediaType = MediaType.Subtitle;
                return;
            }

            // We should never really hit this line
            m_Main          = null;
            m_MainMediaType = MediaType.None;
        }