Go to the documentation of this file.
40 #include <stdatomic.h>
60 #define HASH_METHOD "SHA512/256"
81 #define HEADER_MAGIC MKTAG(u'\xFF', 'S', 'h', '$')
82 #define HEADER_VERSION 2
109 typedef struct Block {
125 #define DEF_SET_ONCE(ctype, atype) \
126 static int set_once_##atype(atomic_##atype *const ptr, const ctype value) \
129 av_assert1(value != 0); \
130 if (atomic_compare_exchange_strong_explicit( \
131 ptr, &prev, value, memory_order_release, memory_order_relaxed)) \
133 else if (prev == value) \
136 return AVERROR(EINVAL); \
186 munmap(
s->cache_data,
s->cache_size);
188 munmap(
s->spacemap,
s->map_size);
198 s->nb_hit,
s->nb_miss);
220 ret = set_once_ullong(&
s->spacemap->filesize, new_size);
223 "%"PRId64
", got: %"PRIu64
"!\n", new_size,
240 if (!
s->cache_dir || !
s->cache_dir[0]) {
242 "directory using the -cache_dir option.\n");
246 s->fd =
s->mapfd = -1;
251 options,
h->protocol_whitelist,
h->protocol_blacklist,
h);
263 char filename[2 * 16 + 1];
265 sprintf(&filename[
i * 2],
"%02X",
hash[
i]);
266 s->cache_path =
av_asprintf(
"%s/%s.cache",
s->cache_dir, filename);
267 s->map_path =
av_asprintf(
"%s/%s.spacemap",
s->cache_dir, filename);
268 if (!
s->cache_path || !
s->map_path) {
274 s->cache_path,
s->inner->filename);
278 if (
s->fd < 0 ||
s->mapfd < 0) {
328 h->max_packet_size =
s->block_size;
329 h->min_packet_size =
s->block_size;
345 munmap(
s->cache_data,
s->cache_size);
346 s->cache_data =
NULL;
351 int ret = fstat(
s->fd, &st);
364 s->cache_data = mmap(
NULL,
filesize, PROT_READ | PROT_WRITE, MAP_SHARED,
s->fd, 0);
365 if (
s->cache_data == MAP_FAILED) {
366 s->cache_data =
NULL;
378 if (map_size <= s->map_size)
383 ret = fstat(
s->mapfd, &st);
389 if (st.st_size >= map_size)
393 ret = flock(
s->mapfd, LOCK_EX);
401 ret = fstat(
s->mapfd, &st);
407 if (st.st_size >= map_size)
410 ret = ftruncate(
s->mapfd, map_size);
415 st.st_size = map_size;
420 munmap(
s->spacemap,
s->map_size);
421 s->map_size = st.st_size;
422 s->spacemap = mmap(
NULL,
s->map_size, PROT_READ | PROT_WRITE, MAP_SHARED,
s->mapfd, 0);
423 if (
s->spacemap == MAP_FAILED) {
431 flock(
s->mapfd, LOCK_UN);
439 flock(
s->mapfd, LOCK_UN);
448 size_t map_bytes =
sizeof(
Spacemap) + num_blocks *
sizeof(
Block);
457 if (map_bytes < num_blocks)
460 const off_t old_size =
s->map_size;
466 if (
s->map_size > old_size) {
469 "%s %zu bytes, capacity: %"PRId64
" blocks = %zu MB\n",
470 ret ?
"Resized spacemap to" :
"Mapped spacemap with",
471 (
size_t)
s->map_size, num_blocks,
472 (num_blocks * (
int64_t)
s->block_size) >> 20);
498 ret = set_once_ushort(&
s->spacemap->block_shift,
s->block_shift);
502 "but requested block shift is %d.\n",
shift,
s->block_shift);
503 if (shift < 9 || shift > 30) {
510 ret = set_once_uchar(&
s->spacemap->hash[
i],
hash[
i]);
514 for (
int j = 0; j < 32; j++)
517 for (
int j = 0; j < 32; j++)
597 const int64_t block_pos = block_id *
s->block_size;
598 int block_size =
clamp_size(
h,
s->block_size, block_pos);
603 Block *
const block = &
s->spacemap->blocks[block_id];
606 int verify_read = 0, is_race = 0;
614 av_assert1(block_pos + block_size <= s->cache_size);
615 tmp =
s->cache_data + block_pos;
628 "offset 0x%"PRIx64
": expected CRC: 0x%04X, got: 0x%04X\n",
629 block_id, block_pos,
state, crc);
646 if (!
s->retry_errors)
654 memory_order_acquire,
655 memory_order_acquire))
669 }
else if (pending_since) {
671 if (
new - pending_since >=
s->timeout) {
688 const int read_only =
s->read_only ||
s->write_err || verify_read;
689 int64_t inner_pos = read_only ?
s->pos : block_pos;
690 if (
s->inner_pos != inner_pos) {
691 inner_pos =
ffurl_seek(
s->inner, inner_pos, SEEK_SET);
701 memory_order_relaxed,
702 memory_order_relaxed);
708 s->inner_pos = inner_pos;
718 if (verify_read && memcmp(buf,
tmp,
ret)) {
720 "in block 0x%"PRIx64
" at offset 0x%"PRIx64
" + %"PRId64
"!\n",
724 s->pos =
s->inner_pos = inner_pos +
ret;
729 if (
s->cache_data && !is_race) {
731 tmp =
s->cache_data + block_pos;
744 while (bytes_read < block_size) {
760 memory_order_relaxed,
761 memory_order_relaxed);
769 if (bytes_read < block_size) {
776 if (bytes_read > 0) {
786 memory_order_relaxed,
787 memory_order_relaxed);
791 "offset 0x%"PRIx64
", CRC 0x%04X\n", bytes_read, block_id,
842 return s->pos =
s->inner_pos = res;
867 #define OFFSET(x) offsetof(SharedContext, x)
868 #define D AV_OPT_FLAG_DECODING_PARAM
872 {
"block_shift",
"Set the base 2 logarithm of the block size",
OFFSET(block_shift),
AV_OPT_TYPE_INT, {.i64 = 15}, 9, 30, .flags =
D },
873 {
"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 },
874 {
"cache_verify",
"Verify correctness of the cache against the source",
OFFSET(verify),
AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, .flags =
D },
875 {
"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 },
876 {
"retry_errors",
"Re-request blocks even if they previously failed",
OFFSET(retry_errors),
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 uint16_t get_block_crc(const uint8_t *block, size_t block_size)
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.
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)
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.