Skip to content

Commit

Permalink
Merge branch 'bestsource' into feature
Browse files Browse the repository at this point in the history
  • Loading branch information
arch1t3cht committed Apr 3, 2024
2 parents aa68c2e + 087286e commit a7b6f93
Show file tree
Hide file tree
Showing 13 changed files with 225 additions and 110 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ subprojects/glib*
subprojects/googletest-*
subprojects/harfbuzz
subprojects/icu
subprojects/jansson
subprojects/libass
subprojects/libffi*
subprojects/libpng-*
Expand All @@ -47,3 +46,4 @@ subprojects/dirent-*
subprojects/hunspell-*
subprojects/uchardet-*
subprojects/vapoursynth
subprojects/xxhash
46 changes: 32 additions & 14 deletions src/audio_provider_bestsource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@
#ifdef WITH_BESTSOURCE
#include <libaegisub/audio/provider.h>

#include "bestsource_common.h"

#include "audiosource.h"

#include "bestsource_common.h"
#include "compat.h"
#include "options.h"

Expand All @@ -38,7 +39,7 @@
namespace {
class BSAudioProvider final : public agi::AudioProvider {
std::map<std::string, std::string> bsopts;
BestAudioSource bs;
std::unique_ptr<BestAudioSource> bs;
AudioProperties properties;

void FillBuffer(void *Buf, int64_t Start, int64_t Count) const override;
Expand All @@ -52,32 +53,49 @@ class BSAudioProvider final : public agi::AudioProvider {
/// @param filename The filename to open
BSAudioProvider::BSAudioProvider(agi::fs::path const& filename, agi::BackgroundRunner *br) try
: bsopts()
, bs(filename.string(), -1, -1, 0, GetBSCacheFile(filename), &bsopts)
{
bs.SetMaxCacheSize(OPT_GET("Provider/Audio/BestSource/Max Cache Size")->GetInt() << 20);
provider_bs::CleanBSCache();
auto track = provider_bs::SelectTrack(filename, true).first;

if (track == provider_bs::TrackSelection::NoTracks)
throw agi::AudioDataNotFound("no audio tracks found");
else if (track == provider_bs::TrackSelection::None)
throw agi::UserCancelException("audio loading cancelled by user");

bool cancelled = false;
br->Run([&](agi::ProgressSink *ps) {
ps->SetTitle(from_wx(_("Indexing")));
ps->SetMessage(from_wx(_("Creating cache... This can take a while!")));
ps->SetIndeterminate();
if (bs.GetExactDuration()) {
LOG_D("bs") << "File cached and has exact samples.";
ps->SetMessage(from_wx(_("Indexing file... This will take a while!")));
try {
bs = agi::make_unique<BestAudioSource>(filename.string(), static_cast<int>(track), -1, false, 0, provider_bs::GetCacheFile(filename), &bsopts, 0, [=](int Track, int64_t Current, int64_t Total) {
ps->SetProgress(Current, Total);
return !ps->IsCancelled();
});
} catch (BestSourceException const& err) {
if (std::string(err.what()) == "Indexing canceled by user")
cancelled = true;
else
throw err;
}
});
BSCleanCache();
properties = bs.GetAudioProperties();
float_samples = properties.IsFloat;
bytes_per_sample = properties.BytesPerSample;
if (cancelled)
throw agi::UserCancelException("audio loading cancelled by user");

bs->SetMaxCacheSize(OPT_GET("Provider/Audio/BestSource/Max Cache Size")->GetInt() << 20);
properties = bs->GetAudioProperties();
float_samples = properties.AF.Float;
bytes_per_sample = properties.AF.BytesPerSample;
sample_rate = properties.SampleRate;
channels = properties.Channels;
num_samples = properties.NumSamples;
decoded_samples = OPT_GET("Provider/Audio/BestSource/Aegisub Cache")->GetBool() ? 0 : num_samples;
}
catch (AudioException const& err) {
catch (BestSourceException const& err) {
throw agi::AudioProviderError("Failed to create BestAudioSource");
}

void BSAudioProvider::FillBuffer(void *Buf, int64_t Start, int64_t Count) const {
const_cast<BestAudioSource &>(bs).GetPackedAudio(reinterpret_cast<uint8_t *>(Buf), Start, Count);
bs->GetPackedAudio(reinterpret_cast<uint8_t *>(Buf), Start, Count);
}

}
Expand Down
66 changes: 58 additions & 8 deletions src/bestsource_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@

#ifdef WITH_BESTSOURCE
#include "bestsource_common.h"
#include "tracklist.h"

extern "C" {
#include <libavutil/avutil.h>
}

#include "format.h"
#include "options.h"
#include "utils.h"

Expand All @@ -31,26 +37,70 @@
#include <boost/crc.hpp>
#include <boost/filesystem/path.hpp>

namespace provider_bs {

std::pair<TrackSelection, bool> SelectTrack(agi::fs::path const& filename, bool audio) {
std::map<std::string, std::string> opts;
BestTrackList tracklist(filename.string(), &opts);

int n = tracklist.GetNumTracks();
AVMediaType type = audio ? AVMEDIA_TYPE_AUDIO : AVMEDIA_TYPE_VIDEO;

std::vector<int> TrackNumbers;
wxArrayString Choices;
bool has_audio = false;

for (int i = 0; i < n; i++) {
BestTrackList::TrackInfo info = tracklist.GetTrackInfo(i);
has_audio = has_audio || (info.MediaType == AVMEDIA_TYPE_AUDIO);

if (info.MediaType == type) {
TrackNumbers.push_back(i);
Choices.Add(agi::wxformat(_("Track %02d: %s"), i, info.CodecString));
}
}

TrackSelection result;

std::string GetBSCacheFile(agi::fs::path const& filename) {
// BS can store all its index data in a single file, but we make a separate index file
// for each video file to ensure that the old index is invalidated if the file is modified.
// While BS does check the filesize of the files, it doesn't check the modification time.
uintmax_t len = agi::fs::Size(filename);
if (TrackNumbers.empty()) {
result = TrackSelection::NoTracks;
} else if (TrackNumbers.size() == 1) {
result = static_cast<TrackSelection>(TrackNumbers[0]);
} else {
int Choice = wxGetSingleChoiceIndex(
audio ? _("Multiple video tracks detected, please choose the one you wish to load:") : _("Multiple audio tracks detected, please choose the one you wish to load:"),
audio ? _("Choose video track") : _("Choose audio track"),
Choices);

if (Choice >= 0)
result = static_cast<TrackSelection>(TrackNumbers[Choice]) ;
else
result = TrackSelection::None;
}

return std::make_pair(result, has_audio);
}

std::string GetCacheFile(agi::fs::path const& filename) {
boost::crc_32_type hash;
hash.process_bytes(filename.string().c_str(), filename.string().size());

auto result = config::path->Decode("?local/bsindex/" + filename.filename().string() + "_" + std::to_string(hash.checksum()) + "_" + std::to_string(len) + "_" + std::to_string(agi::fs::ModifiedTime(filename)) + ".json");
auto result = config::path->Decode("?local/bsindex/" + filename.filename().string() + "_" + std::to_string(hash.checksum()) + "_" + std::to_string(agi::fs::ModifiedTime(filename)));
agi::fs::CreateDirectory(result.parent_path());

return result.string();
}

void BSCleanCache() {
void CleanBSCache() {
CleanCache(config::path->Decode("?local/bsindex/"),
"*.json",
"*.bsindex",
OPT_GET("Provider/BestSource/Cache/Size")->GetInt(),
OPT_GET("Provider/BestSource/Cache/Files")->GetInt());

// Delete old cache files: TODO remove this after a while
CleanCache(config::path->Decode("?local/bsindex/"),
"*.json", 0, 0);
}
}

#endif // WITH_BESTSOURCE
19 changes: 17 additions & 2 deletions src/bestsource_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,24 @@

#ifdef WITH_BESTSOURCE

namespace std { class string_view; }

#include <bsshared.h>

#include <libaegisub/fs_fwd.h>
#include <libaegisub/background_runner.h>

namespace provider_bs {

enum class TrackSelection : int {
None = -1,
NoTracks = -2,
};

std::pair<TrackSelection, bool> SelectTrack(agi::fs::path const& filename, bool audio);
std::string GetCacheFile(agi::fs::path const& filename);
void CleanBSCache();

std::string GetBSCacheFile(agi::fs::path const& filename);
void BSCleanCache();
}

#endif /* WITH_BESTSOURCE */
1 change: 1 addition & 0 deletions src/libresrc/default_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@
"BestSource" : {
"Max Cache Size" : 1024,
"Threads" : 0,
"Apply RFF": true,
"Seek Preroll" : 12
},
"VapourSynth" : {
Expand Down
1 change: 1 addition & 0 deletions src/libresrc/osx/default_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@
"BestSource" : {
"Max Cache Size" : 1024,
"Threads" : 0,
"Apply RFF": true,
"Seek Preroll" : 12
},
"VapourSynth" : {
Expand Down
1 change: 1 addition & 0 deletions src/preferences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,7 @@ void Advanced_Video(wxTreebook *book, Preferences *parent) {
p->OptionAdd(bs, _("Max cache size (MB)"), "Provider/Video/BestSource/Max Cache Size");
p->OptionAdd(bs, _("Decoder Threads (0 to autodetect)"), "Provider/Video/BestSource/Threads");
p->OptionAdd(bs, _("Seek preroll (Frames)"), "Provider/Video/BestSource/Seek Preroll");
p->OptionAdd(bs, _("Apply RFF"), "Provider/Video/BestSource/Apply RFF");
#endif

p->SetSizerAndFit(p->sizer);
Expand Down
Loading

0 comments on commit a7b6f93

Please sign in to comment.