Skip to content

Commit

Permalink
Introduce FormatProbe
Browse files Browse the repository at this point in the history
  • Loading branch information
bsdelf committed Sep 2, 2018
1 parent 849ff4e commit bc309f4
Show file tree
Hide file tree
Showing 27 changed files with 376 additions and 19 deletions.
13 changes: 13 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ endif()
option(WITH_PLUGIN_ALSA "ALSA output" ${TRY_PLUGIN_ALSA})
option(WITH_PLUGIN_LIBAO "Libao output" OFF)

#==== Format Probe ====#
option(WITH_PLUGIN_FORMAT_PROBE "Format Probe" ON)

#==== Codecs ====#
if(LIB_FAAC AND LIB_MP4V2)
set(TRY_PLUGIN_FAAC ON)
Expand Down Expand Up @@ -298,6 +301,16 @@ if(WITH_PLUGIN_LIBAO)
install(TARGETS AoOutput LIBRARY DESTINATION lib/mous)
endif()

if(WITH_PLUGIN_FORMAT_PROBE)
file(GLOB PLUGIN_FORMAT_PROBE_SRC plugins/format-probe/*)
add_library(FormatProbe SHARED ${PLUGIN_FORMAT_PROBE_SRC})
if(LIB_MP4V2)
target_compile_definitions(FormatProbe PRIVATE ENABLE_MP4)
target_link_libraries(FormatProbe ${LIB_MP4V2})
endif()
install(TARGETS FormatProbe LIBRARY DESTINATION lib/mous)
endif()

if(WITH_PLUGIN_LPCM)
file(GLOB LPCM_CODEC_SRC plugins/lpcm/*)
add_library(LpcmCodec SHARED ${LPCM_CODEC_SRC})
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
| mpg123 | MP3 decoding (\*.mp3) | mpg123 |
| lame | MP3 encoding (\*.mp3) | lame |
| fdk-aac | AAC codec (\*.m4a, \*.mp4) | fdk-aac, mp4v2 |
| alac | ALAC codec (\*.m4a, \*.mp4) | mp4v2 |
| wavpack | WavPack codec (\*.wv) | wavpack |
| vorbis | Ogg Vorbis codec (\*.ogg) | libvorbis, libogg |
| flac | FLAC codec (\*.flac) | flac |
Expand Down
3 changes: 3 additions & 0 deletions apps/cli/ctx.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ Context::Context()
}

PluginFinder()
.OnPlugin(PluginType::FormatProbe, [this](const std::shared_ptr<Plugin>& plugin) {
player.LoadFormatProbePlugin(plugin);
})
.OnPlugin(PluginType::Decoder, [this](const std::shared_ptr<Plugin>& plugin) {
decoderPlugins.push_back(plugin);
player.LoadDecoderPlugin(plugin);
Expand Down
3 changes: 3 additions & 0 deletions apps/ncurses/ServerContext.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ bool ServerContext::Init()
bool hasOutput = false;
const auto env = GlobalAppEnv::Instance();
PluginFinder()
.OnPlugin(PluginType::FormatProbe, [this](const std::shared_ptr<Plugin>& plugin) {
player.LoadFormatProbePlugin(plugin);
})
.OnPlugin(PluginType::Decoder, [&, this](const std::shared_ptr<Plugin>& plugin) {
player.LoadDecoderPlugin(plugin);
hasDecoder = true;
Expand Down
3 changes: 3 additions & 0 deletions apps/qt5/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ void MainWindow::InitMousCore()
int tagParserPluginCount = 0;

PluginFinder()
.OnPlugin(PluginType::FormatProbe, [this](const std::shared_ptr<Plugin>& plugin) {
m_Player->LoadFormatProbePlugin(plugin);
})
.OnPlugin(PluginType::Decoder, [&, this](const std::shared_ptr<Plugin>& plugin) {
m_Player->LoadDecoderPlugin(plugin);
m_ConvFactory->LoadDecoderPlugin(plugin);
Expand Down
5 changes: 5 additions & 0 deletions core/Player.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ PlayerStatus Player::Status() const
return impl->Status();
}

void Player::LoadFormatProbePlugin(const std::shared_ptr<Plugin>& plugin)
{
return impl->LoadFormatProbePlugin(plugin);
}

void Player::LoadDecoderPlugin(const std::shared_ptr<Plugin>& plugin)
{
return impl->LoadDecoderPlugin(plugin);
Expand Down
77 changes: 67 additions & 10 deletions core/PlayerImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ using namespace scx;
#include <util/Plugin.h>
#include <plugin/Decoder.h>
#include <plugin/Output.h>
#include <plugin/FormatProbe.h>

namespace mous {

Expand Down Expand Up @@ -192,18 +193,44 @@ class Player::Impl

PlayerStatus Status() const { return m_Status; }

void LoadFormatProbePlugin(const std::shared_ptr<Plugin>& plugin)
{
auto probe = std::make_shared<FormatProbe>(plugin);
if (!probe || !*probe) {
return;
}
const auto suffixes = probe->FileSuffix();
for (const auto& suffix: suffixes) {
const auto& str = ToLower(suffix);
auto iter = m_Probes.find(str);
if (iter == m_Probes.end()) {
m_Probes.emplace(suffix, probe);
}
}
}

void LoadDecoderPlugin(const std::shared_ptr<Plugin>& plugin)
{
auto decoder = std::make_shared<Decoder>(plugin);
if (!decoder || !*decoder) {
return;
}
const vector<string>& list = decoder->FileSuffix();
for (const string& item : list) {
const string& suffix = ToLower(item);
auto iter = m_Decoders.find(suffix);
const auto& suffixes = decoder->FileSuffix();
const auto& encodings = decoder->Encodings();
for (const auto& suffix : suffixes) {
const auto& str = ToLower(suffix);
const auto key = "suffix/" + str;
const auto iter = m_Decoders.find(key);
if (iter == m_Decoders.end()) {
m_Decoders.emplace(key, decoder);
}
}
for (const auto& encoding : encodings) {
const auto& str = ToLower(encoding);
const auto key = "encoding/" + str;
const auto iter = m_Decoders.find(key);
if (iter == m_Decoders.end()) {
m_Decoders.emplace(suffix, decoder);
m_Decoders.emplace(key, decoder);
}
}
}
Expand Down Expand Up @@ -236,14 +263,22 @@ class Player::Impl
m_Output->Close();
m_Output.reset();
}

m_Probes.clear();
}

vector<string> SupportedSuffixes() const
{
vector<string> list;
list.reserve(m_Decoders.size());
std::string prefix("suffix/");
for (const auto& entry : m_Decoders) {
list.push_back(entry.first);
const auto pos = entry.first.find(prefix);
if (pos == std::string::npos) {
continue;
}
auto&& suffix = entry.first.substr(prefix.size());
list.push_back(std::move(suffix));
}
return list;
}
Expand Down Expand Up @@ -275,12 +310,33 @@ class Player::Impl
return ErrorCode::PlayerNoOutput;
}

string suffix = ToLower(FileHelper::FileSuffix(path));
auto iter = m_Decoders.find(suffix);
if (iter == m_Decoders.end()) {
m_Decoder.reset();
{
const auto& suffix = ToLower(FileHelper::FileSuffix(path));
// detect encoding
std::string encoding;
{
auto iter = m_Probes.find(suffix);
if (iter != m_Probes.end()) {
encoding = iter->second->Probe(path);
}
}
if (encoding.size() > 0) {
const auto iter = m_Decoders.find("encoding/" + encoding);
if (iter != m_Decoders.end()) {
m_Decoder = iter->second;
}
}
if (!m_Decoder) {
auto iter = m_Decoders.find("suffix/" + suffix);
if (iter != m_Decoders.end()) {
m_Decoder = iter->second;
}
}
}
if (!m_Decoder) {
return ErrorCode::PlayerNoDecoder;
}
m_Decoder = iter->second;

ErrorCode err = m_Decoder->Open(path);
if (err != ErrorCode::Ok) {
Expand Down Expand Up @@ -548,6 +604,7 @@ class Player::Impl
double m_UnitPerMs = 0;

std::map<std::string, std::shared_ptr<Decoder>> m_Decoders;
std::map<std::string, std::shared_ptr<FormatProbe>> m_Probes;

scx::Signal<void(void)> m_SigFinished;
};
Expand Down
8 changes: 7 additions & 1 deletion plugins/alac/Decoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,12 @@ static const BaseOption** GetOptions(void* ptr) {

static const char** GetSuffixes(void* ptr) {
(void) ptr;
static const char* suffixes[] { "alac", nullptr };
static const char* suffixes[] { "m4a", nullptr };
return suffixes;
}

static const char** GetEncodings(void* ptr) {
(void) ptr;
static const char* encodings[] { "alac", nullptr };
return encodings;
}
6 changes: 6 additions & 0 deletions plugins/fdk-aac/decoder/Decoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,9 @@ const char** GetSuffixes(void* ptr) {
static const char* suffixes[] { "m4a", "mp4", nullptr };
return suffixes;
}

static const char** GetEncodings(void* ptr) {
(void) ptr;
static const char* encodings[] { "aac", nullptr };
return encodings;
}
6 changes: 6 additions & 0 deletions plugins/flac/Decoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -200,3 +200,9 @@ static const char** GetSuffixes(void* ptr) {
static const char* suffixes[] { "flac", nullptr };
return suffixes;
}

static const char** GetEncodings(void* ptr) {
(void) ptr;
static const char* encodings[] { "flac", nullptr };
return encodings;
}
67 changes: 67 additions & 0 deletions plugins/format-probe/FormatProbe.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include <stdio.h>
#include <strings.h>
#include <map>
#include <string>
#include <scx/Conv.h>
#include <scx/FileHelper.h>
using namespace scx;
#include <plugin/FormatProbeProto.h>
using namespace mous;
#ifdef ENABLE_CAF
#include "ProbeCaf.h"
#endif
#ifdef ENABLE_MP4
#include "ProbeMp4.h"
#endif

using ProbeFunc = const char* (*)(void* ptr, const char* path);

namespace {
struct Self {
const std::map<std::string, ProbeFunc> probes {
#ifdef ENABLE_CAF
{ "caf", ProbeCaf },
#endif
#ifdef ENABLE_MP4
{ "alac", ProbeMp4 },
{ "m4a", ProbeMp4 },
{ "mp4", ProbeMp4 },
#endif
};
};
}

static void* Create(void) {
return new Self;
}

static void Destroy(void* ptr) {
delete SELF;
}

static const char* Probe(void* ptr, const char* path) {
const auto& suffix = ToLower(FileHelper::FileSuffix(path));
const auto iter = SELF->probes.find(suffix);
return iter != SELF->probes.end() ? iter->second(ptr, path) : nullptr;
}

static const BaseOption** GetOptions(void* ptr) {
(void) ptr;
return nullptr;
}

const char** GetSuffixes(void* ptr) {
(void) ptr;
static const char* suffixes[] {
"alac",
#ifdef ENABLE_CAF
"caf",
#endif
#ifdef ENABLE_MP4
"m4a",
"mp4",
#endif
nullptr
};
return suffixes;
}
9 changes: 9 additions & 0 deletions plugins/format-probe/Plugin.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include <util/PluginHelper.h>
using namespace mous;

MOUS_EXPORT_PLUGIN(
PluginType::FormatProbe,
"format-probe",
"Format Probe",
2
)
5 changes: 5 additions & 0 deletions plugins/format-probe/ProbeCaf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once

static const char* ProbeCaf(void* ptr, const char* path) {
return nullptr;
}
53 changes: 53 additions & 0 deletions plugins/format-probe/ProbeMp4.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#pragma once

#include <mp4v2/mp4v2.h>

namespace {
struct MP4File {
explicit MP4File(const char* path) {
handle = MP4Read(path);
}
~MP4File() {
if (handle) {
MP4Close(handle);
handle = nullptr;
}
}
operator bool() const {
return handle;
}
MP4FileHandle handle = nullptr;
};
}

static const char* ProbeMp4(void* ptr, const char* path) {
MP4File file(path);
if (!file) {
return nullptr;
}
MP4TrackId trackid = MP4_INVALID_TRACK_ID;
auto ntrack = MP4GetNumberOfTracks(file.handle);
for (decltype(ntrack) itrack = 0; itrack < ntrack; ++itrack) {
trackid = MP4FindTrackId(file.handle, itrack);
if (trackid != MP4_INVALID_TRACK_ID) {
const auto type = MP4GetTrackType(file.handle, trackid);
if (MP4_IS_AUDIO_TRACK_TYPE(type)) {
break;
};
}
}
if (trackid == MP4_INVALID_TRACK_ID) {
return nullptr;
}
const char* media_data_name = MP4GetTrackMediaDataName(file.handle, trackid);
if (strcasecmp(media_data_name, "mp4a") == 0) {
const auto type = MP4GetTrackEsdsObjectTypeId(file.handle, trackid);
if (type == MP4_MPEG4_AUDIO_TYPE) {
return "aac";
}
}
if (strcasecmp(media_data_name, "alac") == 0) {
return "alac";
}
return nullptr;
}
6 changes: 6 additions & 0 deletions plugins/lpcm/Decoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,10 @@ static const char** GetSuffixes(void* ptr) {
(void) ptr;
static const char* suffixes[] { "wav", nullptr };
return suffixes;
}

static const char** GetEncodings(void* ptr) {
(void) ptr;
static const char* encodings[] { "lpcm", nullptr };
return encodings;
}
Loading

0 comments on commit bc309f4

Please sign in to comment.