Beispiel #1
0
static int stream_getc(stream_t *stream)
{
    int c = stream_peek(stream);
    if (c != EOF)
        stream->pos++;
    return c;
}
Beispiel #2
0
Datei: rar.c Projekt: 0x0all/mpv
static int SkipEnd(struct stream *s, const rar_block_t *hdr)
{
    if (!(hdr->flags & RAR_BLOCK_END_HAS_NEXT))
        return -1;

    if (SkipBlock(s, hdr))
        return -1;

    /* Now, we need to look for a marker block,
     * It seems that there is garbage at EOF */
    for (;;) {
        bstr peek = stream_peek(s, rar_marker_size);

        if (peek.len < rar_marker_size)
            return -1;

        if (!memcmp(peek.start, rar_marker, rar_marker_size))
            break;

        if (!stream_skip(s, 1))
            return -1;
    }

    /* Skip marker and archive blocks */
    if (IgnoreBlock(s, RAR_BLOCK_MARKER))
        return -1;
    if (IgnoreBlock(s, RAR_BLOCK_ARCHIVE))
        return -1;

    return 0;
}
Beispiel #3
0
Datei: rar.c Projekt: 0x0all/mpv
static int PeekBlock(struct stream *s, rar_block_t *hdr)
{
    bstr data = stream_peek(s, 11);
    const uint8_t *peek = (uint8_t *)data.start;
    int peek_size = data.len;

    if (peek_size < 7)
        return -1;

    hdr->crc   = AV_RL16(&peek[0]);
    hdr->type  = peek[2];
    hdr->flags = AV_RL16(&peek[3]);
    hdr->size  = AV_RL16(&peek[5]);
    hdr->add_size = 0;
    if ((hdr->flags & 0x8000) ||
        hdr->type == RAR_BLOCK_FILE ||
        hdr->type == RAR_BLOCK_SUBBLOCK) {
        if (peek_size < 11)
            return -1;
        hdr->add_size = AV_RL32(&peek[7]);
    }

    if (hdr->size < 7)
        return -1;
    return 0;
}
Beispiel #4
0
static json_t *parse_value(stream_t *stream, size_t flags, json_error_t *error)
{
    json_t *result = NULL;
    char *string;
    int c = stream_peek(stream);

    switch (c) {
    case 'd':
        result = parse_dict(stream, flags, error);
        break;
    case 'l':
        result = parse_list(stream, flags, error);
        break;
    case 'i':
        stream_getc(stream);
        result = parse_integer(stream, flags, error);
        break;
    case EOF:
        error_set(error, stream, "unexpected EOF");
        break;
    default:
        if (json_isdigit(c)) {
            string = parse_string(stream, flags, error);
            if (string) {
                result = json_string_nocheck(string);
                jsonp_free(string);
            }
        } else {
            error_set(error, stream, "invalid character: %c", c);
        }
    }
    return result;
}
Beispiel #5
0
static int open_file(struct demuxer *demuxer, enum demux_check check)
{
    bool force = check < DEMUX_CHECK_UNSAFE || check == DEMUX_CHECK_REQUEST;

    struct pl_parser *p = talloc_zero(NULL, struct pl_parser);
    p->pl = talloc_zero(p, struct playlist);

    bstr probe_buf = stream_peek(demuxer->stream, PROBE_SIZE);
    p->s = open_memory_stream(probe_buf.start, probe_buf.len);
    p->utf16 = stream_skip_bom(p->s);
    p->probing = true;
    const struct pl_format *fmt = probe_pl(p, force);
    free_stream(p->s);
    playlist_clear(p->pl);
    if (!fmt) {
        talloc_free(p);
        return -1;
    }

    p->probing = false;
    p->s = demuxer->stream;
    p->utf16 = stream_skip_bom(p->s);
    bool ok = fmt->parse(p) >= 0;
    if (ok)
        playlist_add_base_path(p->pl, mp_dirname(demuxer->filename));
    demuxer->playlist = talloc_steal(demuxer, p->pl);
    demuxer->filetype = fmt->name;
    talloc_free(p);
    return ok ? 0 : -1;
}
Beispiel #6
0
Datei: rar.c Projekt: 0x0all/mpv
int RarProbe(struct stream *s)
{
    bstr peek = stream_peek(s, rar_marker_size);
    if (peek.len < rar_marker_size)
        return -1;
    if (memcmp(peek.start, rar_marker, rar_marker_size))
        return -1;
    return 0;
}
Beispiel #7
0
static json_t *parse_dict(stream_t *stream, size_t flags,
                          json_error_t *error)
{
    int c;
    char *key;
    json_t *value;
    json_t *object = json_object();
    if(!object)
        return NULL;

    c = stream_getc(stream);
    assert(c == 'd');

    while (1) {
        c = stream_peek(stream);
        if (c == EOF) {
            error_set(error, stream, "unterminated dictionary");
            goto error;
        }
        if (c == 'e')
            break;

        key = parse_string(stream, flags, error);
        if (!key)
            goto error;

        if(flags & JSON_REJECT_DUPLICATES) {
            if(json_object_get(object, key)) {
                jsonp_free(key);
                error_set(error, stream, "duplicate object key");
                goto error;
            }
        }

        value = parse_value(stream, flags, error);
        if (!value) {
            jsonp_free(key);
            goto error;
        }

        if(json_object_set_nocheck(object, key, value)) {
            jsonp_free(key);
            json_decref(value);
            goto error;
        }

        json_decref(value);
        jsonp_free(key);
    }
    stream_getc(stream);
    return object;

error:
    json_decref(object);
    return NULL;
}
Beispiel #8
0
static int validate_number(stream_t *stream, json_error_t *error)
{
    /* strtol functions allow extra spaces before the number */
    int c = stream_peek(stream);
    if (c != '-' && !json_isdigit(c)) {
        error_set(error, stream, "invalid number: %c", c);
        return -1;
    }
    return 0;
}
Beispiel #9
0
static json_t *parse_bencode(stream_t *stream, size_t flags,
                             json_error_t *error)
{
    json_t *result = parse_value(stream, flags, error);
    if (!result)
        return NULL;

    if (!(flags & JSON_DISABLE_EOF_CHECK)) {
        if (stream_peek(stream) != EOF) {
            error_set(error, stream, "end of file expected");
            json_decref(result);
            return NULL;
        }
    }
    return result;
}
Beispiel #10
0
static int parse_m3u(struct pl_parser *p)
{
    bstr line = bstr_strip(pl_get_line(p));
    if (p->probing && !bstr_equals0(line, "#EXTM3U")) {
        // Last resort: if the file extension is m3u, it might be headerless.
        if (p->check_level == DEMUX_CHECK_UNSAFE) {
            char *ext = mp_splitext(p->real_stream->url, NULL);
            bstr data = stream_peek(p->real_stream, PROBE_SIZE);
            if (ext && data.len > 10 && maybe_text(data)) {
                const char *exts[] = {"m3u", "m3u8", NULL};
                for (int n = 0; exts[n]; n++) {
                    if (strcasecmp(ext, exts[n]) == 0)
                        goto ok;
                }
            }
        }
        return -1;
    }

ok:
    if (p->probing)
        return 0;

    char *title = NULL;
    while (line.len || !pl_eof(p)) {
        if (bstr_eatstart0(&line, "#EXTINF:")) {
            bstr duration, btitle;
            if (bstr_split_tok(line, ",", &duration, &btitle) && btitle.len) {
                talloc_free(title);
                title = bstrto0(NULL, btitle);
            }
        } else if (bstr_startswith0(line, "#EXT-X-")) {
            p->format = "hls";
        } else if (line.len > 0 && !bstr_startswith0(line, "#")) {
            char *fn = bstrto0(NULL, line);
            struct playlist_entry *e = playlist_entry_new(fn);
            talloc_free(fn);
            e->title = talloc_steal(e, title);
            title = NULL;
            playlist_add(p->pl, e);
        }
        line = bstr_strip(pl_get_line(p));
    }
    talloc_free(title);
    return 0;
}
Beispiel #11
0
static int d_open(demuxer_t *demuxer, enum demux_check check)
{
    struct priv *p = demuxer->priv = talloc_zero(demuxer, struct priv);

    if (check != DEMUX_CHECK_FORCE)
        return -1;

    char *demux = "+lavf";
    if (demuxer->stream->uncached_type == STREAMTYPE_CDDA)
        demux = "+rawaudio";

    char *t = NULL;
    stream_control(demuxer->stream, STREAM_CTRL_GET_DISC_NAME, &t);
    if (t) {
        mp_tags_set_bstr(demuxer->metadata, bstr0("TITLE"), bstr0(t));
        talloc_free(t);
    }

    // Initialize the playback time. We need to read _some_ data to get the
    // correct stream-layer time (at least with libdvdnav).
    stream_peek(demuxer->stream, 1);
    reset_pts(demuxer);

    p->slave = demux_open(demuxer->stream, demux, NULL, demuxer->global);
    if (!p->slave)
        return -1;

    // So that we don't miss initial packets of delayed subtitle streams.
    demux_set_stream_autoselect(p->slave, true);

    // Can be seekable even if the stream isn't.
    demuxer->seekable = true;

    // With cache enabled, the stream can be seekable. This causes demux_lavf.c
    // (actually libavformat/mpegts.c) to seek sometimes when reading a packet.
    // It does this to seek back a bit in case the current file position points
    // into the middle of a packet.
    demuxer->stream->seekable = false;

    add_dvd_streams(demuxer);
    add_streams(demuxer);
    add_stream_chapters(demuxer);

    return 0;
}
Beispiel #12
0
static json_t *parse_list(stream_t *stream, size_t flags,
                          json_error_t *error)
{
    int c;
    json_t *elem;
    json_t *array = json_array();
    if(!array)
        return NULL;

    c = stream_getc(stream);
    assert(c == 'l');

    while (1) {
        c = stream_peek(stream);
        if (c == EOF) {
            error_set(error, stream, "unterminated list");
            goto error;
        }
        if (c == 'e')
            break;

        elem = parse_value(stream, flags, error);
        if (!elem)
            goto error;

        if(json_array_append(array, elem)) {
            json_decref(elem);
            goto error;
        }
        json_decref(elem);
    }
    stream_getc(stream);
    return array;

error:
    json_decref(array);
    return NULL;
}
Beispiel #13
0
static int parse_m3u(struct pl_parser *p)
{
    bstr line = bstr_strip(pl_get_line(p));
    if (p->probing && !bstr_equals0(line, "#EXTM3U")) {
        // Last resort: if the file extension is m3u, it might be headerless.
        if (p->check_level == DEMUX_CHECK_UNSAFE) {
            char *ext = mp_splitext(p->real_stream->url, NULL);
            bstr data = stream_peek(p->real_stream, PROBE_SIZE);
            if (ext && !strcmp(ext, "m3u") && data.len > 10 && maybe_text(data))
                goto ok;
        }
        return -1;
    }
ok:
    if (p->probing)
        return 0;
    while (line.len || !pl_eof(p)) {
        if (line.len > 0 && !bstr_startswith0(line, "#"))
            pl_add(p, line);
        line = bstr_strip(pl_get_line(p));
    }
    return 0;
}
Beispiel #14
0
static int d_open(demuxer_t *demuxer, enum demux_check check)
{
    struct priv *p = demuxer->priv = talloc_zero(demuxer, struct priv);

    if (check != DEMUX_CHECK_FORCE)
        return -1;

    struct demuxer_params params = {.force_format = "+lavf"};

    if (demuxer->stream->uncached_type == STREAMTYPE_CDDA)
        params.force_format = "+rawaudio";

    char *t = NULL;
    stream_control(demuxer->stream, STREAM_CTRL_GET_DISC_NAME, &t);
    if (t) {
        mp_tags_set_str(demuxer->metadata, "TITLE", t);
        talloc_free(t);
    }

    // Initialize the playback time. We need to read _some_ data to get the
    // correct stream-layer time (at least with libdvdnav).
    stream_peek(demuxer->stream, 1);
    reset_pts(demuxer);

    p->slave = demux_open(demuxer->stream, &params, demuxer->global);
    if (!p->slave)
        return -1;

    // So that we don't miss initial packets of delayed subtitle streams.
    demux_set_stream_autoselect(p->slave, true);

    // With cache enabled, the stream can be seekable. This causes demux_lavf.c
    // (actually libavformat/mpegts.c) to seek sometimes when reading a packet.
    // It does this to seek back a bit in case the current file position points
    // into the middle of a packet.
    if (demuxer->stream->uncached_type != STREAMTYPE_CDDA) {
        demuxer->stream->seekable = false;

        // Can be seekable even if the stream isn't.
        demuxer->seekable = true;

        demuxer->rel_seeks = true;
    }

    add_dvd_streams(demuxer);
    add_streams(demuxer);
    add_stream_chapters(demuxer);

    return 0;
}

static void d_close(demuxer_t *demuxer)
{
    struct priv *p = demuxer->priv;
    free_demuxer(p->slave);
}

static int d_control(demuxer_t *demuxer, int cmd, void *arg)
{
    struct priv *p = demuxer->priv;

    switch (cmd) {
    case DEMUXER_CTRL_GET_TIME_LENGTH: {
        double len;
        if (stream_control(demuxer->stream, STREAM_CTRL_GET_TIME_LENGTH, &len) < 1)
            break;
        *(double *)arg = len;
        return DEMUXER_CTRL_OK;
    }
    case DEMUXER_CTRL_RESYNC:
        demux_flush(p->slave);
        break; // relay to slave demuxer
    case DEMUXER_CTRL_SWITCHED_TRACKS:
        reselect_streams(demuxer);
        return DEMUXER_CTRL_OK;
    }
    return demux_control(p->slave, cmd, arg);
}

const demuxer_desc_t demuxer_desc_disc = {
    .name = "disc",
    .desc = "CD/DVD/BD wrapper",
    .fill_buffer = d_fill_buffer,
    .open = d_open,
    .close = d_close,
    .seek = d_seek,
    .control = d_control,
};
Beispiel #15
0
/* Returns a list of parts, or NULL on parse error.
 * Syntax (without file header or URI prefix):
 *    url      ::= <entry> ( (';' | '\n') <entry> )*
 *    entry    ::= <param> ( <param> ',' )*
 *    param    ::= [<string> '='] (<string> | '%' <number> '%' <bytes>)
 */
static struct tl_parts *parse_edl(bstr str)
{
    struct tl_parts *tl = talloc_zero(NULL, struct tl_parts);
    while (str.len) {
        if (bstr_eatstart0(&str, "#"))
            bstr_split_tok(str, "\n", &(bstr){0}, &str);
        if (bstr_eatstart0(&str, "\n") || bstr_eatstart0(&str, ";"))
            continue;
        struct tl_part p = { .length = -1 };
        int nparam = 0;
        while (1) {
            bstr name, val;
            // Check if it's of the form "name=..."
            int next = bstrcspn(str, "=%,;\n");
            if (next > 0 && next < str.len && str.start[next] == '=') {
                name = bstr_splice(str, 0, next);
                str = bstr_cut(str, next + 1);
            } else {
                const char *names[] = {"file", "start", "length"}; // implied name
                name = bstr0(nparam < 3 ? names[nparam] : "-");
            }
            if (bstr_eatstart0(&str, "%")) {
                int len = bstrtoll(str, &str, 0);
                if (!bstr_startswith0(str, "%") || (len > str.len - 1))
                    goto error;
                val = bstr_splice(str, 1, len + 1);
                str = bstr_cut(str, len + 1);
            } else {
                next = bstrcspn(str, ",;\n");
                val = bstr_splice(str, 0, next);
                str = bstr_cut(str, next);
            }
            // Interpret parameters. Explicitly ignore unknown ones.
            if (bstr_equals0(name, "file")) {
                p.filename = bstrto0(tl, val);
            } else if (bstr_equals0(name, "start")) {
                if (!parse_time(val, &p.offset))
                    goto error;
                p.offset_set = true;
            } else if (bstr_equals0(name, "length")) {
                if (!parse_time(val, &p.length))
                    goto error;
            } else if (bstr_equals0(name, "timestamps")) {
                if (bstr_equals0(val, "chapters"))
                    p.chapter_ts = true;
            }
            nparam++;
            if (!bstr_eatstart0(&str, ","))
                break;
        }
        if (!p.filename)
            goto error;
        MP_TARRAY_APPEND(tl, tl->parts, tl->num_parts, p);
    }
    if (!tl->num_parts)
        goto error;
    return tl;
error:
    talloc_free(tl);
    return NULL;
}

static struct demuxer *open_source(struct timeline *tl, char *filename)
{
    for (int n = 0; n < tl->num_sources; n++) {
        struct demuxer *d = tl->sources[n];
        if (strcmp(d->stream->url, filename) == 0)
            return d;
    }
    struct demuxer *d = demux_open_url(filename, NULL, tl->cancel, tl->global);
    if (d) {
        MP_TARRAY_APPEND(tl, tl->sources, tl->num_sources, d);
    } else {
        MP_ERR(tl, "EDL: Could not open source file '%s'.\n", filename);
    }
    return d;
}

static double demuxer_chapter_time(struct demuxer *demuxer, int n)
{
    if (n < 0 || n >= demuxer->num_chapters)
        return -1;
    return demuxer->chapters[n].pts;
}

// Append all chapters from src to the chapters array.
// Ignore chapters outside of the given time range.
static void copy_chapters(struct demux_chapter **chapters, int *num_chapters,
                          struct demuxer *src, double start, double len,
                          double dest_offset)
{
    for (int n = 0; n < src->num_chapters; n++) {
        double time = demuxer_chapter_time(src, n);
        if (time >= start && time <= start + len) {
            struct demux_chapter ch = {
                .pts = dest_offset + time - start,
                .metadata = mp_tags_dup(*chapters, src->chapters[n].metadata),
            };
            MP_TARRAY_APPEND(NULL, *chapters, *num_chapters, ch);
        }
    }
}

// return length of the source in seconds, or -1 if unknown
static double source_get_length(struct demuxer *demuxer)
{
    double time;
    // <= 0 means DEMUXER_CTRL_NOTIMPL or DEMUXER_CTRL_DONTKNOW
    if (demux_control(demuxer, DEMUXER_CTRL_GET_TIME_LENGTH, &time) <= 0)
        time = -1;
    return time;
}

static void resolve_timestamps(struct tl_part *part, struct demuxer *demuxer)
{
    if (part->chapter_ts) {
        double start = demuxer_chapter_time(demuxer, part->offset);
        double length = part->length;
        double end = length;
        if (end >= 0)
            end = demuxer_chapter_time(demuxer, part->offset + part->length);
        if (end >= 0 && start >= 0)
            length = end - start;
        part->offset = start;
        part->length = length;
    }
    if (!part->offset_set)
        part->offset = demuxer->start_time;
}

static void build_timeline(struct timeline *tl, struct tl_parts *parts)
{
    tl->parts = talloc_array_ptrtype(tl, tl->parts, parts->num_parts + 1);
    double starttime = 0;
    for (int n = 0; n < parts->num_parts; n++) {
        struct tl_part *part = &parts->parts[n];
        struct demuxer *source = open_source(tl, part->filename);
        if (!source)
            goto error;

        resolve_timestamps(part, source);

        double end_time = source_get_length(source);
        if (end_time >= 0)
            end_time += source->start_time;

        // Unknown length => use rest of the file. If duration is unknown, make
        // something up.
        if (part->length < 0) {
            if (end_time < 0) {
                MP_WARN(tl, "EDL: source file '%s' has unknown duration.\n",
                        part->filename);
                end_time = 1;
            }
            part->length = end_time - part->offset;
        } else if (end_time >= 0) {
            double end_part = part->offset + part->length;
            if (end_part > end_time) {
                MP_WARN(tl, "EDL: entry %d uses %f "
                        "seconds, but file has only %f seconds.\n",
                        n, end_part, end_time);
            }
        }

        // Add a chapter between each file.
        struct demux_chapter ch = {
            .pts = starttime,
            .metadata = talloc_zero(tl, struct mp_tags),
        };
        mp_tags_set_str(ch.metadata, "title", part->filename);
        MP_TARRAY_APPEND(tl, tl->chapters, tl->num_chapters, ch);

        // Also copy the source file's chapters for the relevant parts
        copy_chapters(&tl->chapters, &tl->num_chapters, source, part->offset,
                      part->length, starttime);

        tl->parts[n] = (struct timeline_part) {
            .start = starttime,
            .source_start = part->offset,
            .source = source,
        };

        starttime += part->length;
    }
    tl->parts[parts->num_parts] = (struct timeline_part) {.start = starttime};
    tl->num_parts = parts->num_parts;
    tl->track_layout = tl->parts[0].source;
    return;

error:
    tl->num_parts = 0;
    tl->num_chapters = 0;
}

// For security, don't allow relative or absolute paths, only plain filenames.
// Also, make these filenames relative to the edl source file.
static void fix_filenames(struct tl_parts *parts, char *source_path)
{
    struct bstr dirname = mp_dirname(source_path);
    for (int n = 0; n < parts->num_parts; n++) {
        struct tl_part *part = &parts->parts[n];
        char *filename = mp_basename(part->filename); // plain filename only
        part->filename = mp_path_join_bstr(parts, dirname, bstr0(filename));
    }
}

static void build_mpv_edl_timeline(struct timeline *tl)
{
    struct priv *p = tl->demuxer->priv;

    struct tl_parts *parts = parse_edl(p->data);
    if (!parts) {
        MP_ERR(tl, "Error in EDL.\n");
        return;
    }
    MP_TARRAY_APPEND(tl, tl->sources, tl->num_sources, tl->demuxer);
    // Source is .edl and not edl:// => don't allow arbitrary paths
    if (tl->demuxer->stream->uncached_type != STREAMTYPE_EDL)
        fix_filenames(parts, tl->demuxer->filename);
    build_timeline(tl, parts);
    talloc_free(parts);
}

static int try_open_file(struct demuxer *demuxer, enum demux_check check)
{
    struct priv *p = talloc_zero(demuxer, struct priv);
    demuxer->priv = p;
    demuxer->fully_read = true;

    struct stream *s = demuxer->stream;
    if (s->uncached_type == STREAMTYPE_EDL) {
        p->data = bstr0(s->path);
        return 0;
    }
    if (check >= DEMUX_CHECK_UNSAFE) {
        if (!bstr_equals0(stream_peek(s, strlen(HEADER)), HEADER))
            return -1;
    }
    p->data = stream_read_complete(s, demuxer, 1000000);
    if (p->data.start == NULL)
        return -1;
    bstr_eatstart0(&p->data, HEADER);
    return 0;
}

const struct demuxer_desc demuxer_desc_edl = {
    .name = "edl",
    .desc = "Edit decision list",
    .open = try_open_file,
    .load_timeline = build_mpv_edl_timeline,
};
Beispiel #16
0
Datei: rar.c Projekt: 0x0all/mpv
static int SkipFile(struct stream *s, int *count, rar_file_t ***file,
                    const rar_block_t *hdr, const char *volume_mrl)
{
    int min_size = 7+21;
    if (hdr->flags & RAR_BLOCK_FILE_HAS_HIGH)
        min_size += 8;
    if (hdr->size < (unsigned)min_size)
        return -1;

    bstr data = stream_peek(s, min_size);
    if (data.len < min_size)
        return -1;
    const uint8_t *peek = (uint8_t *)data.start;

    /* */
    uint32_t file_size_low = AV_RL32(&peek[7+4]);
    uint8_t  method = peek[7+18];
    uint16_t name_size = AV_RL16(&peek[7+19]);
    uint32_t file_size_high = 0;
    if (hdr->flags & RAR_BLOCK_FILE_HAS_HIGH)
        file_size_high = AV_RL32(&peek[7+29]);
    const uint64_t file_size = ((uint64_t)file_size_high << 32) | file_size_low;

    char *name = calloc(1, name_size + 1);
    if (!name)
        return -1;

    const int name_offset = (hdr->flags & RAR_BLOCK_FILE_HAS_HIGH) ? (7+33) : (7+25);
    if (name_offset + name_size <= hdr->size) {
        const int max_size = name_offset + name_size;
        bstr namedata = stream_peek(s, max_size);
        if (namedata.len < max_size) {
            free(name);
            return -1;
        }
        memcpy(name, &namedata.start[name_offset], name_size);
    }

    rar_file_t *current = NULL;
    if (method != 0x30) {
        MP_WARN(s, "Ignoring compressed file %s (method=0x%2.2x)\n", name, method);
        goto exit;
    }

    /* */
    if( *count > 0 )
        current = (*file)[*count - 1];

    if (current &&
        (current->is_complete ||
          strcmp(current->name, name) ||
          (hdr->flags & RAR_BLOCK_FILE_HAS_PREVIOUS) == 0))
        current = NULL;

    if (!current) {
        if (hdr->flags & RAR_BLOCK_FILE_HAS_PREVIOUS)
            goto exit;
        current = calloc(1, sizeof(*current));
        if (!current)
            goto exit;
        MP_TARRAY_APPEND(NULL, *file, *count, current);

        current->name = name;
        current->size = file_size;
        current->is_complete = false;
        current->real_size = 0;
        current->chunk_count = 0;
        current->chunk = NULL;

        name = NULL;
    }

    /* Append chunks */
    rar_file_chunk_t *chunk = malloc(sizeof(*chunk));
    if (chunk) {
        chunk->mrl = strdup(volume_mrl);
        chunk->offset = stream_tell(s) + hdr->size;
        chunk->size = hdr->add_size;
        chunk->cummulated_size = 0;
        if (current->chunk_count > 0) {
            rar_file_chunk_t *previous = current->chunk[current->chunk_count-1];

            chunk->cummulated_size += previous->cummulated_size +
                                      previous->size;
        }

        MP_TARRAY_APPEND(NULL, current->chunk, current->chunk_count, chunk);

        current->real_size += hdr->add_size;
    }
    if ((hdr->flags & RAR_BLOCK_FILE_HAS_NEXT) == 0)
        current->is_complete = true;

exit:
    /* */
    free(name);

    /* We stop on the first non empty file if we cannot seek */
    if (current) {
        bool can_seek = s->end_pos > 0;
        if (!can_seek && current->size > 0)
            return -1;
    }

    if (SkipBlock(s, hdr))
        return -1;
    return 0;
}
Beispiel #17
0
Datei: misc.c Projekt: Ionic/mpv
void update_vo_playback_state(struct MPContext *mpctx)
{
    if (mpctx->video_out && mpctx->video_out->config_ok) {
        struct voctrl_playback_state oldstate = mpctx->vo_playback_state;
        struct voctrl_playback_state newstate = {
            .taskbar_progress = mpctx->opts->vo->taskbar_progress,
            .playing = mpctx->playing,
            .paused = mpctx->paused,
            .percent_pos = get_percent_pos(mpctx),
        };

        if (oldstate.taskbar_progress != newstate.taskbar_progress ||
            oldstate.playing != newstate.playing ||
            oldstate.paused != newstate.paused ||
            oldstate.percent_pos != newstate.percent_pos)
        {
            // Don't update progress bar if it was and still is hidden
            if ((oldstate.playing && oldstate.taskbar_progress) ||
                (newstate.playing && newstate.taskbar_progress))
            {
                vo_control_async(mpctx->video_out,
                                 VOCTRL_UPDATE_PLAYBACK_STATE, &newstate);
            }
            mpctx->vo_playback_state = newstate;
        }
    } else {
        mpctx->vo_playback_state = (struct voctrl_playback_state){ 0 };
    }
}

void update_window_title(struct MPContext *mpctx, bool force)
{
    if (!mpctx->video_out && !mpctx->ao) {
        talloc_free(mpctx->last_window_title);
        mpctx->last_window_title = NULL;
        return;
    }
    char *title = mp_property_expand_string(mpctx, mpctx->opts->wintitle);
    if (!mpctx->last_window_title || force ||
        strcmp(title, mpctx->last_window_title) != 0)
    {
        talloc_free(mpctx->last_window_title);
        mpctx->last_window_title = talloc_steal(mpctx, title);

        if (mpctx->video_out)
            vo_control(mpctx->video_out, VOCTRL_UPDATE_WINDOW_TITLE, title);

        if (mpctx->ao) {
            ao_control(mpctx->ao, AOCONTROL_UPDATE_STREAM_TITLE, title);
        }
    } else {
        talloc_free(title);
    }
}

void error_on_track(struct MPContext *mpctx, struct track *track)
{
    if (!track || !track->selected)
        return;
    mp_deselect_track(mpctx, track);
    if (track->type == STREAM_AUDIO)
        MP_INFO(mpctx, "Audio: no audio\n");
    if (track->type == STREAM_VIDEO)
        MP_INFO(mpctx, "Video: no video\n");
    if (mpctx->opts->stop_playback_on_init_failure ||
        !(mpctx->vo_chain || mpctx->ao_chain))
    {
        if (!mpctx->stop_play)
            mpctx->stop_play = PT_ERROR;
        if (mpctx->error_playing >= 0)
            mpctx->error_playing = MPV_ERROR_NOTHING_TO_PLAY;
    }
    mp_wakeup_core(mpctx);
}

int stream_dump(struct MPContext *mpctx, const char *source_filename)
{
    struct MPOpts *opts = mpctx->opts;
    stream_t *stream = stream_open(source_filename, mpctx->global);
    if (!stream)
        return -1;

    int64_t size = stream_get_size(stream);

    FILE *dest = fopen(opts->stream_dump, "wb");
    if (!dest) {
        MP_ERR(mpctx, "Error opening dump file: %s\n", mp_strerror(errno));
        return -1;
    }

    bool ok = true;

    while (mpctx->stop_play == KEEP_PLAYING && ok) {
        if (!opts->quiet && ((stream->pos / (1024 * 1024)) % 2) == 1) {
            uint64_t pos = stream->pos;
            MP_MSG(mpctx, MSGL_STATUS, "Dumping %lld/%lld...",
                   (long long int)pos, (long long int)size);
        }
        bstr data = stream_peek(stream, STREAM_MAX_BUFFER_SIZE);
        if (data.len == 0) {
            ok &= stream->eof;
            break;
        }
        ok &= fwrite(data.start, data.len, 1, dest) == 1;
        stream_skip(stream, data.len);
        mp_wakeup_core(mpctx); // don't actually sleep
        mp_idle(mpctx); // but process input
    }

    ok &= fclose(dest) == 0;
    free_stream(stream);
    return ok ? 0 : -1;
}

void merge_playlist_files(struct playlist *pl)
{
    if (!pl->first)
        return;
    char *edl = talloc_strdup(NULL, "edl://");
    for (struct playlist_entry *e = pl->first; e; e = e->next) {
        if (e != pl->first)
            edl = talloc_strdup_append_buffer(edl, ";");
        // Escape if needed
        if (e->filename[strcspn(e->filename, "=%,;\n")] ||
            bstr_strip(bstr0(e->filename)).len != strlen(e->filename))
        {
            // %length%
            edl = talloc_asprintf_append_buffer(edl, "%%%zd%%", strlen(e->filename));
        }
        edl = talloc_strdup_append_buffer(edl, e->filename);
    }
    playlist_clear(pl);
    playlist_add_file(pl, edl);
    talloc_free(edl);
}