/// <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; }
/// <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; }
/// <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; }
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(); } }
/// <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); }
/// <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; } }
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; }