コード例 #1
0
ファイル: cue.c プロジェクト: ThreeGe/mpv
static double read_time(struct bstr *data)
{
    struct bstr s = *data;
    bool ok = true;
    double t1 = read_int_2(&s);
    ok = eat_char(&s, ':') && ok;
    double t2 = read_int_2(&s);
    ok = eat_char(&s, ':') && ok;
    double t3 = read_int_2(&s);
    ok = ok && t1 >= 0 && t2 >= 0 && t3 >= 0;
    return ok ? t1 * 60.0 + t2 + t3 * SECS_PER_CUE_FRAME : 0;
}
コード例 #2
0
ファイル: cue.c プロジェクト: ThreeGe/mpv
struct cue_file *mp_parse_cue(struct bstr data)
{
    struct cue_file *f = talloc_zero(NULL, struct cue_file);
    f->tags = talloc_zero(f, struct mp_tags);

    data = skip_utf8_bom(data);

    char *filename = NULL;
    // Global metadata, and copied into new tracks.
    struct cue_track proto_track = {0};
    struct cue_track *cur_track = NULL;

    while (data.len) {
        struct bstr param;
        int cmd = read_cmd(&data, &param);
        switch (cmd) {
        case CUE_ERROR:
            talloc_free(f);
            return NULL;
        case CUE_TRACK: {
            MP_TARRAY_GROW(f, f->tracks, f->num_tracks);
            f->num_tracks += 1;
            cur_track = &f->tracks[f->num_tracks - 1];
            *cur_track = proto_track;
            cur_track->tags = talloc_zero(f, struct mp_tags);
            break;
        }
        case CUE_TITLE:
        case CUE_PERFORMER: {
            static const char *metanames[] = {
                [CUE_TITLE] = "title",
                [CUE_PERFORMER] = "performer",
            };
            struct mp_tags *tags = cur_track ? cur_track->tags : f->tags;
            mp_tags_set_bstr(tags, bstr0(metanames[cmd]), param);
            break;
        }
        case CUE_INDEX: {
            int type = read_int_2(&param);
            double time = read_time(&param);
            if (cur_track) {
                if (type == 1) {
                    cur_track->start = time;
                    cur_track->filename = filename;
                } else if (type == 0) {
                    cur_track->pregap_start = time;
                }
            }
            break;
        }
        case CUE_FILE:
            // NOTE: FILE comes before TRACK, so don't use cur_track->filename
            filename = read_quoted(f, &param);
            break;
        }
    }

    return f;
}
コード例 #3
0
ファイル: tl_cue.c プロジェクト: CrimsonVoid/mpv
void build_cue_timeline(struct MPContext *mpctx)
{
    void *ctx = talloc_new(NULL);

    struct bstr data = mpctx->demuxer->file_contents;
    data = skip_utf8_bom(data);

    struct cue_track *tracks = NULL;
    size_t track_count = 0;

    struct bstr filename = {0};
    // Global metadata, and copied into new tracks.
    struct cue_track proto_track = {0};
    struct cue_track *cur_track = &proto_track;

    while (data.len) {
        struct bstr param;
        switch (read_cmd(&data, &param)) {
        case CUE_ERROR:
            mp_msg(MSGT_CPLAYER, MSGL_ERR, "CUE: error parsing input file!\n");
            goto out;
        case CUE_TRACK: {
            track_count++;
            tracks = talloc_realloc(ctx, tracks, struct cue_track, track_count);
            cur_track = &tracks[track_count - 1];
            *cur_track = proto_track;
            break;
        }
        case CUE_TITLE:
            cur_track->title = read_quoted(&param);
            break;
        case CUE_INDEX: {
            int type = read_int_2(&param);
            double time = read_time(&param);
            if (type == 1) {
                cur_track->start = time;
                cur_track->filename = filename;
            } else if (type == 0) {
                cur_track->pregap_start = time;
            }
            break;
        }
        case CUE_FILE:
            // NOTE: FILE comes before TRACK, so don't use cur_track->filename
            filename = read_quoted(&param);
            break;
        }
    }

    if (track_count == 0) {
        mp_msg(MSGT_CPLAYER, MSGL_ERR, "CUE: no tracks found!\n");
        goto out;
    }

    // Remove duplicate file entries. This might be too sophisticated, since
    // CUE files usually use either separate files for every single track, or
    // only one file for all tracks.

    struct bstr *files = 0;
    size_t file_count = 0;

    for (size_t n = 0; n < track_count; n++) {
        struct cue_track *track = &tracks[n];
        track->source = -1;
        for (size_t file = 0; file < file_count; file++) {
            if (bstrcmp(files[file], track->filename) == 0) {
                track->source = file;
                break;
            }
        }
        if (track->source == -1) {
            file_count++;
            files = talloc_realloc(ctx, files, struct bstr, file_count);
            files[file_count - 1] = track->filename;
            track->source = file_count - 1;
        }
    }
コード例 #4
0
ファイル: tl_cue.c プロジェクト: CrimsonVoid/mpv
static struct bstr read_quoted(struct bstr *data)
{
    *data = bstr_lstrip(*data);
    if (!eat_char(data, '"'))
        return (struct bstr) {0};
    int end = bstrchr(*data, '"');
    if (end < 0)
        return (struct bstr) {0};
    struct bstr res = bstr_splice(*data, 0, end);
    *data = bstr_cut(*data, end + 1);
    return res;
}

// Read a 2 digit unsigned decimal integer.
// Return -1 on failure.
static int read_int_2(struct bstr *data)
{
    *data = bstr_lstrip(*data);
    if (data->len && data->start[0] == '-')
        return -1;
    struct bstr s = *data;
    int res = (int)bstrtoll(s, &s, 10);
    if (data->len == s.len || data->len - s.len > 2)
        return -1;
    *data = s;
    return res;
}

static double read_time(struct bstr *data)
{
    struct bstr s = *data;
    bool ok = true;
    double t1 = read_int_2(&s);
    ok = eat_char(&s, ':') && ok;
    double t2 = read_int_2(&s);
    ok = eat_char(&s, ':') && ok;
    double t3 = read_int_2(&s);
    ok = ok && t1 >= 0 && t2 >= 0 && t3 >= 0;
    return ok ? t1 * 60.0 + t2 + t3 * SECS_PER_CUE_FRAME : 0;
}

static struct bstr skip_utf8_bom(struct bstr data)
{
    return bstr_startswith0(data, "\xEF\xBB\xBF") ? bstr_cut(data, 3) : data;
}

// Check if the text in data is most likely CUE data. This is used by the
// demuxer code to check the file type.
// data is the start of the probed file, possibly cut off at a random point.
bool mp_probe_cue(struct bstr data)
{
    bool valid = false;
    data = skip_utf8_bom(data);
    for (;;) {
        enum cue_command cmd = read_cmd(&data, NULL);
        // End reached. Since the line was most likely cut off, don't use the
        // result of the last parsing call.
        if (data.len == 0)
            break;
        if (cmd == CUE_ERROR)
            return false;
        if (cmd != CUE_EMPTY)
            valid = true;
    }
    return valid;
}