From 3b7939a8c294dc3ee103d99e6ff00e2800cf39f3 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Tue, 24 Aug 2021 20:47:03 +0200 Subject: [PATCH] mp4: Provide whence parameter for the seek callback. This adds a parameter to make ->seek() work like the lseek(2) system call. This is easy to implement in both the memory-mapped callback case used to retrieve the file information and the metadata update case where ->seek() is a trivial wrapper for lseek(2). With the additional functionality in place we don't need to track the file size and the current file offset any more in mp4.c as these values can now be obtained by calling ->seek() with a zero offset and whence set to SEEK_END and SEEK_CUR, respectively. This also makes the code more robust against corrupt mp4 files because we no longer rely on the values from the atom headers to compute the file size. The way mp4.c calls ->seek() should never cause the underlying lseek(2) system call to fail. Therefore it suffices to check the return value only in the callback wrapper and abort on failure. --- aac_afh.c | 21 ++++++++++++++++----- mp4.c | 20 ++++++-------------- mp4.h | 2 +- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/aac_afh.c b/aac_afh.c index 0a80bfcf..b6c90d59 100644 --- a/aac_afh.c +++ b/aac_afh.c @@ -41,11 +41,19 @@ static ssize_t aac_afh_read_cb(void *user_data, void *dest, size_t want) return rv; } -static uint32_t aac_afh_seek_cb(void *user_data, uint64_t pos) +static off_t aac_afh_seek_cb(void *user_data, off_t offset, int whence) { struct aac_afh_context *c = user_data; - c->fpos = pos; - return 0; + + if (whence == SEEK_SET) + c->fpos = offset; + else if (whence == SEEK_CUR) + c->fpos += offset; + else if (whence == SEEK_END) + c->fpos = c->mapsize + offset; + else + assert(false); + return c->fpos; } static int aac_afh_open(const void *map, size_t mapsize, void **afh_context) @@ -167,10 +175,13 @@ static ssize_t aac_afh_meta_read_cb(void *user_data, void *dest, size_t want) return read(fd, dest, want); } -static uint32_t aac_afh_meta_seek_cb(void *user_data, uint64_t pos) +static off_t aac_afh_meta_seek_cb(void *user_data, off_t offset, int whence) { int fd = *(int *)user_data; - return lseek(fd, pos, SEEK_SET); + off_t ret = lseek(fd, offset, whence); + + assert(ret != (off_t)-1); + return ret; } static ssize_t aac_afh_meta_write_cb(void *user_data, void *dest, size_t count) diff --git a/mp4.c b/mp4.c index fc8c41b4..08812c89 100644 --- a/mp4.c +++ b/mp4.c @@ -45,7 +45,6 @@ struct mp4_track { struct mp4 { const struct mp4_callback *cb; - int64_t current_position; uint64_t moov_offset; uint64_t moov_size; @@ -57,8 +56,6 @@ struct mp4 { uint32_t udta_size; uint8_t last_atom; - uint64_t file_size; - /* incremental track index while reading the file */ int32_t total_tracks; /* track data */ @@ -83,7 +80,6 @@ static int read_data(struct mp4 *f, void *data, size_t size) /* regard EAGAIN as an error as reads should be blocking. */ if (ret <= 0) return ret < 0? -1 : 0; - f->current_position += ret; size -= ret; } return 1; @@ -212,17 +208,14 @@ static int atom_read_header(struct mp4 *f, uint8_t *atom_type, return 1; } -static int64_t get_position(const struct mp4 *f) +static off_t get_position(const struct mp4 *f) { - return f->current_position; + return f->cb->seek(f->cb->user_data, 0, SEEK_CUR); } -static int32_t set_position(struct mp4 *f, int64_t position) +static void set_position(struct mp4 *f, off_t position) { - f->cb->seek(f->cb->user_data, position); - f->current_position = position; - - return 0; + f->cb->seek(f->cb->user_data, position, SEEK_SET); } static int read_stsz(struct mp4 *f) @@ -696,7 +689,6 @@ static int open_file(const struct mp4_callback *cb, bool meta_only, struct mp4 * f->cb = cb; while ((ret = atom_read_header(f, &atom_type, &header_size, &size)) > 0) { - f->file_size += size; f->last_atom = atom_type; if (atom_type != ATOM_MOOV || size <= header_size) { /* skip */ set_position(f, get_position(f) + size - header_size); @@ -979,7 +971,6 @@ static int write_data(struct mp4 *f, void *data, size_t size) continue; return -ERRNO_TO_PARA_ERROR(errno); } - f->current_position += ret; size -= ret; } return 1; @@ -1003,7 +994,8 @@ int mp4_meta_update(struct mp4 *f) ret = write_data(f, "free", 4); /* rename old moov to free */ if (ret < 0) goto free_moov; - set_position(f, f->file_size); /* write new moov atom at EOF */ + /* write new moov atom at EOF */ + f->cb->seek(f->cb->user_data, 0, SEEK_END); } else /* overwrite old moov atom */ set_position(f, f->moov_offset); write_u32_be(buf, new_moov_size + 8); diff --git a/mp4.h b/mp4.h index 30a609f3..243b75ca 100644 --- a/mp4.h +++ b/mp4.h @@ -1,7 +1,7 @@ struct mp4_callback { ssize_t (*read)(void *user_data, void *buffer, size_t length); ssize_t (*write)(void *user_data, void *buffer, size_t count); - uint32_t (*seek)(void *user_data, uint64_t position); + off_t (*seek)(void *user_data, off_t offset, int whence); uint32_t (*truncate)(void *user_data); void *user_data; }; -- 2.39.5