[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