TODO: bump minor, update doc/APIchanges API allows protocol implementations to provide API that allows to list directory content. API is similar to POSIX opendir/readdir/closedir.
Signed-off-by: Lukasz Marek <lukasz.m.lu...@gmail.com> --- libavformat/avio.c | 76 +++++++++++++++++++++++++++++++++++++++++++++- libavformat/avio.h | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++- libavformat/url.h | 55 ++++++++++++++++++++++++++++++++++ 3 files changed, 217 insertions(+), 2 deletions(-) diff --git a/libavformat/avio.c b/libavformat/avio.c index 0a2a0a9..021ffc3 100644 --- a/libavformat/avio.c +++ b/libavformat/avio.c @@ -23,12 +23,14 @@ #include "libavutil/dict.h" #include "libavutil/opt.h" #include "libavutil/time.h" +#include "libavutil/avassert.h" #include "os_support.h" #include "avformat.h" #if CONFIG_NETWORK #include "network.h" #endif #include "url.h" +#include "avio_internal.h" static URLProtocol *first_protocol = NULL; @@ -286,6 +288,45 @@ fail: return ret; } +void ffurl_close_dir(URLContext *s) +{ + if (s) { + if (s->prot->url_close_dir) + s->prot->url_close_dir(s); + ffurl_close(s); + } +} + +int ffurl_open_dir(URLContext **s, const char *url, + const AVIOInterruptCB *int_cb, AVDictionary **options) +{ + int ret; + + if ((ret = ffurl_alloc(s, url, AVIO_FLAG_READ, int_cb)) < 0) + return ret; + if (!(*s)->prot->url_open_dir || !(*s)->prot->url_read_dir || !(*s)->prot->url_close_dir) { + ret = AVERROR(ENOSYS); + goto fail; + } + if ((*s)->prot->priv_data_class && + (ret = av_opt_set_dict((*s)->priv_data, options)) < 0) + goto fail; + if ((ret = av_opt_set_dict(*s, options)) < 0) + goto fail; + if ((ret = (*s)->prot->url_open_dir(*s)) < 0) + goto fail; + return 0; + fail: + ffurl_close_dir(*s); + *s = NULL; + return ret; +} + +int ffurl_next_dir_entry(URLContext *s, const AVIODirEntry **next) +{ + return s->prot->url_read_dir(s, next); +} + static inline int retry_transfer_wrapper(URLContext *h, uint8_t *buf, int size, int size_min, int (*transfer_func)(URLContext *h, @@ -389,7 +430,6 @@ int ffurl_close(URLContext *h) return ffurl_closep(&h); } - const char *avio_find_protocol_name(const char *url) { URLProtocol *p = url_find_protocol(url); @@ -416,6 +456,40 @@ int avio_check(const char *url, int flags) return ret; } +void avio_close_dir(AVIOContext *s) +{ + if (s) { + ffurl_close_dir(s->opaque); + av_free(s); + } +} + +int avio_open_dir(AVIOContext **s, const char *url, + const AVIOInterruptCB *int_cb, AVDictionary **options) +{ + URLContext *h; + int ret; + av_assert0(s); + if ((ret = ffurl_open_dir(&h, url, int_cb, options)) < 0) + return ret; + + *s = avio_alloc_context(NULL, 0, h->flags, h, NULL, NULL, NULL); + if (!*s) { + avio_close_dir(*s); + return AVERROR(ENOMEM); + } + if (h->prot) { + (*s)->next_dir_entry = (int(*)(void *, const AVIODirEntry**))h->prot->url_read_dir; + } + (*s)->av_class = &ffio_url_class; + return 0; +} + +int avio_read_dir(AVIOContext *s, AVIODirEntry const **next) +{ + return ffurl_next_dir_entry(s->opaque, next); +} + int64_t ffurl_size(URLContext *h) { int64_t pos, size; diff --git a/libavformat/avio.h b/libavformat/avio.h index 4004b6f..20fd32b 100644 --- a/libavformat/avio.h +++ b/libavformat/avio.h @@ -34,7 +34,6 @@ #include "libavformat/version.h" - #define AVIO_SEEKABLE_NORMAL 0x0001 /**< Seeking works like for a local file */ /** @@ -54,6 +53,41 @@ typedef struct AVIOInterruptCB { } AVIOInterruptCB; /** + * Directory entry types. + */ +enum AVIODirEntryType { + AVIO_ENTRY_UNKNOWN, + AVIO_ENTRY_BLOCK_DEVICE, + AVIO_ENTRY_CHARACTER_DEVICE, + AVIO_ENTRY_DIRECTORY, + AVIO_ENTRY_NAMED_PIPE, + AVIO_ENTRY_SYMBOLIC_LINK, + AVIO_ENTRY_SOCKET, + AVIO_ENTRY_FILE +}; + +/** + * Describes single entry of the directory. + * + * Only name and type fileds are guaranteed be set. + * The other fields are protocol or/and platform dependent and might be unknown. + */ +typedef struct AVIODirEntry { + char *name; /**< Filename without a path. */ + int utf8; /**< Set to 1 when name is encoded with UTF-8, 0 otherwise. + Name can be encoded with UTF-8 eventhough 0 is set. + Encoding might be unknown. */ + enum AVIODirEntryType type; /**< Type of the entry. */ + int64_t size; /**< File size in bytes. */ + int64_t modification_timestamp; /**< Time of last modification in microseconds since unix epoch. */ + int64_t access_timestamp; /**< Time of last access in microseconds since unix epoch. */ + int64_t status_change_timestamp; /**< Time of last status change in microseconds since unix epoch. */ + uint32_t user_id; /**< User ID of the owner. */ + uint32_t group_id; /**< Group ID of the owner. */ + uint32_t filemode; /**< Unix file mode. */ +} AVIODirEntry; + +/** * Bytestream IO Context. * New fields can be added to the end with minor version bumps. * Removal, reordering and changes to existing fields require a major @@ -153,6 +187,13 @@ typedef struct AVIOContext { * This field is internal to libavformat and access from outside is not allowed. */ int orig_buffer_size; + + /** + * Get next directory entry. + * Returns next directory entry or NULL when more entries. Returned + * entry must be valid until next call of AVIOContext.next_dir_entry(). + */ + int (*next_dir_entry)(void *opaque, AVIODirEntry const **next); } AVIOContext; /* unbuffered I/O */ @@ -181,6 +222,51 @@ const char *avio_find_protocol_name(const char *url); int avio_check(const char *url, int flags); /** + * Open directory for reading. + * + * @warning Context created this way cannot be used for I/O operation other than + * avio_read_dir() and avio_close_dir(). + * + * @param s directory read context. Pointer to a NULL pointer must be passed. + * @param url url of the directory to be listed. It can contain a protocol prefix + * like "ftp://", "sftp://" etc. When no protocol prefix is provided + * then url is treated as path to a directory on local filesystem. + * @param int_cb an interrupt callback to be used at the protocols level + * @param options an AVDictionary filled with protocol-private options. + * On return this parameter will be destroyed and replaced with a dict + * containing options that were not found. May be NULL. + * See protocol's documentation to get list valid options. + * @return >=0 on success or negative on error. Specific errors: + * AVERROR(ENOSYS) - not implemented by protocol. + * AVERROR(EINVAL) - invalid URL. + * AVERROR(ENOTDIR) - URL is not a directory. + * AVERROR(EACCES) - no access to the directory. + */ +int avio_open_dir(AVIOContext **s, const char *url, + const AVIOInterruptCB *int_cb, AVDictionary **options); + +/** + * Get next directory entry. + * + * @note This function doesn't return current directory "." nor parent directory "..". + * + * @param s directory read context. + * @param[out] next next entry or NULL when no more entries. Returned entry is + * valid until next call of avio_read_dir() or avio_close_dir(). + * @return >=0 on success or negative on error. + */ +int avio_read_dir(AVIOContext *s, AVIODirEntry const **next); + +/** + * Close directory. + * + * All resources are freed and context cannot be used anymore. + * + * @param s directory read context to be closed. + */ +void avio_close_dir(AVIOContext *s); + +/** * Allocate and initialize an AVIOContext for buffered I/O. It must be later * freed with av_free(). * diff --git a/libavformat/url.h b/libavformat/url.h index 712ea0f..4c9c197 100644 --- a/libavformat/url.h +++ b/libavformat/url.h @@ -89,6 +89,23 @@ typedef struct URLProtocol { const AVClass *priv_data_class; int flags; int (*url_check)(URLContext *h, int mask); + /** + * Open directory for reading. + * Allocates all resources required by directory listing routine. + * It is called once before subsequent url_read_dir calls. + */ + int (*url_open_dir)(URLContext *h); + /** + * Get next directory entry. + * Returns next directory entry or NULL when more entries. Returned + * entry must be valid until next call of avio_read_dir() or avio_close_dir(). + */ + int (*url_read_dir)(URLContext *h, const AVIODirEntry **next); + /** + * Close directory. + * Releases all resources allocated by url_open_dir and url_read_dir. + */ + void (*url_close_dir)(URLContext *h); } URLProtocol; /** @@ -282,5 +299,43 @@ int ff_url_join(char *str, int size, const char *proto, void ff_make_absolute_url(char *buf, int size, const char *base, const char *rel); +/** + * Open directory for reading. + * + * @param s directory read context. Pointer to a NULL pointer must be passed. + * @param url url of the directory to be listed. It can contain a protocol prefix + * like "ftp://", "sftp://" etc. When no protocol prefix is provided + * then url is treated as path to a directory on local filesystem. + * @param int_cb an interrupt callback to be used at the protocols level + * @param options an AVDictionary filled with protocol-private options. + * On return this parameter will be destroyed and replaced with a dict + * containing options that were not found. May be NULL. + * See protocol's documentation to get list valid options. + * @return >=0 on success or negative on error. + */ +int ffurl_open_dir(URLContext **s, const char *url, + const AVIOInterruptCB *int_cb, AVDictionary **options); + +/** + * Get next directory entry. + * + * @note This function doesn't return current directory "." nor parent directory "..". + * + * @param s directory read context. + * @param[out] next next entry or NULL when no more entries. Returned entry is + * valid until next call of avio_read_dir() or avio_close_dir(). + * @return >=0 on success or negative on error. + */ +int ffurl_next_dir_entry(URLContext *s, const AVIODirEntry **next); + +/** + * Close directory. + * + * All resources are freed and context cannot be used anymore. + * + * @param s directory read context to be closed. + */ +void ffurl_close_dir(URLContext *s); + #endif /* AVFORMAT_URL_H */ -- 1.9.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel