コード例 #1
0
        /// <summary>
        /// Removes the component of specified media type (if registered).
        /// It calls the dispose method of the media component too.
        /// </summary>
        /// <param name="mediaType">Type of the media.</param>
        internal void RemoveComponent(MediaType mediaType)
        {
            lock (ComponentSyncLock)
            {
                var component = default(MediaComponent);
                switch (mediaType)
                {
                case MediaType.Audio:
                    component = m_Audio;
                    m_Audio   = null;
                    break;

                case MediaType.Video:
                    component = m_Video;
                    m_Video   = null;
                    break;

                case MediaType.Subtitle:
                    component  = m_Subtitle;
                    m_Subtitle = null;
                    break;

                default:
                    break;
                }

                component?.Dispose();
                UpdateComponentBackingFields();
            }
        }
コード例 #2
0
        /// <summary>
        /// Removes the component of specified media type (if registered).
        /// It calls the dispose method of the media component too.
        /// </summary>
        /// <param name="mediaType">Type of the media.</param>
        internal void RemoveComponent(MediaType mediaType)
        {
            lock (ComponentSyncLock)
            {
                var component = default(MediaComponent);
                if (mediaType == MediaType.Audio)
                {
                    component = m_Audio;
                    m_Audio   = null;
                }
                else if (mediaType == MediaType.Video)
                {
                    component = m_Video;
                    m_Video   = null;
                }
                else if (mediaType == MediaType.Subtitle)
                {
                    component  = m_Subtitle;
                    m_Subtitle = null;
                }

                component?.Dispose();
                UpdateComponentBackingFields();
            }
        }
コード例 #3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="VideoFrame" /> class.
        /// </summary>
        /// <param name="frame">The frame.</param>
        /// <param name="component">The video component.</param>
        internal VideoFrame(AVFrame *frame, VideoComponent component)
            : base(frame, component, MediaType.Video)
        {
            var timeBase     = ffmpeg.av_guess_frame_rate(component.Container.InputContext, component.Stream, frame);
            var mainOffset   = component.Container.Components.Main.StartTime;
            var repeatFactor = 1d + (0.5d * frame->repeat_pict);

            Duration = frame->pkt_duration <= 0 ?
                       repeatFactor.ToTimeSpan(new AVRational {
                num = timeBase.den, den = timeBase.num
            }) :
                       frame->pkt_duration.ToTimeSpan(component.Stream->time_base);

            // for video frames, we always get the best effort timestamp as dts and pts might
            // contain different times.
            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 - mainOffset.Ticks);

            EndTime = TimeSpan.FromTicks(StartTime.Ticks + Duration.Ticks);

            // Picture Type, Number and SMTPE TimeCode
            PictureType          = frame->pict_type;
            DisplayPictureNumber = frame->display_picture_number == 0 ?
                                   Extensions.ComputePictureNumber(StartTime, Duration, 1) :
                                   frame->display_picture_number;

            CodedPictureNumber      = frame->coded_picture_number;
            SmtpeTimeCode           = Extensions.ComputeSmtpeTimeCode(component.StartTime, Duration, timeBase, DisplayPictureNumber);
            IsHardwareFrame         = component.IsUsingHardwareDecoding;
            HardwareAcceleratorName = component.HardwareAccelerator?.Name;

            // Process side data such as CC packets
            for (var i = 0; i < frame->nb_side_data; i++)
            {
                var sideData = frame->side_data[i];

                // Get the Closed-Caption packets
                if (sideData->type != AVFrameSideDataType.AV_FRAME_DATA_A53_CC)
                {
                    continue;
                }

                // Parse 3 bytes at a time
                for (var p = 0; p < sideData->size; p += 3)
                {
                    var packet = new ClosedCaptionPacket(TimeSpan.FromTicks(StartTime.Ticks + p), sideData->data, p);
                    if (packet.PacketType == CaptionsPacketType.NullPad || packet.PacketType == CaptionsPacketType.Unrecognized)
                    {
                        continue;
                    }

                    // at this point, we have valid CC data
                    ClosedCaptions.Add(packet);
                }
            }
        }
コード例 #4
0
 /// <summary>
 /// Initializes a new instance of the <see cref="HardwareAccelerator"/> class.
 /// </summary>
 /// <param name="component">The component this accelerator is attached to.</param>
 /// <param name="selectedConfig">The selected hardware device configuration.</param>
 public HardwareAccelerator(VideoComponent component, HardwareDeviceInfo selectedConfig)
 {
     Component         = component;
     Name              = selectedConfig.DeviceTypeName;
     DeviceType        = selectedConfig.DeviceType;
     PixelFormat       = selectedConfig.PixelFormat;
     GetFormatCallback = new AVCodecContext_get_format(GetPixelFormat);
 }
コード例 #5
0
 /// <summary>
 /// Initializes a new instance of the <see cref="HardwareAccelerator"/> class.
 /// </summary>
 /// <param name="component">The component this accelerator is attached to.</param>
 /// <param name="selectedConfig">The selected hardware device configuration.</param>
 public HardwareAccelerator(VideoComponent component, HardwareDeviceInfo selectedConfig)
 {
     Component         = component;
     Name              = selectedConfig.DeviceTypeName;
     DeviceType        = selectedConfig.DeviceType;
     PixelFormat       = selectedConfig.PixelFormat;
     GetFormatCallback = GetPixelFormat;
 }
コード例 #6
0
        /// <summary>
        /// Registers the component in this component set.
        /// </summary>
        /// <param name="component">The component.</param>
        /// <exception cref="ArgumentNullException">When component of the same type is already registered</exception>
        /// <exception cref="NotSupportedException">When MediaType is not supported</exception>
        /// <exception cref="ArgumentException">When the component is null</exception>
        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();
            }
        }
コード例 #7
0
        /// <summary>
        /// Attaches a hardware device context to the specified video component.
        /// </summary>
        /// <param name="component">The component.</param>
        /// <exception cref="Exception">Throws when unable to initialize the hardware device</exception>
        public void AttachDevice(VideoComponent component)
        {
            var result = 0;

            fixed(AVBufferRef **devContextRef = &component.HardwareDeviceContext)
            {
                result = ffmpeg.av_hwdevice_ctx_create(devContextRef, DeviceType, null, null, 0);
                if (result < 0)
                {
                    throw new Exception($"Unable to initialize hardware context for device {Name}");
                }
            }

            component.HardwareAccelerator         = this;
            component.CodecContext->hw_device_ctx = ffmpeg.av_buffer_ref(component.HardwareDeviceContext);
            component.CodecContext->get_format    = GetFormatCallback;
        }
コード例 #8
0
        /// <summary>
        /// Detaches and disposes the hardware device context from the specified video component
        /// </summary>
        /// <param name="component">The component.</param>
        public void DetachDevice(VideoComponent component)
        {
            // TODO: (Floyd) Check the below code in the future because I am not sure
            // how to uninitialize the hardware device context
            if (component.CodecContext != null)
            {
                ffmpeg.av_buffer_unref(&component.CodecContext->hw_device_ctx);
                component.CodecContext->hw_device_ctx = null;
            }

            if (component.HardwareDeviceContext != null)
            {
                fixed(AVBufferRef **hwdc = &component.HardwareDeviceContext)
                {
                    ffmpeg.av_buffer_unref(hwdc);
                    component.HardwareDeviceContext = null;
                    component.HardwareAccelerator   = null;
                }
            }
        }
コード例 #9
0
        /// <summary>
        /// Attaches a hardware accelerator to the specified component.
        /// </summary>
        /// <param name="component">The component.</param>
        /// <param name="selectedConfig">The selected configuration.</param>
        /// <returns>
        /// Whether or not the hardware accelerator was attached
        /// </returns>
        public static bool Attach(VideoComponent component, HardwareDeviceInfo selectedConfig)
        {
            try
            {
                var result = new HardwareAccelerator
                {
                    Component   = component,
                    Name        = selectedConfig.DeviceTypeName,
                    DeviceType  = selectedConfig.DeviceType,
                    PixelFormat = selectedConfig.PixelFormat,
                };

                result.InitializeHardwareContext();
                return(true);
            }
            catch (Exception ex)
            {
                component.Container.Parent?.Log(MediaLogMessageType.Error, $"Could not attach hardware decoder. {ex.Message}");
                return(false);
            }
        }