Merge branch 'v0.22.x'

This commit is contained in:
Max Kellermann 2020-11-16 09:41:20 +01:00
commit fbbbfb9668
10 changed files with 167 additions and 5 deletions

4
NEWS
View File

@ -5,6 +5,10 @@ ver 0.23 (not yet released)
ver 0.22.4 (not yet released)
* decoder
- dsdiff: apply padding to odd-sized chunks
* filter
- ffmpeg: detect the output sample format
* output
- moveoutput: fix always_on and tag lost on move
ver 0.22.3 (2020/11/06)
* playlist

View File

@ -183,9 +183,8 @@ handle_moveoutput(Client &client, Request request, Response &response)
existing_output->ReplaceDummy(output->Steal(),
was_enabled);
else
/* add it to the output list */
dest_partition.outputs.Add(output->Steal(),
was_enabled);
/* copy the AudioOutputControl and add it to the output list */
dest_partition.outputs.AddCopy(output,was_enabled);
instance.EmitIdle(IDLE_OUTPUT);
return CommandResult::OK;

View File

@ -23,6 +23,7 @@
#include "filter/Filter.hxx"
#include "filter/Prepared.hxx"
#include "lib/ffmpeg/Filter.hxx"
#include "lib/ffmpeg/DetectFilterFormat.hxx"
#include "config/Block.hxx"
class PreparedFfmpegFilter final : public PreparedFilter {
@ -60,7 +61,9 @@ PreparedFfmpegFilter::Open(AudioFormat &in_audio_format)
graph.CheckAndConfigure();
auto out_audio_format = in_audio_format; // TODO
const auto out_audio_format =
Ffmpeg::DetectFilterOutputFormat(in_audio_format, *buffer_src,
*buffer_sink);
return std::make_unique<FfmpegFilter>(in_audio_format,
out_audio_format,

View File

@ -0,0 +1,76 @@
/*
* Copyright 2003-2020 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "DetectFilterFormat.hxx"
#include "Frame.hxx"
#include "SampleFormat.hxx"
#include "pcm/Silence.hxx"
#include "pcm/CheckAudioFormat.hxx"
#include "util/WritableBuffer.hxx"
extern "C" {
#include <libavfilter/buffersrc.h>
#include <libavfilter/buffersink.h>
}
#include <cassert>
namespace Ffmpeg {
AudioFormat
DetectFilterOutputFormat(const AudioFormat &in_audio_format,
AVFilterContext &buffer_src,
AVFilterContext &buffer_sink)
{
uint_least64_t silence[MAX_CHANNELS];
const size_t silence_size = in_audio_format.GetFrameSize();
assert(sizeof(silence) >= silence_size);
PcmSilence(WritableBuffer<void>{&silence, silence_size},
in_audio_format.format);
Frame frame;
frame->format = ToFfmpegSampleFormat(in_audio_format.format);
frame->sample_rate = in_audio_format.sample_rate;
frame->channels = in_audio_format.channels;
frame->nb_samples = 1;
frame.GetBuffer();
memcpy(frame.GetData(0), silence, silence_size);
int err = av_buffersrc_add_frame(&buffer_src, frame.get());
if (err < 0)
throw MakeFfmpegError(err, "av_buffersrc_add_frame() failed");
frame.Unref();
err = av_buffersink_get_frame(&buffer_sink, frame.get());
if (err < 0)
throw MakeFfmpegError(err, "av_buffersink_get_frame() failed");
const SampleFormat sample_format = FromFfmpegSampleFormat(AVSampleFormat(frame->format));
if (sample_format == SampleFormat::UNDEFINED)
throw std::runtime_error("Unsupported FFmpeg sample format");
return CheckAudioFormat(frame->sample_rate, sample_format,
frame->channels);
}
} // namespace Ffmpeg

View File

@ -0,0 +1,46 @@
/*
* Copyright 2003-2020 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_FFMPEG_DETECT_FILTER_FORMAT_HXX
#define MPD_FFMPEG_DETECT_FILTER_FORMAT_HXX
struct AVFilterContext;
struct AudioFormat;
namespace Ffmpeg {
/**
* Attempt to detect the output format of the given FFmpeg filter by
* sending one frame of silence and checking what format comes back
* from the filter.
*
* This is a kludge because MPD needs to know the output format of a
* filter while initializing and cannot cope with format changes in
* between.
*
* This function can throw if the FFmpeg filter fails.
*/
AudioFormat
DetectFilterOutputFormat(const AudioFormat &in_audio_format,
AVFilterContext &buffer_src,
AVFilterContext &buffer_sink);
} // namespace Ffmpeg
#endif

View File

@ -20,7 +20,10 @@ endif
ffmpeg_sources = []
if libavfilter_dep.found()
ffmpeg_sources += 'Filter.cxx'
ffmpeg_sources += [
'Filter.cxx',
'DetectFilterFormat.cxx',
]
endif
ffmpeg = static_library(

View File

@ -39,6 +39,17 @@ AudioOutputControl::AudioOutputControl(std::unique_ptr<FilteredAudioOutput> _out
{
}
AudioOutputControl::AudioOutputControl(AudioOutputControl *_output,
AudioOutputClient &_client) noexcept
:output(_output->Steal()),
name(output->GetName()),
client(_client),
thread(BIND_THIS_METHOD(Task))
{
tags =_output->tags;
always_on=_output->always_on;
}
AudioOutputControl::~AudioOutputControl() noexcept
{
StopThread();

View File

@ -245,6 +245,9 @@ public:
AudioOutputControl(std::unique_ptr<FilteredAudioOutput> _output,
AudioOutputClient &_client) noexcept;
AudioOutputControl(AudioOutputControl *_outputControl,
AudioOutputClient &_client) noexcept;
~AudioOutputControl() noexcept;
AudioOutputControl(const AudioOutputControl &) = delete;

View File

@ -140,6 +140,19 @@ MultipleOutputs::Add(std::unique_ptr<FilteredAudioOutput> output,
client.ApplyEnabled();
}
void
MultipleOutputs::AddCopy(AudioOutputControl *outputControl,
bool enable) noexcept
{
// TODO: this operation needs to be protected with a mutex
outputs.emplace_back(std::make_unique<AudioOutputControl>(outputControl,
client));
outputs.back()->LockSetEnabled(enable);
client.ApplyEnabled();
}
void
MultipleOutputs::EnableDisable()
{

View File

@ -128,6 +128,10 @@ public:
void Add(std::unique_ptr<FilteredAudioOutput> output,
bool enable) noexcept;
void AddCopy(AudioOutputControl *outputControl,
bool enable) noexcept;
void SetReplayGainMode(ReplayGainMode mode) noexcept;
/**