[FFmpeg-devel] [PATCH 1/4] lavf: add directory listing API

Lukasz Marek lukasz.m.luki2 at gmail.com
Sat Jul 12 03:12:12 CEST 2014


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);
+    }
+}
+
+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



More information about the ffmpeg-devel mailing list