Example #1
0
File: cache.c Project: ThreeGe/mpv
// Runs in the cache thread
static void cache_execute_control(struct priv *s)
{
    uint64_t old_pos = stream_tell(s->stream);
    s->control_flush = false;

    switch (s->control) {
    case STREAM_CTRL_SET_CACHE_SIZE:
        s->control_res = resize_cache(s, *(int64_t *)s->control_arg);
        break;
    default:
        s->control_res = stream_control(s->stream, s->control, s->control_arg);
    }

    bool pos_changed = old_pos != stream_tell(s->stream);
    bool ok = s->control_res == STREAM_OK;
    if (pos_changed && !ok) {
        MP_ERR(s, "STREAM_CTRL changed stream pos but "
               "returned error, this is not allowed!\n");
    } else if (pos_changed || (ok && control_needs_flush(s->control))) {
        MP_VERBOSE(s, "Dropping cache due to control()\n");
        s->read_filepos = stream_tell(s->stream);
        s->control_flush = true;
        cache_drop_contents(s);
    }

    update_cached_controls(s);
    s->control = CACHE_CTRL_NONE;
    pthread_cond_signal(&s->wakeup);
}
Example #2
0
/**
 * ctpl_input_stream_peek:
 * @stream: A #CtplInputStream
 * @buffer: buffer to fill with the peeked data
 * @count: number of bytes to peek (must be less than or qual to %G_MAXSSIZE, or
 *         a %G_IO_ERROR_INVALID_ARGUMENT will be thrown)
 * @error: return location for errors, or %NULL to ignore them
 * 
 * Peeks data from a #CtplInputStream. Peeking data is like reading, but it
 * doesn't removes the data from the stream.
 * 
 * <warning>
 *   <para>
 *     A peek might resize the internal stream's cache to fit at least @count.
 *     Therefore, peeking too much data at once should be done with some care.
 *   </para>
 * </warning>
 * 
 * Returns: the number of bytes peeked, or -1 on error
 * 
 * Since: 0.2
 */
gssize
ctpl_input_stream_peek (CtplInputStream *stream,
                        void            *buffer,
                        gsize            count,
                        GError         **error)
{
  gssize read_size;
  
  if (G_UNLIKELY (count > G_MAXSSIZE)) {
    g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
                 "Too large count value passed to %s: %"G_GSIZE_FORMAT,
                 G_STRFUNC, count);
    return -1;
  }
  
  if ((stream->buf_size - stream->buf_pos) < count &&
      ! resize_cache (stream, stream->buf_pos + count, error)) {
    read_size = -1;
  } else {
    /* if the buffer is smaller that the request it is at EOF */
    read_size = stream->buf_size - stream->buf_pos;
    if ((gssize)count < read_size) {
      read_size = (gssize)count;
    }
    memcpy (buffer, &stream->buffer[stream->buf_pos], (gsize)read_size);
  }
  
  return read_size;
}
Example #3
0
/**
 * ctpl_input_stream_peek_word:
 * @stream: A #CtplInputStream
 * @accept: string of the character acceptable for the word
 * @accept_len: length of @accept, can be -1 if @accept is 0-terminated
 * @max_len: (default -1): maximum number of bytes to peek, or -1 for no limit
 * @length: (out) (allow-none): return location for the length of the read word,
 *                              or %NULL
 * @error: return location for errors, or %NULL to ignore them
 * 
 * Peeks a word from a #CtplInputStream. See ctpl_input_stream_peek() and
 * ctpl_input_stream_read_word().
 * 
 * Returns: A newly allocated string containing the peeked word that should be
 *          freed with g_free() when no longer needed; or %NULL on error.
 * 
 * Since: 0.2
 */
gchar *
ctpl_input_stream_peek_word (CtplInputStream *stream,
                             const gchar     *accept,
                             gssize           accept_len,
                             gssize           max_len,
                             gsize           *length,
                             GError         **error)
{
  gboolean  success = FALSE;
  GString  *word;
  gsize     accept_length;
  gsize     max_length;
  
  accept_length = (accept_len < 0) ? strlen (accept) : (gsize)accept_len;
  max_length = (max_len < 0) ? G_MAXSIZE : (gsize)max_len;
  word = g_string_new (NULL);
  if (ensure_cache_filled (stream, error)) {
    gsize pos = stream->buf_pos;
    
    success = TRUE;
    do {
      gchar c = stream->buffer[pos++];
      
      if (memchr (accept, c, accept_length)) {
        g_string_append_c (word, c);
      } else {
        break;
      }
      if (pos >= stream->buf_size) {
        success = resize_cache (stream,
                                stream->buf_size + INPUT_STREAM_GROW_SIZE,
                                error);
      }
    } while (success && pos < stream->buf_size && word->len <= max_length);
  }
  if (success && length) {
    *length = word->len;
  }
  
  return g_string_free (word, ! success);
}
Example #4
0
File: cache.c Project: ThreeGe/mpv
// return 1 on success, 0 if the cache is disabled/not needed, and -1 on error
// or if the cache is disabled
int stream_cache_init(stream_t *cache, stream_t *stream,
                      struct mp_cache_opts *opts)
{
    if (opts->size < 1)
        return 0;

    struct priv *s = talloc_zero(NULL, struct priv);
    s->log = cache->log;
    s->eof_pos = -1;

    cache_drop_contents(s);

    s->seek_limit = opts->seek_min * 1024ULL;
    s->back_size = opts->back_buffer * 1024ULL;

    int64_t cache_size = opts->size * 1024ULL;

    int64_t file_size = stream_get_size(stream);
    if (file_size >= 0)
        cache_size = MPMIN(cache_size, file_size);

    if (resize_cache(s, cache_size) != STREAM_OK) {
        MP_ERR(s, "Failed to allocate cache buffer.\n");
        talloc_free(s);
        return -1;
    }

    MP_VERBOSE(cache, "Cache size set to %lld KiB (%lld KiB backbuffer)\n",
               (long long)(s->buffer_size / 1024),
               (long long)(s->back_size / 1024));

    pthread_mutex_init(&s->mutex, NULL);
    pthread_cond_init(&s->wakeup, NULL);

    cache->priv = s;
    s->cache = cache;
    s->stream = stream;

    cache->seek = cache_seek;
    cache->fill_buffer = cache_fill_buffer;
    cache->control = cache_control;
    cache->close = cache_uninit;

    int64_t min = opts->initial * 1024ULL;
    if (min > s->buffer_size - FILL_LIMIT)
        min = s->buffer_size - FILL_LIMIT;

    s->seekable = stream->seekable;

    if (pthread_create(&s->cache_thread, NULL, cache_thread, s) != 0) {
        MP_ERR(s, "Starting cache thread failed.\n");
        return -1;
    }
    s->cache_thread_running = true;

    // wait until cache is filled with at least min bytes
    if (min < 1)
        return 1;
    for (;;) {
        if (mp_cancel_test(cache->cancel))
            return -1;
        int64_t fill;
        int idle;
        if (stream_control(s->cache, STREAM_CTRL_GET_CACHE_FILL, &fill) < 0)
            break;
        if (stream_control(s->cache, STREAM_CTRL_GET_CACHE_IDLE, &idle) < 0)
            break;
        MP_INFO(s, "\rCache fill: %5.2f%% "
                "(%" PRId64 " bytes)   ", 100.0 * fill / s->buffer_size, fill);
        if (fill >= min)
            break;
        if (idle)
            break;    // file is smaller than prefill size
        // Wake up if the cache is done reading some data (or on timeout/abort)
        pthread_mutex_lock(&s->mutex);
        s->control = CACHE_CTRL_PING;
        pthread_cond_signal(&s->wakeup);
        cache_wakeup_and_wait(s, &(double){0});
        pthread_mutex_unlock(&s->mutex);
    }