diff --git a/approot/admin-user.xml b/approot/admin-user.xml
index 754f7ab5..e20f21a6 100644
--- a/approot/admin-user.xml
+++ b/approot/admin-user.xml
@@ -42,17 +42,17 @@
${}
diff --git a/approot/messages.xml b/approot/messages.xml
index e0a253c0..8527a8ea 100644
--- a/approot/messages.xml
+++ b/approot/messages.xml
@@ -45,7 +45,7 @@
Users
-Audio bitrate limit
+Audio transcode bitrate limit
Demo account
Demo account already exists!
Demo password must be the login name!
@@ -114,14 +114,15 @@
Account
Audio
-Bitrate
Cannot save using a demo account!
-Encoding
-Auto
-MP3
-Ogg/Opus
-Ogg/Vorbis
-WebM/Vorbis
+Transcoding
+Transcode bitrate
+Transcode format
+Enable transcoding
+MP3
+Ogg/Opus
+Ogg/Vorbis
+WebM/Vorbis
Settings
New settings saved!
diff --git a/approot/messages_fr.xml b/approot/messages_fr.xml
index 0c5eddbc..3bf1c739 100644
--- a/approot/messages_fr.xml
+++ b/approot/messages_fr.xml
@@ -45,7 +45,7 @@
Utilisateurs
-Limite du bitrate
+Limite du bitrate pour le transcodage
Compte de démonstration
Le compte de démonstration existe déjà !
Le password doit être égal au login !
@@ -101,7 +101,7 @@
Effacer
{1} pistes
{1} pistes ajoutées
-{1} pistes ajouées
+{1} pistes ajoutées
Liste de lecture
Mode radio
Repéter
@@ -115,14 +115,15 @@
Compte
Audio
Auto
-Bitrate
Impossible de sauvegarder en utilisant un compte de démo !
-Encodage
-Auto
-MP3
-Ogg/Opus
-Ogg/Vorbis
-WebM/Vorbis
+Transcodage
+Bitrate du transcodage
+Format du transcodage
+Activer le transcodage
+MP3
+Ogg/Opus
+Ogg/Vorbis
+WebM/Vorbis
Paramètres
Paramètres sauvegardés !
diff --git a/approot/settings.xml b/approot/settings.xml
index 8770bd6e..ad628e9c 100644
--- a/approot/settings.xml
+++ b/approot/settings.xml
@@ -7,28 +7,39 @@
diff --git a/src/api/subsonic/SubsonicResource.cpp b/src/api/subsonic/SubsonicResource.cpp
index 71f70c53..ebf97b3b 100644
--- a/src/api/subsonic/SubsonicResource.cpp
+++ b/src/api/subsonic/SubsonicResource.cpp
@@ -1354,9 +1354,9 @@ createTranscoder(RequestContext& context)
// "If set to zero, no limit is imposed"
if (!maxBitRate || *maxBitRate == 0)
- maxBitRate = user->getAudioBitrate() / 1000;
+ maxBitRate = user->getAudioTranscodeBitrate() / 1000;
- *maxBitRate = clamp(*maxBitRate, std::size_t {48}, user->getMaxAudioBitrate() / 1000);
+ *maxBitRate = clamp(*maxBitRate, std::size_t {48}, user->getMaxAudioTranscodeBitrate() / 1000);
auto track {Database::Track::getById(context.db.getSession(), id.value)};
if (!track)
diff --git a/src/av/AvInfo.cpp b/src/av/AvInfo.cpp
index 62745243..9569c447 100644
--- a/src/av/AvInfo.cpp
+++ b/src/av/AvInfo.cpp
@@ -24,6 +24,7 @@
#include
#include "utils/Logger.hpp"
+#include "utils/Utils.hpp"
namespace Av {
@@ -51,10 +52,8 @@ void AvInit()
}
-
-
MediaFile::MediaFile(const boost::filesystem::path& p)
-: _p(p), _context(nullptr)
+: _p {p}
{
int error = avformat_open_input(&_context, _p.string().c_str(), nullptr, nullptr);
if (error < 0)
@@ -77,6 +76,12 @@ MediaFile::~MediaFile()
avformat_close_input(&_context);
}
+std::string
+MediaFile::getFormatName() const
+{
+ return _context->iformat->name;
+}
+
std::chrono::milliseconds
MediaFile::getDuration() const
{
@@ -127,9 +132,9 @@ MediaFile::getStreamInfo() const
{
std::vector res;
- for (std::size_t i = 0; i < _context->nb_streams; ++i)
+ for (std::size_t i {}; i < _context->nb_streams; ++i)
{
- AVStream* avstream = _context->streams[i];
+ AVStream* avstream { _context->streams[i]};
// Skip attached pics
if (avstream->disposition & AV_DISPOSITION_ATTACHED_PIC)
@@ -233,4 +238,30 @@ MediaFile::getAttachedPictures(std::size_t nbMaxPictures) const
return pictures;
}
+boost::optional guessMediaFileFormat(const boost::filesystem::path& file)
+{
+ AVOutputFormat* format {av_guess_format(NULL,file.string().c_str(),NULL)};
+ if (!format || !format->name)
+ return {};
+
+ auto formats {splitString(format->name, ",")};
+ if (formats.size() > 1)
+ LMS_LOG(AV, INFO) << "File '" << file.string() << "' reported several formats: '" << format->name << "'";
+
+ std::vector mimeTypes;
+ if (format->mime_type)
+ mimeTypes = splitString(format->mime_type, ",");
+
+ if (mimeTypes.empty())
+ LMS_LOG(AV, INFO) << "File '" << file.string() << "', no mime type found!";
+ else if (mimeTypes.size() > 1)
+ LMS_LOG(AV, INFO) << "File '" << file.string() << "' reported several mime types: '" << format->mime_type << "'";
+
+ MediaFileFormat res;
+ res.format = formats.front();
+ res.mimeType = mimeTypes.empty() ? "application/octet-stream" : mimeTypes.front();
+
+ return res;
+}
+
} // namespace Av
diff --git a/src/av/AvInfo.hpp b/src/av/AvInfo.hpp
index acdfae43..11f6dfd4 100644
--- a/src/av/AvInfo.hpp
+++ b/src/av/AvInfo.hpp
@@ -69,9 +69,12 @@ class MediaFile
MediaFile(const boost::filesystem::path& p);
~MediaFile();
- // non copyable
MediaFile(const MediaFile&) = delete;
MediaFile& operator=(const MediaFile&) = delete;
+ MediaFile(MediaFile&&) = delete;
+ MediaFile& operator=(MediaFile&&) = delete;
+
+ std::string getFormatName() const;
const boost::filesystem::path& getPath() const {return _p;};
@@ -84,11 +87,19 @@ class MediaFile
std::vector getAttachedPictures(std::size_t nbMaxPictures) const;
private:
- MediaFile();
boost::filesystem::path _p;
- AVFormatContext* _context;
+ AVFormatContext* _context {};
};
+
+struct MediaFileFormat
+{
+ std::string mimeType;
+ std::string format;
+};
+
+boost::optional guessMediaFileFormat(const boost::filesystem::path& file);
+
} // namespace Av
diff --git a/src/av/AvTranscoder.cpp b/src/av/AvTranscoder.cpp
index 84ccae8e..1a37cb56 100644
--- a/src/av/AvTranscoder.cpp
+++ b/src/av/AvTranscoder.cpp
@@ -22,6 +22,7 @@
#include
#include
+#include "AvInfo.hpp"
#include "utils/Path.hpp"
#include "utils/Logger.hpp"
@@ -99,10 +100,6 @@ Transcoder::start()
args.push_back("-i");
args.push_back(_filePath.string());
- // Output bitrates
- args.push_back("-b:a");
- args.push_back(std::to_string(_parameters.bitrate));
-
// Stream mapping, if set
if (_parameters.stream)
{
@@ -121,37 +118,63 @@ Transcoder::start()
args.push_back("-vn");
// Codecs and formats
- switch( _parameters.encoding)
+ if (_parameters.encoding)
{
- case Encoding::MP3:
- args.push_back("-f");
- args.push_back("mp3");
- break;
+ // Output bitrates
+ args.push_back("-b:a");
+ args.push_back(std::to_string(_parameters.bitrate));
- case Encoding::OGG_OPUS:
- args.push_back("-acodec");
- args.push_back("libopus");
- args.push_back("-f");
- args.push_back("ogg");
- break;
+ switch (*_parameters.encoding)
+ {
+ case Encoding::MP3:
+ args.push_back("-f");
+ args.push_back("mp3");
+ break;
- case Encoding::OGG_VORBIS:
- args.push_back("-acodec");
- args.push_back("libvorbis");
- args.push_back("-f");
- args.push_back("ogg");
- break;
+ case Encoding::OGG_OPUS:
+ args.push_back("-acodec");
+ args.push_back("libopus");
+ args.push_back("-f");
+ args.push_back("ogg");
+ break;
- case Encoding::WEBM_VORBIS:
- args.push_back("-acodec");
- args.push_back("libvorbis");
- args.push_back("-f");
- args.push_back("webm");
- break;
+ case Encoding::OGG_VORBIS:
+ args.push_back("-acodec");
+ args.push_back("libvorbis");
+ args.push_back("-f");
+ args.push_back("ogg");
+ break;
+
+ case Encoding::WEBM_VORBIS:
+ args.push_back("-acodec");
+ args.push_back("libvorbis");
+ args.push_back("-f");
+ args.push_back("webm");
+ break;
- default:
+ default:
+ return false;
+ }
+
+ _outputMimeType = encodingToMimetype(*_parameters.encoding);
+ }
+ else
+ {
+ auto mediaFileFormat {guessMediaFileFormat(_filePath)};
+
+ if (!mediaFileFormat)
+ {
+ LMS_LOG(AV, ERROR) << "Cannot guess media file format for '" << _filePath.string() << "'";
return false;
+ }
+
+ args.push_back("-acodec");
+ args.push_back("copy");
+ args.push_back("-f");
+ args.push_back(mediaFileFormat->format);
+
+ _outputMimeType = mediaFileFormat->mimeType;
}
args.push_back("pipe:1");
@@ -204,14 +227,10 @@ Transcoder::process(std::vector& output, std::size_t maxSize)
output.resize(maxSize);
- LMS_LOG_TRANSCODE(DEBUG) << "Reading up to " << output.size() << " bytes";
-
//Read on the output stream
_child->out().read(reinterpret_cast(&output[0]), maxSize);
output.resize(_child->out().gcount());
- LMS_LOG_TRANSCODE(DEBUG) << "Read " << output.size() << " bytes";
-
if (_child->out().fail())
{
LMS_LOG_TRANSCODE(DEBUG) << "Stdout FAILED";
diff --git a/src/av/AvTranscoder.hpp b/src/av/AvTranscoder.hpp
index b089183f..b8e0fcd1 100644
--- a/src/av/AvTranscoder.hpp
+++ b/src/av/AvTranscoder.hpp
@@ -19,15 +19,13 @@
#pragma once
-#include