/// <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) { m_Pointer = (AVSubtitle *)InternalPointer; // Extract timing information (pts for Subtitles is always in AV_TIME_BASE units) var timeOffset = TimeSpan.FromTicks(frame->pts.ToTimeSpan(ffmpeg.AV_TIME_BASE).Ticks - component.Container.MediaStartTimeOffset.Ticks); StartTime = TimeSpan.FromTicks(timeOffset.Ticks + ((long)frame->start_display_time).ToTimeSpan(StreamTimeBase).Ticks); EndTime = TimeSpan.FromTicks(timeOffset.Ticks + ((long)frame->end_display_time).ToTimeSpan(StreamTimeBase).Ticks); Duration = TimeSpan.FromTicks(EndTime.Ticks - StartTime.Ticks); // Extract text strings for (var i = 0; i < frame->num_rects; i++) { var rect = frame->rects[i]; if (rect->text != null) { Text.Add(Utils.PtrToStringUTF8(rect->text)); } } // Immediately release the frame as the struct was created in managed memory // Accessing it later will eventually caused a memory access error. Release(); }
/// <summary> /// Initializes a new instance of the <see cref="VideoFrame" /> class. /// </summary> /// <param name="frame">The frame.</param> /// <param name="component">The component.</param> internal VideoFrame(AVFrame *frame, MediaComponent component) : base(frame, component) { m_Pointer = (AVFrame *)InternalPointer; // for vide frames, we always get the best effort timestamp as dts and pts might // contain different times. frame->pts = ffmpeg.av_frame_get_best_effort_timestamp(frame); StartTime = frame->pts == Constants.AV_NOPTS ? TimeSpan.FromTicks(component.Container.MediaStartTimeOffset.Ticks) : TimeSpan.FromTicks(frame->pts.ToTimeSpan(StreamTimeBase).Ticks - component.Container.MediaStartTimeOffset.Ticks); var repeatFactor = 1d + (0.5d * frame->repeat_pict); var timeBase = ffmpeg.av_guess_frame_rate(component.Container.InputContext, component.Stream, frame); Duration = repeatFactor.ToTimeSpan(new AVRational { num = timeBase.den, den = timeBase.num }); EndTime = TimeSpan.FromTicks(StartTime.Ticks + Duration.Ticks); }
/// <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) { m_Pointer = (AVFrame *)InternalPointer; // Compute the timespans //frame->pts = ffmpeg.av_frame_get_best_effort_timestamp(frame); StartTime = frame->pts == Constants.AV_NOPTS ? TimeSpan.FromTicks(component.Container.MediaStartTimeOffset.Ticks) : TimeSpan.FromTicks(frame->pts.ToTimeSpan(StreamTimeBase).Ticks - component.Container.MediaStartTimeOffset.Ticks); // Compute the audio frame duration if (frame->pkt_duration != 0) { Duration = frame->pkt_duration.ToTimeSpan(StreamTimeBase); } else { Duration = TimeSpan.FromTicks((long)Math.Round(TimeSpan.TicksPerMillisecond * 1000d * frame->nb_samples / frame->sample_rate, 0)); } EndTime = TimeSpan.FromTicks(StartTime.Ticks + Duration.Ticks); }
/// <summary> /// Initializes a new instance of the <see cref="MediaFrame" /> class. /// </summary> /// <param name="pointer">The pointer.</param> /// <param name="component">The component.</param> internal MediaFrame(void *pointer, MediaComponent component) { InternalPointer = pointer; StreamTimeBase = component.Stream->time_base; }