public List <FrameField> GetVideoFrameFields(List <int> fieldNumbers) { var result = new List <FrameField>(); fieldNumbers = (from f in fieldNumbers orderby f select f).ToList(); foreach (var frameNumber in fieldNumbers) { if ((frameNumber < 0) || (frameNumber >= TotalFields)) { result.Add(null); continue; } SeekToField(frameNumber, SeekModes.Accurate); if (_pendingFrame != null) { FrameField frame = _pendingFrame.Fields[_pendingFrame.CurrentIndex]; //frame.Image.Save(@"D:\temp\image-" + frame.FrameNumber.ToString("00000") + ".png", System.Drawing.Imaging.ImageFormat.Png); result.Add(frame); } else { result.Add(null); } _pendingFrame.CurrentIndex++; if (_pendingFrame.CurrentIndex >= _pendingFrame.Fields.Length) { _pendingFrame = ReadVideoFrame(); } } return(result); }
private void SeekToPTS(long pts, SeekModes seekMode) { if (seekMode == SeekModes.PreviousKeyFrame) { SeekToPTS(pts, true); } else if (seekMode == SeekModes.NextKeyFrame) { SeekToPTS(pts, false); while (!_pendingFrame.IsKeyFrame) { var previousFrame = _pendingFrame; _pendingFrame = ReadVideoFrame(); if (_pendingFrame == null) { _pendingFrame = previousFrame; return; } DisposeFrame(ref previousFrame); } } else { SeekToPTS(pts, false); } }
private static void DisposeFrame(ref PendingFrame frame) { if (frame != null) { frame.Dispose(); frame = null; } }
public FrameField GetVideoFrameField(int fieldNumber, SeekModes seekMode = SeekModes.Accurate) { FrameField frame = null; SeekToField(fieldNumber, seekMode); if (_pendingFrame != null) { frame = _pendingFrame.Fields[_pendingFrame.CurrentIndex]; //frame.Image.Save(@"D:\temp\image-" + frame.FrameNumber.ToString("00000") + ".png", System.Drawing.Imaging.ImageFormat.Png); } _pendingFrame.CurrentIndex++; if (_pendingFrame.CurrentIndex >= _pendingFrame.Fields.Length) { _pendingFrame = ReadVideoFrame(); } return(frame); }
private PendingFrame ProcessFrame() { _frameOrig = (FFmpeg.AVFrame)Marshal.PtrToStructure(_pFrameOrig, typeof(FFmpeg.AVFrame)); IntPtr pStream = Marshal.ReadIntPtr(_formatContext.streams, _videoStreamIndex * 4); var stream = (FFmpeg.AVStream)Marshal.PtrToStructure(pStream, typeof(FFmpeg.AVStream)); _videoCodecContext = (FFmpeg.AVCodecContext)Marshal.PtrToStructure(stream.codec, typeof(FFmpeg.AVCodecContext)); if (_videoFrameFirstDTS == null) { _videoFrameFirstDTS = _frameOrig.pkt_dts; } if (_videoFieldDTSDuration == null) { _videoFieldDTSDuration = _frameOrig.pkt_duration / _videoCodecContext.ticks_per_frame; } var fieldList = new List <FrameField>(); //---------- Start YUV Image ---------- if (OutputYData || OutputYImage) { _scalerY.ProcessImage(_pFrameOrig, _frameOrig); } //---------- End YUV Image ---------- //---------- Start RGB Image ---------- if (OutputRGBImage && !OutputYImage) { _scalerRGB.ProcessImage(_pFrameOrig, _frameOrig); } //---------- End RGB Image ---------- for (int fieldIndex = 0; fieldIndex < _videoCodecContext.ticks_per_frame; fieldIndex++) { var field = new FrameField(); if (OutputYData || OutputYImage) { field.YData = _scalerY.GetYData(fieldIndex); if (OutputYImage) { field.Image = _scalerY.GetImage(fieldIndex); //field.Image.Save(@"D:\temp\image.png", System.Drawing.Imaging.ImageFormat.Png); } } if (OutputRGBImage && !OutputYImage) { field.Image = _scalerRGB.GetImage(fieldIndex); //field.Image.Save(@"D:\temp\image.png", System.Drawing.Imaging.ImageFormat.Png); } field.PTS = (_frameOrig.pkt_dts - _videoFrameFirstDTS.Value) + (fieldIndex * _videoFieldDTSDuration.Value); field.Seconds = field.PTS * _videoCodecContext.pkt_timebase.num / (double)_videoCodecContext.pkt_timebase.den; field.FieldIndex = fieldIndex; field.FieldNumber = (int)(field.PTS / _videoFieldDTSDuration.Value); field.FrameNumber = (int)(field.FieldNumber / _videoCodecContext.ticks_per_frame); field.FilePosition = _frameOrig.pkt_pos; field.AVFrame = _frameOrig; fieldList.Add(field); } var frame = new PendingFrame(); frame.Fields = fieldList.ToArray(); return(frame); }
private void SeekToPTS(long pts, bool stopAtKeyframe, bool forceSeek = false) { if (forceSeek == false) { if ((_pendingFrame != null) && (_pendingFrame.Fields != null)) { for (int fieldIndex = 0; fieldIndex < _pendingFrame.Fields.Length; fieldIndex++) { var field = _pendingFrame.Fields[fieldIndex]; if ((field.PTS == pts)) { _pendingFrame.CurrentIndex = fieldIndex; return; } } } } long seekPTS = pts; if (seekPTS < long.MaxValue) { seekPTS = seekPTS / PTSPerField / _videoCodecContext.ticks_per_frame * _videoCodecContext.ticks_per_frame * PTSPerField; if (long.MaxValue - seekPTS > _videoFrameFirstDTS.Value) { seekPTS += _videoFrameFirstDTS.Value; } } var originalPendingFrame = _pendingFrame; long lastSeekFilePosition = -1L; while (true) { if (seekPTS < 0) { seekPTS = 0; } int ret = FFmpeg.avformat_seek_file(_pFormatContext, _videoStreamIndex, 0, seekPTS, seekPTS, FFmpeg.AVSEEK_FLAG.AVSEEK_FLAG_NONE); if (ret < 0) { throw new Exception("Failed to seek to first frame: " + ret.ToString()); } FFmpeg.avcodec_flush_buffers(_pVideoCodecContext); var pb = (FFmpeg.ByteIOContext)Marshal.PtrToStructure(_formatContext.pb, typeof(FFmpeg.ByteIOContext)); if (lastSeekFilePosition != -1L) { if ((lastSeekFilePosition == pb.pos) && (seekPTS != 0)) { seekPTS -= (PTSPerField * _videoCodecContext.ticks_per_frame); continue; } } lastSeekFilePosition = pb.pos; if (_pendingFrame != originalPendingFrame) { DisposeFrame(ref _pendingFrame); } _pendingFrame = ReadVideoFrame(); if (_pendingFrame != null) { if (_pendingFrame.Fields.First().PTS == pts) { return; } if (_pendingFrame.Fields.First().PTS > pts) { if (seekPTS == 0) { return; } seekPTS -= PTSPerField * _videoCodecContext.ticks_per_frame; continue; } while (true) { if (stopAtKeyframe && _pendingFrame.IsKeyFrame) { _pendingFrame.CurrentIndex = 0; return; } for (int fieldIndex = 0; fieldIndex < _pendingFrame.Fields.Length; fieldIndex++) { var field = _pendingFrame.Fields[fieldIndex]; if (field.PTS >= pts) { _pendingFrame.CurrentIndex = fieldIndex; return; } } var previousFrame = _pendingFrame; _pendingFrame = ReadVideoFrame(); if (_pendingFrame == null) { _pendingFrame = previousFrame; _pendingFrame.CurrentIndex = _pendingFrame.Fields.Length - 1; return; } if (previousFrame != originalPendingFrame) { DisposeFrame(ref previousFrame); } } } } }