static ssize_t read_cb(struct archive *arch, void *priv, const void **buffer) { struct mp_archive_volume *vol = priv; if (!volume_seek(vol)) return -1; int res = stream_read_partial(vol->src, vol->mpa->buffer, sizeof(vol->mpa->buffer)); *buffer = vol->mpa->buffer; return MPMAX(res, 0); }
// Runs in the cache thread. // Returns true if reading was attempted, and the mutex was shortly unlocked. static bool cache_fill(struct priv *s) { int64_t read = s->read_filepos; int len = 0; // drop cache contents only if seeking backward or too much fwd. // This is also done for on-disk files, since it loses the backseek cache. // That in turn can cause major bandwidth increase and performance // issues with e.g. mov or badly interleaved files if (read < s->min_filepos || read > s->max_filepos + s->seek_limit) { MP_VERBOSE(s, "Dropping cache at pos %"PRId64", " "cached range: %"PRId64"-%"PRId64".\n", read, s->min_filepos, s->max_filepos); cache_drop_contents(s); } if (stream_tell(s->stream) != s->max_filepos && s->seekable) { MP_VERBOSE(s, "Seeking underlying stream: %"PRId64" -> %"PRId64"\n", stream_tell(s->stream), s->max_filepos); stream_seek(s->stream, s->max_filepos); if (stream_tell(s->stream) != s->max_filepos) goto done; } if (mp_cancel_test(s->cache->cancel)) goto done; // number of buffer bytes which should be preserved in backwards direction int64_t back = MPCLAMP(read - s->min_filepos, 0, s->back_size); // limit maximum readahead so that the backbuffer space is reserved, even // if the backbuffer is not used. limit it to ensure that we don't stall the // network when starting a file, or we wouldn't download new data until we // get new free space again. (unless everything fits in the cache.) if (s->stream_size > s->buffer_size) back = MPMAX(back, s->back_size); // number of buffer bytes that are valid and can be read int64_t newb = FFMAX(s->max_filepos - read, 0); // max. number of bytes that can be written (starting from max_filepos) int64_t space = s->buffer_size - (newb + back); // offset into the buffer that maps to max_filepos int64_t pos = s->max_filepos - s->offset; if (pos >= s->buffer_size) pos -= s->buffer_size; // wrap-around if (space < FILL_LIMIT) { s->idle = true; s->reads++; // don't stuck main thread return false; } // limit to end of buffer (without wrapping) if (pos + space >= s->buffer_size) space = s->buffer_size - pos; // limit read size (or else would block and read the entire buffer in 1 call) space = FFMIN(space, s->stream->read_chunk); // back+newb+space <= buffer_size int64_t back2 = s->buffer_size - (space + newb); // max back size if (s->min_filepos < (read - back2)) s->min_filepos = read - back2; // The read call might take a long time and block, so drop the lock. pthread_mutex_unlock(&s->mutex); len = stream_read_partial(s->stream, &s->buffer[pos], space); pthread_mutex_lock(&s->mutex); // Do this after reading a block, because at least libdvdnav updates the // stream position only after actually reading something after a seek. if (s->start_pts == MP_NOPTS_VALUE) { double pts; if (stream_control(s->stream, STREAM_CTRL_GET_CURRENT_TIME, &pts) > 0) s->start_pts = pts; } s->max_filepos += len; if (pos + len == s->buffer_size) s->offset += s->buffer_size; // wrap... done: s->eof = len <= 0; s->idle = s->eof; s->reads++; if (s->eof) { s->eof_pos = stream_tell(s->stream); MP_TRACE(s, "EOF reached.\n"); } pthread_cond_signal(&s->wakeup); return true; }
// Runs in the cache thread. // Returns true if reading was attempted, and the mutex was shortly unlocked. static bool cache_fill(struct priv *s) { int64_t read = s->read_filepos; int len; if (read < s->min_filepos || read > s->max_filepos) { // seek... mp_msg(MSGT_CACHE, MSGL_DBG2, "Out of boundaries... seeking to 0x%" PRIX64 " \n", read); // drop cache contents only if seeking backward or too much fwd. // This is also done for on-disk files, since it loses the backseek cache. // That in turn can cause major bandwidth increase and performance // issues with e.g. mov or badly interleaved files if (read < s->min_filepos || read >= s->max_filepos + s->seek_limit) { mp_msg(MSGT_CACHE, MSGL_V, "Dropping cache at pos %"PRId64", " "cached range: %"PRId64"-%"PRId64".\n", read, s->min_filepos, s->max_filepos); cache_drop_contents(s); stream_seek(s->stream, read); } } // number of buffer bytes which should be preserved in backwards direction int64_t back = mp_clipi64(read - s->min_filepos, 0, s->back_size); // number of buffer bytes that are valid and can be read int64_t newb = FFMAX(s->max_filepos - read, 0); // max. number of bytes that can be written (starting from max_filepos) int64_t space = s->buffer_size - (newb + back); // offset into the buffer that maps to max_filepos int pos = s->max_filepos - s->offset; if (pos >= s->buffer_size) pos -= s->buffer_size; // wrap-around if (space < s->fill_limit) { s->idle = true; return false; } // limit to end of buffer (without wrapping) if (pos + space >= s->buffer_size) space = s->buffer_size - pos; // limit read size (or else would block and read the entire buffer in 1 call) space = FFMIN(space, s->stream->read_chunk); // back+newb+space <= buffer_size int64_t back2 = s->buffer_size - (space + newb); // max back size if (s->min_filepos < (read - back2)) s->min_filepos = read - back2; // The read call might take a long time and block, so drop the lock. pthread_mutex_unlock(&s->mutex); len = stream_read_partial(s->stream, &s->buffer[pos], space); pthread_mutex_lock(&s->mutex); double pts; if (stream_control(s->stream, STREAM_CTRL_GET_CURRENT_TIME, &pts) <= 0) pts = MP_NOPTS_VALUE; for (int64_t b_pos = pos; b_pos < pos + len + BYTE_META_CHUNK_SIZE; b_pos += BYTE_META_CHUNK_SIZE) { s->bm[b_pos / BYTE_META_CHUNK_SIZE] = (struct byte_meta){.stream_pts = pts}; } s->max_filepos += len; if (pos + len == s->buffer_size) s->offset += s->buffer_size; // wrap... s->eof = len > 0 ? 0 : 1; s->idle = s->eof; pthread_cond_signal(&s->wakeup); return true; }