SoundSource::OpenResult SoundSourceOpus::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) {
    // From opus/opusfile.h
    // On Windows, this string must be UTF-8 (to allow access to
    // files whose names cannot be represented in the current
    // MBCS code page).
    // All other systems use the native character encoding.
#ifdef _WIN32
    QByteArray qBAFilename = getLocalFileName().toUtf8();
#else
    QByteArray qBAFilename = getLocalFileName().toLocal8Bit();
#endif

    int errorCode = 0;

    DEBUG_ASSERT(!m_pOggOpusFile);
    m_pOggOpusFile = op_open_file(qBAFilename.constData(), &errorCode);
    if (!m_pOggOpusFile) {
        qWarning() << "Failed to open OggOpus file:" << getUrlString()
                << "errorCode" << errorCode;
        return OpenResult::FAILED;
    }

    if (!op_seekable(m_pOggOpusFile)) {
        qWarning() << "SoundSourceOpus:"
                << "Stream in"
                << getUrlString()
                << "is not seekable";
        return OpenResult::UNSUPPORTED_FORMAT;
    }

    const int channelCount = op_channel_count(m_pOggOpusFile, kCurrentStreamLink);
    if (0 < channelCount) {
        setChannelCount(channelCount);
    } else {
        qWarning() << "Failed to read channel configuration of OggOpus file:" << getUrlString();
        return OpenResult::FAILED;
    }

    const ogg_int64_t pcmTotal = op_pcm_total(m_pOggOpusFile, kEntireStreamLink);
    if (0 <= pcmTotal) {
        setFrameCount(pcmTotal);
    } else {
        qWarning() << "Failed to read total length of OggOpus file:" << getUrlString();
        return OpenResult::FAILED;
    }

    const opus_int32 bitrate = op_bitrate(m_pOggOpusFile, kEntireStreamLink);
    if (0 < bitrate) {
        setBitrate(bitrate / 1000);
    } else {
        qWarning() << "Failed to determine bitrate of OggOpus file:" << getUrlString();
        return OpenResult::FAILED;
    }

    setSamplingRate(kSamplingRate);

    m_curFrameIndex = getMinFrameIndex();

    return OpenResult::SUCCEEDED;
}
Exemple #2
0
/*
 * et_opus_read_file_info:
 * @file: file to read info from
 * @ETFileInfo: ET_File_Info to put information into
 * @error: a GError or %NULL
 *
 * Read header information of an Opus file.
 *
 * Returns: %TRUE if successful otherwise %FALSE
 */
gboolean
et_opus_read_file_info (GFile *gfile, ET_File_Info *ETFileInfo,
                        GError **error)
{
    OggOpusFile *file;
    const OpusHead* head;
    GFileInfo *info;

    g_return_val_if_fail (gfile != NULL && ETFileInfo != NULL, FALSE);
    g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

    file = et_opus_open_file (gfile, error);

    if (!file)
    {
        g_assert (error == NULL || *error != NULL);
        return FALSE;
    }

    /* FIXME: Improve error-checking. */
    head = op_head (file, -1);
    /* TODO: Read the vendor string from the Vorbis comment? */
    ETFileInfo->version = head->version;
    ETFileInfo->bitrate = op_bitrate (file, -1) / 1000;
    ETFileInfo->mode = head->channel_count;

    /* All Opus audio is encoded at 48 kHz, but the input sample rate can
     * differ, and then input_sample_rate will be set. */
    if (head->input_sample_rate != 0)
    {
        ETFileInfo->samplerate = head->input_sample_rate;
    }
    else
    {
        ETFileInfo->samplerate = 48000;
    }

    ETFileInfo->duration = op_pcm_total (file, -1) / 48000;
    op_free (file);

    info = g_file_query_info (gfile, G_FILE_ATTRIBUTE_STANDARD_SIZE,
                              G_FILE_QUERY_INFO_NONE, NULL, NULL);

    if (info)
    {
        ETFileInfo->size = g_file_info_get_size (info);
        g_object_unref (info);
    }
    else
    {
        ETFileInfo->size = 0;
    }

    g_assert (error == NULL || *error == NULL);
    return TRUE;
}
/*
   Parse the the file to get metadata
 */
Result SoundSourceOpus::parseHeader() {
    int error = 0;

    QByteArray qBAFilename = m_qFilename.toLocal8Bit();

    OggOpusFile *l_ptrOpusFile = op_open_file(qBAFilename.constData(), &error);
    this->setBitrate((int)op_bitrate(l_ptrOpusFile, -1) / 1000);
    this->setSampleRate(48000);
    this->setChannels(2);
    qint64 l_lLength = op_pcm_total(l_ptrOpusFile, -1) * 2;
    this->setDuration(l_lLength / (48000 * 2));
    this->setType("opus");

// If we don't have new enough Taglib we use libopusfile parser!
#if (TAGLIB_MAJOR_VERSION >= 1) && (TAGLIB_MINOR_VERSION >= 9)
    TagLib::Ogg::Opus::File f(qBAFilename.constData());

    // Takes care of all the default metadata
    bool result = processTaglibFile(f);

    TagLib::Ogg::XiphComment *tag = f.tag();

    if (tag) {
        processXiphComment(tag);
    }
#else
    // From Taglib 1.9.x Opus is supported
    // Before that we have parse tags by this code
    int i = 0;
    const OpusTags *l_ptrOpusTags = op_tags(l_ptrOpusFile, -1);


    // This is left for debug reasons !!
    // qDebug() << "opus: We have " << l_ptrOpusTags->comments;
    for( i = 0; i < l_ptrOpusTags->comments; i ++){
      QString l_SWholeTag = QString(l_ptrOpusTags->user_comments[i]);
      QString l_STag = l_SWholeTag.left(l_SWholeTag.indexOf("="));
      QString l_SPayload = l_SWholeTag.right((l_SWholeTag.length() - l_SWholeTag.indexOf("=")) - 1);

      if (!l_STag.compare("ARTIST") ) {
            this->setArtist(l_SPayload);
      } else if (!l_STag.compare("ALBUM")) {
            this->setAlbum(l_SPayload);
      } else if (!l_STag.compare("BPM")) {
            this->setBPM(l_SPayload.toFloat());
      } else if (!l_STag.compare("YEAR") || !l_STag.compare("DATE")) {
            this->setYear(l_SPayload);
      } else if (!l_STag.compare("GENRE")) {
            this->setGenre(l_SPayload);
      } else if (!l_STag.compare("TRACKNUMBER")) {
            this->setTrackNumber(l_SPayload);
      } else if (!l_STag.compare("COMPOSER")) {
            this->setComposer(l_SPayload);
      } else if (!l_STag.compare("ALBUMARTIST")) {
            this->setAlbumArtist(l_SPayload);
      } else if (!l_STag.compare("TITLE")) {
            this->setTitle(l_SPayload);
      } else if (!l_STag.compare("REPLAYGAIN_TRACK_PEAK")) {
      } else if (!l_STag.compare("REPLAYGAIN_TRACK_GAIN")) {
            this->parseReplayGainString (l_SPayload);
      } else if (!l_STag.compare("REPLAYGAIN_ALBUM_PEAK")) {
      } else if (!l_STag.compare("REPLAYGAIN_ALBUM_GAIN")) {
      }

      // This is left fot debug reasons!!
      //qDebug() << "Comment" << i << l_ptrOpusTags->comment_lengths[i] <<
      //" (" << l_ptrOpusTags->user_comments[i] << ")" << l_STag << "*" << l_SPayload;
    }

    op_free(l_ptrOpusFile);
    return OK;
#endif


#if TAGLIB_MAJOR_VERSION >= 1 && TAGLIB_MINOR_VERSION >= 9
    return result ? OK : ERR;
#endif

}
Exemple #4
0
Result SoundSourceOpus::parseTrackMetadataAndCoverArt(
        TrackMetadata* pTrackMetadata,
        QImage* pCoverArt) const {
    if (OK == SoundSource::parseTrackMetadataAndCoverArt(
            pTrackMetadata, pCoverArt)) {
        // Done if the default implementation in the base class
        // supports Opus files.
        return OK;
    }

    // Beginning with version 1.9.0 TagLib supports the Opus format.
    // Until this becomes the minimum version required by Mixxx tags
    // in .opus files must also be parsed using opusfile. The following
    // code should removed as soon as it is no longer needed!
    //
    // NOTE(uklotzde): The following code has been found in SoundSourceOpus
    // and will not be improved. We are aware of its shortcomings like
    // the lack of proper error handling.

    // From opus/opusfile.h
    // On Windows, this string must be UTF-8 (to allow access to
    // files whose names cannot be represented in the current
    // MBCS code page).
    // All other systems use the native character encoding.
#ifdef _WIN32
    QByteArray qBAFilename = getLocalFileName().toUtf8();
#else
    QByteArray qBAFilename = getLocalFileName().toLocal8Bit();
#endif

    int error = 0;
    OggOpusFileOwner l_ptrOpusFile(
            op_open_file(qBAFilename.constData(), &error));

    int i = 0;
    const OpusTags *l_ptrOpusTags = op_tags(l_ptrOpusFile, -1);

    pTrackMetadata->setChannels(op_channel_count(l_ptrOpusFile, -1));
    pTrackMetadata->setSampleRate(Mixxx::SoundSourceOpus::kSamplingRate);
    pTrackMetadata->setBitrate(op_bitrate(l_ptrOpusFile, -1) / 1000);
    pTrackMetadata->setDuration(
            op_pcm_total(l_ptrOpusFile, -1) / pTrackMetadata->getSampleRate());

    bool hasDate = false;
    for (i = 0; i < l_ptrOpusTags->comments; ++i) {
        QString l_SWholeTag = QString(l_ptrOpusTags->user_comments[i]);
        QString l_STag = l_SWholeTag.left(l_SWholeTag.indexOf("="));
        QString l_SPayload = l_SWholeTag.right((l_SWholeTag.length() - l_SWholeTag.indexOf("=")) - 1);

        if (!l_STag.compare("ARTIST")) {
            pTrackMetadata->setArtist(l_SPayload);
        } else if (!l_STag.compare("ALBUM")) {
            pTrackMetadata->setAlbum(l_SPayload);
        } else if (!l_STag.compare("BPM")) {
            pTrackMetadata->setBpm(l_SPayload.toFloat());
        } else if (!l_STag.compare("DATE")) {
            // Prefer "DATE" over "YEAR"
            pTrackMetadata->setYear(l_SPayload.trimmed());
            // Avoid to overwrite "DATE" with "YEAR"
            hasDate |= !pTrackMetadata->getYear().isEmpty();
        } else if (!hasDate && !l_STag.compare("YEAR")) {
            pTrackMetadata->setYear(l_SPayload.trimmed());
        } else if (!l_STag.compare("GENRE")) {
            pTrackMetadata->setGenre(l_SPayload);
        } else if (!l_STag.compare("TRACKNUMBER")) {
            pTrackMetadata->setTrackNumber(l_SPayload);
        } else if (!l_STag.compare("COMPOSER")) {
            pTrackMetadata->setComposer(l_SPayload);
        } else if (!l_STag.compare("ALBUMARTIST")) {
            pTrackMetadata->setAlbumArtist(l_SPayload);
        } else if (!l_STag.compare("TITLE")) {
            pTrackMetadata->setTitle(l_SPayload);
        } else if (!l_STag.compare("REPLAYGAIN_TRACK_GAIN")) {
            bool trackGainRatioValid = false;
            double trackGainRatio = ReplayGain::parseGain2Ratio(l_SPayload, &trackGainRatioValid);
            if (trackGainRatioValid) {
                ReplayGain trackGain(pTrackMetadata->getReplayGain());
                trackGain.setRatio(trackGainRatio);
                pTrackMetadata->setReplayGain(trackGain);
            }
        }

        // This is left fot debug reasons!!
        //qDebug() << "Comment" << i << l_ptrOpusTags->comment_lengths[i] <<
        //" (" << l_ptrOpusTags->user_comments[i] << ")" << l_STag << "*" << l_SPayload;
    }

    return OK;
}