diff --git a/TODO b/TODO index fb226661..25ee53c1 100644 --- a/TODO +++ b/TODO @@ -26,7 +26,6 @@ [Transcode] - some early playback end spotted on flac files or huge audio files (> several hours) -- limit transcode bitrate to the media bitrate (no need to upscale) [UI] - handle internationalization diff --git a/remote/server/MediaRequestHandler.cpp b/remote/server/MediaRequestHandler.cpp index bd31cfbd..d76c12ac 100644 --- a/remote/server/MediaRequestHandler.cpp +++ b/remote/server/MediaRequestHandler.cpp @@ -100,7 +100,8 @@ MediaRequestHandler::processAudioPrepare(const MediaRequest::Prepare::Audio& req try { Transcode::InputMediaFile inputFile(track->getPath()); - Transcode::Parameters parameters(inputFile, Transcode::Format::get( format ), bitrate); + Transcode::Parameters parameters(inputFile, Transcode::Format::get( format )); + parameters.setBitrate( Transcode::Stream::Audio, bitrate); _transcoder = std::make_shared( parameters ); diff --git a/transcode/AvConvTranscoder.cpp b/transcode/AvConvTranscoder.cpp index 22ba612b..6a2b53f5 100644 --- a/transcode/AvConvTranscoder.cpp +++ b/transcode/AvConvTranscoder.cpp @@ -58,9 +58,9 @@ AvConvTranscoder::AvConvTranscoder(const Parameters& parameters) oss << " -i \"" << _parameters.getInputMediaFile().getPath().string() << "\""; // Output bitrates - oss << " -b:a " << _parameters.getOutputAudioBitrate() ; + oss << " -b:a " << _parameters.getOutputBitrate(Stream::Audio) ; if (_parameters.getOutputFormat().getType() == Format::Video) - oss << " -b:v " << _parameters.getOutputVideoBitrate(); + oss << " -b:v " << _parameters.getOutputBitrate(Stream::Video); // Stream mapping { diff --git a/transcode/InputMediaFile.cpp b/transcode/InputMediaFile.cpp index 6944fb8f..ca4ac21d 100644 --- a/transcode/InputMediaFile.cpp +++ b/transcode/InputMediaFile.cpp @@ -53,6 +53,7 @@ InputMediaFile::InputMediaFile(const boost::filesystem::path& p) _streams.push_back( Stream(avStreamId, type, + avStream.getCodecContext().getBitRate(), avStream.getMetadata().get("language"), // TODO define somewhere else? avStream.getCodecContext().getCodecDesc() )); @@ -90,5 +91,18 @@ InputMediaFile::getStreams(Stream::Type type) const return res; } +const Stream& +InputMediaFile::getStream(Stream::Id index) const +{ + BOOST_FOREACH(const Stream& stream, _streams) + { + if (stream.getId() == index) + return stream; + } + LMS_LOG(MOD_TRANSCODE, SEV_CRIT) << "Cannot find stream index " << index << " in stream map!"; + throw std::runtime_error("InputMediaFile::getStream, cannot find stream idx"); +} + + } // namespace Transcode diff --git a/transcode/InputMediaFile.hpp b/transcode/InputMediaFile.hpp index 1bca1316..34edb4ce 100644 --- a/transcode/InputMediaFile.hpp +++ b/transcode/InputMediaFile.hpp @@ -38,6 +38,7 @@ class InputMediaFile const std::vector< CoverArt::CoverArt >& getCovers(void) const { return _covers; } // Stream handling + const Stream& getStream(Stream::Id id) const; std::vector getStreams(Stream::Type type) const; const std::map& getBestStreams(void) const {return _bestStreams;} diff --git a/transcode/Parameters.cpp b/transcode/Parameters.cpp index b502ba97..0d5f52aa 100644 --- a/transcode/Parameters.cpp +++ b/transcode/Parameters.cpp @@ -1,3 +1,6 @@ + +#include "logger/Logger.hpp" + #include "av/InputFormatContext.hpp" #include "Parameters.hpp" @@ -13,30 +16,61 @@ getMimeType(Format format) } Parameters::Parameters(const InputMediaFile& inputMediaFile, - const Format& outputFormat, - std::size_t audioBitrate) + const Format& outputFormat) : _mediaFile(inputMediaFile), -_outputFormat(outputFormat), -_outputAudioBitrate(audioBitrate), -_outputVideoBitrate(0) +_outputFormat(outputFormat) { // By default, select the best stream indexes _inputStreams = _mediaFile.getBestStreams(); + +// setBitrate(Stream::Audio, 0); +// setBitrate(Stream::Video, 0); } -Parameters::Parameters(const InputMediaFile& inputMediaFile, - const Format& outputFormat, - std::size_t audioBitrate, - std::size_t videoBitrate) - : -_mediaFile(inputMediaFile), -_outputFormat(outputFormat), -_outputAudioBitrate(audioBitrate), -_outputVideoBitrate(videoBitrate) +std::size_t +Parameters::setBitrate(Stream::Type type, std::size_t bitrate) { - // By default, select the best stream indexes - _inputStreams = _mediaFile.getBestStreams(); + // Limit the output bitrate to the input bitrate + if (_inputStreams.find(type) != _inputStreams.end()) + { + const Transcode::Stream& stream = _mediaFile.getStream( _inputStreams[type] ); + + LMS_LOG(MOD_TRANSCODE, SEV_DEBUG) << "Stream bitrate = " << stream.getBitrate(); + + if (!bitrate || bitrate > stream.getBitrate()) + { + LMS_LOG(MOD_TRANSCODE, SEV_INFO) << "Setting bitrate for stream idx " << _inputStreams[type] << " to input bitrate (" << stream.getBitrate() << ")"; + _outputBitrate[type] = stream.getBitrate(); + } + else + { + LMS_LOG(MOD_TRANSCODE, SEV_DEBUG) << "Setting bitrate for stream idx " << _inputStreams[type] << " to " << bitrate; + _outputBitrate[type] = bitrate; + } + return _outputBitrate[type]; + } + else + { + LMS_LOG(MOD_TRANSCODE, SEV_DEBUG) << "Cannot find stream type " << type; + return 0; + } +} + +std::size_t +Parameters::getOutputBitrate(Stream::Type type) const +{ + std::map::const_iterator it = _outputBitrate.find(type); + + if (it != _inputStreams.end()) + { + return it->second; + } + else + { + LMS_LOG(MOD_TRANSCODE, SEV_DEBUG) << "output bitrate not set for type " << type; + return 0; + } } } // namespace Transcode diff --git a/transcode/Parameters.hpp b/transcode/Parameters.hpp index eb7eee00..80560b44 100644 --- a/transcode/Parameters.hpp +++ b/transcode/Parameters.hpp @@ -18,12 +18,12 @@ class Parameters { public: - Parameters(const InputMediaFile& InputFile, const Format& outputFormat, std::size_t audioBitrate); - Parameters(const InputMediaFile& InputFile, const Format& outputFormat, std::size_t audioBitrate, std::size_t videoBitrate); + Parameters(const InputMediaFile& InputFile, const Format& outputFormat); // Modifiers void setOffset(boost::posix_time::time_duration offset) { _offset = offset; } // Set input offset void setOutputFormat(const Format& format) { _outputFormat = format; } + std::size_t setBitrate(Stream::Type type, std::size_t bitrate); // Manually select an input stream to output // There can be only one stream per each type (video, audio, subtitle) @@ -34,8 +34,7 @@ class Parameters { //Accessors boost::posix_time::time_duration getOffset(void) const {return _offset;} const Format& getOutputFormat(void) const { return _outputFormat; } - std::size_t getOutputAudioBitrate(void) const { return _outputAudioBitrate; } - std::size_t getOutputVideoBitrate(void) const { return _outputVideoBitrate; } + std::size_t getOutputBitrate(Stream::Type type) const; const InputMediaFile& getInputMediaFile(void) const { return _mediaFile;} InputMediaFile& getInputMediaFile(void) { return _mediaFile;} @@ -47,8 +46,7 @@ class Parameters { boost::posix_time::time_duration _offset; // start input offset Format _outputFormat; // OGA, OGV, etc. - std::size_t _outputAudioBitrate; // 192000, 128000, etc. - std::size_t _outputVideoBitrate; // 300000, 700000, etc. + std::map _outputBitrate; StreamMap _inputStreams; diff --git a/transcode/Stream.hpp b/transcode/Stream.hpp index 9bc4382d..5425af96 100644 --- a/transcode/Stream.hpp +++ b/transcode/Stream.hpp @@ -20,12 +20,13 @@ class Stream typedef std::size_t Id; - Stream(Id id, Type type, const std::string& lang, const std::string& desc) - : _id(id), _type(type), _language(lang), _desc(desc) {} + Stream(Id id, Type type, std::size_t bitrate, const std::string& lang, const std::string& desc) + : _id(id), _type(type), _bitrate(bitrate), _language(lang), _desc(desc) {} // Accessors Id getId() const { return _id;} Type getType() const { return _type;} + std::size_t getBitrate() const { return _bitrate;} const std::string& getLanguage() const { return _language;} const std::string& getDesc() const { return _desc;} @@ -33,6 +34,7 @@ class Stream Id _id; Type _type; + std::size_t _bitrate; std::string _language; std::string _desc; diff --git a/ui/audio/AudioWidget.cpp b/ui/audio/AudioWidget.cpp index 16b4fca6..3bafe42b 100644 --- a/ui/audio/AudioWidget.cpp +++ b/ui/audio/AudioWidget.cpp @@ -57,7 +57,9 @@ AudioWidget::playTrack(boost::filesystem::path p) Transcode::InputMediaFile inputFile(p); // TODO get the input stream bitrate and min the result with the desired bitrate - Transcode::Parameters parameters(inputFile, Transcode::Format::get(Transcode::Format::OGA), bitrate); + Transcode::Parameters parameters(inputFile, Transcode::Format::get(Transcode::Format::OGA)); + + parameters.setBitrate(Transcode::Stream::Audio, bitrate); _mediaPlayer->load( parameters ); diff --git a/ui/video/VideoWidget.cpp b/ui/video/VideoWidget.cpp index 39758cb0..d5356a2b 100644 --- a/ui/video/VideoWidget.cpp +++ b/ui/video/VideoWidget.cpp @@ -51,7 +51,10 @@ VideoWidget::playVideo(boost::filesystem::path p) else encoding = Transcode::Format::FLV; - Transcode::Parameters parameters(inputFile, Transcode::Format::get(encoding), 128000, 500000); + Transcode::Parameters parameters(inputFile, Transcode::Format::get(encoding)); + + parameters.setBitrate(Transcode::Stream::Audio, 128000); // TODO + parameters.setBitrate(Transcode::Stream::Video, 500000); // TODO _mediaPlayer = new VideoMediaPlayerWidget(parameters, this); _mediaPlayer->close().connect(this, &VideoWidget::backToList);