Selaa lähdekoodia

UI: Add (AAC) audio encoder inspection helpers

Palana 10 vuotta sitten
vanhempi
sitoutus
6a136ade4f
3 muutettua tiedostoa jossa 175 lisäystä ja 0 poistoa
  1. 2 0
      obs/CMakeLists.txt
  2. 167 0
      obs/audio-encoders.cpp
  3. 6 0
      obs/audio-encoders.hpp

+ 2 - 0
obs/CMakeLists.txt

@@ -126,6 +126,7 @@ set(obs_SOURCES
 	hotkey-edit.cpp
 	source-label.cpp
 	remote-text.cpp
+	audio-encoders.cpp
 	qt-wrappers.cpp)
 
 set(obs_HEADERS
@@ -166,6 +167,7 @@ set(obs_HEADERS
 	hotkey-edit.hpp
 	source-label.hpp
 	remote-text.hpp
+	audio-encoders.hpp
 	qt-wrappers.hpp)
 
 set(obs_UI

+ 167 - 0
obs/audio-encoders.cpp

@@ -0,0 +1,167 @@
+#include <algorithm>
+#include <iomanip>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "audio-encoders.hpp"
+
+using namespace std;
+
+static const string encoders[] = {
+	"ffmpeg_aac",
+	"libfdk_aac",
+	"CoreAudio_AAC",
+};
+
+static const string &fallbackEncoder = encoders[0];
+
+static const char *NullToEmpty(const char *str)
+{
+	return str ? str : "";
+}
+
+static const char *EncoderName(const char *id)
+{
+	return NullToEmpty(obs_encoder_get_display_name(id));
+}
+
+static map<int, const char*> bitrateMap;
+static once_flag populateBitrateMap;
+
+static void HandleIntProperty(obs_property_t *prop, const char *id)
+{
+	const int max_ = obs_property_int_max(prop);
+	const int step = obs_property_int_step(prop);
+
+	for (int i = obs_property_int_min(prop); i <= max_; i += step)
+		bitrateMap[i] = id;
+}
+
+static void HandleListProperty(obs_property_t *prop, const char *id)
+{
+	obs_combo_format format = obs_property_list_format(prop);
+	if (format != OBS_COMBO_FORMAT_INT) {
+		blog(LOG_ERROR, "Encoder '%s' (%s) returned bitrate "
+				"OBS_PROPERTY_LIST property of unhandled "
+				"format %d",
+				EncoderName(id), id, static_cast<int>(format));
+		return;
+	}
+
+	const size_t count = obs_property_list_item_count(prop);
+	for (size_t i = 0; i < count; i++) {
+		int bitrate = static_cast<int>(
+				obs_property_list_item_int(prop, i));
+		bitrateMap[bitrate] = id;
+	}
+}
+
+static void HandleEncoderProperties(const char *id)
+{
+	auto DestroyProperties = [](obs_properties_t *props)
+	{
+		obs_properties_destroy(props);
+	};
+	std::unique_ptr<obs_properties_t, decltype(DestroyProperties)> props{
+			obs_get_encoder_properties(id),
+			DestroyProperties};
+
+	if (!props) {
+		blog(LOG_ERROR, "Failed to get properties for encoder "
+				"'%s' (%s)",
+				EncoderName(id), id);
+		return;
+	}
+
+	obs_property_t *bitrate = obs_properties_get(props.get(), "bitrate");
+
+	obs_property_type type = obs_property_get_type(bitrate);
+	switch (type) {
+	case OBS_PROPERTY_INT:
+		return HandleIntProperty(bitrate, id);
+
+	case OBS_PROPERTY_LIST:
+		return HandleListProperty(bitrate, id);
+
+	default: break;
+	}
+
+	blog(LOG_ERROR, "Encoder '%s' (%s) returned bitrate property "
+			"of unhandled type %d", EncoderName(id), id,
+			static_cast<int>(type));
+}
+
+static const char *GetCodec(const char *id)
+{
+	return NullToEmpty(obs_get_encoder_codec(id));
+}
+
+static const string aac_ = "AAC";
+static void PopulateBitrateMap()
+{
+	call_once(populateBitrateMap, []()
+	{
+		HandleEncoderProperties(fallbackEncoder.c_str());
+
+		const char *id = nullptr;
+		for (size_t i = 0; obs_enum_encoder_types(i, &id); i++) {
+			auto Compare = [=](const string &val)
+			{
+				return val == NullToEmpty(id);
+			};
+
+			if (find_if(begin(encoders), end(encoders), Compare) !=
+				end(encoders))
+				continue;
+
+			if (aac_ != GetCodec(id))
+				continue;
+
+			HandleEncoderProperties(id);
+		}
+
+		for (auto &encoder : encoders) {
+			if (encoder == fallbackEncoder)
+				continue;
+
+			if (aac_ != GetCodec(encoder.c_str()))
+				continue;
+
+			HandleEncoderProperties(encoder.c_str());
+		}
+
+		if (bitrateMap.empty()) {
+			blog(LOG_ERROR, "Could not enumerate any AAC encoder "
+					"bitrates");
+			return;
+		}
+
+		ostringstream ss;
+		for (auto &entry : bitrateMap)
+			ss << "\n	" << setw(3) << entry.first
+			   << " kbit/s: '" << EncoderName(entry.second) << "' ("
+			   << entry.second << ')';
+
+		blog(LOG_INFO, "AAC encoder bitrate mapping:%s",
+				ss.str().c_str());
+	});
+}
+
+const map<int, const char*> &GetAACEncoderBitrateMap()
+{
+	PopulateBitrateMap();
+	return bitrateMap;
+}
+
+const char *GetAACEncoderForBitrate(int bitrate)
+{
+	auto &map_ = GetAACEncoderBitrateMap();
+	auto res = map_.find(bitrate);
+	if (res == end(map_))
+		return NULL;
+	return res->second;
+}

+ 6 - 0
obs/audio-encoders.hpp

@@ -0,0 +1,6 @@
+#include <obs.hpp>
+
+#include <map>
+
+const std::map<int, const char*> &GetAACEncoderBitrateMap();
+const char *GetAACEncoderForBitrate(int bitrate);