From 633d6e8334f8f17e15cb939194343852ba7c35b1 Mon Sep 17 00:00:00 2001 From: Fredrik Mellbin Date: Tue, 10 Dec 2024 21:36:01 +0100 Subject: [PATCH] Allow mv-hevc viewid to be passed into the source --- src/audiosource.cpp | 4 ++-- src/avisynth.cpp | 11 ++++++----- src/vapoursynth.cpp | 7 ++++--- src/videosource.cpp | 29 +++++++++++++++++++---------- src/videosource.h | 7 ++++--- 5 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/audiosource.cpp b/src/audiosource.cpp index 7ace965..07cb694 100644 --- a/src/audiosource.cpp +++ b/src/audiosource.cpp @@ -494,7 +494,7 @@ void BestAudioSource::InitializeFormatSets() { double BestAudioSource::GetRelativeStartTime(int Track) const { if (Track < 0) { try { - std::unique_ptr Dec(new LWVideoDecoder(Source, "", 0, Track, 0, LAVFOptions)); + std::unique_ptr Dec(new LWVideoDecoder(Source, "", 0, Track, 0, 0, LAVFOptions)); BSVideoProperties VP; Dec->GetVideoProperties(VP); return AP.StartTime - VP.StartTime; @@ -503,7 +503,7 @@ double BestAudioSource::GetRelativeStartTime(int Track) const { return 0; } else { try { - std::unique_ptr Dec(new LWVideoDecoder(Source, "", 0, Track, 0, LAVFOptions)); + std::unique_ptr Dec(new LWVideoDecoder(Source, "", 0, Track, 0, 0, LAVFOptions)); BSVideoProperties VP; Dec->GetVideoProperties(VP); return AP.StartTime - VP.StartTime; diff --git a/src/avisynth.cpp b/src/avisynth.cpp index 1111d31..215b21c 100644 --- a/src/avisynth.cpp +++ b/src/avisynth.cpp @@ -71,7 +71,7 @@ class AvisynthVideoSource : public IClip { int64_t FPSDen; bool RFF; public: - AvisynthVideoSource(const char *Source, int Track, + AvisynthVideoSource(const char *Source, int Track, int ViewID, int AFPSNum, int AFPSDen, bool RFF, int Threads, int SeekPreRoll, bool EnableDrefs, bool UseAbsolutePath, int CacheMode, const char *CachePath, int CacheSize, const char *HWDevice, int ExtraHWFrames, const char *Timecodes, int StartNumber, int VariableFormat, IScriptEnvironment *Env) @@ -95,7 +95,7 @@ class AvisynthVideoSource : public IClip { if (StartNumber >= 0) Opts["start_number"] = std::to_string(StartNumber); - V.reset(new BestVideoSource(CreateProbablyUTF8Path(Source), HWDevice ? HWDevice : "", ExtraHWFrames, Track, Threads, CacheMode, CachePath, &Opts)); + V.reset(new BestVideoSource(CreateProbablyUTF8Path(Source), HWDevice ? HWDevice : "", ExtraHWFrames, Track, ViewID, Threads, CacheMode, CachePath, &Opts)); V->SelectFormatSet(VariableFormat); @@ -286,8 +286,9 @@ static AVSValue __cdecl CreateBSVideoSource(AVSValue Args, void *UserData, IScri const char *Timecodes = Args[14].AsString(nullptr); int StartNumber = Args[15].AsInt(-1); int VariableFormat = Args[16].AsInt(0); + int ViewID = Args[17].AsInt(0); - return new AvisynthVideoSource(Source, Track, FPSNum, FPSDen, RFF, Threads, SeekPreroll, EnableDrefs, UseAbsolutePath, CacheMode, CachePath, CacheSize, HWDevice, ExtraHWFrames, Timecodes, StartNumber, VariableFormat, Env); + return new AvisynthVideoSource(Source, Track, ViewID, FPSNum, FPSDen, RFF, Threads, SeekPreroll, EnableDrefs, UseAbsolutePath, CacheMode, CachePath, CacheSize, HWDevice, ExtraHWFrames, Timecodes, StartNumber, VariableFormat, Env); } class AvisynthAudioSource : public IClip { @@ -430,9 +431,9 @@ static constexpr auto PopulateArgNames() { return Result; } -static constexpr char BSVideoSourceAvsArgs[] = "[source]s[track]i[fpsnum]i[fpsden]i[rff]b[threads]i[seekpreroll]i[enable_drefs]b[use_absolute_path]b[cachemode]i[cachepath]s[cachesize]i[hwdevice]s[extrahwframes]i[timecodes]s[start_number]i[variableformat]i"; +static constexpr char BSVideoSourceAvsArgs[] = "[source]s[track]i[fpsnum]i[fpsden]i[rff]b[threads]i[seekpreroll]i[enable_drefs]b[use_absolute_path]b[cachemode]i[cachepath]s[cachesize]i[hwdevice]s[extrahwframes]i[timecodes]s[start_number]i[variableformat]i[viewid]i"; static constexpr char BSAudioSourceAvsArgs[] = "[source]s[track]i[adjustdelay]i[threads]i[enable_drefs]b[use_absolute_path]b[drc_scale]f[cachemode]i[cachepath]s[cachesize]i"; -static constexpr char BSSourceAvsArgs[] = "[source]s[atrack]i[vtrack]i[fpsnum]i[fpsden]i[rff]b[threads]i[seekpreroll]i[enable_drefs]b[use_absolute_path]b[cachemode]i[cachepath]s[acachesize]i[vcachesize]i[hwdevice]s[extrahwframes]i[timecodes]s[start_number]i[variableformat]i[adjustdelay]i[drc_scale]f"; +static constexpr char BSSourceAvsArgs[] = "[source]s[atrack]i[vtrack]i[fpsnum]i[fpsden]i[rff]b[threads]i[seekpreroll]i[enable_drefs]b[use_absolute_path]b[cachemode]i[cachepath]s[acachesize]i[vcachesize]i[hwdevice]s[extrahwframes]i[timecodes]s[start_number]i[variableformat]i[adjustdelay]i[drc_scale]f[viewid]i"; static constexpr std::array BSVArgNames = PopulateArgNames(); static constexpr std::array BSAArgNames = PopulateArgNames(); diff --git a/src/vapoursynth.cpp b/src/vapoursynth.cpp index 46c5243..9a529c5 100644 --- a/src/vapoursynth.cpp +++ b/src/vapoursynth.cpp @@ -139,6 +139,7 @@ static void VS_CC CreateBestVideoSource(const VSMap *In, VSMap *Out, void *, VSC int Track = vsapi->mapGetIntSaturated(In, "track", 0, &err); if (err) Track = -1; + int ViewID = vsapi->mapGetIntSaturated(In, "viewid", 0, &err); int VariableFormat = vsapi->mapGetIntSaturated(In, "variableformat", 0, &err); if (err) VariableFormat = -1; @@ -182,7 +183,7 @@ static void VS_CC CreateBestVideoSource(const VSMap *In, VSMap *Out, void *, VSC if (ShowProgress) { auto NextUpdate = std::chrono::high_resolution_clock::now(); int LastValue = -1; - D->V.reset(new BestVideoSource(Source, HWDevice ? HWDevice : "", ExtraHWFrames, Track, Threads, CacheMode, CachePath ? CachePath : "", &Opts, + D->V.reset(new BestVideoSource(Source, HWDevice ? HWDevice : "", ExtraHWFrames, Track, ViewID, Threads, CacheMode, CachePath ? CachePath : "", &Opts, [vsapi, Core, &NextUpdate, &LastValue](int Track, int64_t Cur, int64_t Total) { if (NextUpdate < std::chrono::high_resolution_clock::now()) { if (Total == INT64_MAX && Cur == Total) { @@ -200,7 +201,7 @@ static void VS_CC CreateBestVideoSource(const VSMap *In, VSMap *Out, void *, VSC })); } else { - D->V.reset(new BestVideoSource(Source, HWDevice ? HWDevice : "", ExtraHWFrames, Track, Threads, CacheMode, CachePath ? CachePath : "", &Opts)); + D->V.reset(new BestVideoSource(Source, HWDevice ? HWDevice : "", ExtraHWFrames, Track, ViewID, Threads, CacheMode, CachePath ? CachePath : "", &Opts)); } D->V->SelectFormatSet(VariableFormat); @@ -437,7 +438,7 @@ static void VS_CC SetLogLevel(const VSMap *In, VSMap *Out, void *, VSCore *, con VS_EXTERNAL_API(void) VapourSynthPluginInit2(VSPlugin *plugin, const VSPLUGINAPI *vspapi) { vspapi->configPlugin("com.vapoursynth.bestsource", "bs", "Best Source 2", VS_MAKE_VERSION(BEST_SOURCE_VERSION_MAJOR, BEST_SOURCE_VERSION_MINOR), VS_MAKE_VERSION(VAPOURSYNTH_API_MAJOR, 0), 0, plugin); - vspapi->registerFunction("VideoSource", "source:data;track:int:opt;variableformat:int:opt;fpsnum:int:opt;fpsden:int:opt;rff:int:opt;threads:int:opt;seekpreroll:int:opt;enable_drefs:int:opt;use_absolute_path:int:opt;cachemode:int:opt;cachepath:data:opt;cachesize:int:opt;hwdevice:data:opt;extrahwframes:int:opt;timecodes:data:opt;start_number:int:opt;showprogress:int:opt;", "clip:vnode;", CreateBestVideoSource, nullptr, plugin); + vspapi->registerFunction("VideoSource", "source:data;track:int:opt;variableformat:int:opt;fpsnum:int:opt;fpsden:int:opt;rff:int:opt;viewid:int:opt;threads:int:opt;seekpreroll:int:opt;enable_drefs:int:opt;use_absolute_path:int:opt;cachemode:int:opt;cachepath:data:opt;cachesize:int:opt;hwdevice:data:opt;extrahwframes:int:opt;timecodes:data:opt;start_number:int:opt;showprogress:int:opt;", "clip:vnode;", CreateBestVideoSource, nullptr, plugin); vspapi->registerFunction("AudioSource", "source:data;track:int:opt;adjustdelay:int:opt;threads:int:opt;enable_drefs:int:opt;use_absolute_path:int:opt;drc_scale:float:opt;cachemode:int:opt;cachepath:data:opt;cachesize:int:opt;showprogress:int:opt;", "clip:anode;", CreateBestAudioSource, nullptr, plugin); vspapi->registerFunction("TrackInfo", "source:data;enable_drefs:int:opt;use_absolute_path:int:opt;", "mediatype:int;mediatypestr:data;codec:int;codecstr:data;disposition:int;dispositionstr:data;", GetTrackInfo, nullptr, plugin); vspapi->registerFunction("Metadata", "source:data;track:int:opt;enable_drefs:int:opt;use_absolute_path:int:opt;", "any", GetMetadata, nullptr, plugin); diff --git a/src/videosource.cpp b/src/videosource.cpp index 744b769..6884038 100644 --- a/src/videosource.cpp +++ b/src/videosource.cpp @@ -115,7 +115,7 @@ bool LWVideoDecoder::DecodeNextFrame(bool SkipOutput) { return false; } -void LWVideoDecoder::OpenFile(const std::filesystem::path &SourceFile, const std::string &HWDeviceName, int ExtraHWFrames, int Track, int Threads, const std::map &LAVFOpts) { +void LWVideoDecoder::OpenFile(const std::filesystem::path &SourceFile, const std::string &HWDeviceName, int ExtraHWFrames, int Track, int ViewID, int Threads, const std::map &LAVFOpts) { TrackNumber = Track; AVHWDeviceType Type = AV_HWDEVICE_TYPE_NONE; @@ -232,14 +232,20 @@ void LWVideoDecoder::OpenFile(const std::filesystem::path &SourceFile, const std throw BestSourceException("Couldn't allocate frame"); } - if (avcodec_open2(CodecContext, Codec, nullptr) < 0) + AVDictionary *CodecDict = nullptr; + if (ViewID >= 0) + av_dict_set(&CodecDict, "view_ids", std::to_string(ViewID).c_str(), 0); + + if (avcodec_open2(CodecContext, Codec, &CodecDict) < 0) throw BestSourceException("Could not open video codec"); + + av_dict_free(&CodecDict); } -LWVideoDecoder::LWVideoDecoder(const std::filesystem::path &SourceFile, const std::string &HWDeviceName, int ExtraHWFrames, int Track, int Threads, const std::map &LAVFOpts) { +LWVideoDecoder::LWVideoDecoder(const std::filesystem::path &SourceFile, const std::string &HWDeviceName, int ExtraHWFrames, int Track, int ViewID, int Threads, const std::map &LAVFOpts) { try { Packet = av_packet_alloc(); - OpenFile(SourceFile, HWDeviceName, ExtraHWFrames, Track, Threads, LAVFOpts); + OpenFile(SourceFile, HWDeviceName, ExtraHWFrames, Track, ViewID, Threads, LAVFOpts); } catch (...) { Free(); throw; @@ -868,8 +874,8 @@ bool BestVideoSource::NearestCommonFrameRate(BSRational &FPS) { return false; } -BestVideoSource::BestVideoSource(const std::filesystem::path &SourceFile, const std::string &HWDeviceName, int ExtraHWFrames, int Track, int Threads, int CacheMode, const std::filesystem::path &CachePath, const std::map *LAVFOpts, const ProgressFunction &Progress) - : Source(SourceFile), HWDevice(HWDeviceName), ExtraHWFrames(!HWDeviceName.empty() ? ExtraHWFrames : 0), VideoTrack(Track), Threads(Threads) { +BestVideoSource::BestVideoSource(const std::filesystem::path &SourceFile, const std::string &HWDeviceName, int ExtraHWFrames, int Track, int ViewID, int Threads, int CacheMode, const std::filesystem::path &CachePath, const std::map *LAVFOpts, const ProgressFunction &Progress) + : Source(SourceFile), HWDevice(HWDeviceName), ExtraHWFrames(!HWDeviceName.empty() ? ExtraHWFrames : 0), VideoTrack(Track), ViewID(ViewID), Threads(Threads) { // Only make file path absolute if it exists to pass through special protocol paths std::error_code ec; if (std::filesystem::exists(SourceFile, ec)) @@ -884,7 +890,7 @@ BestVideoSource::BestVideoSource(const std::filesystem::path &SourceFile, const if (CacheMode < 0 || CacheMode > 4) throw BestSourceException("CacheMode must be between 0 and 4"); - std::unique_ptr Decoder(new LWVideoDecoder(Source, HWDevice, ExtraHWFrames, VideoTrack, Threads, LAVFOptions)); + std::unique_ptr Decoder(new LWVideoDecoder(Source, HWDevice, ExtraHWFrames, VideoTrack, ViewID, Threads, LAVFOptions)); Decoder->GetVideoProperties(VP); VideoTrack = Decoder->GetTrack(); @@ -986,7 +992,7 @@ void BestVideoSource::SetSeekPreRoll(int64_t Frames) { } bool BestVideoSource::IndexTrack(const ProgressFunction &Progress) { - std::unique_ptr Decoder(new LWVideoDecoder(Source, HWDevice, ExtraHWFrames, VideoTrack, Threads, LAVFOptions)); + std::unique_ptr Decoder(new LWVideoDecoder(Source, HWDevice, ExtraHWFrames, VideoTrack, ViewID, Threads, LAVFOptions)); int64_t FileSize = Progress ? Decoder->GetSourceSize() : -1; @@ -1274,7 +1280,7 @@ BestVideoFrame *BestVideoSource::GetFrameInternal(int64_t N) { int Index = (EmptySlot >= 0) ? EmptySlot : LeastRecentlyUsed; if (!Decoders[Index]) - Decoders[Index].reset(new LWVideoDecoder(Source, HWDevice, ExtraHWFrames, VideoTrack, Threads, LAVFOptions)); + Decoders[Index].reset(new LWVideoDecoder(Source, HWDevice, ExtraHWFrames, VideoTrack, ViewID, Threads, LAVFOptions)); DecoderLastUse[Index] = DecoderSequenceNum++; @@ -1299,7 +1305,7 @@ BestVideoFrame *BestVideoSource::GetFrameLinearInternal(int64_t N, int64_t SeekF // If an empty slot exists simply spawn a new decoder there or reuse the least recently used decoder slot if no free ones exist if (Index < 0) { Index = (EmptySlot >= 0) ? EmptySlot : LeastRecentlyUsed; - Decoders[Index].reset(new LWVideoDecoder(Source, HWDevice, ExtraHWFrames, VideoTrack, Threads, LAVFOptions)); + Decoders[Index].reset(new LWVideoDecoder(Source, HWDevice, ExtraHWFrames, VideoTrack, ViewID, Threads, LAVFOptions)); } std::unique_ptr &Decoder = Decoders[Index]; @@ -1541,6 +1547,7 @@ bool BestVideoSource::WriteVideoTrackIndex(bool AbsolutePath, const std::filesys WriteBSHeader(F, true); WriteInt64(F, FileSize); WriteInt(F, VideoTrack); + WriteInt(F, ViewID); WriteString(F, HWDevice); WriteInt(F, ExtraHWFrames); @@ -1623,6 +1630,8 @@ bool BestVideoSource::ReadVideoTrackIndex(bool AbsolutePath, const std::filesyst return false; if (!ReadCompareInt(F, VideoTrack)) return false; + if (!ReadCompareInt(F, ViewID)) + return false; if (!ReadCompareString(F, HWDevice)) return false; if (!ReadCompareInt(F, ExtraHWFrames)) diff --git a/src/videosource.h b/src/videosource.h index 6dec657..07e66c3 100644 --- a/src/videosource.h +++ b/src/videosource.h @@ -113,12 +113,12 @@ class LWVideoDecoder { AVPacket *Packet = nullptr; bool Seeked = false; - void OpenFile(const std::filesystem::path &SourceFile, const std::string &HWDeviceName, int ExtraHWFrames, int Track, int Threads, const std::map &LAVFOpts); + void OpenFile(const std::filesystem::path &SourceFile, const std::string &HWDeviceName, int ExtraHWFrames, int Track, int ViewID, int Threads, const std::map &LAVFOpts); bool ReadPacket(); bool DecodeNextFrame(bool SkipOutput = false); void Free(); public: - LWVideoDecoder(const std::filesystem::path &SourceFile, const std::string &HWDeviceName, int ExtraHWFrames, int Track, int Threads, const std::map &LAVFOpts); // Positive track numbers are absolute. Negative track numbers mean nth audio track to simplify things. + LWVideoDecoder(const std::filesystem::path &SourceFile, const std::string &HWDeviceName, int ExtraHWFrames, int Track, int ViewID, int Threads, const std::map &LAVFOpts); // Positive track numbers are absolute. Negative track numbers mean nth audio track to simplify things. ~LWVideoDecoder(); [[nodiscard]] int64_t GetSourceSize() const; [[nodiscard]] int64_t GetSourcePostion() const; @@ -273,6 +273,7 @@ class BestVideoSource { int ExtraHWFrames; int VideoTrack; int VariableFormat = -1; + int ViewID; int Threads; bool LinearMode = false; uint64_t DecoderSequenceNum = 0; @@ -292,7 +293,7 @@ class BestVideoSource { bool NearestCommonFrameRate(BSRational &FPS); void InitializeFormatSets(); public: - BestVideoSource(const std::filesystem::path &SourceFile, const std::string &HWDeviceName, int ExtraHWFrames, int Track, int Threads, int CacheMode, const std::filesystem::path &CachePath, const std::map *LAVFOpts, const ProgressFunction &Progress = nullptr); + BestVideoSource(const std::filesystem::path &SourceFile, const std::string &HWDeviceName, int ExtraHWFrames, int Track, int ViewID, int Threads, int CacheMode, const std::filesystem::path &CachePath, const std::map *LAVFOpts, const ProgressFunction &Progress = nullptr); [[nodiscard]] int GetTrack() const; // Useful when opening nth video track to get the actual number void SetMaxCacheSize(size_t Bytes); /* Default max size is 1GB */ void SetSeekPreRoll(int64_t Frames); /* The number of frames to cache before the position being fast forwarded to */