From: Thomas Goyne <plorkyeran@aegisub.org>
Date: Wed, 6 Apr 2016 11:24:21 -0700
Subject: Use FFMS_DoIndexing2 when using a recent version of ffms2

And clean up the audio track selection logic a bit.
---
 src/audio_provider_ffmpegsource.cpp | 40 ++++++++++-----------------------
 src/ffmpegsource_common.cpp         | 44 +++++++++++++++++++++++++++----------
 src/ffmpegsource_common.h           | 25 ++++++---------------
 src/video_provider_ffmpegsource.cpp | 12 +++++-----
 4 files changed, 56 insertions(+), 65 deletions(-)

diff --git a/src/audio_provider_ffmpegsource.cpp b/src/audio_provider_ffmpegsource.cpp
index 4e44b1d..606d5b4 100644
--- a/src/audio_provider_ffmpegsource.cpp
+++ b/src/audio_provider_ffmpegsource.cpp
@@ -91,18 +91,20 @@ void FFmpegSourceAudioProvider::LoadAudio(agi::fs::path const& filename) {
 	}
 
 	std::map<int, std::string> TrackList = GetTracksOfType(Indexer, FFMS_TYPE_AUDIO);
-	if (TrackList.empty())
-		throw agi::AudioDataNotFound("no audio tracks found");
 
 	// initialize the track number to an invalid value so we can detect later on
 	// whether the user actually had to choose a track or not
 	int TrackNumber = -1;
 	if (TrackList.size() > 1) {
-		TrackNumber = AskForTrackSelection(TrackList, FFMS_TYPE_AUDIO);
-		// if it's still -1 here, user pressed cancel
-		if (TrackNumber == -1)
+		auto Selection = AskForTrackSelection(TrackList, FFMS_TYPE_AUDIO);
+		if (Selection == TrackSelection::None)
 			throw agi::UserCancelException("audio loading canceled by user");
+		TrackNumber = static_cast<int>(Selection);
 	}
+	else if (TrackList.size() == 1)
+		TrackNumber = TrackList.begin()->first;
+	else
+		throw agi::AudioDataNotFound("no audio tracks found");
 
 	// generate a name for the cache file
 	agi::fs::path CacheName = GetCacheFilename(filename);
@@ -114,24 +116,13 @@ void FFmpegSourceAudioProvider::LoadAudio(agi::fs::path const& filename) {
 	if (Index && FFMS_IndexBelongsToFile(Index, filename.string().c_str(), &ErrInfo))
 		Index = nullptr;
 
-	// index valid but track number still not set?
 	if (Index) {
-		// track number not set? just grab the first track
-		if (TrackNumber < 0)
-			TrackNumber = FFMS_GetFirstTrackOfType(Index, FFMS_TYPE_AUDIO, &ErrInfo);
-		if (TrackNumber < 0)
-			throw agi::AudioDataNotFound(std::string("Couldn't find any audio tracks: ") + ErrInfo.Buffer);
-
-		// index is valid and track number is now set,
-		// but do we have indexing info for the desired audio track?
+		// we already have an index, but the desired track may not have been
+		// indexed, and if it wasn't we need to reindex
 		FFMS_Track *TempTrackData = FFMS_GetTrackFromIndex(Index, TrackNumber);
 		if (FFMS_GetNumFrames(TempTrackData) <= 0)
 			Index = nullptr;
 	}
-	// no valid index exists and the file only has one audio track, index it
-	else if (TrackNumber < 0)
-		TrackNumber = FFMS_TRACKMASK_ALL;
-	// else: do nothing (keep track mask as it is)
 
 	// reindex if the error handling mode has changed
 	FFMS_IndexErrorHandling ErrorHandling = GetErrorHandlingMode();
@@ -142,17 +133,10 @@ void FFmpegSourceAudioProvider::LoadAudio(agi::fs::path const& filename) {
 
 	// moment of truth
 	if (!Index) {
-		int TrackMask;
-		if (OPT_GET("Provider/FFmpegSource/Index All Tracks")->GetBool() || TrackNumber == FFMS_TRACKMASK_ALL)
-			TrackMask = FFMS_TRACKMASK_ALL;
-		else
-			TrackMask = (1 << TrackNumber);
-
+		TrackSelection TrackMask = static_cast<TrackSelection>(TrackNumber);
+		if (OPT_GET("Provider/FFmpegSource/Index All Tracks")->GetBool())
+			TrackMask = TrackSelection::All;
 		Index = DoIndexing(Indexer, CacheName, TrackMask, ErrorHandling);
-
-		// if tracknumber still isn't set we need to set it now
-		if (TrackNumber == FFMS_TRACKMASK_ALL)
-			TrackNumber = FFMS_GetFirstTrackOfType(Index, FFMS_TYPE_AUDIO, &ErrInfo);
 	}
 	else
 		FFMS_CancelIndexing(Indexer);
diff --git a/src/ffmpegsource_common.cpp b/src/ffmpegsource_common.cpp
index 5ebb073..11a5abd 100644
--- a/src/ffmpegsource_common.cpp
+++ b/src/ffmpegsource_common.cpp
@@ -80,7 +80,10 @@ FFmpegSourceProvider::FFmpegSourceProvider(agi::BackgroundRunner *br)
 /// @param Indexer		A pointer to the indexer object representing the file to be indexed
 /// @param CacheName    The filename of the output index file
 /// @param Trackmask    A binary mask of the track numbers to index
-FFMS_Index *FFmpegSourceProvider::DoIndexing(FFMS_Indexer *Indexer, agi::fs::path const& CacheName, int Trackmask, FFMS_IndexErrorHandling IndexEH) {
+FFMS_Index *FFmpegSourceProvider::DoIndexing(FFMS_Indexer *Indexer,
+	                                         agi::fs::path const& CacheName,
+	                                         TrackSelection Track,
+	                                         FFMS_IndexErrorHandling IndexEH) {
 	char FFMSErrMsg[1024];
 	FFMS_ErrorInfo ErrInfo;
 	ErrInfo.Buffer		= FFMSErrMsg;
@@ -98,8 +101,22 @@ FFMS_Index *FFmpegSourceProvider::DoIndexing(FFMS_Indexer *Indexer, agi::fs::pat
 			ps->SetProgress(Current, Total);
 			return ps->IsCancelled();
 		};
-		Index = FFMS_DoIndexing(Indexer, Trackmask, FFMS_TRACKMASK_NONE,
+#if FFMS_VERSION >= ((2 << 24) | (21 << 16) | (0 << 8) | 0)
+		if (Track == TrackSelection::All)
+			FFMS_TrackTypeIndexSettings(Indexer, FFMS_TYPE_AUDIO, 1, 0);
+		else if (Track != TrackSelection::None)
+			FFMS_TrackIndexSettings(Indexer, static_cast<int>(Track), 1, 0);
+		FFMS_SetProgressCallback(Indexer, callback, ps);
+		Index = FFMS_DoIndexing2(Indexer, IndexEH, &ErrInfo);
+#else
+		int Trackmask = 0;
+		if (Track == TrackSelection::All)
+			Trackmask = std::numeric_limits<int>::max();
+		else if (Track != TrackSelection::None)
+			Trackmask = 1 << static_cast<int>(Track);
+		Index = FFMS_DoIndexing(Indexer, Trackmask, 0,
 			nullptr, nullptr, IndexEH, callback, ps, &ErrInfo);
+#endif
 	});
 
 	if (Index == nullptr)
@@ -119,21 +136,24 @@ std::map<int, std::string> FFmpegSourceProvider::GetTracksOfType(FFMS_Indexer *I
 	std::map<int,std::string> TrackList;
 	int NumTracks = FFMS_GetNumTracksI(Indexer);
 
+	// older versions of ffms2 can't index audio tracks past 31
+#if FFMS_VERSION < ((2 << 24) | (21 << 16) | (0 << 8) | 0)
+	if (Type == FFMS_TYPE_AUDIO)
+		NumTracks = std::min(NumTracks, std::numeric_limits<int>::digits);
+#endif
+
 	for (int i=0; i<NumTracks; i++) {
 		if (FFMS_GetTrackTypeI(Indexer, i) == Type) {
-			const char *CodecName = FFMS_GetCodecNameI(Indexer, i);
-			if (CodecName)
-				TrackList.insert(std::pair<int,std::string>(i, CodecName));
+			if (auto CodecName = FFMS_GetCodecNameI(Indexer, i))
+				TrackList[i] = CodecName;
 		}
 	}
 	return TrackList;
 }
 
-/// @brief Ask user for which track he wants to load
-/// @param TrackList	A std::map with the track numbers as keys and codec names as values
-/// @param Type			The track type to ask about
-/// @return				Returns the track number chosen (an integer >= 0) on success, or a negative integer if the user cancelled.
-int FFmpegSourceProvider::AskForTrackSelection(const std::map<int, std::string> &TrackList, FFMS_TrackType Type) {
+FFmpegSourceProvider::TrackSelection
+FFmpegSourceProvider::AskForTrackSelection(const std::map<int, std::string> &TrackList,
+                                           FFMS_TrackType Type) {
 	std::vector<int> TrackNumbers;
 	wxArrayString Choices;
 
@@ -148,8 +168,8 @@ int FFmpegSourceProvider::AskForTrackSelection(const std::map<int, std::string>
 		Choices);
 
 	if (Choice < 0)
-		return Choice;
-	return TrackNumbers[Choice];
+		return TrackSelection::None;
+	return static_cast<TrackSelection>(TrackNumbers[Choice]);
 }
 
 /// @brief Set ffms2 log level according to setting in config.dat
diff --git a/src/ffmpegsource_common.h b/src/ffmpegsource_common.h
index 5ef44b6..26a8a5f 100644
--- a/src/ffmpegsource_common.h
+++ b/src/ffmpegsource_common.h
@@ -42,11 +42,6 @@
 
 namespace agi { class BackgroundRunner; }
 
-/// Index all tracks
-#define FFMS_TRACKMASK_ALL		-1
-/// Index no tracks
-#define FFMS_TRACKMASK_NONE		0
-
 /// @class FFmpegSourceProvider
 /// @brief Base class for FFMS2 source providers; contains common functions etc
 class FFmpegSourceProvider {
@@ -57,24 +52,18 @@ class FFmpegSourceProvider {
 public:
 	FFmpegSourceProvider(agi::BackgroundRunner *br);
 
-	/// Logging level constants from avutil/log.h
-	enum FFMS_LogLevel {
-		/// nothing printed
-		FFMS_LOG_QUIET		= -8,
-		FFMS_LOG_PANIC		= 0,
-		FFMS_LOG_FATAL		= 8,
-		FFMS_LOG_ERROR		= 16,
-		FFMS_LOG_WARNING	= 24,
-		FFMS_LOG_INFO		= 32,
-		FFMS_LOG_VERBOSE	= 40,
-		FFMS_LOG_DEBUG		= 48,
+	enum class TrackSelection : int {
+		None = -1,
+		All = -2
 	};
 
 	void CleanCache();
 
-	FFMS_Index *DoIndexing(FFMS_Indexer *Indexer, agi::fs::path const& Cachename, int Trackmask, FFMS_IndexErrorHandling IndexEH);
+	FFMS_Index *DoIndexing(FFMS_Indexer *Indexer, agi::fs::path const& Cachename,
+		                   TrackSelection Track,
+		                   FFMS_IndexErrorHandling IndexEH);
 	std::map<int, std::string> GetTracksOfType(FFMS_Indexer *Indexer, FFMS_TrackType Type);
-	int AskForTrackSelection(const std::map<int, std::string>& TrackList, FFMS_TrackType Type);
+	TrackSelection AskForTrackSelection(const std::map<int, std::string>& TrackList, FFMS_TrackType Type);
 	agi::fs::path GetCacheFilename(agi::fs::path const& filename);
 	void SetLogLevel();
 	FFMS_IndexErrorHandling GetErrorHandlingMode();
diff --git a/src/video_provider_ffmpegsource.cpp b/src/video_provider_ffmpegsource.cpp
index 5231a08..f4ed6a2 100644
--- a/src/video_provider_ffmpegsource.cpp
+++ b/src/video_provider_ffmpegsource.cpp
@@ -166,14 +166,12 @@ void FFmpegSourceVideoProvider::LoadVideo(agi::fs::path const& filename, std::st
 	if (TrackList.size() <= 0)
 		throw VideoNotSupported("no video tracks found");
 
-	// initialize the track number to an invalid value so we can detect later on
-	// whether the user actually had to choose a track or not
 	int TrackNumber = -1;
 	if (TrackList.size() > 1) {
-		TrackNumber = AskForTrackSelection(TrackList, FFMS_TYPE_VIDEO);
-		// if it's still -1 here, user pressed cancel
-		if (TrackNumber == -1)
+		auto Selection = AskForTrackSelection(TrackList, FFMS_TYPE_VIDEO);
+		if (Selection == TrackSelection::None)
 			throw agi::UserCancelException("video loading cancelled by user");
+		TrackNumber = static_cast<int>(Selection);
 	}
 
 	// generate a name for the cache file
@@ -197,9 +195,9 @@ void FFmpegSourceVideoProvider::LoadVideo(agi::fs::path const& filename, std::st
 
 	// moment of truth
 	if (!Index) {
-		int TrackMask = FFMS_TRACKMASK_NONE;
+		auto TrackMask = TrackSelection::None;
 		if (OPT_GET("Provider/FFmpegSource/Index All Tracks")->GetBool() || OPT_GET("Video/Open Audio")->GetBool())
-			TrackMask = FFMS_TRACKMASK_ALL;
+			TrackMask = TrackSelection::All;
 		Index = DoIndexing(Indexer, CacheName, TrackMask, GetErrorHandlingMode());
 	}
 	else {
