diff --git a/NEWS b/NEWS index 1b57dd4c1..d9ba7a9f8 100644 --- a/NEWS +++ b/NEWS @@ -54,6 +54,11 @@ ver 0.20 (not yet released) * update - apply .mpdignore matches to subdirectories +ver 0.19.20 (not yet released) +* decoder + - ffmpeg: ignore empty packets + - sidplay: fix playback speed with libsidplayfp + ver 0.19.19 (2016/08/23) * decoder - ffmpeg: bug fix for FFmpeg 3.1 support diff --git a/doc/mpdconf.example b/doc/mpdconf.example index 7f9dddecb..2609c38c1 100644 --- a/doc/mpdconf.example +++ b/doc/mpdconf.example @@ -165,7 +165,7 @@ # Permissions ################################################################# # # If this setting is set, MPD will require password authorization. The password -# can setting can be specified multiple times for different password profiles. +# setting can be specified multiple times for different password profiles. # #password "password@read,add,control,admin" # diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx index ddc0083d0..ba23cf0cb 100644 --- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx +++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx @@ -757,7 +757,7 @@ FfmpegDecode(Decoder &decoder, InputStream &input, FfmpegCheckTag(decoder, input, format_context, audio_stream); #endif - if (packet.stream_index == audio_stream) { + if (packet.size > 0 && packet.stream_index == audio_stream) { cmd = ffmpeg_send_packet(decoder, input, packet, *codec_context, diff --git a/src/decoder/plugins/SidplayDecoderPlugin.cxx b/src/decoder/plugins/SidplayDecoderPlugin.cxx index 68ef618e0..6b24aaa4e 100644 --- a/src/decoder/plugins/SidplayDecoderPlugin.cxx +++ b/src/decoder/plugins/SidplayDecoderPlugin.cxx @@ -357,12 +357,19 @@ sidplay_file_decode(Decoder &decoder, Path path_fs) DecoderCommand cmd; do { short buffer[4096]; - size_t nbytes; - nbytes = player.play(buffer, ARRAY_SIZE(buffer)); - if (nbytes == 0) + const auto result = player.play(buffer, ARRAY_SIZE(buffer)); + if (result <= 0) break; +#ifdef HAVE_SIDPLAYFP + /* libsidplayfp returns the number of samples */ + const size_t nbytes = result * sizeof(buffer[0]); +#else + /* libsidplay2 returns the number of bytes */ + const size_t nbytes = result; +#endif + decoder_timestamp(decoder, (double)player.time() / timebase); cmd = decoder_data(decoder, nullptr, buffer, nbytes, 0); @@ -379,12 +386,9 @@ sidplay_file_decode(Decoder &decoder, Path path_fs) } /* ignore data until target time is reached */ - while(data_time 0) data_time = player.time(); - } decoder_command_finished(decoder); } diff --git a/src/storage/CompositeStorage.cxx b/src/storage/CompositeStorage.cxx index b1655d0bf..e28cb487a 100644 --- a/src/storage/CompositeStorage.cxx +++ b/src/storage/CompositeStorage.cxx @@ -266,22 +266,13 @@ CompositeStorage::FindStorage(const char *uri) const return result; } -CompositeStorage::FindResult -CompositeStorage::FindStorage(const char *uri, Error &error) const -{ - auto result = FindStorage(uri); - if (result.directory == nullptr) - error.Set(composite_domain, "No such directory"); - return result; -} - bool CompositeStorage::GetInfo(const char *uri, bool follow, StorageFileInfo &info, Error &error) { const ScopeLock protect(mutex); - auto f = FindStorage(uri, error); + auto f = FindStorage(uri); if (f.directory->storage != nullptr && f.directory->storage->GetInfo(f.uri, follow, info, error)) return true; @@ -296,6 +287,7 @@ CompositeStorage::GetInfo(const char *uri, bool follow, StorageFileInfo &info, return true; } + error.Set(composite_domain, "No such directory"); return false; } @@ -305,13 +297,15 @@ CompositeStorage::OpenDirectory(const char *uri, { const ScopeLock protect(mutex); - auto f = FindStorage(uri, error); + auto f = FindStorage(uri); const Directory *directory = f.directory->Find(f.uri); if (directory == nullptr || directory->children.empty()) { /* no virtual directories here */ - if (f.directory->storage == nullptr) + if (f.directory->storage == nullptr) { + error.Set(composite_domain, "No such directory"); return nullptr; + } return f.directory->storage->OpenDirectory(f.uri, error); } diff --git a/src/storage/CompositeStorage.hxx b/src/storage/CompositeStorage.hxx index 89d2f90d3..05d6b3130 100644 --- a/src/storage/CompositeStorage.hxx +++ b/src/storage/CompositeStorage.hxx @@ -44,7 +44,7 @@ class CompositeStorage final : public Storage { */ struct Directory { /** - * The #Storage mounted n this virtual directory. All + * The #Storage mounted in this virtual directory. All * "leaf" Directory instances must have a #Storage. * Other Directory instances may have one, and child * mounts will be "mixed" in. @@ -154,9 +154,16 @@ private: } } + /** + * Follow the given URI path, and find the outermost directory + * which is a #Storage mount point. If there are no mounts, + * it returns the root directory (with a nullptr "storage" + * attribute, of course). FindResult::uri contains the + * remaining unused part of the URI (may be empty if all of + * the URI was used). + */ gcc_pure FindResult FindStorage(const char *uri) const; - FindResult FindStorage(const char *uri, Error &error) const; const char *MapToRelativeUTF8(const Directory &directory, const char *uri) const; diff --git a/src/tag/TagItem.hxx b/src/tag/TagItem.hxx index 7e212146b..ad9eaa773 100644 --- a/src/tag/TagItem.hxx +++ b/src/tag/TagItem.hxx @@ -34,13 +34,14 @@ struct TagItem { /** * the value of this tag; this is a variable length string */ - char value[sizeof(long) - sizeof(type)]; + char value[1]; TagItem() = default; TagItem(const TagItem &other) = delete; TagItem &operator=(const TagItem &other) = delete; }; +static_assert(sizeof(TagItem) == 2, "Unexpected size"); static_assert(alignof(TagItem) == 1, "Unexpected alignment"); #endif