[RFC] Browser remote content API
Hi, I have an idea of new API, hopely useful. FFmpeg allows to use content on remote servers via network protocols (http, ftp, sftp). It can be read, written, played, probed etc, but in case user want to make application with some UI that displays that content (file names, dirs) then they need to implement it aside. It would be nice to extend URLProtocol with some kind of "readdir" callback. Furhtermore, it would be nice to have single function that read media related metadata like resolution, duration, codec,maybe thumbnail etc. (copy paste from ffprobe can be probably done). Maybe this is a project for GSoC? -- Best Regards, Lukasz Marek Insanity: doing the same thing over and over again and expecting different results. - Albert Einstein
On Sun, Feb 09, 2014 at 02:14:22AM +0100, Lukasz Marek wrote:
Hi,
I have an idea of new API, hopely useful.
FFmpeg allows to use content on remote servers via network protocols (http, ftp, sftp). It can be read, written, played, probed etc, but in case user want to make application with some UI that displays that content (file names, dirs) then they need to implement it aside. It would be nice to extend URLProtocol with some kind of "readdir" callback.
yes reordered your mail a bit
Maybe this is a project for GSoC?
how much does a student need to read and understand (i means specs) to implement this, is that together with implementation realistic within the 12 weeks ? iam a bit concerned that theres maybe too much code and specs reading involved. That is a student would have to wrap his head around 3 different protocol implementations and specifications but if you think it can be done, then make one of the 3 protocols the qualification task, a student passing that not only shows that he can do it he also would have 1/3 less work in the summer also i would suggest you design and implement the API without the student to not complicate that further
Furhtermore, it would be nice to have single function that read media related metadata like resolution, duration, codec,maybe thumbnail etc. (copy paste from ffprobe can be probably done).
i dont understand how this is related to the rest of your mail
[...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB The worst form of inequality is to try to make unequal things equal. -- Aristotle
On 09.02.2014 06:02, Michael Niedermayer wrote:
On Sun, Feb 09, 2014 at 02:14:22AM +0100, Lukasz Marek wrote:
Hi,
I have an idea of new API, hopely useful.
FFmpeg allows to use content on remote servers via network protocols (http, ftp, sftp). It can be read, written, played, probed etc, but in case user want to make application with some UI that displays that content (file names, dirs) then they need to implement it aside. It would be nice to extend URLProtocol with some kind of "readdir" callback.
yes
reordered your mail a bit
Maybe this is a project for GSoC?
how much does a student need to read and understand (i means specs) to implement this, is that together with implementation realistic within the 12 weeks ?
Yes, it is realistic.
iam a bit concerned that theres maybe too much code and specs reading involved. That is a student would have to wrap his head around 3 different protocol implementations and specifications
I would add also file protocol, to have one API for all protocols. sftp is done on top of libssh library and it has ready functions for this. It doesn't require any protocol knowledge. Authorization, connection etc is already done. ftp may also reuse existing code. One difference is to send different command instead of STOR/RETR. Server responds with the same format like "ls -l" on linux shell. So all student have to understand is how ftp works at high level and read deeply about LIST command (mostly about response format). http I don't know, but probably it is also not complicated.
but if you think it can be done, then make one of the 3 protocols the qualification task, a student passing that not only shows that he can do it he also would have 1/3 less work in the summer
OK, I will prepare this tomorrow.
also i would suggest you design and implement the API without the student to not complicate that further
Not sure I understand. You want a student to implement this at protocol level only (new callback) and lavf would be prepared before?
Furhtermore, it would be nice to have single function that read media related metadata like resolution, duration, codec,maybe thumbnail etc. (copy paste from ffprobe can be probably done).
i dont understand how this is related to the rest of your mail
It is not really related, but I think extending protocols by listening remote dirs is quite easy as for 3 months project. This second API is also quite useful when you build UI in player (all good iOS players I saw present this kind of metadata). But it can be omitted or moved to another project if you think it's too much. -- Best Regards, Lukasz Marek You can avoid reality, but you cannot avoid the consequences of avoiding reality. - Ayn Rand
On Sun, Feb 09, 2014 at 10:18:32PM +0100, Lukasz Marek wrote:
On 09.02.2014 06:02, Michael Niedermayer wrote:
On Sun, Feb 09, 2014 at 02:14:22AM +0100, Lukasz Marek wrote:
Hi,
I have an idea of new API, hopely useful.
FFmpeg allows to use content on remote servers via network protocols (http, ftp, sftp). It can be read, written, played, probed etc, but in case user want to make application with some UI that displays that content (file names, dirs) then they need to implement it aside. It would be nice to extend URLProtocol with some kind of "readdir" callback.
yes
reordered your mail a bit
Maybe this is a project for GSoC?
how much does a student need to read and understand (i means specs) to implement this, is that together with implementation realistic within the 12 weeks ?
Yes, it is realistic.
iam a bit concerned that theres maybe too much code and specs reading involved. That is a student would have to wrap his head around 3 different protocol implementations and specifications
I would add also file protocol, to have one API for all protocols.
sftp is done on top of libssh library and it has ready functions for this. It doesn't require any protocol knowledge. Authorization, connection etc is already done. ftp may also reuse existing code. One difference is to send different command instead of STOR/RETR. Server responds with the same format like "ls -l" on linux shell. So all student have to understand is how ftp works at high level and read deeply about LIST command (mostly about response format). http I don't know, but probably it is also not complicated.
but if you think it can be done, then make one of the 3 protocols the qualification task, a student passing that not only shows that he can do it he also would have 1/3 less work in the summer
OK, I will prepare this tomorrow.
also i would suggest you design and implement the API without the student to not complicate that further
Not sure I understand. You want a student to implement this at protocol level only (new callback) and lavf would be prepared before?
it will take you less time to design and add the framework/API without a student than with. so why do it with one ? you know ffmpeg and the API, the student doesnt
Furhtermore, it would be nice to have single function that read media related metadata like resolution, duration, codec,maybe thumbnail etc. (copy paste from ffprobe can be probably done).
i dont understand how this is related to the rest of your mail
It is not really related, but I think extending protocols by listening remote dirs is quite easy as for 3 months project. This
how many webservers are out there ? how standarized is their html output for directory listings ?
second API is also quite useful when you build UI in player (all good iOS players I saw present this kind of metadata). But it can be omitted or moved to another project if you think it's too much.
nothing stops you from adding some optional stuff "in case there is lots of time left" but it should be clear that doing this is not neccessary for the student to finish the task successfully also to have a practical properties gathering API you need multiple threads id guess, and you want the user app to receive partial data as it comes in, so this all doesnt look all that easy to me. and then you probably also want to cache the results maybe so they dont need to be re-retrieved if for example file dates / sizes havent changed. id say this sounds like it could be better off as a seperate project [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB Those who are too smart to engage in politics are punished by being governed by those who are dumber. -- Plato
On 10 February 2014 03:29, Michael Niedermayer <michaelni@gmx.at> wrote:
On Sun, Feb 09, 2014 at 10:18:32PM +0100, Lukasz Marek wrote:
On 09.02.2014 06:02, Michael Niedermayer wrote:
On Sun, Feb 09, 2014 at 02:14:22AM +0100, Lukasz Marek wrote:
Hi,
I have an idea of new API, hopely useful.
FFmpeg allows to use content on remote servers via network protocols (http, ftp, sftp). It can be read, written, played, probed etc, but in case user want to make application with some UI that displays that content (file names, dirs) then they need to implement it aside. It would be nice to extend URLProtocol with some kind of "readdir" callback.
yes
reordered your mail a bit
Maybe this is a project for GSoC?
how much does a student need to read and understand (i means specs) to implement this, is that together with implementation realistic within the 12 weeks ?
Yes, it is realistic.
iam a bit concerned that theres maybe too much code and specs reading involved. That is a student would have to wrap his head around 3 different protocol implementations and specifications
I would add also file protocol, to have one API for all protocols.
sftp is done on top of libssh library and it has ready functions for this. It doesn't require any protocol knowledge. Authorization, connection etc is already done. ftp may also reuse existing code. One difference is to send different command instead of STOR/RETR. Server responds with the same format like "ls -l" on linux shell. So all student have to understand is how ftp works at high level and read deeply about LIST command (mostly about response format). http I don't know, but probably it is also not complicated.
but if you think it can be done, then make one of the 3 protocols the qualification task, a student passing that not only shows that he can do it he also would have 1/3 less work in the summer
OK, I will prepare this tomorrow.
also i would suggest you design and implement the API without the student to not complicate that further
Not sure I understand. You want a student to implement this at protocol level only (new callback) and lavf would be prepared before?
it will take you less time to design and add the framework/API without a student than with. so why do it with one ?
you know ffmpeg and the API, the student doesnt
Furhtermore, it would be nice to have single function that read media related metadata like resolution, duration, codec,maybe thumbnail etc. (copy paste from ffprobe can be probably done).
i dont understand how this is related to the rest of your mail
It is not really related, but I think extending protocols by listening remote dirs is quite easy as for 3 months project. This
how many webservers are out there ? how standarized is their html output for directory listings ?
second API is also quite useful when you build UI in player (all good iOS players I saw present this kind of metadata). But it can be omitted or moved to another project if you think it's too much.
nothing stops you from adding some optional stuff "in case there is lots of time left" but it should be clear that doing this is not neccessary for the student to finish the task successfully
also to have a practical properties gathering API you need multiple threads id guess, and you want the user app to receive partial data as it comes in, so this all doesnt look all that easy to me. and then you probably also want to cache the results maybe so they dont need to be re-retrieved if for example file dates / sizes havent changed. id say this sounds like it could be better off as a seperate project
OK, I agree I added this project in "unmentioned project secion". I would like to ask someone to review it (especially grammar) I set myself as possible backup mentor. I may help on protocol related things, but I cannot promise I will be able to be accessible on IRC for most of the time.
On 10.02.2014 03:29, Michael Niedermayer wrote:
also i would suggest you design and implement the API without the student to not complicate that further
Not sure I understand. You want a student to implement this at protocol level only (new callback) and lavf would be prepared before? it will take you less time to design and add the framework/API without a student than with. so why do it with one ?
you know ffmpeg and the API, the student doesnt
I've attached implementation of my proposal API. Second patch is just for testing purposes, but probably may be helpful for the student. Example may be also merged at some point when first protocol supports it. -- Best Regards, Lukasz Marek When you look long into an abyss, the abyss looks into you. - Friedrich Nietzsche
L'octidi 28 pluviôse, an CCXXII, Lukasz Marek a écrit :
I've attached implementation of my proposal API.
Second patch is just for testing purposes, but probably may be helpful for the student. Example may be also merged at some point when first protocol supports it.
-- Best Regards, Lukasz Marek
When you look long into an abyss, the abyss looks into you. - Friedrich Nietzsche
From be932968c1ba2b9f4e34dd096f31df2ddba97249 Mon Sep 17 00:00:00 2001 From: Lukasz Marek <lukasz.m.luki@gmail.com> Date: Sun, 16 Feb 2014 00:44:09 +0100 Subject: [PATCH 1/2] lavf/avio: add directory list API
TODO: minor bump and APIchnage update.
This is preparation for GSoC project.
Signed-off-by: Lukasz Marek <lukasz.m.luki@gmail.com> --- libavformat/avio.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ libavformat/avio.h | 49 +++++++++++++++++++++++++++++++++ libavformat/url.h | 1 + 3 files changed, 130 insertions(+)
I believe the implementation could go in a separate file.
diff --git a/libavformat/avio.c b/libavformat/avio.c index 225d982..1851654 100644 --- a/libavformat/avio.c +++ b/libavformat/avio.c @@ -23,6 +23,7 @@ #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 @@ -395,6 +396,85 @@ int avio_check(const char *url, int flags) return ret; }
+void avio_free_dir_list(AVIODirEntryList **entries) +{ + AVIODirEntryList *list; + int i; + + if (!entries || !(*entries)) + return; + list = *entries; + for (i = 0; i < list->nb_entries; i++) { + if (list->enties[i]) { + av_free(list->enties[i]->name); + av_free(list->enties[i]); + } + } + av_free(list->enties); + av_freep(entries); +} + +static int cmp_dir_entires(AVIODirEntry *e1, AVIODirEntry *e2, int flags) +{ + int ret = flags & AVIO_SORT_DESCENDING; + av_assert0(e1 && e2); + if ((flags & AVIO_SORT_DIRS_FIRST) && e1->type != e2->type) + return e1->type != AVIO_ENTRY_DIR; + if (flags & AVIO_SORT_BY_SIZE) { + if (e1->size != e2->size) + return e1->size > e2->size ? ret : !ret; + } else if (flags & AVIO_SORT_BY_CREATION_DATE) { + if (e1->creation_timestamp != e2->creation_timestamp) + return e1->creation_timestamp > e2->creation_timestamp ? ret : !ret; + } else if (flags & AVIO_SORT_BY_MODIFICATION_DATE) { + if (e1->modification_timestamp != e2->modification_timestamp) + return e1->modification_timestamp > e2->modification_timestamp ? ret : !ret; + } + return strcmp(e1->name, e2->name) < 0 ? ret : !ret; +} + +int avio_list_dir(const char *url, AVIODirEntryList **entries, int sort_flags, + AVDictionary **options) +{ + int ret, i1, i2; + URLContext *h; + AVIODirEntryList *list; + + av_assert0(entries); + *entries = NULL; + if ((ret = ffurl_alloc(&h, url, 0, NULL))) + return ret; + if (!h->prot->url_list_dir) { + ret = AVERROR(ENOSYS); + goto fail; + }
+ if (options && h->prot->priv_data_class && + (ret = av_opt_set_dict(h->priv_data, options)) < 0) + goto fail; +
Why not set directly options on h?
+ list = av_mallocz(sizeof(**entries));
sizeof(*list)?
+ if (!list) { + ret = AVERROR(ENOMEM); + goto fail; + }
+ *entries = list;
IMHO, should go when success is certain.
+ if ((ret = h->prot->url_list_dir(h, url, list)) < 0) + goto fail; +
+ for (i1 = 0; i1 < list->nb_entries - 1; i1++) + for (i2 = i1 + 1; i2 < list->nb_entries; i2++) { + if (cmp_dir_entires(list->enties[i1], list->enties[i2], sort_flags)) + FFSWAP(AVIODirEntry *, list->enties[i1], list->enties[i2]); + }
I can see why you would do it (lack of extra argument to the sort function of qsort), but I believe a custom local implementation of sort is not a good idea. You can probably use Michael's AV_QSORT macro: since it is a macro, calling the cmp function with an extra argument should be possible.
+ + ffurl_close(h); + return 0; + fail: + ffurl_close(h); + avio_free_dir_list(entries); + return ret; +} + int64_t ffurl_size(URLContext *h) { int64_t pos, size; diff --git a/libavformat/avio.h b/libavformat/avio.h index 4f4ac3c..ff8ec22 100644 --- a/libavformat/avio.h +++ b/libavformat/avio.h @@ -53,6 +53,32 @@ typedef struct AVIOInterruptCB { void *opaque; } AVIOInterruptCB;
+enum AVIODirEntryType { + AVIO_ENTRY_UNKNOWN, + AVIO_ENTRY_DIR, + AVIO_ENTRY_FILE +}; + +/** + * Describes single entry of the directory. + */ +typedef struct AVIODirEntry { + char *name; /**< filename */
+ enum AVIODirEntryType type; /**< one of AVIO_ENTRY_* value */
Very minor nit: putting the fields with smaller type after the bigger ones is better for packing.
+ int64_t size; /**< file size */
+ int64_t creation_timestamp; /**< creation timestamp */
ANy reason to include this one and not atime and ctime which are much more common?
+ int64_t modification_timestamp; /**< modification timestamp */
Also: I suppose this is in AV_TIME_BASE (microseconds) since the Unix epoch. Maybe the doxy should state it. As is, the doxy for the fields could be completely removed.
+} AVIODirEntry; + +/** + * List of directory entries. + * @see avio_list_dir() + */ +typedef struct AVIODirEntryList { + AVIODirEntry **enties; + int nb_entries; +} AVIODirEntryList; + /** * Bytestream IO Context. * New fields can be added to the end with minor version bumps. @@ -164,6 +190,29 @@ typedef struct AVIOContext { */ int avio_check(const char *url, int flags);
+#define AVIO_SORT_DESCENDING 0x001 /**< use descending mode instead of ascending */ +#define AVIO_SORT_DIRS_FIRST 0x002 /**< move all dir names (sorted) in front of the list */
+#define AVIO_SORT_BY_SIZE 0x004 /**< sort by size before sorting by name */ +#define AVIO_SORT_BY_CREATION_DATE 0x008 /**< sort by creation date before sorting by name */ +#define AVIO_SORT_BY_MODIFICATION_DATE 0x010 /**< sort by modification date before sorting by name */
Inconsistent naming: time / date.
+ +/** + * Allow to read content of the directory. + * + * @param url directory to be listed. + * @param[out] entries sorted directory entries. + * @param sort_flags combination of AVIO_SORT_* flags. + * @param options protocol options. + * @return 0 on success or <0 on error. + */ +int avio_list_dir(const char *url, AVIODirEntryList **entries, int sort_flags, + AVDictionary **options); + +/** + * Free directory entries list. + */ +void avio_free_dir_list(AVIODirEntryList **entries); + /** * 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..f64f34d 100644 --- a/libavformat/url.h +++ b/libavformat/url.h @@ -89,6 +89,7 @@ typedef struct URLProtocol { const AVClass *priv_data_class; int flags; int (*url_check)(URLContext *h, int mask); + int (*url_list_dir)(URLContext *h, const char *dir, AVIODirEntryList *entries); } URLProtocol;
/**
Regards, -- Nicolas George
On Sun, Feb 16, 2014 at 12:51:42AM +0100, Lukasz Marek wrote:
On 10.02.2014 03:29, Michael Niedermayer wrote:
also i would suggest you design and implement the API without the student to not complicate that further
Not sure I understand. You want a student to implement this at protocol level only (new callback) and lavf would be prepared before? it will take you less time to design and add the framework/API without a student than with. so why do it with one ?
you know ffmpeg and the API, the student doesnt
I've attached implementation of my proposal API.
Second patch is just for testing purposes, but probably may be helpful for the student. Example may be also merged at some point when first protocol supports it.
-- Best Regards, Lukasz Marek
When you look long into an abyss, the abyss looks into you. - Friedrich Nietzsche
avio.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ avio.h | 49 +++++++++++++++++++++++++++++++++++++++ url.h | 1 3 files changed, 130 insertions(+) 6cc952d48db502c0efe27b6ec7113543730e67f6 0001-lavf-avio-add-directory-list-API.patch From be932968c1ba2b9f4e34dd096f31df2ddba97249 Mon Sep 17 00:00:00 2001 From: Lukasz Marek <lukasz.m.luki@gmail.com> Date: Sun, 16 Feb 2014 00:44:09 +0100 Subject: [PATCH 1/2] lavf/avio: add directory list API
TODO: minor bump and APIchnage update.
This is preparation for GSoC project.
Signed-off-by: Lukasz Marek <lukasz.m.luki@gmail.com> --- libavformat/avio.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ libavformat/avio.h | 49 +++++++++++++++++++++++++++++++++ libavformat/url.h | 1 + 3 files changed, 130 insertions(+)
diff --git a/libavformat/avio.c b/libavformat/avio.c index 225d982..1851654 100644 --- a/libavformat/avio.c +++ b/libavformat/avio.c @@ -23,6 +23,7 @@ #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 @@ -395,6 +396,85 @@ int avio_check(const char *url, int flags) return ret; }
+void avio_free_dir_list(AVIODirEntryList **entries) +{ + AVIODirEntryList *list; + int i; + + if (!entries || !(*entries)) + return; + list = *entries; + for (i = 0; i < list->nb_entries; i++) { + if (list->enties[i]) { + av_free(list->enties[i]->name); + av_free(list->enties[i]); + } + } + av_free(list->enties); + av_freep(entries); +} + +static int cmp_dir_entires(AVIODirEntry *e1, AVIODirEntry *e2, int flags) +{ + int ret = flags & AVIO_SORT_DESCENDING; + av_assert0(e1 && e2); + if ((flags & AVIO_SORT_DIRS_FIRST) && e1->type != e2->type) + return e1->type != AVIO_ENTRY_DIR; + if (flags & AVIO_SORT_BY_SIZE) { + if (e1->size != e2->size) + return e1->size > e2->size ? ret : !ret; + } else if (flags & AVIO_SORT_BY_CREATION_DATE) { + if (e1->creation_timestamp != e2->creation_timestamp) + return e1->creation_timestamp > e2->creation_timestamp ? ret : !ret; + } else if (flags & AVIO_SORT_BY_MODIFICATION_DATE) { + if (e1->modification_timestamp != e2->modification_timestamp) + return e1->modification_timestamp > e2->modification_timestamp ? ret : !ret; + } + return strcmp(e1->name, e2->name) < 0 ? ret : !ret; +} + +int avio_list_dir(const char *url, AVIODirEntryList **entries, int sort_flags, + AVDictionary **options) +{ + int ret, i1, i2; + URLContext *h; + AVIODirEntryList *list; + + av_assert0(entries); + *entries = NULL; + if ((ret = ffurl_alloc(&h, url, 0, NULL))) + return ret; + if (!h->prot->url_list_dir) { + ret = AVERROR(ENOSYS); + goto fail; + } + if (options && h->prot->priv_data_class && + (ret = av_opt_set_dict(h->priv_data, options)) < 0) + goto fail; + + list = av_mallocz(sizeof(**entries)); + if (!list) { + ret = AVERROR(ENOMEM); + goto fail; + } + *entries = list; + if ((ret = h->prot->url_list_dir(h, url, list)) < 0) + goto fail; + + for (i1 = 0; i1 < list->nb_entries - 1; i1++) + for (i2 = i1 + 1; i2 < list->nb_entries; i2++) { + if (cmp_dir_entires(list->enties[i1], list->enties[i2], sort_flags)) + FFSWAP(AVIODirEntry *, list->enties[i1], list->enties[i2]); + } + + ffurl_close(h); + return 0; + fail: + ffurl_close(h); + avio_free_dir_list(entries); + return ret; +} + int64_t ffurl_size(URLContext *h) { int64_t pos, size; diff --git a/libavformat/avio.h b/libavformat/avio.h index 4f4ac3c..ff8ec22 100644 --- a/libavformat/avio.h +++ b/libavformat/avio.h @@ -53,6 +53,32 @@ typedef struct AVIOInterruptCB { void *opaque; } AVIOInterruptCB;
+enum AVIODirEntryType { + AVIO_ENTRY_UNKNOWN, + AVIO_ENTRY_DIR, + AVIO_ENTRY_FILE +};
+ +/** + * Describes single entry of the directory. + */ +typedef struct AVIODirEntry { + char *name; /**< filename */ + enum AVIODirEntryType type; /**< one of AVIO_ENTRY_* value */ + int64_t size; /**< file size */ + int64_t creation_timestamp; /**< creation timestamp */ + int64_t modification_timestamp; /**< modification timestamp */ +} AVIODirEntry;
user, group, access rights, symbolic link destination whats the encoding of name ? utf-8 ? undefined ? some flag or tri-state field or other system that indicated if the target matches filename case sensitively or not might be usefull too [....] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB Why not whip the teacher when the pupil misbehaves? -- Diogenes of Sinope
On Sun, 16 Feb 2014 00:51:42 +0100 Lukasz Marek <lukasz.m.luki@gmail.com> wrote:
diff --git a/libavformat/avio.h b/libavformat/avio.h index 4f4ac3c..ff8ec22 100644 --- a/libavformat/avio.h +++ b/libavformat/avio.h @@ -53,6 +53,32 @@ typedef struct AVIOInterruptCB { void *opaque; } AVIOInterruptCB;
+enum AVIODirEntryType { + AVIO_ENTRY_UNKNOWN, + AVIO_ENTRY_DIR, + AVIO_ENTRY_FILE +};
From the UNIX point of view, there are many more entry types, and from the other point of view (accessing arbitrary content), it gets even worse, because entries could for example be links pointing elsewhere.
+/** + * Describes single entry of the directory. + */ +typedef struct AVIODirEntry { + char *name; /**< filename */ + enum AVIODirEntryType type; /**< one of AVIO_ENTRY_* value */ + int64_t size; /**< file size */ + int64_t creation_timestamp; /**< creation timestamp */ + int64_t modification_timestamp; /**< modification timestamp */ +} AVIODirEntry; + +/** + * List of directory entries. + * @see avio_list_dir() + */ +typedef struct AVIODirEntryList { + AVIODirEntry **enties; + int nb_entries; +} AVIODirEntryList; + /** * Bytestream IO Context. * New fields can be added to the end with minor version bumps. @@ -164,6 +190,29 @@ typedef struct AVIOContext { */ int avio_check(const char *url, int flags);
+#define AVIO_SORT_DESCENDING 0x001 /**< use descending mode instead of ascending */ +#define AVIO_SORT_DIRS_FIRST 0x002 /**< move all dir names (sorted) in front of the list */ +#define AVIO_SORT_BY_SIZE 0x004 /**< sort by size before sorting by name */ +#define AVIO_SORT_BY_CREATION_DATE 0x008 /**< sort by creation date before sorting by name */ +#define AVIO_SORT_BY_MODIFICATION_DATE 0x010 /**< sort by modification date before sorting by name */
Why would the API sort for you? You could add a separate sort API function, but I think the user can just sort on his own. Even if you include this, how do you change after which criteria it sorts first?
+/** + * Allow to read content of the directory. + * + * @param url directory to be listed. + * @param[out] entries sorted directory entries. + * @param sort_flags combination of AVIO_SORT_* flags. + * @param options protocol options. + * @return 0 on success or <0 on error. + */ +int avio_list_dir(const char *url, AVIODirEntryList **entries, int sort_flags, + AVDictionary **options); + +/** + * Free directory entries list. + */ +void avio_free_dir_list(AVIODirEntryList **entries);
I think an opendir()/readdir() style API would be better. You're not forced to allocate a huge list of entries (and reallocate it several times as you append to it), and you wouldn't need to allocate memory for each entry. Details could be queried by a separate stat()-style function. The function could take the opendir() handle as parameter, so that in case of remote protocols the entry could be retrieved from a cache. It also could help keeping down the load, as it's the user's decision whether to call the underlying stat() implementation.
/** * 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..f64f34d 100644 --- a/libavformat/url.h +++ b/libavformat/url.h @@ -89,6 +89,7 @@ typedef struct URLProtocol { const AVClass *priv_data_class; int flags; int (*url_check)(URLContext *h, int mask); + int (*url_list_dir)(URLContext *h, const char *dir, AVIODirEntryList *entries); } URLProtocol;
/**
+/** + * Allow to read content of the directory. + * + * @param url directory to be listed. + * @param[out] entries sorted directory entries. + * @param sort_flags combination of AVIO_SORT_* flags. + * @param options protocol options. + * @return 0 on success or <0 on error. + */ +int avio_list_dir(const char *url, AVIODirEntryList **entries, int sort_flags, + AVDictionary **options); + +/** + * Free directory entries list. + */ +void avio_free_dir_list(AVIODirEntryList **entries);
I think an opendir()/readdir() style API would be better. You're not forced to allocate a huge list of entries (and reallocate it several times as you append to it), and you wouldn't need to allocate memory for each entry.
Details could be queried by a separate stat()-style function. The function could take the opendir() handle as parameter, so that in case of remote protocols the entry could be retrieved from a cache. It also could help keeping down the load, as it's the user's decision whether to call the underlying stat() implementation.
I had this in mind, but I'm not sure it is good idea. Using a cache would require a context, proof me wrong, but there is any in public API and I think in many cases it would ended in situation where the same data are in cache and on user's structure. FTP and HTTP protocol provide all information at once and second function may just confuse user which may not know these protocols. Your solution would make sense for file protocol, but I treat it as minor in this, because this API is more relevant for network protocol. One case that make it more sense is sftp, but I have to check its API. Now I have an idea to add a flag in AVIODirEntryList to inform user that extra information may be obtained with stat function, but it still doesn't solve problem with context. Connecting to server and authorization may be slow and it may takes much longer than querying all params during single call. I prepare it just for GSoC project and until someone gets deeper into it, it is hard to predict all issues that may occur. As a comment for all other comments from you, Michael and Nicolas, I wanted to make this API simple and I omitted some details as file permissions etc. I see you all point it so I will resent updated version later. Thanks for comments for everyone. -- Best Regards, Lukasz Marek If you can't explain it simply, you don't understand it well enough. - Albert Einstein
On Sun, Feb 16, 2014 at 06:52:21PM +0100, Lukasz Marek wrote:
+/** + * Allow to read content of the directory. + * + * @param url directory to be listed. + * @param[out] entries sorted directory entries. + * @param sort_flags combination of AVIO_SORT_* flags. + * @param options protocol options. + * @return 0 on success or <0 on error. + */ +int avio_list_dir(const char *url, AVIODirEntryList **entries, int sort_flags, + AVDictionary **options); + +/** + * Free directory entries list. + */ +void avio_free_dir_list(AVIODirEntryList **entries);
I think an opendir()/readdir() style API would be better. You're not forced to allocate a huge list of entries (and reallocate it several times as you append to it), and you wouldn't need to allocate memory for each entry.
Details could be queried by a separate stat()-style function. The function could take the opendir() handle as parameter, so that in case of remote protocols the entry could be retrieved from a cache. It also could help keeping down the load, as it's the user's decision whether to call the underlying stat() implementation.
I had this in mind, but I'm not sure it is good idea. Using a cache would require a context, proof me wrong, but there is any in public API and I think in many cases it would ended in situation where the same data are in cache and on user's structure. FTP and HTTP protocol provide all information at once and second function may just confuse user which may not know these protocols. Your solution would make sense for file protocol, but I treat it as minor in this, because this API is more relevant for network protocol. One case that make it more sense is sftp, but I have to check its API.
Now I have an idea to add a flag in AVIODirEntryList to inform user that extra information may be obtained with stat function, but it still doesn't solve problem with context. Connecting to server and authorization may be slow and it may takes much longer than querying all params during single call. I prepare it just for GSoC project and until someone gets deeper into it, it is hard to predict all issues that may occur.
As a comment for all other comments from you, Michael and Nicolas, I wanted to make this API simple and I omitted some details as file permissions etc. I see you all point it so I will resent updated version later.
i didnt mean that all that has to be added now, if you had other plans, it was more meant to make sure its not forgotten/missed [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB Many things microsoft did are stupid, but not doing something just because microsoft did it is even more stupid. If everything ms did were stupid they would be bankrupt already.
On 17.02.2014 05:13, Michael Niedermayer wrote:
On Sun, Feb 16, 2014 at 06:52:21PM +0100, Lukasz Marek wrote:
+/** + * Allow to read content of the directory. + * + * @param url directory to be listed. + * @param[out] entries sorted directory entries. + * @param sort_flags combination of AVIO_SORT_* flags. + * @param options protocol options. + * @return 0 on success or <0 on error. + */ +int avio_list_dir(const char *url, AVIODirEntryList **entries, int sort_flags, + AVDictionary **options); + +/** + * Free directory entries list. + */ +void avio_free_dir_list(AVIODirEntryList **entries);
I think an opendir()/readdir() style API would be better. You're not forced to allocate a huge list of entries (and reallocate it several times as you append to it), and you wouldn't need to allocate memory for each entry.
Details could be queried by a separate stat()-style function. The function could take the opendir() handle as parameter, so that in case of remote protocols the entry could be retrieved from a cache. It also could help keeping down the load, as it's the user's decision whether to call the underlying stat() implementation.
I had this in mind, but I'm not sure it is good idea. Using a cache would require a context, proof me wrong, but there is any in public API and I think in many cases it would ended in situation where the same data are in cache and on user's structure. FTP and HTTP protocol provide all information at once and second function may just confuse user which may not know these protocols. Your solution would make sense for file protocol, but I treat it as minor in this, because this API is more relevant for network protocol. One case that make it more sense is sftp, but I have to check its API.
Now I have an idea to add a flag in AVIODirEntryList to inform user that extra information may be obtained with stat function, but it still doesn't solve problem with context. Connecting to server and authorization may be slow and it may takes much longer than querying all params during single call. I prepare it just for GSoC project and until someone gets deeper into it, it is hard to predict all issues that may occur.
As a comment for all other comments from you, Michael and Nicolas, I wanted to make this API simple and I omitted some details as file permissions etc. I see you all point it so I will resent updated version later.
i didnt mean that all that has to be added now, if you had other plans, it was more meant to make sure its not forgotten/missed
It is old topic, but some time ago I implemented most of it. I'm pushing it in separate threads. I included most of the remarks.
participants (5)
-
Lukasz M -
Lukasz Marek -
Michael Niedermayer -
Nicolas George -
wm4