Merge branch 'v0.20.x'

This commit is contained in:
Max Kellermann 2018-02-17 13:37:03 +01:00
commit 60efdce5ff
8 changed files with 91 additions and 35 deletions

5
NEWS
View File

@ -26,6 +26,11 @@ ver 0.21 (not yet released)
- sndio: new mixer plugin
* require GCC 5.0
ver 0.20.18 (not yet released)
* decoder
- flac: improve seeking precision
* fix gapless CUE song transitions
ver 0.20.17 (2018/02/11)
* output
- alsa: fix crash bug with 8 channels

View File

@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.musicpd"
android:installLocation="auto"
android:versionCode="16"
android:versionName="0.20.17">
android:versionCode="17"
android:versionName="0.20.18">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17"/>

View File

@ -293,6 +293,7 @@ DecoderBridge::CommandFinished()
initial_seek_running = false;
timestamp = dc.start_time.ToDoubleS();
absolute_frame = dc.start_time.ToScale<uint64_t>(dc.in_audio_format.sample_rate);
return;
}
@ -312,6 +313,7 @@ DecoderBridge::CommandFinished()
convert->Reset();
timestamp = dc.seek_time.ToDoubleS();
absolute_frame = dc.seek_time.ToScale<uint64_t>(dc.in_audio_format.sample_rate);
}
dc.command = DecoderCommand::NONE;
@ -420,6 +422,7 @@ DecoderBridge::SubmitTimestamp(double t)
assert(t >= 0);
timestamp = t;
absolute_frame = uint64_t(t * dc.in_audio_format.sample_rate);
}
DecoderCommand
@ -455,6 +458,29 @@ DecoderBridge::SubmitData(InputStream *is,
return cmd;
}
cmd = DecoderCommand::NONE;
const size_t frame_size = dc.in_audio_format.GetFrameSize();
size_t data_frames = length / frame_size;
if (dc.end_time.IsPositive()) {
/* enforce the given end time */
const uint64_t end_frame =
dc.end_time.ToScale<uint64_t>(dc.in_audio_format.sample_rate);
if (absolute_frame >= end_frame)
return DecoderCommand::STOP;
const uint64_t remaining_frames = end_frame - absolute_frame;
if (data_frames >= remaining_frames) {
/* past the end of the range: truncate this
data submission and stop the decoder */
data_frames = remaining_frames;
length = data_frames * frame_size;
cmd = DecoderCommand::STOP;
}
}
if (convert != nullptr) {
assert(dc.in_audio_format != dc.out_audio_format);
@ -512,15 +538,11 @@ DecoderBridge::SubmitData(InputStream *is,
timestamp += (double)nbytes /
dc.out_audio_format.GetTimeToSize();
if (dc.end_time.IsPositive() &&
timestamp >= dc.end_time.ToDoubleS())
/* the end of this range has been reached:
stop decoding */
return DecoderCommand::STOP;
}
return DecoderCommand::NONE;
absolute_frame += data_frames;
return cmd;
}
DecoderCommand

View File

@ -50,6 +50,11 @@ public:
*/
double timestamp = 0;
/**
* The time stamp of the next data chunk, in PCM frames.
*/
uint64_t absolute_frame = 0;
/**
* Is the initial seek (to the start position of the sub-song)
* pending, or has it been performed already?

View File

@ -24,7 +24,6 @@
#include "config.h"
#include "FlacCommon.hxx"
#include "FlacMetadata.hxx"
#include "util/ConstBuffer.hxx"
#include "Log.hxx"
#include <exception>
@ -143,25 +142,10 @@ FlacDecoder::OnWrite(const FLAC__Frame &frame,
if (!initialized && !OnFirstFrame(frame.header))
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
const auto data = pcm_import.Import(buf, frame.header.blocksize);
chunk = pcm_import.Import(buf, frame.header.blocksize);
unsigned bit_rate = nbytes * 8 * frame.header.sample_rate /
kbit_rate = nbytes * 8 * frame.header.sample_rate /
(1000 * frame.header.blocksize);
auto cmd = GetClient()->SubmitData(GetInputStream(),
data.data, data.size,
bit_rate);
switch (cmd) {
case DecoderCommand::NONE:
case DecoderCommand::START:
break;
case DecoderCommand::STOP:
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
case DecoderCommand::SEEK:
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}

View File

@ -27,6 +27,7 @@
#include "FlacInput.hxx"
#include "FlacPcm.hxx"
#include "../DecoderAPI.hxx"
#include "util/ConstBuffer.hxx"
#include <FLAC/stream_decoder.h>
@ -41,6 +42,12 @@ struct FlacDecoder : public FlacInput {
*/
bool unsupported = false;
/**
* The kbit_rate parameter for the next
* DecoderBridge::SubmitData() call.
*/
uint16_t kbit_rate;
FlacPcmImport pcm_import;
/**
@ -51,6 +58,13 @@ struct FlacDecoder : public FlacInput {
Tag tag;
/**
* Decoded PCM data obtained by our libFLAC write callback.
* If this is non-empty, then DecoderBridge::SubmitData()
* should be called.
*/
ConstBuffer<void> chunk = nullptr;
FlacDecoder(DecoderClient &_client, InputStream &_input_stream)
:FlacInput(_input_stream, &_client) {}

View File

@ -139,19 +139,40 @@ flac_decoder_initialize(FlacDecoder *data, FLAC__StreamDecoder *sd)
return data->initialized;
}
static DecoderCommand
FlacSubmitToClient(DecoderClient &client, FlacDecoder &d) noexcept
{
if (d.tag.IsEmpty() && d.chunk.empty())
return client.GetCommand();
if (!d.tag.IsEmpty()) {
auto cmd = client.SubmitTag(d.GetInputStream(),
std::move(d.tag));
d.tag.Clear();
if (cmd != DecoderCommand::NONE)
return cmd;
}
if (!d.chunk.empty()) {
auto cmd = client.SubmitData(d.GetInputStream(),
d.chunk.data,
d.chunk.size,
d.kbit_rate);
d.chunk = nullptr;
if (cmd != DecoderCommand::NONE)
return cmd;
}
return DecoderCommand::NONE;
}
static void
flac_decoder_loop(FlacDecoder *data, FLAC__StreamDecoder *flac_dec)
{
DecoderClient &client = *data->GetClient();
while (true) {
DecoderCommand cmd;
if (!data->tag.IsEmpty()) {
cmd = client.SubmitTag(data->GetInputStream(),
std::move(data->tag));
data->tag.Clear();
} else
cmd = client.GetCommand();
DecoderCommand cmd = FlacSubmitToClient(client, *data);
if (cmd == DecoderCommand::SEEK) {
FLAC__uint64 seek_sample = client.GetSeekFrame();
@ -160,6 +181,11 @@ flac_decoder_loop(FlacDecoder *data, FLAC__StreamDecoder *flac_dec)
client.CommandFinished();
} else
client.SeekError();
/* FLAC__stream_decoder_seek_absolute()
decodes one frame and may have provided
data to be submitted to the client */
continue;
} else if (cmd == DecoderCommand::STOP)
break;

View File

@ -52,7 +52,7 @@ class OpusEncoder final : public OggEncoder {
ogg_int64_t packetno = 0;
ogg_int64_t granulepos;
ogg_int64_t granulepos = 0;
public:
OpusEncoder(AudioFormat &_audio_format, ::OpusEncoder *_enc);