Go to the documentation of this file.
40 #include <stdatomic.h>
60 #define HASH_METHOD "SHA512/256"
62 #define HEADER_MAGIC MKTAG(u'\xFF', 'S', 'h', '$')
63 #define HEADER_VERSION 3
110 typedef struct Block {
126 #define DEF_SET_ONCE(ctype, atype) \
127 static int set_once_##atype(atomic_##atype *const ptr, const ctype value) \
130 av_assert1(value != 0); \
131 if (atomic_compare_exchange_strong_explicit( \
132 ptr, &prev, value, memory_order_release, memory_order_relaxed)) \
134 else if (prev == value) \
137 return AVERROR(EINVAL); \
188 munmap(
s->cache_data,
s->cache_size);
190 munmap(
s->spacemap,
s->map_size);
200 s->nb_hit,
s->nb_miss);
222 ret = set_once_ullong(&
s->spacemap->filesize, new_size);
225 "%"PRId64
", got: %"PRIu64
"!\n", new_size,
242 if (!
s->cache_dir || !
s->cache_dir[0]) {
244 "directory using the -cache_dir option.\n");
248 s->fd =
s->mapfd = -1;
253 options,
h->protocol_whitelist,
h->protocol_blacklist,
h);
265 char filename[2 * 16 + 1];
267 sprintf(&filename[
i * 2],
"%02X",
hash[
i]);
268 s->cache_path =
av_asprintf(
"%s/%s.cache",
s->cache_dir, filename);
269 s->map_path =
av_asprintf(
"%s/%s.spacemap",
s->cache_dir, filename);
270 if (!
s->cache_path || !
s->map_path) {
276 s->cache_path,
s->inner->filename);
280 if (
s->fd < 0 ||
s->mapfd < 0) {
330 h->max_packet_size =
s->block_size;
331 h->min_packet_size =
s->block_size;
347 munmap(
s->cache_data,
s->cache_size);
348 s->cache_data =
NULL;
353 int ret = fstat(
s->fd, &st);
366 s->cache_data = mmap(
NULL,
filesize, PROT_READ | PROT_WRITE, MAP_SHARED,
s->fd, 0);
367 if (
s->cache_data == MAP_FAILED) {
368 s->cache_data =
NULL;
380 if (map_size <= s->map_size)
385 ret = fstat(
s->mapfd, &st);
391 if (st.st_size >= map_size)
395 ret = flock(
s->mapfd, LOCK_EX);
403 ret = fstat(
s->mapfd, &st);
409 if (st.st_size >= map_size)
412 ret = ftruncate(
s->mapfd, map_size);
417 st.st_size = map_size;
422 munmap(
s->spacemap,
s->map_size);
423 s->map_size = st.st_size;
424 s->spacemap = mmap(
NULL,
s->map_size, PROT_READ | PROT_WRITE, MAP_SHARED,
s->mapfd, 0);
425 if (
s->spacemap == MAP_FAILED) {
433 flock(
s->mapfd, LOCK_UN);
441 flock(
s->mapfd, LOCK_UN);
450 size_t map_bytes =
sizeof(
Spacemap) + num_blocks *
sizeof(
Block);
459 if (map_bytes < num_blocks)
462 const off_t old_size =
s->map_size;
468 if (
s->map_size > old_size) {
471 "%s %zu bytes, capacity: %"PRId64
" blocks = %zu MB\n",
472 ret ?
"Resized spacemap to" :
"Mapped spacemap with",
473 (
size_t)
s->map_size, num_blocks,
474 (num_blocks * (
int64_t)
s->block_size) >> 20);
500 ret = set_once_ushort(&
s->spacemap->block_shift,
s->block_shift);
504 "but requested block shift is %d.\n",
shift,
s->block_shift);
505 if (shift < 9 || shift > 30) {
512 ret = set_once_uchar(&
s->spacemap->hash[
i],
hash[
i]);
516 for (
int j = 0; j < 32; j++)
519 for (
int j = 0; j < 32; j++)
599 const int64_t block_pos = block_id *
s->block_size;
600 int block_size =
clamp_size(
h,
s->block_size, block_pos);
605 Block *
const block = &
s->spacemap->blocks[block_id];
608 int verify_read = 0, is_race = 0;
616 av_assert1(block_pos + block_size <= s->cache_size);
617 tmp =
s->cache_data + block_pos;
630 "offset 0x%"PRIx64
": expected CRC: 0x%08X, got: 0x%08X\n",
631 block_id, block_pos,
state, crc);
632 if (
s->retry_corrupt)
660 memory_order_acquire,
661 memory_order_acquire))
675 }
else if (pending_since) {
677 if (
new - pending_since >=
s->timeout) {
694 const int read_only =
s->read_only ||
s->write_err || verify_read;
695 int64_t inner_pos = read_only ?
s->pos : block_pos;
696 if (
s->inner_pos != inner_pos) {
697 inner_pos =
ffurl_seek(
s->inner, inner_pos, SEEK_SET);
707 memory_order_relaxed,
708 memory_order_relaxed);
714 s->inner_pos = inner_pos;
724 if (verify_read && memcmp(buf,
tmp,
ret)) {
726 "in block 0x%"PRIx64
" at offset 0x%"PRIx64
" + %"PRId64
"!\n",
730 s->pos =
s->inner_pos = inner_pos +
ret;
735 if (
s->cache_data && !is_race) {
737 tmp =
s->cache_data + block_pos;
750 while (bytes_read < block_size) {
766 memory_order_relaxed,
767 memory_order_relaxed);
775 if (bytes_read < block_size) {
782 if (bytes_read > 0) {
792 memory_order_relaxed,
793 memory_order_relaxed);
797 "offset 0x%"PRIx64
", CRC 0x%08X\n", bytes_read, block_id,
848 return s->pos =
s->inner_pos = res;
873 #define OFFSET(x) offsetof(SharedContext, x)
874 #define D AV_OPT_FLAG_DECODING_PARAM
878 {
"block_shift",
"Set the base 2 logarithm of the block size",
OFFSET(block_shift),
AV_OPT_TYPE_INT, {.i64 = 15}, 9, 30, .flags =
D },
879 {
"read_only",
"Don't write data to the cache, only read from it",
OFFSET(read_only),
AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, .flags =
D },
880 {
"cache_verify",
"Verify correctness of the cache against the source",
OFFSET(verify),
AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, .flags =
D },
881 {
"cache_timeout",
"Time in us to wait before re-fetching pending blocks",
OFFSET(timeout),
AV_OPT_TYPE_INT64, {.i64 = 10000}, 0, INT64_MAX, .flags =
D },
882 {
"retry_errors",
"Re-request blocks even if they previously failed",
OFFSET(retry_errors),
AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, .flags =
D },
883 {
"retry_corrupt",
"Re-request blocks that fail the CRC check",
OFFSET(retry_corrupt),
AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, .flags =
D },
static int64_t ffurl_seek(URLContext *h, int64_t pos, int whence)
Change the position that will be used by the next read/write operation on the resource accessed by h.
int64_t av_gettime_relative(void)
Get the current time in microseconds since some unspecified starting point.
#define AV_LOG_WARNING
Something somehow does not look correct.
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
static int shared_close(URLContext *h)
static int set_filesize(URLContext *h, int64_t new_size)
#define AVERROR_EOF
End of file.
static int64_t get_filesize(URLContext *h)
char * av_asprintf(const char *fmt,...)
static int write_cache(SharedContext *s, const uint8_t *buf, size_t size, off_t offset)
@ BLOCK_PENDING
a thread is currently trying to write this block
#define AVSEEK_SIZE
Passing this as the "whence" parameter to a seek function causes it to return the filesize without se...
#define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure)
const URLProtocol ff_shared_protocol
#define AV_LOG_VERBOSE
Detailed information.
int ffurl_close(URLContext *h)
static uint8_t hash[HASH_SIZE]
static int hash_uri(uint8_t hash[HASH_SIZE], const char *uri)
static av_cold void close(AVCodecParserContext *s)
static int read_cache(SharedContext *s, uint8_t *buf, size_t size, off_t offset)
@ BLOCK_FAILED
the underlying I/O source failed to read this block
int ffurl_get_short_seek(void *urlcontext)
Return the current short seek threshold value for this URL.
FFmpeg hosted at Telepoint in bulgaria ns2 avcodec org Replica Name hosted at Prometeus Cdlan in italy instead several VMs run on it Main server peering exchange and hosting They have multiple DC buildings in Sofia and FFmpeg is hosted in XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX The building is locked down and accessible only with personal key cards that are registered People who are granted access to a rack have to go through the access center with their ID to get logged and receive a one time access card that can open the service elevator and only the hall where the destination rack is All racks are locked
static int shared_get_file_handle(URLContext *h)
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
#define FF_ARRAY_ELEMS(a)
atomic_uchar hash[HASH_SIZE]
int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options, const char *whitelist, const char *blacklist, URLContext *parent)
Create an URLContext for accessing to the resource indicated by url, and open it.
static int spacemap_init(URLContext *h, const uint8_t hash[HASH_SIZE])
int avpriv_open(const char *filename, int flags,...)
A wrapper for open() setting O_CLOEXEC.
#define DEF_SET_ONCE(ctype, atype)
int av_hash_alloc(AVHashContext **ctx, const char *name)
Allocate a hash context for the algorithm specified by name.
@ AV_OPT_TYPE_INT64
Underlying C type is int64_t.
#define av_assert0(cond)
assert() equivalent, that is always enabled.
static const AVClass shared_context_class
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
static AVFormatContext * ctx
int write_err
write error occurred
int av_usleep(unsigned usec)
Sleep for a period of time.
#define atomic_load(object)
#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure)
@ BLOCK_NONE
block is not cached
#define LIBAVUTIL_VERSION_INT
Describe the class of an AVClass context structure.
void av_hash_init(AVHashContext *ctx)
Initialize or reset a hash context.
const char * av_default_item_name(void *ptr)
Return the context name.
int block_shift
requested shift; may disagree with actual
static int spacemap_remap(URLContext *h, size_t map_size)
void av_hash_update(AVHashContext *ctx, const uint8_t *src, size_t len)
Update a hash context with additional data.
#define atomic_load_explicit(object, order)
void av_hash_freep(AVHashContext **ctx)
Free hash context and set hash context pointer to NULL.
static int read_block(ALSDecContext *ctx, ALSBlockData *bd)
Read the block data.
off_t cache_size
size of mapped memory region (for munmap)
static int shift(int a, int b)
#define i(width, name, range_min, range_max)
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
void av_hash_final(AVHashContext *ctx, uint8_t *dst)
Finalize a hash context and compute the actual hash value.
static int shared_get_short_seek(URLContext *h)
const AVCRC * av_crc_get_table(AVCRCId crc_id)
Get an initialized standard CRC table.
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
int av_strstart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str.
static int spacemap_grow(URLContext *h, int64_t block)
static int64_t filesize(AVIOContext *pb)
static int64_t shared_seek(URLContext *h, int64_t pos, int whence)
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
#define atomic_store_explicit(object, desired, order)
static uint32_t get_block_crc(const uint8_t *block, size_t block_size)
uint8_t * cache_data
optional mmap of the cache file
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
static const AVOption options[]
uint32_t av_crc(const AVCRC *ctx, uint32_t crc, const uint8_t *buffer, size_t length)
Calculate the CRC of a block.
static int shared_open(URLContext *h, const char *arg, int flags, AVDictionary **options)
@ AV_OPT_TYPE_INT
Underlying C type is int.
int av_hash_get_size(const AVHashContext *ctx)
#define HASH_METHOD
This hash should be resistant against collision attacks, so that an attacker could not generate e....
static int cache_map(URLContext *h, int64_t filesize)
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
int64_t pos
current logical position
The exact code depends on how similar the blocks are and how related they are to the block
int64_t ffurl_size(URLContext *h)
Return the filesize of the resource accessed by h, AVERROR(ENOSYS) if the operation is not supported ...
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
static int shared_read(URLContext *h, unsigned char *buf, int size)
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
static size_t clamp_size(URLContext *h, size_t size, int64_t pos)
atomic_ushort block_shift
int ffurl_get_file_handle(URLContext *h)
Return the file descriptor associated with this URL.
static int ffurl_read(URLContext *h, uint8_t *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf.