Example #1
0
static bool try_open(struct MPContext *mpctx, char *filename)
{
    struct bstr bfilename = bstr0(filename);
    // Avoid trying to open itself or another .cue file. Best would be
    // to check the result of demuxer auto-detection, but the demuxer
    // API doesn't allow this without opening a full demuxer.
    if (bstr_case_endswith(bfilename, bstr0(".cue"))
        || bstrcasecmp(bstr0(mpctx->demuxer->filename), bfilename) == 0)
        return false;

    struct stream *s = stream_open(filename, mpctx->opts);
    if (!s)
        return false;
    struct demuxer *d = demux_open(s, NULL, NULL, mpctx->opts);
    // Since .bin files are raw PCM data with no headers, we have to explicitly
    // open them. Also, try to avoid to open files that are most likely not .bin
    // files, as that would only play noise. Checking the file extension is
    // fragile, but it's about the only way we have.
    // TODO: maybe also could check if the .bin file is a multiple of the Audio
    //       CD sector size (2352 bytes)
    if (!d && bstr_case_endswith(bfilename, bstr0(".bin"))) {
        mp_msg(MSGT_CPLAYER, MSGL_WARN, "CUE: Opening as BIN file!\n");
        d = demux_open(s, "rawaudio", NULL, mpctx->opts);
    }
    if (d) {
        add_source(mpctx, d);
        return true;
    }
    mp_msg(MSGT_CPLAYER, MSGL_ERR, "Could not open source '%s'!\n", filename);
    free_stream(s);
    return false;
}
Example #2
0
static bool try_open(struct timeline *tl, char *filename)
{
    struct bstr bfilename = bstr0(filename);
    // Avoid trying to open itself or another .cue file. Best would be
    // to check the result of demuxer auto-detection, but the demuxer
    // API doesn't allow this without opening a full demuxer.
    if (bstr_case_endswith(bfilename, bstr0(".cue"))
        || bstrcasecmp(bstr0(tl->demuxer->filename), bfilename) == 0)
        return false;

    struct demuxer *d = demux_open_url(filename, NULL, tl->cancel, tl->global);
    // Since .bin files are raw PCM data with no headers, we have to explicitly
    // open them. Also, try to avoid to open files that are most likely not .bin
    // files, as that would only play noise. Checking the file extension is
    // fragile, but it's about the only way we have.
    // TODO: maybe also could check if the .bin file is a multiple of the Audio
    //       CD sector size (2352 bytes)
    if (!d && bstr_case_endswith(bfilename, bstr0(".bin"))) {
        MP_WARN(tl, "CUE: Opening as BIN file!\n");
        struct demuxer_params p = {.force_format = "rawaudio"};
        d = demux_open_url(filename, &p, tl->cancel, tl->global);
    }
    if (d) {
        add_source(tl, d);
        return true;
    }
    MP_ERR(tl, "Could not open source '%s'!\n", filename);
    return false;
}
Example #3
0
static int parse_ref_init(struct pl_parser *p)
{
    bstr line = bstr_strip(pl_get_line(p));
    if (!bstr_equals0(line, "[Reference]"))
        return -1;

    // ASF http streaming redirection - this is needed because ffmpeg http://
    // and mmsh:// can not automatically switch automatically between each
    // others. Both protocols use http - MMSH requires special http headers
    // to "activate" it, and will in other cases return this playlist.
    static const char *const mmsh_types[] = {"audio/x-ms-wax",
        "audio/x-ms-wma", "video/x-ms-asf", "video/x-ms-afs", "video/x-ms-wmv",
        "video/x-ms-wma", "application/x-mms-framed",
        "application/vnd.ms.wms-hdr.asfv1", NULL};
    bstr burl = bstr0(p->s->url);
    if (bstr_eatstart0(&burl, "http://") && check_mimetype(p->s, mmsh_types)) {
        MP_INFO(p, "Redirecting to mmsh://\n");
        playlist_add_file(p->pl, talloc_asprintf(p, "mmsh://%.*s", BSTR_P(burl)));
        return 0;
    }

    while (!pl_eof(p)) {
        line = bstr_strip(pl_get_line(p));
        if (bstr_case_startswith(line, bstr0("Ref"))) {
            bstr_split_tok(line, "=", &(bstr){0}, &line);
            if (line.len)
                pl_add(p, line);
        }
    }
    return 0;
}
Example #4
0
static stream_t *open_stream_plugin(const stream_info_t *sinfo,
                                    const char *filename,
                                    int mode, struct MPOpts *options,
                                    int *file_format, int *ret,
                                    char **redirected_url)
{
  void* arg = NULL;
  stream_t* s;
  m_struct_t* desc = (m_struct_t*)sinfo->opts;

  // Parse options
  if(desc) {
    arg = m_struct_alloc(desc);
    if(sinfo->opts_url) {
      m_option_t url_opt =
	{ "stream url", arg , CONF_TYPE_CUSTOM_URL, 0, 0 ,0, (void *)sinfo->opts };
      if (m_option_parse(&url_opt, bstr0("stream url"), bstr0(filename), arg) < 0) {
	mp_tmsg(MSGT_OPEN,MSGL_ERR, "URL parsing failed on url %s\n",filename);
	m_struct_free(desc,arg);
	return NULL;
      }
    }
  }
  s = new_stream(-2,-2);
  s->opts = options;
  s->url=strdup(filename);
  s->flags |= mode;
  *ret = sinfo->open(s,mode,arg,file_format);
  if((*ret) != STREAM_OK) {
#ifdef CONFIG_NETWORKING
    if (*ret == STREAM_REDIRECTED && redirected_url) {
        if (s->streaming_ctrl && s->streaming_ctrl->url
            && s->streaming_ctrl->url->url)
          *redirected_url = strdup(s->streaming_ctrl->url->url);
        else
          *redirected_url = NULL;
    }
    streaming_ctrl_free(s->streaming_ctrl);
#endif
    free(s->url);
    free(s);
    return NULL;
  }
  if(s->type <= -2)
    mp_msg(MSGT_OPEN,MSGL_WARN, "Warning streams need a type !!!!\n");
  if(s->flags & MP_STREAM_SEEK && !s->seek)
    s->flags &= ~MP_STREAM_SEEK;
  if(s->seek && !(s->flags & MP_STREAM_SEEK))
    s->flags |= MP_STREAM_SEEK;

  s->mode = mode;

  mp_msg(MSGT_OPEN,MSGL_V, "STREAM: [%s] %s\n",sinfo->name,filename);
  mp_msg(MSGT_OPEN,MSGL_V, "STREAM: Description: %s\n",sinfo->info);
  mp_msg(MSGT_OPEN,MSGL_V, "STREAM: Author: %s\n", sinfo->author);
  mp_msg(MSGT_OPEN,MSGL_V, "STREAM: Comment: %s\n", sinfo->comment);

  return s;
}
Example #5
0
// Add entry, but only if it's not yet on the list, and if the codec matches.
// If codec == NULL, don't compare codecs.
static void add_new(struct mp_decoder_list *to, struct mp_decoder_entry *entry,
                    const char *codec)
{
    if (!entry || (codec && strcmp(entry->codec, codec) != 0))
        return;
    if (!find_decoder(to, bstr0(entry->family), bstr0(entry->decoder)))
        mp_add_decoder_entry(to, entry);
}
Example #6
0
File: json.c Project: Akemi/mpv
static void add_indent(bstr *b, int indent)
{
    if (indent < 0)
        return;
    bstr_xappend(NULL, b, bstr0("\n"));
    for (int n = 0; n < indent; n++)
        bstr_xappend(NULL, b, bstr0(" "));
}
Example #7
0
// Select a decoder from the given list for the given codec. The selection
// can be influenced by the selection string, which can specify a priority
// list of preferred decoders.
// This returns a list of decoders to try, with the preferred decoders first.
// The selection string corresponds to --vd/--ad directly, and has the
// following syntax:
//   selection = [<entry> ("," <entry>)*]
//       entry = <family> ":" <decoder>         // prefer decoder
//       entry = <family> ":*"                  // prefer all decoders
//       entry = "+" <family> ":" <decoder>     // force a decoder
//       entry = "-" <family> ":" <decoder>     // exclude a decoder
//       entry = "-"                            // don't add fallback decoders
// Forcing a decoder means it's added even if the codec mismatches.
struct mp_decoder_list *mp_select_decoders(struct mp_decoder_list *all,
                                           const char *codec,
                                           const char *selection)
{
    struct mp_decoder_list *list = talloc_zero(NULL, struct mp_decoder_list);
    struct mp_decoder_list *remove = talloc_zero(NULL, struct mp_decoder_list);
    if (!codec)
        codec = "unknown";
    bool stop = false;
    bstr sel = bstr0(selection);
    while (sel.len) {
        bstr entry;
        bstr_split_tok(sel, ",", &entry, &sel);
        if (bstr_equals0(entry, "-")) {
            stop = true;
            break;
        }
        bool force = bstr_eatstart0(&entry, "+");
        bool exclude = !force && bstr_eatstart0(&entry, "-");
        struct mp_decoder_list *dest = exclude ? remove : list;
        bstr family, decoder;
        if (!bstr_split_tok(entry, ":", &family, &decoder)) {
            mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Decoders must be specified as "
                   "'family:decoder' for the --ad/--vd options.\n");
            break;
        }
        if (bstr_equals0(decoder, "*")) {
            for (int n = 0; n < all->num_entries; n++) {
                struct mp_decoder_entry *cur = &all->entries[n];
                if (bstr_equals0(family, cur->family))
                    add_new(dest, cur, codec);
            }
        } else {
            add_new(dest, find_decoder(all, family, decoder),
                    force ? NULL : codec);
        }
    }
    if (!stop) {
        // Add the remaining codecs which haven't been added yet
        for (int n = 0; n < all->num_entries; n++)
            add_new(list, &all->entries[n], codec);
    }
    for (int n = 0; n < remove->num_entries; n++) {
        struct mp_decoder_entry *ex = &remove->entries[n];
        struct mp_decoder_entry *del =
            find_decoder(list, bstr0(ex->family), bstr0(ex->decoder));
        if (del) {
            int index = del - &list->entries[0];
            MP_TARRAY_REMOVE_AT(list->entries, list->num_entries, index);
        }
    }
    talloc_free(remove);
    return list;
}
Example #8
0
void playlist_add_base_path(struct playlist *pl, bstr base_path)
{
    if (base_path.len == 0 || bstrcmp0(base_path, ".") == 0)
        return;
    for (struct playlist_entry *e = pl->first; e; e = e->next) {
        if (!mp_is_url(bstr0(e->filename))) {
            char *new_file = mp_path_join(e, base_path, bstr0(e->filename));
            talloc_free(e->filename);
            e->filename = new_file;
        }
    }
}
Example #9
0
static bool open_source(struct MPContext *mpctx, struct bstr filename)
{
    void *ctx = talloc_new(NULL);
    bool res = false;

    struct bstr dirname = mp_dirname(mpctx->demuxer->filename);

    struct bstr base_filename = bstr0(mp_basename(bstrdup0(ctx, filename)));
    if (!base_filename.len) {
        mp_msg(MSGT_CPLAYER, MSGL_WARN,
               "CUE: Invalid audio filename in .cue file!\n");
    } else {
        char *fullname = mp_path_join(ctx, dirname, base_filename);
        if (try_open(mpctx, fullname)) {
            res = true;
            goto out;
        }
    }

    // Try an audio file with the same name as the .cue file (but different
    // extension).
    // Rationale: this situation happens easily if the audio file or both files
    // are renamed.

    struct bstr cuefile =
        bstr_strip_ext(bstr0(mp_basename(mpctx->demuxer->filename)));

    DIR *d = opendir(bstrdup0(ctx, dirname));
    if (!d)
        goto out;
    struct dirent *de;
    while ((de = readdir(d))) {
        char *dename0 = de->d_name;
        struct bstr dename = bstr0(dename0);
        if (bstr_case_startswith(dename, cuefile)) {
            mp_msg(MSGT_CPLAYER, MSGL_WARN, "CUE: No useful audio filename "
                    "in .cue file found, trying with '%s' instead!\n",
                    dename0);
            if (try_open(mpctx, mp_path_join(ctx, dirname, dename))) {
                res = true;
                break;
            }
        }
    }
    closedir(d);

out:
    talloc_free(ctx);
    if (!res)
        mp_msg(MSGT_CPLAYER, MSGL_ERR, "CUE: Could not open audio file!\n");
    return res;
}
Example #10
0
// selection is a ","-separated list of decoders, all in the given family.
struct mp_decoder_list *mp_select_decoder_list(struct mp_decoder_list *all,
                                               const char *codec,
                                               const char *family,
                                               const char *selection)
{
    struct mp_decoder_list *list = talloc_zero(NULL, struct mp_decoder_list);
    bstr sel = bstr0(selection);
    while (sel.len) {
        bstr decoder;
        bstr_split_tok(sel, ",", &decoder, &sel);
        add_new(list, find_decoder(all, bstr0(family), decoder), codec);
    }
    return list;
}
Example #11
0
char *mp_get_win_config_path(const char *filename)
{
    wchar_t w_appdir[MAX_PATH + 1] = {0};
    wchar_t w_exedir[MAX_PATH + 1] = {0};
    char *res = NULL;
    void *tmp = talloc_new(NULL);

#ifndef __CYGWIN__
    if (SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE, NULL,
        SHGFP_TYPE_CURRENT, w_appdir) != S_OK)
        w_appdir[0] = '\0';
#endif

    get_exe_dir(w_exedir);

    if (filename && filename[0] && w_exedir[0]) {
        char *dir = mp_to_utf8(tmp, w_exedir);
        char *temp = mp_path_join(tmp, bstr0(dir), bstr0("mpv"));
        res = mp_path_join(NULL, bstr0(temp), bstr0(filename));
        if (!mp_path_exists(res) || mp_path_isdir(res)) {
            talloc_free(res);
            res = NULL;
        }
    }

    if (!res && w_appdir[0]) {
        char *dir = mp_to_utf8(tmp, w_appdir);
        char *temp = mp_path_join(tmp, bstr0(dir), bstr0("mpv"));
        res = mp_path_join(NULL, bstr0(temp), bstr0(filename));
    }

    talloc_free(tmp);
    return res;
}
Example #12
0
static int open_f(stream_t *stream)
{
    stream->fill_buffer = fill_buffer;
    stream->seek = seek;
    stream->seekable = true;
    stream->control = control;
    stream->read_chunk = 1024 * 1024;

    struct priv *p = talloc_zero(stream, struct priv);
    stream->priv = p;

    // Initial data
    bstr data = bstr0(stream->url);
    bool use_hex = bstr_eatstart0(&data, "hex://");
    if (!use_hex)
        bstr_eatstart0(&data, "memory://");
    stream_control(stream, STREAM_CTRL_SET_CONTENTS, &data);

    if (use_hex && !bstr_decode_hex(stream, p->data, &p->data)) {
        MP_FATAL(stream, "Invalid data.\n");
        return STREAM_ERROR;
    }

    return STREAM_OK;
}
Example #13
0
static void fill_plaintext(struct sd *sd, double pts)
{
    struct sd_ass_priv *ctx = sd->priv;
    ASS_Track *track = ctx->shadow_track;

    ass_flush_events(track);

    char *text = get_text(sd, pts);
    if (!text)
        return;

    bstr dst = {0};
    while (*text) {
        if (*text == '{')
            bstr_xappend(NULL, &dst, bstr0("\\"));
        bstr_xappend(NULL, &dst, (bstr){text, 1});
        // Break ASS escapes with U+2060 WORD JOINER
        if (*text == '\\')
            mp_append_utf8_bstr(NULL, &dst, 0x2060);
        text++;
    }

    if (!dst.start || !dst.start[0])
        return;

    int n = ass_alloc_event(track);
    ASS_Event *event = track->events + n;
    event->Start = 0;
    event->Duration = INT_MAX;
    event->Style = track->default_style;
    event->Text = strdup(dst.start);

    if (track->default_style < track->n_styles)
        track->styles[track->default_style].Alignment = ctx->on_top ? 6 : 2;
}
Example #14
0
File: json.c Project: Akemi/mpv
static int json_append_str(char **dst, struct mpv_node *src, int indent)
{
    bstr buffer = bstr0(*dst);
    int r = json_append(&buffer, src, indent);
    *dst = buffer.start;
    return r;
}
Example #15
0
static int init(struct ao *ao)
{
    struct priv *priv = ao->priv;

    ao->untimed = priv->untimed;

    struct mp_chmap_sel sel = {.tmp = ao};
    if (priv->channel_layouts) {
        for (int n = 0; priv->channel_layouts[n]; n++) {
            struct mp_chmap map = {0};
            if (!mp_chmap_from_str(&map, bstr0(priv->channel_layouts[n]))) {
                MP_FATAL(ao, "Invalid channel map in option.\n");
                return -1;
            }
            mp_chmap_sel_add_map(&sel, &map);
        }
    } else {
        mp_chmap_sel_add_any(&sel);
    }
    if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
        mp_chmap_from_channels(&ao->channels, 2);

    priv->latency = priv->latency_sec * ao->samplerate;

    // A "buffer" for this many seconds of audio
    int bursts = (int)(ao->samplerate * priv->bufferlen + 1) / priv->outburst;
    priv->buffersize = priv->outburst * bursts + priv->latency;

    priv->last_time = mp_time_sec();

    return 0;
}
Example #16
0
struct playlist_entry *playlist_entry_new(const char *filename)
{
    struct playlist_entry *e = talloc_zero(NULL, struct playlist_entry);
    char *local_filename = mp_file_url_to_filename(e, bstr0(filename));
    e->filename = local_filename ? local_filename : talloc_strdup(e, filename);
    return e;
}
Example #17
0
static int parse_dir(struct pl_parser *p)
{
    if (p->real_stream->type != STREAMTYPE_DIR)
        return -1;
    if (p->probing)
        return 0;

    char *path = mp_file_get_path(p, bstr0(p->real_stream->url));

    char **files = NULL;
    int num_files = 0;
    struct stat dir_stack[MAX_DIR_STACK];

    scan_dir(p, path, dir_stack, 0, &files, &num_files);

    if (files)
        qsort(files, num_files, sizeof(files[0]), cmp_filename);

    for (int n = 0; n < num_files; n++)
        playlist_add_file(p->pl, files[n]);

    p->add_base = false;

    return num_files > 0 ? 0 : -1;
}
Example #18
0
struct lavc_conv *lavc_conv_create(struct mp_log *log, const char *codec_name,
                                   char *extradata, int extradata_len)
{
    struct lavc_conv *priv = talloc_zero(NULL, struct lavc_conv);
    priv->log = log;
    priv->cur_list = talloc_array(priv, char*, 0);
    priv->codec = talloc_strdup(priv, codec_name);
    AVCodecContext *avctx = NULL;
    const char *fmt = get_lavc_format(priv->codec);
    AVCodec *codec = avcodec_find_decoder(mp_codec_to_av_codec_id(fmt));
    if (!codec)
        goto error;
    avctx = avcodec_alloc_context3(codec);
    if (!avctx)
        goto error;
    avctx->extradata_size = extradata_len;
    avctx->extradata = talloc_memdup(priv, extradata, extradata_len);
    if (avcodec_open2(avctx, codec, NULL) < 0)
        goto error;
    // Documented as "set by libavcodec", but there is no other way
    avctx->time_base = (AVRational) {1, 1000};
    priv->avctx = avctx;
    priv->extradata = talloc_strndup(priv, avctx->subtitle_header,
                                     avctx->subtitle_header_size);
    disable_styles(bstr0(priv->extradata));
    return priv;

 error:
    MP_FATAL(priv, "Could not open libavcodec subtitle converter\n");
    av_free(avctx);
    talloc_free(priv);
    return NULL;
}
Example #19
0
static int parse_mov_rtsptext(struct pl_parser *p)
{
    bstr line = pl_get_line(p);
    if (!bstr_eatstart(&line, bstr0("RTSPtext")))
        return -1;
    if (p->probing)
        return 0;
    line = bstr_strip(line);
    do {
        if (bstr_case_startswith(line, bstr0("rtsp://"))) {
            pl_add(p, line);
            return 0;
        }
    } while (!pl_eof(p) && (line = bstr_strip(pl_get_line(p))).len);
    return -1;
}
Example #20
0
File: json.c Project: 0x0all/mpv
/* Write the contents of *src as JSON, and append the JSON string to *dst.
 * This will use strlen() to determine the start offset, and ta_get_size()
 * and ta_realloc() to extend the memory allocation of *dst.
 * Returns: 0 on success, <0 on failure.
 */
int json_write(char **dst, struct mpv_node *src)
{
    bstr buffer = bstr0(*dst);
    int r = json_append(&buffer, src);
    *dst = buffer.start;
    return r;
}
Example #21
0
File: json.c Project: 0x0all/mpv
static int read_str(void *ta_parent, struct mpv_node *dst, char **src)
{
    if (!eat_c(src, '"'))
        return -1; // not a string
    char *str = *src;
    char *cur = str;
    bool has_escapes = false;
    while (cur[0] && cur[0] != '"') {
        if (cur[0] == '\\') {
            has_escapes = true;
            // skip >\"< and >\\< (latter to handle >\\"< correctly)
            if (cur[1] == '"' || cur[1] == '\\')
                cur++;
        }
        cur++;
    }
    if (cur[0] != '"')
        return -1; // invalid termination
    // Mutate input string so we have a null-terminated string to the literal.
    // This is a stupid micro-optimization, so we can avoid allocation.
    cur[0] = '\0';
    *src = cur + 1;
    if (has_escapes) {
        bstr unescaped = {0};
        bstr r = bstr0(str);
        if (!mp_append_escaped_string(ta_parent, &unescaped, &r))
            return -1; // broken escapes
        str = unescaped.start; // the function guarantees null-termination
    }
    dst->format = MPV_FORMAT_STRING;
    dst->u.string = str;
    return 0;
}
Example #22
0
static void mp_load_per_file_config(struct MPContext *mpctx)
{
    struct MPOpts *opts = mpctx->opts;
    char *confpath;
    char cfg[512];
    const char *file = mpctx->filename;

    if (snprintf(cfg, sizeof(cfg), "%s.conf", file) >= sizeof(cfg)) {
        MP_WARN(mpctx, "Filename is too long, "
                "can not load file or directory specific config files\n");
        return;
    }

    char *name = mp_basename(cfg);

    if (opts->use_filedir_conf) {
        bstr dir = mp_dirname(cfg);
        char *dircfg = mp_path_join(NULL, dir, bstr0("mpv.conf"));
        try_load_config(mpctx, dircfg, FILE_LOCAL_FLAGS);
        talloc_free(dircfg);

        if (try_load_config(mpctx, cfg, FILE_LOCAL_FLAGS))
            return;
    }

    if ((confpath = mp_find_user_config_file(NULL, mpctx->global, name))) {
        try_load_config(mpctx, confpath, FILE_LOCAL_FLAGS);

        talloc_free(confpath);
    }
}
Example #23
0
void mp_load_auto_profiles(struct MPContext *mpctx)
{
    struct MPOpts *opts = mpctx->opts;

    mp_auto_load_profile(mpctx, "protocol",
                         mp_split_proto(bstr0(mpctx->filename), NULL));
    mp_auto_load_profile(mpctx, "extension",
                         bstr0(mp_splitext(mpctx->filename, NULL)));

    mp_load_per_file_config(mpctx);

    if (opts->vo.video_driver_list)
        mp_auto_load_profile(mpctx, "vo", bstr0(opts->vo.video_driver_list[0].name));
    if (opts->audio_driver_list)
        mp_auto_load_profile(mpctx, "ao", bstr0(opts->audio_driver_list[0].name));
}
Example #24
0
// Iterate entries. The first call establishes the first entry. Returns false
// if no entry found, otherwise returns true and sets mpa->entry/entry_filename.
bool mp_archive_next_entry(struct mp_archive *mpa)
{
    mpa->entry = NULL;
    talloc_free(mpa->entry_filename);
    mpa->entry_filename = NULL;

    while (!mp_cancel_test(mpa->primary_src->cancel)) {
        struct archive_entry *entry;
        int r = archive_read_next_header(mpa->arch, &entry);
        if (r == ARCHIVE_EOF)
            break;
        if (r < ARCHIVE_OK)
            MP_ERR(mpa, "%s\n", archive_error_string(mpa->arch));
        if (r < ARCHIVE_WARN) {
            MP_FATAL(mpa, "could not read archive entry\n");
            break;
        }
        if (archive_entry_filetype(entry) != AE_IFREG)
            continue;
        // Some archives may have no filenames, or libarchive won't return some.
        const char *fn = archive_entry_pathname(entry);
        char buf[64];
        if (!fn || bstr_validate_utf8(bstr0(fn)) < 0) {
            snprintf(buf, sizeof(buf), "mpv_unknown#%d", mpa->entry_num);
            fn = buf;
        }
        mpa->entry = entry;
        mpa->entry_filename = talloc_strdup(mpa, fn);
        mpa->entry_num += 1;
        return true;
    }

    return false;
}
Example #25
0
static void write_arg(bstr *cmdline, char *arg)
{
    // Empty args must be represented as an empty quoted string
    if (!arg[0]) {
        bstr_xappend(NULL, cmdline, bstr0("\"\""));
        return;
    }

    // If the string doesn't have characters that need to be escaped, it's best
    // to leave it alone for the sake of Windows programs that don't process
    // quoted args correctly.
    if (!strpbrk(arg, " \t\"")) {
        bstr_xappend(NULL, cmdline, bstr0(arg));
        return;
    }

    // If there are characters that need to be escaped, write a quoted string
    bstr_xappend(NULL, cmdline, bstr0("\""));

    // Escape the argument. To match the behavior of CommandLineToArgvW,
    // backslashes are only escaped if they appear before a quote or the end of
    // the string.
    int num_slashes = 0;
    for (int pos = 0; arg[pos]; pos++) {
        switch (arg[pos]) {
        case '\\':
            // Count consecutive backslashes
            num_slashes++;
            break;
        case '"':
            // Write the argument up to the point before the quote
            bstr_xappend(NULL, cmdline, (struct bstr){arg, pos});
            arg += pos;
            pos = 0;

            // Double backslashes preceding the quote
            for (int i = 0; i < num_slashes; i++)
                bstr_xappend(NULL, cmdline, bstr0("\\"));
            num_slashes = 0;

            // Escape the quote itself
            bstr_xappend(NULL, cmdline, bstr0("\\"));
            break;
        default:
            num_slashes = 0;
        }
    }
Example #26
0
File: cue.c Project: 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;
}
Example #27
0
static bool test_ext_list(bstr ext, const char *const *list)
{
    for (int n = 0; list[n]; n++) {
        if (bstrcasecmp(bstr0(list[n]), ext) == 0)
            return true;
    }
    return false;
}
Example #28
0
static bool is_sub_ext(bstr ext)
{
    for (int n = 0; sub_exts[n]; n++) {
        if (bstrcasecmp(bstr0(sub_exts[n]), ext) == 0)
            return true;
    }
    return false;
}
Example #29
0
static int name_to_imgfmt(const char *name)
{
    for (int n = 0; format_names[n].name; n++) {
        if (strcasecmp(format_names[n].name, name) == 0)
            return format_names[n].fmt;
    }
    return mp_imgfmt_from_name(bstr0(name), false);
}
Example #30
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;
}