Precache the first and last parts of Google Drive MP3s to reduce the

number of requests when using accurate tagging.
This commit is contained in:
John Maguire 2012-07-30 13:41:29 +02:00
parent fd1d70c644
commit 08286102da
3 changed files with 50 additions and 8 deletions

View File

@ -1,16 +1,16 @@
/* This file is part of Clementine.
Copyright 2012, David Sansome <me@davidsansome.com>
Clementine 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 3 of the License, or
(at your option) any later version.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
@ -25,7 +25,11 @@
#include <taglib/id3v2framefactory.h>
#include <taglib/mpegfile.h>
using TagLib::ByteVector;
namespace {
static const int kTaglibPrefixCacheBytes = 64 * 1024; // Should be enough.
static const int kTaglibSuffixCacheBytes = 2 * 1024;
}
GoogleDriveStream::GoogleDriveStream(
const QUrl& url, const QString& filename, const long length,
@ -37,7 +41,8 @@ GoogleDriveStream::GoogleDriveStream(
auth_(auth),
cursor_(0),
network_(network),
cache_(length) {
cache_(length),
num_requests_(0) {
}
TagLib::FileName GoogleDriveStream::name() const {
@ -68,6 +73,25 @@ TagLib::ByteVector GoogleDriveStream::GetCached(int start, int end) {
return ret;
}
void GoogleDriveStream::Precache() {
// For reading the tags of an MP3, TagLib tends to request:
// 1. The first 1024 bytes
// 2. Somewhere between the first 2KB and first 60KB
// 3. The last KB or two.
// 4. Somewhere in the first 64KB again
//
// So, if we precache the first 64KB and the last 2KB we should be sorted :-)
// Ideally, we would use bytes=0-655364,-2048 but Google Drive does not seem
// to support multipart byte ranges yet so we have to make do with two
// requests.
seek(0, TagLib::IOStream::Beginning);
readBlock(kTaglibPrefixCacheBytes);
seek(kTaglibSuffixCacheBytes, TagLib::IOStream::End);
readBlock(kTaglibSuffixCacheBytes);
clear();
}
TagLib::ByteVector GoogleDriveStream::readBlock(ulong length) {
const uint start = cursor_;
const uint end = qMin(cursor_ + length - 1, length_ - 1);
@ -89,6 +113,7 @@ TagLib::ByteVector GoogleDriveStream::readBlock(ulong length) {
"Range", QString("bytes=%1-%2").arg(start).arg(end).toUtf8());
QNetworkReply* reply = network_->get(request);
++num_requests_;
QEventLoop loop;
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
@ -103,11 +128,11 @@ TagLib::ByteVector GoogleDriveStream::readBlock(ulong length) {
return bytes;
}
void GoogleDriveStream::writeBlock(const ByteVector&) {
void GoogleDriveStream::writeBlock(const TagLib::ByteVector&) {
qLog(Debug) << Q_FUNC_INFO << "not implemented";
}
void GoogleDriveStream::insert(const ByteVector&, ulong, ulong) {
void GoogleDriveStream::insert(const TagLib::ByteVector&, ulong, ulong) {
qLog(Debug) << Q_FUNC_INFO << "not implemented";
}

View File

@ -47,6 +47,17 @@ class GoogleDriveStream : public TagLib::IOStream {
virtual long length();
virtual void truncate(long);
google::sparsetable<char>::size_type cached_bytes() const {
return cache_.num_nonempty();
}
int num_requests() const {
return num_requests_;
}
// Use educated guess to request the bytes that TagLib will probably want.
void Precache();
private:
bool CheckCache(int start, int end);
void FillCache(int start, TagLib::ByteVector data);
@ -63,6 +74,7 @@ class GoogleDriveStream : public TagLib::IOStream {
QNetworkAccessManager* network_;
google::sparsetable<char> cache_;
int num_requests_;
};
#endif // GOOGLEDRIVESTREAM_H

View File

@ -616,10 +616,11 @@ void TagReaderWorker::ReadGoogleDrive(const QUrl& download_url,
GoogleDriveStream* stream = new GoogleDriveStream(
download_url, title, size, access_token, network_);
stream->Precache();
TagLib::MPEG::File tag(
stream, // Takes ownership.
TagLib::ID3v2::FrameFactory::instance(),
TagLib::AudioProperties::Fast);
TagLib::AudioProperties::Accurate);
if (tag.tag()) {
song->set_title(tag.tag()->title().toCString(true));
song->set_artist(tag.tag()->artist().toCString(true));
@ -631,6 +632,10 @@ void TagReaderWorker::ReadGoogleDrive(const QUrl& download_url,
if (tag.audioProperties()) {
song->set_length_nanosec(tag.audioProperties()->length() * kNsecPerSec);
}
qLog(Debug) << "Google Drive Tagging Stats for:"
<< song->title().c_str();
qLog(Debug) << "Downloaded bytes:" << stream->cached_bytes()
<< "Number of requests:" << stream->num_requests();
}
}
#endif // HAVE_GOOGLE_DRIVE