[FFmpeg-devel] [PATCH 1/4] lavf: add directory listing API
Nicolas George
george at nsup.org
Tue Jul 15 14:54:47 CEST 2014
Le quartidi 24 messidor, an CCXXII, Lukasz Marek a écrit :
> 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.luki2 at 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);
> + }
> +}
Maybe ffurl_close_dirp(), and use ffurl_closep().
> +
> +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);
> + }
> +}
Here and similarly for the other functions: do you think we need the
indirection avio_ -> ffurl_? It exist for the current API because the ffurl_
stuff used to be public, but I see no reason to make new code more complex
like that.
> +
> +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"
>
> -
Spurious change.
> #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
> +};
Any reason for the order? IMHO, alphabetic would be better, and frequency
even better: FILE=0, then DIRECTORY, then the strange Unix stuff. Ans
UNKNOWN either last or special with -1.
> +
> +/**
> + * 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. */
const?
> + 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. */
What would it be otherwise?
> + 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. */
Is there a way of distinguishing unknown values from actual values?
> +} 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);
I believe the "const" qualifier is supposed to come in front of the type.
cdecl, at least, does not like that syntax.
> } 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.
Please specify whether the return code for EOF is 0 or AVERROR_EOF.
> + */
> +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);
If these function remain, do they need to be made global to the library?
Making them static to the file should be enough.
> +
> +/**
> + * 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 */
Regards,
--
Nicolas George
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20140715/fadb71e6/attachment.asc>
More information about the ffmpeg-devel
mailing list