void TextSubtitleParser::LoadSubtitles(const QString &fileName,
                                       TextSubtitles &target,
                                       bool inBackground)
{
    if (inBackground)
    {
        if (!SubtitleLoadHelper::IsLoading(&target))
            MThreadPool::globalInstance()->
                start(new SubtitleLoadHelper(fileName, &target),
                      "SubtitleLoadHelper");
        return;
    }
    demux_sputext_t sub_data;
    RemoteFileWrapper rfile(fileName/*, false, false, 0*/);

    LOG(VB_VBI, LOG_INFO,
        QString("Preparing to load subtitle file (%1)").arg(fileName));
    if (!rfile.isOpen())
    {
        LOG(VB_VBI, LOG_INFO,
            QString("Failed to load subtitle file (%1)").arg(fileName));
        return;
    }
    target.SetHasSubtitles(true);
    target.SetFilename(fileName);

    // Only reload if rfile.GetFileSize() has changed.
    off_t new_len = rfile.GetFileSize();
    if (target.GetByteCount() == new_len)
    {
        LOG(VB_VBI, LOG_INFO,
            QString("Filesize unchanged (%1), not reloading subs (%2)")
            .arg(new_len).arg(fileName));
        target.SetLastLoaded();
        return;
    }
    LOG(VB_VBI, LOG_INFO,
        QString("Preparing to read %1 subtitle bytes from %2")
        .arg(new_len).arg(fileName));
    target.SetByteCount(new_len);
    sub_data.rbuffer_len = new_len;
    sub_data.rbuffer_text = new char[sub_data.rbuffer_len + 1];
    sub_data.rbuffer_cur = 0;
    sub_data.errs = 0;
    int numread = rfile.Read(sub_data.rbuffer_text, sub_data.rbuffer_len);
    LOG(VB_VBI, LOG_INFO,
        QString("Finished reading %1 subtitle bytes (requested %2)")
        .arg(numread).arg(new_len));

    // try to determine the text codec
    QByteArray test(sub_data.rbuffer_text, sub_data.rbuffer_len);
    QTextCodec *textCodec = QTextCodec::codecForUtfText(test, NULL);
    if (!textCodec)
    {
        LOG(VB_VBI, LOG_WARNING, "Failed to autodetect a UTF encoding.");
        QString codec = gCoreContext->GetSetting("SubtitleCodec", "");
        if (!codec.isEmpty())
            textCodec = QTextCodec::codecForName(codec.toLatin1());
        if (!textCodec)
            textCodec = QTextCodec::codecForName("utf-8");
        if (!textCodec)
        {
            LOG(VB_VBI, LOG_ERR,
                QString("Failed to find codec for subtitle file '%1'")
                .arg(fileName));
            return;
        }
    }

    LOG(VB_VBI, LOG_INFO, QString("Opened subtitle file '%1' with codec '%2'")
        .arg(fileName).arg(textCodec->name().constData()));

    // load the entire subtitle file, converting to unicode as we go
    QScopedPointer<QTextDecoder> dec(textCodec->makeDecoder());
    QString data = dec->toUnicode(sub_data.rbuffer_text, sub_data.rbuffer_len);
    if (data.isEmpty())
    {
        LOG(VB_VBI, LOG_WARNING,
            QString("Data loaded from subtitle file '%1' is empty.")
            .arg(fileName));
        return;
    }

    // convert back to utf-8 for parsing
    QByteArray ba = data.toUtf8();
    delete[] sub_data.rbuffer_text;
    sub_data.rbuffer_text = ba.data();
    sub_data.rbuffer_len = ba.size();

    subtitle_t *loaded_subs = sub_read_file(&sub_data);
    if (!loaded_subs)
    {
        // Don't delete[] sub_data.rbuffer_text; because the
        // QByteArray destructor will clean up.
        LOG(VB_VBI, LOG_ERR, QString("Failed to read subtitles from '%1'")
            .arg(fileName));
        return;
    }

    LOG(VB_VBI, LOG_INFO, QString("Found %1 subtitles in file '%2'")
        .arg(sub_data.num).arg(fileName));
    target.SetFrameBasedTiming(!sub_data.uses_time);
    target.Clear();

    // convert the subtitles to our own format, free the original structures
    // and convert back to unicode
    textCodec = QTextCodec::codecForName("utf-8");
    if (textCodec)
        dec.reset(textCodec->makeDecoder());

    for (int sub_i = 0; sub_i < sub_data.num; ++sub_i)
    {
        const subtitle_t *sub = &loaded_subs[sub_i];
        text_subtitle_t newsub(sub->start, sub->end);

        if (!target.IsFrameBasedTiming())
        {
            newsub.start *= 10; // convert from csec to msec
            newsub.end *= 10;
        }

        for (int line = 0; line < sub->lines; ++line)
        {
            const char *subLine = sub->text[line];
            QString str;
            if (textCodec)
                str = dec->toUnicode(subLine, strlen(subLine));
            else
                str = QString(subLine);
            newsub.textLines.push_back(str);

            free(sub->text[line]);
        }
        target.AddSubtitle(newsub);
    }

    // textCodec object is managed by Qt, do not delete...

    free(loaded_subs);
    // Don't delete[] sub_data.rbuffer_text; because the QByteArray
    // destructor will clean up.

    target.SetLastLoaded();
}
Esempio n. 2
0
bool TextSubtitleParser::LoadSubtitles(const QString &fileName,
                                       TextSubtitles &target)
{
    demux_sputext_t sub_data;
    RemoteFile rfile(fileName, false, false, 0);

    LOG(VB_VBI, LOG_INFO,
        QString("Preparing to load subtitle file (%1)").arg(fileName));
    if (!rfile.Open())
    {
        LOG(VB_VBI, LOG_INFO,
            QString("Failed to load subtitle file (%1)").arg(fileName));
        return false;
    }
    target.SetHasSubtitles(true);
    target.SetFilename(fileName);

    // Only reload if rfile.GetRealFileSize() has changed.
    off_t new_len = rfile.GetFileSize();
    if (target.GetByteCount() == new_len)
    {
        LOG(VB_VBI, LOG_INFO,
            QString("Filesize unchanged (%1), not reloading subs (%2)")
            .arg(new_len).arg(fileName));
        target.SetLastLoaded();
        return new_len;
    }
    LOG(VB_VBI, LOG_INFO,
        QString("Preparing to read %1 subtitle bytes from %2")
        .arg(new_len).arg(fileName));
    target.SetByteCount(new_len);
    sub_data.rbuffer_len = new_len;
    sub_data.rbuffer_text = new char[sub_data.rbuffer_len + 1];
    sub_data.rbuffer_cur = 0;
    sub_data.errs = 0;
    int numread = rfile.Read(sub_data.rbuffer_text, sub_data.rbuffer_len);
    LOG(VB_VBI, LOG_INFO,
        QString("Finished reading %1 subtitle bytes (requested %2)")
        .arg(numread).arg(new_len));
    subtitle_t *loaded_subs = sub_read_file(&sub_data);
    if (!loaded_subs)
    {
        delete sub_data.rbuffer_text;
        return false;
    }

    target.SetFrameBasedTiming(!sub_data.uses_time);
    target.Clear();

    QTextCodec *textCodec = NULL;
    QString codec = gCoreContext->GetSetting("SubtitleCodec", "");
    if (!codec.isEmpty())
        textCodec = QTextCodec::codecForName(codec.toLatin1());
    if (!textCodec)
        textCodec = QTextCodec::codecForName("utf-8");
    if (!textCodec)
    {
        delete sub_data.rbuffer_text;
        return false;
    }

    QTextDecoder *dec = textCodec->makeDecoder();

    // convert the subtitles to our own format and free the original structures
    for (int sub_i = 0; sub_i < sub_data.num; ++sub_i)
    {
        const subtitle_t *sub = &loaded_subs[sub_i];
        text_subtitle_t newsub(sub->start, sub->end);

        if (!target.IsFrameBasedTiming())
        {
            newsub.start *= 10; // convert from csec to msec
            newsub.end *= 10;
        }

        for (int line = 0; line < sub->lines; ++line)
        {
            const char *subLine = sub->text[line];
            QString str = dec->toUnicode(subLine, strlen(subLine));
            newsub.textLines.push_back(str);

            free(sub->text[line]);
        }
        target.AddSubtitle(newsub);
    }

    delete dec;
    // textCodec object is managed by Qt, do not delete...

    free(loaded_subs);
    delete sub_data.rbuffer_text;

    target.SetLastLoaded();

    return true;
}