avutil/file: add av_file_map_shared() and av_file_unmap_shared()

av_file_map() maps a private copy of a file by name. Code that shares a
file between processes needs the opposite, a writable mapping backed by
the file, of a descriptor it opened itself, that grows with the file.
Provide it with mmap() on POSIX and with a file mapping object on
Windows, which also extends the file to the requested size.

Signed-off-by: Kacper Michajłow <kasper93@gmail.com>
This commit is contained in:
Kacper Michajłow committed 2026-09-23 16:50:45 +02:00
1 parent 284f1f1ea9
commit dea75789c3
4 files changed
+110 -33

No files matched your search

+3
View File
@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2026-06-23.
API changes, most recent first:
2026-09-xx - xxxxxxxxxx - lavu 61.8.100 - file.h
Add av_file_map_shared() and av_file_unmap_shared().
2026-09-12 - xxxxxxxxxx - lavc 63.13.100 - codec_id.h, defs.h
Add AV_CODEC_ID_ASTC and the AV_PROFILE_ASTC_* profile values.
+77 -32
View File
@@ -60,6 +60,57 @@ static const AVClass file_log_ctx_class = {
.parent_log_context_offset = offsetof(FileLogContext, log_ctx),
};
#if HAVE_MMAP || HAVE_MAPVIEWOFFILE
/* Map the first size bytes of the file, as a private copy or shared and
* writable. The shared mapping extends the file to size, on Windows the
* mapping object does it. */
static int map_file(int fd, size_t size, int shared, void **ptr)
{
#if HAVE_MMAP
if (shared) {
struct stat st;
if (fstat(fd, &st) < 0)
return AVERROR(errno);
if (st.st_size < size && ftruncate(fd, size) < 0)
return AVERROR(errno);
}
void *map = mmap(NULL, size, PROT_READ | PROT_WRITE,
shared ? MAP_SHARED : MAP_PRIVATE, fd, 0);
if (map == MAP_FAILED)
return AVERROR(errno);
#else
HANDLE fh = (HANDLE)_get_osfhandle(fd);
if (fh == INVALID_HANDLE_VALUE)
return AVERROR(EBADF);
HANDLE mh = CreateFileMapping(fh, NULL,
shared ? PAGE_READWRITE : PAGE_READONLY,
(uint64_t)size >> 32, size, NULL);
if (!mh)
return AVERROR(EIO);
void *map = MapViewOfFile(mh, shared ? FILE_MAP_ALL_ACCESS : FILE_MAP_COPY,
0, 0, size);
CloseHandle(mh);
if (!map)
return AVERROR(EIO);
#endif
*ptr = map;
return 0;
}
static void unmap_file(void *ptr, size_t size)
{
#if HAVE_MMAP
munmap(ptr, size);
#else
UnmapViewOfFile(ptr);
#endif
}
#endif
int av_file_map(const char *filename, uint8_t **bufptr, size_t *size,
int log_offset, void *log_ctx)
{
@@ -96,39 +147,15 @@ int av_file_map(const char *filename, uint8_t **bufptr, size_t *size,
goto out;
}
#if HAVE_MMAP
ptr = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
if (ptr == MAP_FAILED) {
err = AVERROR(errno);
av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in mmap(): %s\n", av_err2str(err));
#if HAVE_MMAP || HAVE_MAPVIEWOFFILE
err = map_file(fd, *size, 0, &ptr);
if (err < 0) {
av_log(&file_log_ctx, AV_LOG_ERROR, "Cannot map file '%s': %s\n", filename, av_err2str(err));
close(fd);
*size = 0;
return err;
}
*bufptr = ptr;
#elif HAVE_MAPVIEWOFFILE
{
HANDLE mh, fh = (HANDLE)_get_osfhandle(fd);
mh = CreateFileMapping(fh, NULL, PAGE_READONLY, 0, 0, NULL);
if (!mh) {
av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in CreateFileMapping()\n");
close(fd);
*size = 0;
return -1;
}
ptr = MapViewOfFile(mh, FILE_MAP_COPY, 0, 0, *size);
CloseHandle(mh);
if (!ptr) {
av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in MapViewOfFile()\n");
close(fd);
*size = 0;
return -1;
}
*bufptr = ptr;
}
#else
*bufptr = av_malloc(*size);
if (!*bufptr) {
@@ -149,11 +176,29 @@ void av_file_unmap(uint8_t *bufptr, size_t size)
{
if (!size || !bufptr)
return;
#if HAVE_MMAP
munmap(bufptr, size);
#elif HAVE_MAPVIEWOFFILE
UnmapViewOfFile(bufptr);
#if HAVE_MMAP || HAVE_MAPVIEWOFFILE
unmap_file(bufptr, size);
#else
av_free(bufptr);
#endif
}
int av_file_map_shared(int fd, size_t size, void **bufptr)
{
*bufptr = NULL;
if (!size)
return AVERROR(EINVAL);
#if HAVE_MMAP || HAVE_MAPVIEWOFFILE
return map_file(fd, size, 1, bufptr);
#else
return AVERROR(ENOSYS);
#endif
}
void av_file_unmap_shared(void *bufptr, size_t size)
{
#if HAVE_MMAP || HAVE_MAPVIEWOFFILE
if (size && bufptr)
unmap_file(bufptr, size);
#endif
}
+29
View File
@@ -59,4 +59,33 @@ int av_file_map(const char *filename, uint8_t **bufptr, size_t *size,
*/
void av_file_unmap(uint8_t *bufptr, size_t size);
/**
* Map the beginning of an open file into memory for shared read and write
* access.
*
* Unlike av_file_map() the mapping is not a private copy of the file, every
* store to the returned memory is written to the file and is visible to
* every other mapping of it, in this process and in other processes. The
* file is extended to size bytes if it is shorter, it is never shortened.
* The mapping must be released with av_file_unmap_shared().
*
* @param fd file descriptor of a file opened for reading and writing
* @param size number of bytes to map, must not be zero
* @param[out] bufptr pointee is set to the mapped memory
* @return 0 in case of success, a negative value corresponding to an
* AVERROR error code in case of failure, AVERROR(ENOSYS) when the platform
* has no shared file mappings
*/
av_warn_unused_result
int av_file_map_shared(int fd, size_t size, void **bufptr);
/**
* Unmap the memory mapped by av_file_map_shared().
*
* @param bufptr the memory previously mapped by av_file_map_shared()
* @param size size in bytes of the mapping, must be the same as passed
* to av_file_map_shared()
*/
void av_file_unmap_shared(void *bufptr, size_t size);
#endif /* AVUTIL_FILE_H */
+1 -1
View File
@@ -79,7 +79,7 @@
*/
#define LIBAVUTIL_VERSION_MAJOR 61
#define LIBAVUTIL_VERSION_MINOR 7
#define LIBAVUTIL_VERSION_MINOR 8
#define LIBAVUTIL_VERSION_MICRO 100
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \