// ------------------------------------------------ // Copyright Joe Marshall 2024- All Rights Reserved // ------------------------------------------------ // // An implementation of IMediaSamples for the new // v2 video timing in Unreal media player. // // With new timing, whilst in theory IMediaSamples // is a queue, in use only the most recent sample // is ever read. // // Given we know that, this class dumps any // previous samples immediately, which allows // the underlying hardware image to be released as // soon as possible, which makes video decoding // work more efficiently. // ------------------------------------------------ #pragma once #include "IMediaSamples.h" #include "AndroidVulkanTextureSample.h" #include "UnrealLogging.h" // for v2 video timing, the sample queue just // holds a single image class FVideoMediaSampleHolder : public IMediaSamples { public: void AddVideo(TSharedRef &InSample) { if (VideoSample.IsValid()) { // force sample texture clear because // we're not going to display it VideoSample->Clear(); UE_LOGFMT(LogDirectVideo, VeryVerbose, "Clearing videoframe {0}", VideoSample.GetSharedReferenceCount()); } UE_LOGFMT(LogDirectVideo, VeryVerbose, "CSet video frame {0}", VideoSample.IsValid()); VideoSample = InSample; } virtual bool FetchVideo(TRange TimeRange, TSharedPtr &OutSample) { UE_LOGFMT(LogDirectVideo, VeryVerbose, "BFetch video frame {0}", VideoSample.IsValid()); if (VideoSample.IsValid()) { OutSample = VideoSample; VideoSample.Reset(); return true; } return false; // override in child classes, if supported } virtual bool FetchVideo(TRange TimeRange, TSharedPtr &OutSample) { UE_LOGFMT(LogDirectVideo, VeryVerbose, "AFetch video frame {0}", VideoSample.IsValid()); if (VideoSample.IsValid()) { OutSample = VideoSample; VideoSample.Reset(); return true; } return false; // override in child classes, if supported } virtual void FlushSamples() { UE_LOGFMT(LogDirectVideo, VeryVerbose, "Flush samples {0}", VideoSample.IsValid()); // override in child classes, if supported VideoSample.Reset(); } virtual bool PeekVideoSampleTime(FMediaTimeStamp &TimeStamp) override { if (VideoSample.IsValid()) { TimeStamp = VideoSample->GetTime(); UE_LOGFMT(LogDirectVideo, VeryVerbose, "Peek timestamp {0}", TimeStamp.Time.GetTotalSeconds()); return true; } else { UE_LOGFMT(LogDirectVideo, VeryVerbose, "Peek timestamp False"); } return false; } virtual int32 NumVideoSamples() const { UE_LOGFMT(LogDirectVideo, VeryVerbose, "Query num samples {0}", VideoSample.IsValid()); if (VideoSample.IsValid()) { return 1; } else { return 0; } } bool DiscardVideoSamples(const TRange &TimeRange, bool bReverse) { UE_LOGFMT(LogDirectVideo, VeryVerbose, "Discard video samples {0}", VideoSample.IsValid()); return false; } virtual uint32 PurgeOutdatedVideoSamples(const FMediaTimeStamp &ReferenceTime, bool bReversed, FTimespan MaxAge) { UE_LOGFMT(LogDirectVideo, VeryVerbose, "PurgeOutdatedVideoSamples {0} {1}", VideoSample.IsValid(), ReferenceTime.Time.GetTicks() * 100); return 0; }; TSharedPtr VideoSample; };