| 801 | } |
| 802 | |
| 803 | bool FFMS_VideoSource::SeekTo(int n, int SeekOffset) { |
| 804 | bool ForceSeek = false; |
| 805 | if (Stage == DecodeStage::INITIALIZE_SOURCE) { |
| 806 | ForceSeek = true; |
| 807 | Stage = DecodeStage::INITIALIZE; |
| 808 | } |
| 809 | |
| 810 | // The semantics here are basically "return true if we don't know exactly where our seek ended up (destination isn't frame 0)" |
| 811 | if (SeekMode >= 0) { |
| 812 | int TargetFrame = n + SeekOffset; |
| 813 | if (TargetFrame < 0) |
| 814 | throw FFMS_Exception(FFMS_ERROR_SEEKING, FFMS_ERROR_UNKNOWN, |
| 815 | "Frame accurate seeking is not possible in this file"); |
| 816 | |
| 817 | // Seeking too close to the end of the stream can result in a different decoder delay since |
| 818 | // frames are returned as soon as draining starts, so avoid this to keep the delay predictable. |
| 819 | // Is the +1 necessary here? Not sure, but let's keep it to be safe. |
| 820 | int EndOfStreamDist = CodecContext->has_b_frames + 1; |
| 821 | |
| 822 | if (CodecContext->codec_id == AV_CODEC_ID_H264) |
| 823 | // Work around a bug in ffmpeg's h264 decoder where frames are skipped when seeking too |
| 824 | // close to the end in open-gop files: https://trac.ffmpeg.org/ticket/10936 |
| 825 | EndOfStreamDist *= 2; |
| 826 | |
| 827 | TargetFrame = std::min(TargetFrame, Frames.RealFrameNumber(std::max(0, VP.NumFrames - 1 - EndOfStreamDist))); |
| 828 | |
| 829 | if (SeekMode < 3) |
| 830 | TargetFrame = Frames.FindClosestVideoKeyFrame(TargetFrame); |
| 831 | |
| 832 | if (SeekMode == 0) { |
| 833 | if (n < CurrentFrame) { |
| 834 | Seek(Frames[0].OriginalPos); |
| 835 | } |
| 836 | } else { |
| 837 | // 10 frames is used as a margin to prevent excessive seeking since the predicted best keyframe isn't always selected by avformat |
| 838 | if (ForceSeek || n < CurrentFrame || TargetFrame > CurrentFrame + 10 || (SeekMode == 3 && n > CurrentFrame + 10)) { |
| 839 | Seek(TargetFrame); |
| 840 | return true; |
| 841 | } |
| 842 | } |
| 843 | } else if (n < CurrentFrame) { |
| 844 | throw FFMS_Exception(FFMS_ERROR_SEEKING, FFMS_ERROR_INVALID_ARGUMENT, |
| 845 | "Non-linear access attempted"); |
| 846 | } |
| 847 | return false; |
| 848 | } |
| 849 | |
| 850 | FFMS_Frame *FFMS_VideoSource::GetFrame(int n) { |
| 851 | GetFrameCheck(n); |
nothing calls this directly
no test coverage detected