Example #1
0
Tag::Tag(const QString &filename)
    : m_filename(filename)
{
    TagLib::MPEG::File mpegfile(filename.toLocal8Bit().constData());
    TagLib::ID3v2::Tag* id3v2 = mpegfile.ID3v2Tag();
    if (id3v2 && !id3v2->isEmpty()) {
        readRegularTag(id3v2, m_data);

        int picnum = 0;

        TagLib::ID3v2::FrameList frames = id3v2->frameListMap()["APIC"]; // attached picture
        TagLib::ID3v2::FrameList::ConstIterator it = frames.begin();
        while (it != frames.end()) {
            TagLib::ID3v2::AttachedPictureFrame* apic = static_cast<TagLib::ID3v2::AttachedPictureFrame*>(*it);
            TagLib::ByteVector bytes = apic->picture();
            QImage img = QImage::fromData(reinterpret_cast<const uchar*>(bytes.data()), bytes.size());
            if (!img.isNull()) {
                m_data[QLatin1String("picture") + QString::number(picnum++)] = QVariant(img);
            }
            ++it;
        }

    } else {
        TagLib::FileRef fileref(filename.toLocal8Bit().constData());
        if (fileref.isNull())
            return;
        TagLib::Tag* tag = fileref.tag();
        if (!tag || tag->isEmpty())
            return;

        readRegularTag(tag, m_data);
    }
}
Example #2
0
bool writeFileFromVector(const char *path, const TagLib::ByteVector &v) {
  std::ofstream o(path, std::ofstream::binary);
  if (!o) {
    return false;
  }
  o.write(v.data(), v.size());
  return true;
}
Example #3
0
/*
** Write cover data to file.
**
*/
bool CCover::WriteCover(const TagLib::ByteVector& data, const std::wstring& target)
{
	bool written = false;

	FILE* f = _wfopen(target.c_str(), L"wb");
	if (f)
	{
		written = (fwrite(data.data(), 1, data.size(), f) == data.size());
		fclose(f);
	}

	return written;
}
Example #4
0
TagLib::ByteVector CloudStream::readBlock(ulong length) {
  const uint start = cursor_;
  const uint end = qMin(cursor_ + length - 1, length_ - 1);

  if (end < start) {
    return TagLib::ByteVector();
  }

  if (CheckCache(start, end)) {
    TagLib::ByteVector cached = GetCached(start, end);
    cursor_ += cached.size();
    return cached;
  }

  QNetworkRequest request = QNetworkRequest(url_);
  if (!auth_.isEmpty()) {
    request.setRawHeader("Authorization", auth_.toUtf8());
  }
  request.setRawHeader("Range",
                       QString("bytes=%1-%2").arg(start).arg(end).toUtf8());
  request.setAttribute(QNetworkRequest::CacheLoadControlAttribute,
                       QNetworkRequest::AlwaysNetwork);
  // The Ubuntu One server applies the byte range to the gzipped data, rather
  // than the raw data so we must disable compression.
  if (url_.host() == "files.one.ubuntu.com") {
    request.setRawHeader("Accept-Encoding", "identity");
  }

  QNetworkReply* reply = network_->get(request);
  connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
          SLOT(SSLErrors(QList<QSslError>)));
  ++num_requests_;

  QEventLoop loop;
  QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
  loop.exec();
  reply->deleteLater();

  int code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
  if (code >= 400) {
    qLog(Debug) << "Error retrieving url to tag:" << url_;
    return TagLib::ByteVector();
  }

  QByteArray data = reply->readAll();
  TagLib::ByteVector bytes(data.data(), data.size());
  cursor_ += data.size();

  FillCache(start, bytes);
  return bytes;
}
QString extractMBIDFromFile(TagLib::MPEG::File *file)
{
	TagLib::ID3v2::Tag *tag = file->ID3v2Tag();
	TagLib::ID3v2::FrameList ufid = tag->frameListMap()["UFID"];
	if (!ufid.isEmpty()) {
		for (TagLib::ID3v2::FrameList::Iterator i = ufid.begin(); i != ufid.end(); i++) {
			TagLib::ID3v2::UniqueFileIdentifierFrame *frame = dynamic_cast<TagLib::ID3v2::UniqueFileIdentifierFrame *>(*i);
			if (frame && frame->owner() == "http://musicbrainz.org") {
				TagLib::ByteVector id = frame->identifier();
				return QString::fromAscii(id.data(), id.size());
			}
		}
	}
	return QString();
}
Example #6
0
void
CloudStream::FillCache( int start, TagLib::ByteVector data )
{
    for ( int i = 0; i < data.size(); ++i )
    {
        m_cache.set( start + i, data[i] );
    }
}
Example #7
0
TagLib::ByteVector CloudStream::readBlock(ulong length) {
  const uint start = cursor_;
  const uint end = qMin(cursor_ + length - 1, length_ - 1);

  if (end < start) {
    return TagLib::ByteVector();
  }

  if (CheckCache(start, end)) {
    TagLib::ByteVector cached = GetCached(start, end);
    cursor_ += cached.size();
    return cached;
  }

  QNetworkRequest request = QNetworkRequest(url_);
  foreach (const QString& key, headers_) {
      request.setRawHeader(key.toLatin1(), headers_[key].toUtf8());
  }
Example #8
0
/*
** Extracts cover art embedded in APE tags.
**
*/
bool CCover::ExtractAPE(TagLib::APE::Tag* tag, const std::wstring& target)
{
	const TagLib::APE::ItemListMap& listMap = tag->itemListMap();
	if (listMap.contains("COVER ART (FRONT)"))
	{
		const TagLib::ByteVector nullStringTerminator(1, 0);

		TagLib::ByteVector item = listMap["COVER ART (FRONT)"].value();
		int pos = item.find(nullStringTerminator);	// Skip the filename

		if (++pos > 0)
		{
			const TagLib::ByteVector& pic = item.mid(pos);
			return WriteCover(pic, target);
		}
	}

	return false;
}
Example #9
0
bool CoverUtils::coverFromXiphComment(TagLib::Ogg::XiphComment *xiphComment, Album *album) {

    if (!xiphComment) return false;

    const TagLib::StringList &stringList = xiphComment->fieldListMap()["COVERART"];
    if (stringList.isEmpty()) return false;
    TagLib::ByteVector byteVector = stringList.front().data(TagLib::String::Latin1);

    QByteArray encodedData;
    encodedData.setRawData(byteVector.data(), byteVector.size());

    QByteArray data = QByteArray::fromBase64(encodedData);

    QImage image;
    image.loadFromData(data);
    if (!isAcceptableImage(image)) return false;

    qDebug() << "Cover from Xiph!";

    return saveImage(image, album);
}
Example #10
0
/*
** Extracts cover art embedded in APE tags.
**
*/
bool QCoverArt::ExtractAPE(TagLib::APE::Tag* tag)
{
    const TagLib::APE::ItemListMap& listMap = tag->itemListMap();

    if (listMap.contains("COVER ART (FRONT)"))
    {
        const TagLib::ByteVector nullStringTerminator(1, 0);

        TagLib::ByteVector item = listMap["COVER ART (FRONT)"].value();
        int pos = item.find(nullStringTerminator);	// Skip the filename

        if (++pos > 0)
        {
            const TagLib::ByteVector& pic = item.mid(pos);

            img.loadFromData((const unsigned char*)pic.data(), pic.size());
            return true;
        }
    }

    return false;
}
Example #11
0
// NOTE: representation is taken to be a binary value with units in the first column,
//       1/2 in the second and so on.
static qreal readRVA2PeakValue( const TagLib::ByteVector &data, int bits, bool *ok )
{
    qreal peak = 0.0;
    // discarding digits at the end reduces precision, but doesn't otherwise change the value
    if ( bits > 32 )
        bits = 32;
    // the +7 makes sure we round up when we divide by 8
    unsigned int bytes = (bits + 7) / 8;

    // normalize appears not to write a peak at all, and hence sets bits to 0
    if ( bits == 0 )
    {
        if ( ok )
            *ok = true;
    }
    else if ( bits >= 4 && data.size() >= bytes ) // fewer than 4 bits would just be daft
    {
        // excessBits is the number of bits we have to discard at the end
        unsigned int excessBits = (8 * bytes) - bits;
        // mask has 1s everywhere but the last /excessBits/ bits
        quint32 mask = 0xffffffff << excessBits;
        quint32 rawValue = 0;
        for ( unsigned int i = 0; i < bytes; ++i )
        {
            rawValue <<= 8;
            rawValue += (unsigned char)data[i];
        }
        rawValue &= mask;
        peak = rawValue;
        // amount we need to "shift" the value right to make the first digit the unit column
        unsigned int rightShift = (8 * bytes) - 1;
        peak /= (qreal)(1 << rightShift);
        if ( ok )
            *ok = true;
    }
    else
    {
        if ( ok )
            *ok = false;
    }
    return peak;
}
Example #12
0
size_t loadFileIntoVector(const char *path, TagLib::ByteVector &v) 
{
  std::ifstream is(path, std::ifstream::binary);

  if (!is.good()) {
    return 0;
  }

  // get the file size and create an appropriate buffer
  is.seekg(0, is.end); 
  size_t len = is.tellg();
  is.seekg(0, is.beg);

  char *buf = new char[len];

  // read into buffer
  is.read(buf, len);
  v.setData(buf, len);

  is.close();
  delete[] buf;

  return len;
}
Example #13
0
static Meta::ReplayGainTagMap readID3v2Tags( TagLib::ID3v2::Tag *tag )
{
    Meta::ReplayGainTagMap map;
    {   // ID3v2.4.0 native replay gain tag support (as written by Quod Libet, for example).
        TagLib::ID3v2::FrameList frames = tag->frameListMap()["RVA2"];
        frames.append(tag->frameListMap()["XRVA"]);
        if ( !frames.isEmpty() )
        {
            for ( unsigned int i = 0; i < frames.size(); ++i )
            {
                // we have to parse this frame ourselves
                // ID3v2 frame header is 10 bytes, so skip that
                TagLib::ByteVector data = frames[i]->render().mid( 10 );
                unsigned int offset = 0;
                QString desc( data.data() );
                offset += desc.count() + 1;
                unsigned int channel = data.mid( offset, 1 ).toUInt( true );
                // channel 1 is the main volume - the only one we care about
                if ( channel == 1 )
                {
                    ++offset;
                    qint16 adjustment512 = data.mid( offset, 2 ).toShort( true );
                    qreal adjustment = ( (qreal)adjustment512 ) / 512.0;
                    offset += 2;
                    unsigned int peakBits = data.mid( offset, 1 ).toUInt( true );
                    ++offset;
                    bool ok = false;
                    qreal peak = readRVA2PeakValue( data.mid( offset ), peakBits, &ok );
                    if ( ok )
                    {
                        if ( desc.toLower() == "album" )
                        {
                            map[Meta::ReplayGain_Album_Gain] = adjustment;
                            map[Meta::ReplayGain_Album_Peak] = peakToDecibels( peak );
                        }
                        else if ( desc.toLower() == "track" || !map.contains( Meta::ReplayGain_Track_Gain ) )
                        {
                            map[Meta::ReplayGain_Track_Gain] = adjustment;
                            map[Meta::ReplayGain_Track_Peak] = peakToDecibels( peak );
                        }
                    }
                }
            }
            if ( !map.isEmpty() )
                return map;
        }
    }

    {   // Foobar2000-style ID3v2.3.0 tags
        TagLib::ID3v2::FrameList frames = tag->frameListMap()["TXXX"];
        for ( TagLib::ID3v2::FrameList::Iterator it = frames.begin(); it != frames.end(); ++it ) {
            TagLib::ID3v2::UserTextIdentificationFrame* frame =
                dynamic_cast<TagLib::ID3v2::UserTextIdentificationFrame*>( *it );
            if ( frame && frame->fieldList().size() >= 2 )
            {
                QString desc = TStringToQString( frame->description() ).toLower();
                if ( desc == "replaygain_album_gain" )
                    maybeAddGain( frame->fieldList()[1], Meta::ReplayGain_Album_Gain, &map );
                if ( desc == "replaygain_album_peak" )
                    maybeAddPeak( frame->fieldList()[1], Meta::ReplayGain_Album_Peak, &map );
                if ( desc == "replaygain_track_gain" )
                    maybeAddGain( frame->fieldList()[1], Meta::ReplayGain_Track_Gain, &map );
                if ( desc == "replaygain_track_peak" )
                    maybeAddPeak( frame->fieldList()[1], Meta::ReplayGain_Track_Peak, &map );
            }
        }
    }
    return map;
}
Example #14
0
 virtual TagLib::String parse( const TagLib::ByteVector &data ) const
 {
     return QStringToTString( m_codec->toUnicode( data.data(), data.size() ) );
 }
Example #15
0
/*!
 * \brief Write the albumart image to the file
 *
 * \param filename The music file to add the albumart
 * \param albumart The Album Art image to write
 * \returns True if successful
 *
 * \note We always save the image in JPEG format
 */
bool MetaIOID3::writeAlbumArt(const QString &filename,
                              const AlbumArtImage *albumart)
{
    if (filename.isEmpty() || !albumart)
        return false;

    // load the image into a QByteArray
    QImage image(albumart->m_filename);
    QByteArray imageData;
    QBuffer buffer(&imageData);
    buffer.open(QIODevice::WriteOnly);
    image.save(&buffer, "JPEG");

    AttachedPictureFrame::Type type = AttachedPictureFrame::Other;
    switch (albumart->m_imageType)
    {
        case IT_FRONTCOVER:
            type = AttachedPictureFrame::FrontCover;
            break;
        case IT_BACKCOVER:
            type = AttachedPictureFrame::BackCover;
            break;
        case IT_CD:
            type = AttachedPictureFrame::Media;
            break;
        case IT_INLAY:
            type = AttachedPictureFrame::LeafletPage;
            break;
        case IT_ARTIST:
            type = AttachedPictureFrame::Artist;
            break;
        default:
            type = AttachedPictureFrame::Other;
            break;
    }

    if (!OpenFile(filename, true))
        return false;

    TagLib::ID3v2::Tag *tag = GetID3v2Tag();

    if (!tag)
        return false;

    AttachedPictureFrame *apic = findAPIC(tag, type,
                                    QStringToTString(albumart->m_description));

    if (!apic)
    {
        apic = new AttachedPictureFrame();
        tag->addFrame(apic);
        apic->setType(type);
    }

    QString mimetype = "image/jpeg";

    TagLib::ByteVector bytevector;
    bytevector.setData(imageData.data(), imageData.size());

    apic->setMimeType(QStringToTString(mimetype));
    apic->setPicture(bytevector);
    apic->setDescription(QStringToTString(albumart->m_description));

    if (!SaveFile())
        return false;

    return true;
}
Example #16
0
TagLib::ByteVector TagLib::DecodeBase64(const TagLib::ByteVector& input)
{
	SFB::CFError error;
	SFB::SecTransform decoder(SecDecodeTransformCreate(kSecBase64Encoding, &error));
    if(!decoder) {
		LOGGER_WARNING("org.sbooth.AudioEngine", "SecDecodeTransformCreate failed: " << error);
		return {};
	}

	SFB::CFData sourceData(CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)input.data(), (CFIndex)input.size(), kCFAllocatorNull));
	if(!sourceData)
		return {};

    if(!SecTransformSetAttribute(decoder, kSecTransformInputAttributeName, sourceData, &error)) {
		LOGGER_WARNING("org.sbooth.AudioEngine", "SecTransformSetAttribute failed: " << error);
		return {};
	}

	SFB::CFData decodedData((CFDataRef)SecTransformExecute(decoder, &error));
	if(!decodedData)
		return {};

	return {(const char *)CFDataGetBytePtr((CFDataRef)decodedData), (size_t)CFDataGetLength((CFDataRef)decodedData)};
}
TagLib::ByteVector TagLib::EncodeBase64(const TagLib::ByteVector& input)
{
    ByteVector result;

    CFErrorRef error;
    SFB::SecTransform encoder = SecEncodeTransformCreate(kSecBase64Encoding, &error);
    if(nullptr == encoder) {
        LOGGER_WARNING("org.sbooth.AudioEngine", "SecEncodeTransformCreate failed: " << error);
        return TagLib::ByteVector::null;
    }

    SFB::CFData sourceData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)input.data(), (CFIndex)input.size(), kCFAllocatorNull);
    if(!sourceData)
        return TagLib::ByteVector::null;

    if(!SecTransformSetAttribute(encoder, kSecTransformInputAttributeName, sourceData, &error)) {
        LOGGER_WARNING("org.sbooth.AudioEngine", "SecTransformSetAttribute failed: " << error);
        return TagLib::ByteVector::null;
    }

    SFB::CFData encodedData = (CFDataRef)SecTransformExecute(encoder, &error);
    if(!encodedData) {
        LOGGER_WARNING("org.sbooth.AudioEngine", "SecTransformExecute failed: " << error);
        return TagLib::ByteVector::null;
    }

    result.setData((const char *)CFDataGetBytePtr((CFDataRef)encodedData), (TagLib::uint)CFDataGetLength((CFDataRef)encodedData));

    return result;
}
Example #18
0
void MediaScannerThread::run()
{
	if (multiPass)
	{
		qDebug() << "MediaScannerThread: multi non-single pass selected";
		multiPass = false;
		for (int i=0;i<multiPassFileNames.count();i++)
		{
			QString fullPath = multiPassFileNames.at(i);
			TagLib::FileRef testfile(fullPath.toStdString().c_str());
			if (!testfile.isNull())
			{
				ID3Tag *tmpTag = 0;
				if (!tmpTag)
				{
					tmpTag = new ID3Tag();
					tmpTag->valid = false;
				}
				if (TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File *>( testfile.file()))
				{
					if (file->ID3v2Tag(false))
					{
						//Check to see if there are images in the tag
						#ifdef Q_OS_WIN32 //Currently this only works in the windows version of taglib??
						if (!file->ID3v2Tag()->frameListMap()["APIC"].isEmpty())
						{
							TagLib::ID3v2::FrameList frameList = file->ID3v2Tag()->frameListMap()["APIC"];
							TagLib::ID3v2::FrameList::Iterator iter;
							for( iter = frameList.begin(); iter != frameList.end(); ++iter )
							{
								TagLib::ID3v2::AttachedPictureFrame::Type t = (((TagLib::ID3v2::AttachedPictureFrame*)*iter))->type();
								if (t == TagLib::ID3v2::AttachedPictureFrame::Type::FrontCover)
								{
									TagLib::ByteVector pic = (((TagLib::ID3v2::AttachedPictureFrame*)*iter))->picture();
									QImage tmpPicture;
									tmpPicture.loadFromData((uchar*)pic.data(),pic.size());
									tmpTag->frontcover = tmpPicture;
								}
								else if (t == TagLib::ID3v2::AttachedPictureFrame::Type::BackCover)
								{
									TagLib::ByteVector pic = (((TagLib::ID3v2::AttachedPictureFrame*)*iter))->picture();
									QImage tmpPicture;
									tmpPicture.loadFromData((uchar*)pic.data(),pic.size());
									tmpTag->backcover = tmpPicture;
								}
								
							}
						}
						#endif //Q_OS_WIN32
						TagLib::Tag *tag = testfile.tag();
						if (!tmpTag->valid)
						{
							tmpTag->artist = tag->artist().toCString();
							tmpTag->title = tag->title().toCString();
							tmpTag->filename = fullPath;
							emit tagReceived("",0,tmpTag);
						}	
					}

				}
				else
				{
					TagLib::Tag *tag = testfile.tag();
					if (!tmpTag->valid)
					{
						tmpTag->artist = tag->artist().toCString();
						tmpTag->title = tag->title().toCString();
						tmpTag->filename = fullPath;
						emit tagReceived("",0,tmpTag);
					}
				}
			}
			else
			{
				qDebug() << "MediaScannerThread: Invalid File in multipass" << fullPath;
				int stop = 1;
			}
			QThread::msleep(50);
		}
		multiPassFileNames.clear();
		
	}
	else if (singlePass)
	{
		qDebug() << "MediaScannerThread: Non-multi single pass selected";
		singlePass = false;
		QString fullPath = singlePassFileName;
		TagLib::FileRef testfile(fullPath.toStdString().c_str());
		if (!testfile.isNull())
		{
			TagLib::Tag *tag = testfile.tag();
		//if (tag)
		//{
			ID3Tag *tmpTag = 0;
			if (!tmpTag)
			{
				tmpTag = new ID3Tag();
				tmpTag->valid = false;
			}
			if (!tmpTag->valid)
			{
				tmpTag->artist = tag->artist().toCString();
				tmpTag->title = tag->title().toCString();
				tmpTag->filename = fullPath;
				emit tagReceived("",0,tmpTag);
			}
			//ID3Tag *tmpTag = new ID3Tag();
		}
		else
		{
			qDebug() << "MediaScannerThread: Invalid File in singlepass" << fullPath;
		}

	}
	else
	{
		qDebug() << "MediaScannerThread: Non-multi non-single pass selected";
		bool firstScan = true;
		int delay=0;
		bool anyValid = true;
		while (anyValid)
		{
			anyValid = false;
			if (firstScan)
			{
				delay=0;
				//firstScan = false;
			}
			else
			{	
				delay=20;
			}
			for (int i=0;i<m_playLists->count();i++)
			{
				for (int j=0;j<m_playLists->at(i)->size();j++)
				{

					QString fullPath = m_playLists->at(i)->getFileNum(j)->fullPath();
//					qDebug() << fullPath;
					TagLib::FileRef testfile(fullPath.toStdString().c_str());
					if (!testfile.isNull())
					{
						ID3Tag *tmpTag = m_playLists->at(i)->getFileNum(j)->getId3Tag();
						if (!tmpTag)
						{
							tmpTag = new ID3Tag();
							tmpTag->valid = false;
							anyValid = true;
						}
						if (TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File *>( testfile.file()))
						{
							if (file->ID3v2Tag(false))
							{
								//Check to see if there are images in the tag
								#ifdef Q_OS_WIN32 //Currently this only works in the windows version of taglib??
								if (!file->ID3v2Tag()->frameListMap()["APIC"].isEmpty())
								{
									TagLib::ID3v2::FrameList frameList = file->ID3v2Tag()->frameListMap()["APIC"];
									TagLib::ID3v2::FrameList::Iterator iter;
									for( iter = frameList.begin(); iter != frameList.end(); ++iter )
									{
										TagLib::ID3v2::AttachedPictureFrame::Type t = (((TagLib::ID3v2::AttachedPictureFrame*)*iter))->type();
										if (t == TagLib::ID3v2::AttachedPictureFrame::Type::FrontCover)
										{
											TagLib::ByteVector pic = (((TagLib::ID3v2::AttachedPictureFrame*)*iter))->picture();
											QImage tmpPicture;
											tmpPicture.loadFromData((uchar*)pic.data(),pic.size());
											tmpTag->frontcover = tmpPicture;
										}
										else if (t == TagLib::ID3v2::AttachedPictureFrame::Type::BackCover)
										{
											TagLib::ByteVector pic = (((TagLib::ID3v2::AttachedPictureFrame*)*iter))->picture();
											QImage tmpPicture;
											tmpPicture.loadFromData((uchar*)pic.data(),pic.size());
											tmpTag->backcover = tmpPicture;
										}
										
									}
								}
								#endif
								TagLib::Tag *tag = testfile.tag();
								if (!tmpTag->valid)
								{
									tmpTag->artist = tag->artist().toCString();
									tmpTag->title = tag->title().toCString();
									tmpTag->filename = fullPath;
									emit tagReceived(m_playLists->at(i)->title(),j,tmpTag);
								}	
							}
						}
						else
						{
							TagLib::Tag *tag = testfile.tag();
							if (!tmpTag->valid)
							{
								tmpTag->artist = tag->artist().toCString();
								tmpTag->title = tag->title().toCString();
								tmpTag->valid = true;
								tmpTag->filename = fullPath;
								m_playLists->at(i)->setId3(j,tmpTag);
								anyValid = true;
								emit tagReceived(m_playLists->at(i)->title(),j,tmpTag);
							}
							else
							{
								if (tmpTag->filename != fullPath)
								{
									tmpTag->artist = tag->artist().toCString();
									tmpTag->title = tag->title().toCString();
									tmpTag->filename = fullPath;
									tmpTag->valid = true;
									m_playLists->at(i)->setId3(j,tmpTag);
									anyValid = true;
									emit tagReceived(m_playLists->at(i)->title(),j,tmpTag);								
								}
							}
						}
						//ID3Tag *tmpTag = new ID3Tag();
					}
					else
					{
						qDebug() << "MediaScannerThread: Invalid File in standardpass" << fullPath;
					}
					QThread::msleep(delay);
				}
			}
			if (firstScan)
			{
				firstScan = false;
				qDebug() << "Initial scan of id3 tags completed. ";
				if (anyValid)
				{
					qDebug() << "Moving to background  mode...";
				}
				else
				{
					qDebug() << "All files scanned, exiting thread";
				}
			}
			else
			{
				qDebug() << "Secondary id3 scan complete... continuing...";
			}
		}
	}
	/*
	int done = 1;
	return;
	QFile tmpFile("music.conf");
	if (!tmpFile.open(QIODevice::ReadOnly | QIODevice::Text))
	{	
		printf("Error opening configuration file!!!\n");
		return;
	}
	QString musicDir(tmpFile.readLine());
	printf("Music Directory from configuration file: %s\n",musicDir.toStdString().c_str());
	tmpFile.close();
	musicDir = musicDir.mid(0,musicDir.length()-1);
	QDir tmpDir(musicDir);

	tmpDir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
	QDir tmpFiles(musicDir);
	tmpFiles.setFilter(QDir::Files | QDir::NoDotAndDotDot);
	QStringList infoList = tmpDir.entryList();
	foreach (QString info,infoList)
	{
		TagLib::FileRef testfile(info.toStdString().c_str());
		TagLib::Tag *tag = testfile.tag();
		ID3Tag *tmpTag = new ID3Tag();
		tmpTag->artist = tag->artist().to8Bit().c_str();
		tmpTag->title = tag->title().to8Bit().c_str();
		//emit tagReceived(tmpTag);		
	}
	bool inLoop = true;
	//while (inLoop)
	//{
		//QThread::
	//	QThread::sleep(1);
		
	//	ID3Tag *tmpTag = new ID3Tag();
		//tmpTag->artist = 
		
	//}
	*/
}
TagLib::ByteVector TagLib::DecodeBase64(const TagLib::ByteVector& input)
{
#if USE_SECURITY_FRAMEWORK
	ByteVector result;

	CFErrorRef error;
	SecTransformRef decoder = SecDecodeTransformCreate(kSecBase64Encoding, &error);
    if(nullptr == decoder) {
		CFShow(error); 
		return TagLib::ByteVector::null;
	}

	CFDataRef sourceData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)input.data(), input.size(), kCFAllocatorNull);
	if(nullptr == sourceData) {
		CFRelease(decoder), decoder = nullptr;

		return TagLib::ByteVector::null;
	}

    if(!SecTransformSetAttribute(decoder, kSecTransformInputAttributeName, sourceData, &error)) {
		CFShow(error); 

		CFRelease(sourceData), sourceData = nullptr;
		CFRelease(decoder), decoder = nullptr;

		return TagLib::ByteVector::null;
	}

	CFTypeRef decodedData = SecTransformExecute(decoder, &error);
	if(nullptr == decodedData) {
		CFShow(error); 

		CFRelease(sourceData), sourceData = nullptr;
		CFRelease(decoder), decoder = nullptr;

		return TagLib::ByteVector::null;
	}

	result.setData((const char *)CFDataGetBytePtr((CFDataRef)decodedData), (TagLib::uint)CFDataGetLength((CFDataRef)decodedData));

	CFRelease(decodedData), decodedData = nullptr;
	CFRelease(sourceData), sourceData = nullptr;
	CFRelease(decoder), decoder = nullptr;
	
	return result;
#else
	ByteVector result;

	BIO *b64 = BIO_new(BIO_f_base64());
	BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);

	BIO *bio = BIO_new_mem_buf(reinterpret_cast<void *>(const_cast<char *>(input.data())), input.size());
	bio = BIO_push(b64, bio);

	char inbuf [512];
	int inlen;
	while(0 < (inlen = BIO_read(bio, inbuf, 512)))
		result.append(ByteVector(inbuf, inlen));

	BIO_free_all(bio);
	
	return result;
#endif
}
TagLib::ByteVector TagLib::EncodeBase64(const TagLib::ByteVector& input)
{
#if USE_SECURITY_FRAMEWORK
	ByteVector result;

	CFErrorRef error;
	SecTransformRef encoder = SecEncodeTransformCreate(kSecBase64Encoding, &error);
    if(nullptr == encoder) {
		CFShow(error); 
		return TagLib::ByteVector::null;
	}

	CFDataRef sourceData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)input.data(), input.size(), kCFAllocatorNull);
	if(nullptr == sourceData) {
		CFRelease(encoder), encoder = nullptr;
		
		return TagLib::ByteVector::null;
	}

    if(!SecTransformSetAttribute(encoder, kSecTransformInputAttributeName, sourceData, &error)) {
		CFShow(error); 
		
		CFRelease(sourceData), sourceData = nullptr;
		CFRelease(encoder), encoder = nullptr;
		
		return TagLib::ByteVector::null;
	}

	CFTypeRef encodedData = SecTransformExecute(encoder, &error);
	if(nullptr == encodedData) {
		CFShow(error); 
		
		CFRelease(sourceData), sourceData = nullptr;
		CFRelease(encoder), encoder = nullptr;
		
		return TagLib::ByteVector::null;
	}

	result.setData((const char *)CFDataGetBytePtr((CFDataRef)encodedData), (TagLib::uint)CFDataGetLength((CFDataRef)encodedData));

	CFRelease(encodedData), encodedData = nullptr;
	CFRelease(sourceData), sourceData = nullptr;
	CFRelease(encoder), encoder = nullptr;

	return result;
#else
	ByteVector result;

	BIO *b64 = BIO_new(BIO_f_base64());
	BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);

	BIO *bio = BIO_new(BIO_s_mem());
	bio = BIO_push(b64, bio);
	BIO_write(bio, input.data(), input.size());
	(void)BIO_flush(bio);

	void *mem = nullptr;
	long size = BIO_get_mem_data(bio, &mem);
	if(0 < size)
		result.setData(static_cast<const char *>(mem), static_cast<uint>(size));

	BIO_free_all(bio);

	return result;
#endif
}
Example #21
0
void DSFHeader::parse(const TagLib::ByteVector &data)
{
  if (data.size() < DSD_HEADER_SIZE + FMT_HEADER_SIZE) {
    std::cerr <<"DSFHeader::parse(): header size incorrect" << std::endl;
    return;
  }

  const char *hdr = data.data();
  size_t offset = 0;

  //
  // ******** DSD chunk header ********
  // DSD header chunk should start with "DSD ".
  //
  if (hdr[0] != 'D' || hdr[1] != 'S' || hdr[2] != 'D' || hdr[3] != ' ') 
  {
    std::cerr <<"DSD::Header::parse(): DSD header's first 4 bytes != 'DSD '" << std::endl;
    return;
  }
  offset += 4;
  
  // The next 8 bytes contain the size of DSD header
  // (numerical data is stored in little endian)
  if (data.toLongLong(offset, false) != DSD_HEADER_SIZE)
  {
    std::cerr <<"DSD::Header::parse(): DSD header size is incorrect" << std::endl;
    return;
  }
  offset += LONG_INT_SIZE;

  // The next 8 bytes contains the file size
  d->fileSize = bytesToUInt64(&hdr[0], offset);
  offset += LONG_INT_SIZE;

  // The next 8 bytes contains the offset to id3v2 tag (0 if not exists)
  d->ID3v2Offset = bytesToUInt64(&hdr[0], offset);
  offset += LONG_INT_SIZE;

  // 
  // ********* FMT chunk ********
  //
  // FMT header chunk should start with "fmt ".
  //
  if (hdr[offset] != 'f' || hdr[offset + 1] != 'm' || 
      hdr[offset + 2] != 't' || hdr[offset + 3] != ' ') 
  {
    std::cerr <<"DSD::Header::parse(): FMT header's first 4 bytes != 'fmt '" << std::endl;
    return;
  }
  offset += 4;

  // The next 8 bytes contain the size of FMT header, which should be 52
  if (data.toLongLong(offset, false) != FMT_HEADER_SIZE)
  {
    std::cerr <<"DSD::Header::parse(): FMT header size is incorrect" << std::endl;
    return;
  }
  offset += LONG_INT_SIZE;

  // Format version
  // There's only version 1 for now...
  unsigned int ver = data.toUInt(offset, false);
  if (ver != 1) {
    std::cerr <<"DSD::Header::parse(): format version != 1" << std::endl;
    return;
  }
  d->version = static_cast<Version>(ver);
  offset += INT_SIZE;

  // Format ID
  if (data.toUInt(offset, false) != 0) {
    std::cerr <<"DSD::Header::parse(): format ID != 0" << std::endl;
    return;
  }
  offset += INT_SIZE;

  // Channel Type
  unsigned int ct = data.toUInt(offset, false);
  if (ct < 1 || ct > 7) {
    std::cerr <<"DSD::Header::parse(): channel type out of range" << std::endl;
    return;
  }
  d->channelType = static_cast<ChannelType>(ct);
  offset += INT_SIZE;

  // Channel Num
  d->channelNum = data.toUInt(offset, false);
  if (d->channelNum < MinType || d->channelNum > MaxType) {
    std::cerr <<"DSD::Header::parse(): channel num out of range" << std::endl;
    return;
  }
  offset += INT_SIZE;

  // Sampling frequency
  d->sampleRate = data.toUInt(offset, false);
  if (d->sampleRate != 2822400 && d->sampleRate != 5644800) {
    std::cerr <<"DSD::Header::parse(): invalid sampling frequency" << std::endl;
    return;
  }
  offset += INT_SIZE;

  // Bits per sample
  d->bitsPerSample = data.toUInt(offset, false);
  if (d->bitsPerSample != 1 && d->bitsPerSample != 8) {
    std::cerr <<"DSD::Header::parse(): bits per sample invalid" << std::endl;
    return;
  }
  offset += INT_SIZE;

  // Sample count
  d->sampleCount = bytesToUInt64(&hdr[0], offset);
  offset += LONG_INT_SIZE;

  // Block size per channel
  if (data.toUInt(offset, false) != 4096) {
    std::cerr <<"DSD::Header::parse(): block size != 4096" << std::endl;
    return;
  }
    //offset += 4;

  // Reserved
  // offset += 4;

  d->isValid = true;
}
bool
SetAPETagFromMetadata(const AudioMetadata& metadata, TagLib::APE::Tag *tag, bool setAlbumArt)
{
	if(nullptr == tag)
		return false;

	// Standard tags
	SetAPETag(tag, "ALBUM", metadata.GetAlbumTitle());
	SetAPETag(tag, "ARTIST", metadata.GetArtist());
	SetAPETag(tag, "ALBUMARTIST", metadata.GetAlbumArtist());
	SetAPETag(tag, "COMPOSER", metadata.GetComposer());
	SetAPETag(tag, "GENRE", metadata.GetGenre());
	SetAPETag(tag, "DATE", metadata.GetReleaseDate());
	SetAPETag(tag, "DESCRIPTION", metadata.GetComment());
	SetAPETag(tag, "TITLE", metadata.GetTitle());
	SetAPETagNumber(tag, "TRACKNUMBER", metadata.GetTrackNumber());
	SetAPETagNumber(tag, "TRACKTOTAL", metadata.GetTrackTotal());
	SetAPETagBoolean(tag, "COMPILATION", metadata.GetCompilation());
	SetAPETagNumber(tag, "DISCNUMBER", metadata.GetDiscNumber());
	SetAPETagNumber(tag, "DISCTOTAL", metadata.GetDiscTotal());
	SetAPETagNumber(tag, "BPM", metadata.GetBPM());
	SetAPETagNumber(tag, "RATING", metadata.GetRating());
	SetAPETag(tag, "ISRC", metadata.GetISRC());
	SetAPETag(tag, "MCN", metadata.GetMCN());
	SetAPETag(tag, "TITLESORT", metadata.GetTitleSortOrder());
	SetAPETag(tag, "ALBUMTITLESORT", metadata.GetAlbumTitleSortOrder());
	SetAPETag(tag, "ARTISTSORT", metadata.GetArtistSortOrder());
	SetAPETag(tag, "ALBUMARTISTSORT", metadata.GetAlbumArtistSortOrder());
	SetAPETag(tag, "COMPOSERSORT", metadata.GetComposerSortOrder());
	SetAPETag(tag, "GROUPING", metadata.GetGrouping());

	// Additional metadata
	CFDictionaryRef additionalMetadata = metadata.GetAdditionalMetadata();
	if(nullptr != additionalMetadata) {
		CFIndex count = CFDictionaryGetCount(additionalMetadata);
		
		const void * keys [count];
		const void * values [count];
		
		CFDictionaryGetKeysAndValues(additionalMetadata, reinterpret_cast<const void **>(keys), reinterpret_cast<const void **>(values));
		
		for(CFIndex i = 0; i < count; ++i) {
			CFIndex keySize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(reinterpret_cast<CFStringRef>(keys[i])), kCFStringEncodingASCII);
			char key [keySize + 1];
			
			if(!CFStringGetCString(reinterpret_cast<CFStringRef>(keys[i]), key, keySize + 1, kCFStringEncodingASCII)) {
				LOGGER_ERR("org.sbooth.AudioEngine", "CFStringGetCString failed");
				continue;
			}
			
			SetAPETag(tag, key, reinterpret_cast<CFStringRef>(values[i]));
		}
	}
	
	// ReplayGain info
	SetAPETagDouble(tag, "REPLAYGAIN_REFERENCE_LOUDNESS", metadata.GetReplayGainReferenceLoudness(), CFSTR("%2.1f dB"));
	SetAPETagDouble(tag, "REPLAYGAIN_TRACK_GAIN", metadata.GetReplayGainTrackGain(), CFSTR("%+2.2f dB"));
	SetAPETagDouble(tag, "REPLAYGAIN_TRACK_PEAK", metadata.GetReplayGainTrackPeak(), CFSTR("%1.8f"));
	SetAPETagDouble(tag, "REPLAYGAIN_ALBUM_GAIN", metadata.GetReplayGainAlbumGain(), CFSTR("%+2.2f dB"));
	SetAPETagDouble(tag, "REPLAYGAIN_ALBUM_PEAK", metadata.GetReplayGainAlbumPeak(), CFSTR("%1.8f"));

	// Album art
	if(setAlbumArt) {
		tag->removeItem("Cover Art (Front)");
		tag->removeItem("Cover Art (Back)");
#if 0
		tag->removeItem("METADATA_BLOCK_PICTURE");
#endif

		for(auto attachedPicture : metadata.GetAttachedPictures()) {
			// APE can handle front and back covers natively
			if(AttachedPicture::Type::FrontCover == attachedPicture->GetType() || AttachedPicture::Type::FrontCover == attachedPicture->GetType()) {
				TagLib::ByteVector data;
				
				if(attachedPicture->GetDescription())
					data.append(TagLib::StringFromCFString(attachedPicture->GetDescription()).data(TagLib::String::UTF8));
				data.append('\0');
				data.append(TagLib::ByteVector((const char *)CFDataGetBytePtr(attachedPicture->GetData()), (TagLib::uint)CFDataGetLength(attachedPicture->GetData())));

				if(AttachedPicture::Type::FrontCover == attachedPicture->GetType())
					tag->setData("Cover Art (Front)", data);
				else if(AttachedPicture::Type::BackCover == attachedPicture->GetType())
					tag->setData("Cover Art (Back)", data);
			}
#if 0
			else {
				CGImageSourceRef imageSource = CGImageSourceCreateWithData(attachedPicture->GetData(), nullptr);
				if(nullptr == imageSource)
					return false;

				TagLib::FLAC::Picture picture;
				picture.setData(TagLib::ByteVector((const char *)CFDataGetBytePtr(attachedPicture->GetData()), (TagLib::uint)CFDataGetLength(attachedPicture->GetData())));
				picture.setType(static_cast<TagLib::FLAC::Picture::Type>(attachedPicture->GetType()));
				if(attachedPicture->GetDescription())
					picture.setDescription(TagLib::StringFromCFString(attachedPicture->GetDescription()));

				// Convert the image's UTI into a MIME type
				CFStringRef mimeType = UTTypeCopyPreferredTagWithClass(CGImageSourceGetType(imageSource), kUTTagClassMIMEType);
				if(mimeType) {
					picture.setMimeType(TagLib::StringFromCFString(mimeType));
					CFRelease(mimeType), mimeType = nullptr;
				}

				// Flesh out the height, width, and depth
				CFDictionaryRef imagePropertiesDictionary = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nullptr);
				if(imagePropertiesDictionary) {
					CFNumberRef imageWidth = (CFNumberRef)CFDictionaryGetValue(imagePropertiesDictionary, kCGImagePropertyPixelWidth);
					CFNumberRef imageHeight = (CFNumberRef)CFDictionaryGetValue(imagePropertiesDictionary, kCGImagePropertyPixelHeight);
					CFNumberRef imageDepth = (CFNumberRef)CFDictionaryGetValue(imagePropertiesDictionary, kCGImagePropertyDepth);
					
					int height, width, depth;
					
					// Ignore numeric conversion errors
					CFNumberGetValue(imageWidth, kCFNumberIntType, &width);
					CFNumberGetValue(imageHeight, kCFNumberIntType, &height);
					CFNumberGetValue(imageDepth, kCFNumberIntType, &depth);
					
					picture.setHeight(height);
					picture.setWidth(width);
					picture.setColorDepth(depth);
					
					CFRelease(imagePropertiesDictionary), imagePropertiesDictionary = nullptr;
				}

				TagLib::ByteVector encodedBlock = TagLib::EncodeBase64(picture.render());
				tag->addValue("METADATA_BLOCK_PICTURE", TagLib::String(encodedBlock, TagLib::String::UTF8), false);

				CFRelease(imageSource), imageSource = nullptr;
			}
#endif
		}
	}

	return true;
}
Example #23
0
TagLib::ByteVector
CloudStream::readBlock( ulong length )
{
    const uint start = m_cursor;
    const uint end = qMin( m_cursor + length - 1, m_length - 1 );

    //tDebug( LOGINFO ) << "#### CloudStream : parsing from " << m_url.toString();
    //tDebug( LOGINFO ) << "#### CloudStream : parsing from (encoded) " << m_url.toEncoded().constData();
    if ( end < start )
    {
        return TagLib::ByteVector();
    }

    if ( CheckCache( start, end ) )
    {
        TagLib::ByteVector cached = GetCached( start, end );
        m_cursor += cached.size();
        return cached;
    }

    if ( m_num_requests_in_error > MAX_ALLOW_ERROR_QUERY )
    {
        //precache();
        return TagLib::ByteVector();
    }

    if ( m_refreshUrlEachTime )
    {
        if( !refreshStreamUrl() )
        {
            tDebug( LOGINFO ) << "#### CloudStream : cannot refresh streamUrl for " << m_filename;
        }
    }

    QNetworkRequest request = QNetworkRequest( m_url );

    //setings of specials OAuth (1 or 2) headers
    foreach ( const QString& headerName, m_headers.keys() )
    {
        request.setRawHeader( headerName.toLocal8Bit(), m_headers[headerName].toString().toLocal8Bit() );

    }

    request.setRawHeader( "Range", QString( "bytes=%1-%2" ).arg( start ).arg( end ).toUtf8() );
    request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork );
    // The Ubuntu One server applies the byte range to the gzipped data, rather
    // than the raw data so we must disable compression.
    if ( m_url.host() == "files.one.ubuntu.com" )
    {
        request.setRawHeader( "Accept-Encoding", "identity" );
    }

    tDebug() << "######## CloudStream : HTTP request : ";
    tDebug() << "#### CloudStream : url : "  << request.url();

    m_currentBlocklength = length;
    m_currentStart = start;

    m_reply = m_network->get( request );

    connect( m_reply, SIGNAL( sslErrors( QList<QSslError> ) ), SLOT( SSLErrors( QList<QSslError> ) ) );
    connect( m_reply, SIGNAL( finished() ), this, SLOT( onRequestFinished() ) );

    ++m_num_requests;
    return TagLib::ByteVector();
}