Пример #1
0
Teval::Teval(const char_t *Ic, const Tvariable *Ivars): expr(Ic), vars(Ivars)
{
    expr.ConvertToLowerCase();
    expr = stringreplace(expr, _l(" and "), _l("&&"), rfReplaceAll);
    expr = stringreplace(expr, _l(" or "), _l("||"), rfReplaceAll);
    expr = stringreplace(expr, _l(" "), _l(""), rfReplaceAll);
    expr = stringreplace(expr, _l(","), _l("."), rfReplaceAll);
}
Пример #2
0
/* replaces the chars with special meaning with the associated data from the player info struct */
static char *generatetextfromlabel(widget *item)
{
    char *text = malloc(MAX_LABELSIZE);
    char tmp[MAX_LABELSIZE];
    if(!item)
    {
        free(text);
        return NULL;
    }
    strcpy(text, item->label);
    if(item->type == tySlabel) return text;
    stringreplace(text, "$1", "%.2i:%.2i:%.2i", guiInfo.ElapsedTime / 3600,
                 (guiInfo.ElapsedTime / 60) % 60, guiInfo.ElapsedTime % 60);
    stringreplace(text, "$2", "%.4i:%.2i", guiInfo.ElapsedTime / 60, guiInfo.ElapsedTime % 60);
    stringreplace(text, "$3", "%.2i", guiInfo.ElapsedTime / 3600);
    stringreplace(text, "$4", "%.2i", (guiInfo.ElapsedTime / 60) % 60);
    stringreplace(text, "$5", "%.2i", guiInfo.ElapsedTime % 60);
    stringreplace(text, "$6", "%.2i:%.2i:%.2i", guiInfo.RunningTime / 3600,
                 (guiInfo.RunningTime / 60) % 60, guiInfo.RunningTime % 60);
    stringreplace(text, "$7", "%.4i:%.2i", guiInfo.RunningTime / 60, guiInfo.RunningTime % 60);
    stringreplace(text, "$8", "%i:%.2i:%.2i", guiInfo.ElapsedTime / 3600,
                 (guiInfo.ElapsedTime / 60) % 60, guiInfo.ElapsedTime % 60);
    stringreplace(text, "$v", "%3.2f%%", guiInfo.Volume);
    stringreplace(text, "$V", "%3.1f", guiInfo.Volume);
    stringreplace(text, "$U", "%3.0f", guiInfo.Volume);
    stringreplace(text, "$b", "%3.2f%%", guiInfo.Balance);
    stringreplace(text, "$B", "%3.1f", guiInfo.Balance);
    stringreplace(text, "$D", "%3.0f", guiInfo.Balance);
    stringreplace(text, "$t", "%.2i", guiInfo.Track);
    stringreplace(text, "$o", "%s", acp(TranslateFilename(0, tmp, sizeof(tmp))));
    stringreplace(text, "$O", "%s", acp(TranslateFilename(4, tmp, sizeof(tmp))));
    stringreplace(text, "$x", "%i", guiInfo.VideoWidth);
    stringreplace(text, "$y", "%i", guiInfo.VideoHeight);
    stringreplace(text, "$C", "%s", guiInfo.sh_video ? codecname : "");
    stringreplace(text, "$$", "$");

    if(guiInfo.Playing == GUI_STOP)
    {
        stringreplace(text, "$P", "s");
        stringreplace(text, "$s", "s");
    }
    else if(guiInfo.Playing == GUI_PLAY)
    {
        stringreplace(text, "$P", "p");
        stringreplace(text, "$p", "p");
    }
    else if(guiInfo.Playing == GUI_PAUSE)
    {
        stringreplace(text, "$P", "e");
        stringreplace(text, "$e", "e");
    }

    if(guiInfo.AudioChannels == 0) stringreplace(text, "$a", "n");
    else if(guiInfo.AudioChannels == 1) stringreplace(text, "$a", "m");
    else if(guiInfo.AudioChannels == 2) stringreplace(text, "$a", (guiInfo.AudioPassthrough ? "r" : "t"));
    else stringreplace(text, "$a", "r");

    if(guiInfo.StreamType == STREAMTYPE_FILE)
        stringreplace(text, "$T", "f");
    else if(guiInfo.StreamType == STREAMTYPE_DVD || guiInfo.StreamType == STREAMTYPE_DVDNAV)
        stringreplace(text, "$T", "d");
    else if(guiInfo.StreamType == STREAMTYPE_STREAM)
        stringreplace(text, "$T", "u");
    else stringreplace(text, "$T", " ");

    stringreplace(text, "$f", acp(TranslateFilename(1, tmp, sizeof(tmp))));
    stringreplace(text, "$F", acp(TranslateFilename(2, tmp, sizeof(tmp))));

    return text;
}
Пример #3
0
Tsubtitle* TsubtitleParserSSA::parse(Tstream &fd, int flags, REFERENCE_TIME start, REFERENCE_TIME stop)
{
    /*
     * Sub Station Alpha v4 (and v2?) scripts have 9 commas before subtitle
     * other Sub Station Alpha scripts have only 8 commas before subtitle
     * Reading the "ScriptType:" field is not reliable since many scripts appear
     * w/o it
     *
     * http://www.scriptclub.org is a good place to find more examples
     * http://www.eswat.demon.co.uk is where the SSA specs can be found
     */
    wchar_t line0[this->LINE_LEN + 1];
    wchar_t *line = line0;
    int playResXscript = 0, playResYscript = 0;
    while (fd.fgets(line, this->LINE_LEN)) {
#if 0
        DPRINTF(L"%s", line);
#endif
        lineID++;
        if (line[0] == ';') {
            continue;
        }
        wchar_t *cr = strrchr(line, '\n');
        if (cr) {
            *cr = '\0';
        }
        cr = strrchr(line, '\r');
        if (cr) {
            *cr = '\0';
        }
        if (strnicmp(line, L"[Script Info]", 13) == 0) {
            inV4styles = 0;
            inEvents = 0;
            inInfo = 1;
        } else if (inInfo && strnicmp(line, L"PlayResX:", 8) == 0) {
            nmTextSubtitles::strToInt(line + 9, &playResXscript);
        } else if (inInfo && strnicmp(line, L"PlayResY:", 8) == 0) {
            nmTextSubtitles::strToInt(line + 9, &playResYscript);
        } else if (inInfo && strnicmp(line, L"Timer:", 6) == 0) {
            wchar_t *end;
            double t = strtod(line + 7, &end);
            if (*end == '\0' && t != 0) {
                timer = Rational(t / 100.0, _I32_MAX);
            }
        } else if (inInfo && strnicmp(line, L"WrapStyle:", 9) == 0) {
            nmTextSubtitles::strToInt(line + 10, &wrapStyle);
        } else if (inInfo && strnicmp(line, L"ScaledBorderAndShadow:", 21) == 0) {
            nmTextSubtitles::strToInt(line + 22, &scaleBorderAndShadow);
        } else if (strnicmp(line, L"[V4 Styles]", 11) == 0) {
            version = nmTextSubtitles::SSA;
            inV4styles = 2;
            inEvents = 0;
            inInfo = 0;
        } else if (strnicmp(line, L"[V4+ Styles]", 11) == 0) {
            version = nmTextSubtitles::ASS;
            inV4styles = 2;
            inEvents = 0;
            inInfo = 0;
        } else if (strnicmp(line, L"[V4++ Styles]", 11) == 0) {
            version = nmTextSubtitles::ASS2;
            inV4styles = 2;
            inEvents = 0;
            inInfo = 0;
        } else if (strnicmp(line, L"[Events]", 8) == 0) {
            inV4styles = 0;
            inEvents = 2;
            inInfo = 0;
        } else if (inV4styles == 2 && strnicmp(line, L"Format:", 7) == 0) {
            strlwr(line);
            strrmchar(line, L' ');
            typedef std::vector<Tstrpart > Tparts;
            Tparts fields;
            const wchar_t *l = line + 7;
            strtok(l, L",", fields);
            styleFormat.clear();
            for (Tparts::const_iterator f = fields.begin(); f != fields.end(); f++) {
                if (strnicmp(f->first, L"name", 4) == 0) {
                    styleFormat.push_back(&TSSAstyle::name);
                } else if (strnicmp(f->first, L"layer", 5) == 0) {
                    styleFormat.push_back(&TSSAstyle::layer);
                } else if (strnicmp(f->first, L"fontname", 8) == 0) {
                    styleFormat.push_back(&TSSAstyle::fontname);
                } else if (strnicmp(f->first, L"fontsize", 8) == 0) {
                    styleFormat.push_back(&TSSAstyle::fontsize);
                } else if (strnicmp(f->first, L"primaryColour", 13) == 0) {
                    styleFormat.push_back(&TSSAstyle::primaryColour);
                } else if (strnicmp(f->first, L"SecondaryColour", 15) == 0) {
                    styleFormat.push_back(&TSSAstyle::secondaryColour);
                } else if (strnicmp(f->first, L"TertiaryColour", 14) == 0) {
                    styleFormat.push_back(&TSSAstyle::tertiaryColour);
                } else if (strnicmp(f->first, L"OutlineColour", 13) == 0) {
                    styleFormat.push_back(&TSSAstyle::outlineColour);
                } else if (strnicmp(f->first, L"BackColour", 10) == 0) {
                    styleFormat.push_back(&TSSAstyle::backgroundColour);
                } else if (strnicmp(f->first, L"bold", 4) == 0) {
                    styleFormat.push_back(&TSSAstyle::bold);
                } else if (strnicmp(f->first, L"italic", 6) == 0) {
                    styleFormat.push_back(&TSSAstyle::italic);
                } else if (strnicmp(f->first, L"Underline", 9) == 0) {
                    styleFormat.push_back(&TSSAstyle::underline);
                } else if (strnicmp(f->first, L"Strikeout", 9) == 0) {
                    styleFormat.push_back(&TSSAstyle::strikeout);
                } else if (strnicmp(f->first, L"ScaleX", 6) == 0) {
                    styleFormat.push_back(&TSSAstyle::fontScaleX);
                } else if (strnicmp(f->first, L"ScaleY", 6) == 0) {
                    styleFormat.push_back(&TSSAstyle::fontScaleY);
                } else if (strnicmp(f->first, L"Spacing", 7) == 0) {
                    styleFormat.push_back(&TSSAstyle::spacing);
                } else if (strnicmp(f->first, L"Angle", 5) == 0) {
                    styleFormat.push_back(&TSSAstyle::angleZ);
                } else if (strnicmp(f->first, L"outline", 7) == 0) {
                    styleFormat.push_back(&TSSAstyle::outlineWidth);
                } else if (strnicmp(f->first, L"shadow", 6) == 0) {
                    styleFormat.push_back(&TSSAstyle::shadowDepth);
                } else if (strnicmp(f->first, L"alignment", 9) == 0) {
                    styleFormat.push_back(&TSSAstyle::alignment);
                } else if (strnicmp(f->first, L"encoding", 8) == 0) {
                    styleFormat.push_back(&TSSAstyle::encoding);
                } else if (strnicmp(f->first, L"marginl", 7) == 0) {
                    styleFormat.push_back(&TSSAstyle::marginLeft);
                } else if (strnicmp(f->first, L"marginr", 7) == 0) {
                    styleFormat.push_back(&TSSAstyle::marginRight);
                } else if (strnicmp(f->first, L"marginv", 7) == 0) {
                    styleFormat.push_back(&TSSAstyle::marginV);
                } else if (strnicmp(f->first, L"borderstyle", 11) == 0) {
                    styleFormat.push_back(&TSSAstyle::borderStyle);
                } else {
                    styleFormat.push_back(NULL);
                }
            }
            inV4styles = 1;
        } else if (inV4styles && strnicmp(line, L"Style:", 6) == 0) {
            if (inV4styles == 2) {
                styleFormat.clear();
                if (version == nmTextSubtitles::ASS2) {
                    styleFormat.push_back(&TSSAstyle::name);
                    styleFormat.push_back(&TSSAstyle::fontname);
                    styleFormat.push_back(&TSSAstyle::fontsize);
                    styleFormat.push_back(&TSSAstyle::primaryColour);
                    styleFormat.push_back(&TSSAstyle::secondaryColour);
                    styleFormat.push_back(&TSSAstyle::tertiaryColour);
                    styleFormat.push_back(&TSSAstyle::backgroundColour);
                    styleFormat.push_back(&TSSAstyle::bold);
                    styleFormat.push_back(&TSSAstyle::italic);
                    if (version >= nmTextSubtitles::ASS) {
                        styleFormat.push_back(&TSSAstyle::underline);
                    }
                    if (version >= nmTextSubtitles::ASS) {
                        styleFormat.push_back(&TSSAstyle::strikeout);
                    }
                    if (version >= nmTextSubtitles::ASS) {
                        styleFormat.push_back(&TSSAstyle::fontScaleX);
                    }
                    if (version >= nmTextSubtitles::ASS) {
                        styleFormat.push_back(&TSSAstyle::fontScaleY);
                    }
                    if (version >= nmTextSubtitles::ASS) {
                        styleFormat.push_back(&TSSAstyle::spacing);
                    }
                    if (version >= nmTextSubtitles::ASS) {
                        styleFormat.push_back(&TSSAstyle::angleZ);
                    }
                    styleFormat.push_back(&TSSAstyle::borderStyle);
                    styleFormat.push_back(&TSSAstyle::outlineWidth);
                    styleFormat.push_back(&TSSAstyle::shadowDepth);
                    styleFormat.push_back(&TSSAstyle::alignment);
                    styleFormat.push_back(&TSSAstyle::marginLeft);
                    styleFormat.push_back(&TSSAstyle::marginRight);
                    styleFormat.push_back(&TSSAstyle::marginTop);
                    if (version >= nmTextSubtitles::ASS2) {
                        styleFormat.push_back(&TSSAstyle::marginBottom);
                    }
                    styleFormat.push_back(&TSSAstyle::encoding);
                    if (version <= nmTextSubtitles::SSA) {
                        styleFormat.push_back(&TSSAstyle::alpha);
                    }
                    styleFormat.push_back(&TSSAstyle::relativeTo);
                }
                inV4styles = 1;
            }
            strings fields;
            strtok(line + 7, L",", fields);

            // Fix for missing or incomplete movie dimensions in the script
            if (playResXscript == 0 && playResYscript == 0) { // Assume 384x288 like VSFilter
                playResX = 384;
                playResY = 288;
            } else { // At least one of the two is set
                if (playResXscript == 0 || playResYscript == 0) { // Assume 4/3 aspect ratio like VSFilter, but only if one of them is missing
                    if (playResXscript == 0) {
                        playResX = playResYscript * 4 / 3;
                    } else {
                        playResX = playResXscript;
                    }
                    if (playResYscript == 0) {
                        playResY = playResXscript * 3 / 4;
                    } else {
                        playResY = playResYscript;
                    }
                } else { // Both are set, use them
                    playResX = playResXscript;
                    playResY = playResYscript;
                }
            }
            TSSAstyle style(playResX, playResY, version, wrapStyle, scaleBorderAndShadow);
            for (size_t i = 0; i < fields.size() && i < styleFormat.size(); i++)
                if (styleFormat[i]) {
                    style.*(styleFormat[i]) = fields[i];
                }
            styles.add(style);
        } else if (inEvents == 2 && strnicmp(line, L"Format:", 7) == 0) {
            strlwr(line);
            strrmchar(line, L' ');
            typedef std::vector<Tstrpart > Tparts;
            Tparts fields;
            const wchar_t *l = line + 7;
            strtok(l, L",", fields);
            eventFormat.clear();

            // On embedded streams, read order is added as first column
            if (isEmbedded) {
                eventFormat.push_back(&Tevent::readorder);
            }

            for (Tparts::const_iterator f = fields.begin(); f != fields.end(); f++) {
                if (strnicmp(f->first, L"marked", 6) == 0) {
                    eventFormat.push_back(&Tevent::marked);
                } else if (strnicmp(f->first, L"layer", 5) == 0) {
                    eventFormat.push_back(&Tevent::layer);
                } else if (strnicmp(f->first, L"start", 5) == 0) {
                    // On embedded subtitles time is removed
                    if (!isEmbedded) {
                        eventFormat.push_back(&Tevent::start);
                    }
                } else if (strnicmp(f->first, L"end", 3) == 0) {
                    // On embedded subtitles time is removed
                    if (!isEmbedded) {
                        eventFormat.push_back(&Tevent::end);
                    }
                } else if (strnicmp(f->first, L"style", 5) == 0) {
                    eventFormat.push_back(&Tevent::style);
                } else if (strnicmp(f->first, L"name", 4) == 0) {
                    eventFormat.push_back(&Tevent::name);
                } else if (strnicmp(f->first, L"marginL", 7) == 0) {
                    eventFormat.push_back(&Tevent::marginL);
                } else if (strnicmp(f->first, L"marginR", 7) == 0) {
                    eventFormat.push_back(&Tevent::marginR);
                } else if (strnicmp(f->first, L"marginV", 7) == 0) {
                    eventFormat.push_back(&Tevent::marginV);
                } else if (strnicmp(f->first, L"marginR", 7) == 0) {
                    eventFormat.push_back(&Tevent::marginR);
                } else if (strnicmp(f->first, L"effect", 6) == 0) {
                    eventFormat.push_back(&Tevent::effect);
                } else if (strnicmp(f->first, L"text", 4) == 0) {
                    eventFormat.push_back(&Tevent::text);
                } else {
                    eventFormat.push_back(NULL);
                }
            }
            inEvents = 1;
        } else if ((flags & this->SSA_NODIALOGUE) || (inEvents == 1 && strnicmp(line, L"Dialogue:", 8) == 0)) {
            if (eventFormat.empty()) {
                if (!(flags & this->SSA_NODIALOGUE)) {
                    if (version <= nmTextSubtitles::SSA) {
                        eventFormat.push_back(&Tevent::marked);
                    }
                    if (version >= nmTextSubtitles::ASS) {
                        eventFormat.push_back(&Tevent::layer);
                    }
                    eventFormat.push_back(&Tevent::start);
                    eventFormat.push_back(&Tevent::end);
                } else {
                    eventFormat.push_back(&Tevent::readorder);
                    eventFormat.push_back(&Tevent::layer);
                }
                eventFormat.push_back(&Tevent::style);
                eventFormat.push_back(&Tevent::actor);
                eventFormat.push_back(&Tevent::marginL);
                eventFormat.push_back(&Tevent::marginR);
                eventFormat.push_back(&Tevent::marginT);
                if (version >= nmTextSubtitles::ASS2) {
                    eventFormat.push_back(&Tevent::marginB);
                }
                eventFormat.push_back(&Tevent::effect);
                eventFormat.push_back(&Tevent::text);
            }
            strings fields;
            strtok(line + (flags & this->SSA_NODIALOGUE ? 0 : 9), L"," , fields, true, eventFormat.size());
            Tevent event;
            event.dummy = ""; // avoid being optimized.
            for (size_t i = 0; i < fields.size() && i < eventFormat.size(); i++) {
                if (eventFormat[i]) {
                    event.*(eventFormat[i]) = fields[i];
                }
            }
            if (event.text) {
#if 0
                DPRINTF(L"%s", event.text.c_str());
#endif
                int hour1 = 0, min1 = 0, sec1 = 0, hunsec1 = 0;
                int hour2 = 0, min2 = 0, sec2 = 0, hunsec2 = 0;
                if (!(flags & this->PARSETIME) ||
                        (swscanf(event.start.c_str(), L"%d:%d:%d.%d", &hour1, &min1, &sec1, &hunsec1) == 4 &&
                         swscanf(event.end.c_str()  , L"%d:%d:%d.%d", &hour2, &min2, &sec2, &hunsec2) == 4)) {
                    const TSubtitleProps *props = styles.getProps(event.style);
                    TsubtitleText current(this->format, props ? *props : defprops, styles);
                    current.defProps.lineID = lineID;

                    // margins
                    nmTextSubtitles::strToIntMargin(event.marginL, &current.defProps.marginL);
                    nmTextSubtitles::strToIntMargin(event.marginR, &current.defProps.marginR);
                    nmTextSubtitles::strToIntMargin(event.marginV, &current.defProps.marginV);

                    // layer
                    nmTextSubtitles::strToInt(event.layer, &current.defProps.layer);

                    // timestamps
                    if (flags & this->PARSETIME) {
                        current.start = timer.den * this->hmsToTime(hour1, min1, sec1, hunsec1) / timer.num;
                        current.stop = timer.den * this->hmsToTime(hour2, min2, sec2, hunsec2) / timer.num;
                    } else if (start != REFTIME_INVALID && stop != REFTIME_INVALID) {
                        current.start = start;
                        current.stop = stop;
                    }
                    current.defProps.tStart = current.defProps.karaokeStart = current.start;
                    current.defProps.tStop = current.stop;

                    // scroll
                    event.effect = event.effect.ConvertToLowerCase();
                    if (event.effect.find(L"scroll up;") != ffstring::npos) {
                        current.defProps.scroll.directionV = -1;
                    }
                    if (event.effect.find(L"scroll down;") != ffstring::npos) {
                        current.defProps.scroll.directionV = 1;
                    }
                    if (current.defProps.scroll.directionV) {
                        int y1, y2, delay, fadeawayheight = 0;
                        if (swscanf(event.effect.c_str() + event.effect.find(L";"),
                                    L";%d;%d;%d;%d", &y1, &y2, &delay, &fadeawayheight) >= 3) {
                            if (y1 > y2) {
                                std::swap(y1, y2);
                            }
                            current.defProps.scroll.y1 = y1;
                            current.defProps.scroll.y2 = y2;
                            current.defProps.scroll.delay = std::max(delay, 1);
                            current.defProps.scroll.fadeaway = fadeawayheight;
                        }
                    }

                    if (event.effect.find(L"banner;") != ffstring::npos) {
                        current.defProps.scroll.directionV = 0;
                        current.defProps.scroll.directionH = -1;
                        int delay, lefttoright = 0, fadeawaywidth = 0;
                        if (swscanf(event.effect.c_str() + event.effect.find(L";"),
                                    L";%d;%d;%d", &delay, &lefttoright, &fadeawaywidth) >= 1) {
                            current.defProps.scroll.delay = std::max(delay, 1);
                            current.defProps.scroll.directionH = lefttoright ? 1 : -1;
                            current.defProps.scroll.fadeaway = fadeawaywidth;
                        }
                    }

                    // replace \h with non-breaking space (U+00A0).
                    event.text = stringreplace(event.text, L"\\h", L"\xa0", rfReplaceAll);

                    const wchar_t *line2 = event.text.c_str();
                    do {
                        const wchar_t *tmp, *tmp1;
                        int lineBreakReason = 0;
                        do {
                            tmp = strstr(line2, L"\\n");
                            tmp1 = strstr(line2, L"\\N");
                            if (tmp == NULL && tmp1 == NULL) {
                                break;
                            }
                            if (tmp && tmp1) {
                                tmp = std::min(tmp, tmp1);
                            }
                            if (tmp == NULL) {
                                tmp = tmp1;
                            }
                            current.addSSA(line2, tmp - line2, lineBreakReason);
                            lineBreakReason = tmp[1] == 'n' ? 1 : 2;
                            line2 = tmp + 2;
                        } while (1);
                        current.addSSA(line2, lineBreakReason);
                    } while (flags & this->SSA_NODIALOGUE && fd.fgets((wchar_t*)(line2 = line), this->LINE_LEN));
                    textformat.setProps(current.defProps);
                    return store(current);
                }
            }
        }
    }
    return NULL;
}
Пример #4
0
/* replaces the chars with special meaning with the associated data from the player info struct */
static char *generatetextfromlabel(widget *item)
{
    char *text = malloc(MAX_LABELSIZE);
    char tmp[MAX_LABELSIZE];
    unsigned int i;
    if(!item)
    {
        free(text);
        return NULL;
    }
    strcpy(text, item->label);
    if(item->type == tySlabel) return text;
    stringreplace(text, "$1", "%.2i:%.2i:%.2i", guiInfo.ElapsedTime / 3600,
                 (guiInfo.ElapsedTime / 60) % 60, guiInfo.ElapsedTime % 60);
    stringreplace(text, "$2", "%.4i:%.2i", guiInfo.ElapsedTime / 60, guiInfo.ElapsedTime % 60);
    stringreplace(text, "$3", "%.2i", guiInfo.ElapsedTime / 3600);
    stringreplace(text, "$4", "%.2i", (guiInfo.ElapsedTime / 60) % 60);
    stringreplace(text, "$5", "%.2i", guiInfo.ElapsedTime % 60);
    stringreplace(text, "$6", "%.2i:%.2i:%.2i", guiInfo.RunningTime / 3600,
                 (guiInfo.RunningTime / 60) % 60, guiInfo.RunningTime % 60);
    stringreplace(text, "$7", "%.4i:%.2i", guiInfo.RunningTime / 60, guiInfo.RunningTime % 60);
    stringreplace(text, "$8", "%i:%.2i:%.2i", guiInfo.ElapsedTime / 3600,
                 (guiInfo.ElapsedTime / 60) % 60, guiInfo.ElapsedTime % 60);
    stringreplace(text, "$v", "%3.2f", guiInfo.Volume);
    stringreplace(text, "$V", "%3.1f", guiInfo.Volume);
    stringreplace(text, "$b", "%3.2f", guiInfo.Balance);
    stringreplace(text, "$B", "%3.1f", guiInfo.Balance);
    stringreplace(text, "$t", "%.2i", guiInfo.Track);
    stringreplace(text, "$o", "%s", guiInfo.Filename);
    stringreplace(text, "$x", "%i", guiInfo.VideoWidth);
    stringreplace(text, "$y", "%i", guiInfo.VideoHeight);
    stringreplace(text, "$C", "%s", guiInfo.sh_video ? codecname : "");
    stringreplace(text, "$$", "$");

    if(!strcmp(text, "$p") || !strcmp(text, "$s") || !strcmp(text, "$e"))
    {
        if(guiInfo.Playing == GUI_STOP) stringreplace(text, NULL, "s");
        else if(guiInfo.Playing == GUI_PLAY) stringreplace(text, NULL, "p");
        else if(guiInfo.Playing == GUI_PAUSE) stringreplace(text, NULL, "e");
    }

    if(guiInfo.AudioChannels == 0) stringreplace(text, "$a", "n");
    else if(guiInfo.AudioChannels == 1) stringreplace(text, "$a", "m");
    else stringreplace(text, "$a", "t");

    if(guiInfo.StreamType == 0)
        stringreplace(text, "$T", "f");
#ifdef CONFIG_DVDREAD
    else if(guiInfo.StreamType == STREAMTYPE_DVD || guiInfo.StreamType == STREAMTYPE_DVDNAV)
        stringreplace(text, "$T", "d");
#endif
    else stringreplace(text, "$T", "u");

    if(guiInfo.Filename)
    {
        for (i=0; i<strlen(guiInfo.Filename); i++)
            tmp[i] = tolower(guiInfo.Filename[i]);
        stringreplace(text, "$f", tmp);

        for (i=0; i<strlen(guiInfo.Filename); i++)
            tmp[i] = toupper(guiInfo.Filename[i]);
        stringreplace(text, "$F", tmp);
    }

    return text;
}