diff --git a/NEWS b/NEWS index 5976541d8..ac9ca0788 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,8 @@ ver 0.21 (not yet released) ver 0.20.11 (not yet released) * storage - curl: support Content-Type application/xml +* decoder + - ffmpeg: more reliable song duration ver 0.20.10 (2017/08/24) * decoder diff --git a/doc/user.xml b/doc/user.xml index c5c7d341b..e010d5e3e 100644 --- a/doc/user.xml +++ b/doc/user.xml @@ -2991,6 +2991,60 @@ run +
+ <varname>opus</varname> + + + Encodes into Ogg Opus. + + + + + + + Setting + Description + + + + + + bitrate + + + Sets the data rate in bit per second. The special + value "auto" lets libopus + choose a rate (which is the default), and "max" uses + the maximum possible data rate. + + + + + + complexity + + + Sets the Opus + complexity. + + + + + + signal + + + Sets the Opus signal type. Valid values are "auto" + (the default), "voice" and "music". + + + + + +
+
<varname>vorbis</varname> diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx index a035e058c..73d18e4ce 100644 --- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx +++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx @@ -712,7 +712,9 @@ FfmpegDecode(DecoderClient &client, InputStream &input, #endif const SignedSongTime total_time = - FromFfmpegTimeChecked(av_stream.duration, av_stream.time_base); + av_stream.duration != (int64_t)AV_NOPTS_VALUE + ? FromFfmpegTimeChecked(av_stream.duration, av_stream.time_base) + : FromFfmpegTimeChecked(format_context.duration, AV_TIME_BASE_Q); client.Ready(audio_format, input.IsSeekable(), total_time); @@ -842,6 +844,10 @@ FfmpegScanStream(AVFormatContext &format_context, tag_handler_invoke_duration(handler, handler_ctx, FromFfmpegTime(stream.duration, stream.time_base)); + else if (format_context.duration != (int64_t)AV_NOPTS_VALUE) + tag_handler_invoke_duration(handler, handler_ctx, + FromFfmpegTime(format_context.duration, + AV_TIME_BASE_Q)); FfmpegScanMetadata(format_context, audio_stream, handler, handler_ctx); diff --git a/src/output/plugins/SndioOutputPlugin.cxx b/src/output/plugins/SndioOutputPlugin.cxx index 1ae92f1bf..285882665 100644 --- a/src/output/plugins/SndioOutputPlugin.cxx +++ b/src/output/plugins/SndioOutputPlugin.cxx @@ -66,16 +66,14 @@ SndioOutput::Create(EventLoop &, const ConfigBlock &block) { static bool sndio_test_default_device() { - struct sio_hdl *sio_hdl; - - sio_hdl = sio_open(SIO_DEVANY, SIO_PLAY, 0); - if (!sio_hdl) { + auto *hdl = sio_open(SIO_DEVANY, SIO_PLAY, 0); + if (!hdl) { FormatError(sndio_output_domain, - "Error opening default sndio device"); + "Error opening default sndio device"); return false; } - sio_close(sio_hdl); + sio_close(hdl); return true; } @@ -85,8 +83,8 @@ SndioOutput::Open(AudioFormat &audio_format) struct sio_par par; unsigned bits, rate, chans; - sio_hdl = sio_open(device, SIO_PLAY, 0); - if (!sio_hdl) + hdl = sio_open(device, SIO_PLAY, 0); + if (!hdl) throw std::runtime_error("Failed to open default sndio device"); switch (audio_format.format) { @@ -116,9 +114,9 @@ SndioOutput::Open(AudioFormat &audio_format) par.le = SIO_LE_NATIVE; par.appbufsz = rate * buffer_time / 1000; - if (!sio_setpar(sio_hdl, &par) || - !sio_getpar(sio_hdl, &par)) { - sio_close(sio_hdl); + if (!sio_setpar(hdl, &par) || + !sio_getpar(hdl, &par)) { + sio_close(hdl); throw std::runtime_error("Failed to set/get audio params"); } @@ -128,21 +126,21 @@ SndioOutput::Open(AudioFormat &audio_format) par.pchan != chans || par.sig != 1 || par.le != SIO_LE_NATIVE) { - sio_close(sio_hdl); + sio_close(hdl); throw std::runtime_error("Requested audio params cannot be satisfied"); } // Set volume after opening fresh audio stream which does // know nothing about previous audio streams. - sio_setvol(sio_hdl, raw_volume); + sio_setvol(hdl, raw_volume); // sio_onvol returns 0 if no volume knob is available. // This is the case on raw audio devices rather than // the sndiod audio server. - if (sio_onvol(sio_hdl, VolumeCallback, this) == 0) + if (sio_onvol(hdl, VolumeCallback, this) == 0) raw_volume = -1; - if (!sio_start(sio_hdl)) { - sio_close(sio_hdl); + if (!sio_start(hdl)) { + sio_close(hdl); throw std::runtime_error("Failed to start audio device"); } } @@ -150,7 +148,7 @@ SndioOutput::Open(AudioFormat &audio_format) void SndioOutput::Close() noexcept { - sio_close(sio_hdl); + sio_close(hdl); } size_t @@ -158,15 +156,16 @@ SndioOutput::Play(const void *chunk, size_t size) { size_t n; - n = sio_write(sio_hdl, chunk, size); - if (n == 0 && sio_eof(sio_hdl) != 0) + n = sio_write(hdl, chunk, size); + if (n == 0 && sio_eof(hdl) != 0) throw std::runtime_error("sndio write failed"); return n; } void -SndioOutput::SetVolume(unsigned int volume) { - sio_setvol(sio_hdl, volume * SIO_MAXVOL / 100); +SndioOutput::SetVolume(unsigned int volume) +{ + sio_setvol(hdl, volume * SIO_MAXVOL / 100); } static inline unsigned int diff --git a/src/output/plugins/SndioOutputPlugin.hxx b/src/output/plugins/SndioOutputPlugin.hxx index f98c07489..848918898 100644 --- a/src/output/plugins/SndioOutputPlugin.hxx +++ b/src/output/plugins/SndioOutputPlugin.hxx @@ -30,7 +30,7 @@ class SndioOutput final : AudioOutput { MixerListener *listener = nullptr; const char *const device; const unsigned buffer_time; /* in ms */ - struct sio_hdl *sio_hdl; + struct sio_hdl *hdl; int raw_volume; public: