diff --git a/src/core/videosource.cpp b/src/core/videosource.cpp index 0ca0183..664830e 100644 --- a/src/core/videosource.cpp +++ b/src/core/videosource.cpp @@ -204,10 +204,11 @@ FFMS_VideoSource::FFMS_VideoSource(const char *SourceFile, FFMS_Index &Index, in DecodeFrame = av_frame_alloc(); LastDecodedFrame = av_frame_alloc(); + StashedPacket = av_packet_alloc(); - if (!DecodeFrame || !LastDecodedFrame) + if (!DecodeFrame || !LastDecodedFrame || !StashedPacket) throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_ALLOCATION_FAILED, - "Could not allocate dummy frame."); + "Could not allocate dummy frame/packet."); // Dummy allocations so the unallocated case doesn't have to be handled later if (av_image_alloc(SWSFrameData, SWSFrameLinesize, 16, 16, AV_PIX_FMT_GRAY8, 4) < 0) @@ -243,10 +244,20 @@ FFMS_VideoSource::FFMS_VideoSource(const char *SourceFile, FFMS_Index &Index, in // vc1 simply sets has_b_frames to 1 no matter how many there are so instead we set it to the max value // in order to not confuse our own delay guesses later // Doesn't affect actual vc1 reordering unlike h264 - if (CodecContext->codec_id == AV_CODEC_ID_VC1 && CodecContext->has_b_frames) + if (CodecContext->codec_id == AV_CODEC_ID_VC1 && CodecContext->has_b_frames) { Delay = 7 + (CodecContext->thread_count - 1); // the maximum possible value for vc1 - else + } else if (CodecContext->codec_id == AV_CODEC_ID_AV1) { + int64_t AV1Delay; + int optRet = av_opt_get_int(CodecContext, "max_frame_delay", AV_OPT_SEARCH_CHILDREN, &AV1Delay); + if (optRet < 0) { + throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC, + "Could not get AV1 Delay"); + } + printf("GOT AV1 DELAY: %ld\n", AV1Delay); + Delay = AV1Delay; + } else { Delay = CodecContext->has_b_frames + (CodecContext->thread_count - 1); // Normal decoder delay + } // Always try to decode a frame to make sure all required parameters are known int64_t DummyPTS = 0, DummyPos = 0; @@ -635,12 +646,19 @@ bool FFMS_VideoSource::HasPendingDelayedFrames() { bool FFMS_VideoSource::DecodePacket(AVPacket *Packet) { std::swap(DecodeFrame, LastDecodedFrame); - avcodec_send_packet(CodecContext, Packet); + ResendPacket = false; + int Ret = avcodec_send_packet(CodecContext, Packet); + if (Ret == AVERROR(EAGAIN)) { + DelayCounter--; + ResendPacket = true; + } else if (Ret < 0) { + printf("ohno\n"); + } - int Ret = avcodec_receive_frame(CodecContext, DecodeFrame); + Ret = avcodec_receive_frame(CodecContext, DecodeFrame); if (Ret != 0) { std::swap(DecodeFrame, LastDecodedFrame); - if (!(Packet->flags & AV_PKT_FLAG_DISCARD)) + if (!(Packet->flags & AV_PKT_FLAG_DISCARD) || Ret == AVERROR(EAGAIN)) DelayCounter++; } else { if (!!(Packet->flags & AV_PKT_FLAG_DISCARD)) { @@ -733,6 +751,7 @@ void FFMS_VideoSource::Free() { av_freep(&SWSFrameData[0]); av_frame_free(&DecodeFrame); av_frame_free(&LastDecodedFrame); + av_packet_free(&StashedPacket); } void FFMS_VideoSource::DecodeNextFrame(int64_t &AStartTime, int64_t &Pos) { @@ -747,7 +766,14 @@ void FFMS_VideoSource::DecodeNextFrame(int64_t &AStartTime, int64_t &Pos) { "Could not allocate packet."); int ret; - while ((ret = ReadFrame(Packet)) >= 0) { + if (ResendPacket) { + ret = 0; + av_packet_ref(Packet, StashedPacket); + av_packet_unref(StashedPacket); + } else { + ret = ReadFrame(Packet); + } + while (ret >= 0) { if (Packet->stream_index != VideoTrack) { av_packet_unref(Packet); continue; @@ -760,11 +786,21 @@ void FFMS_VideoSource::DecodeNextFrame(int64_t &AStartTime, int64_t &Pos) { Pos = Packet->pos; bool FrameFinished = DecodePacket(Packet); + if (ResendPacket) + av_packet_ref(StashedPacket, Packet); av_packet_unref(Packet); if (FrameFinished) { av_packet_free(&Packet); return; } + + if (ResendPacket) { + ret = 0; + av_packet_ref(Packet, StashedPacket); + av_packet_unref(StashedPacket); + } else { + ret = ReadFrame(Packet); + } } if (IsIOError(ret)) { char err[1024]; diff --git a/src/core/videosource.h b/src/core/videosource.h index 760532e..e81240a 100644 --- a/src/core/videosource.h +++ b/src/core/videosource.h @@ -77,6 +77,9 @@ private: uint8_t *SWSFrameData[4] = {}; int SWSFrameLinesize[4] = {}; + AVPacket *StashedPacket = nullptr; + bool ResendPacket = false; + void DetectInputFormat(); bool HasPendingDelayedFrames();