[FFmpeg-devel] [PATCH] lavf: add zip protocol

Lukasz Marek lukasz.m.luki2 at gmail.com
Fri Mar 27 13:51:45 CET 2015


TODO: add doc, update doc/APIChanges, bump minor
---
 configure                |   4 ++
 libavformat/Makefile     |   2 +
 libavformat/allformats.c |   1 +
 libavformat/zip.c        | 176 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 183 insertions(+)
 create mode 100644 libavformat/zip.c

diff --git a/configure b/configure
index a96bfb7..a36c357 100755
--- a/configure
+++ b/configure
@@ -275,6 +275,7 @@ External library support:
   --disable-sdl            disable sdl [autodetect]
   --enable-x11grab         enable X11 grabbing (legacy) [no]
   --disable-xlib           disable xlib [autodetect]
+  --enable-libzip          enable libzip [no]
   --disable-zlib           disable zlib [autodetect]
 
 Toolchain options:
@@ -1404,6 +1405,7 @@ EXTERNAL_LIBRARY_LIST="
     libxcb_shape
     libxcb_xfixes
     libxvid
+    libzip
     libzmq
     libzvbi
     lzma
@@ -2582,6 +2584,7 @@ udp_protocol_select="network"
 udplite_protocol_select="network"
 unix_protocol_deps="sys_un_h"
 unix_protocol_select="network"
+zip_protocol_deps="zlib"
 
 # filters
 amovie_filter_deps="avcodec avformat"
@@ -4963,6 +4966,7 @@ enabled libsmbclient      && { use_pkg_config smbclient libsmbclient.h smbc_init
                                require smbclient libsmbclient.h smbc_init -lsmbclient; }
 enabled libsoxr           && require libsoxr soxr.h soxr_create -lsoxr
 enabled libssh            && require_pkg_config libssh libssh/sftp.h sftp_init
+enabled libzip            && require_pkg_config libzip zip.h zip_open
 enabled libspeex          && require_pkg_config speex speex/speex.h speex_decoder_init -lspeex
 enabled libstagefright_h264 && require_cpp libstagefright_h264 "binder/ProcessState.h media/stagefright/MetaData.h
     media/stagefright/MediaBufferGroup.h media/stagefright/MediaDebug.h media/stagefright/MediaDefs.h
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 2118ff2..47d3804 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -522,6 +522,8 @@ OBJS-$(CONFIG_TLS_PROTOCOL)              += tls.o
 OBJS-$(CONFIG_UDP_PROTOCOL)              += udp.o
 OBJS-$(CONFIG_UDPLITE_PROTOCOL)          += udp.o
 OBJS-$(CONFIG_UNIX_PROTOCOL)             += unix.o
+OBJS-$(CONFIG_ZIP_PROTOCOL)              += zip.o
+
 
 OBJS-$(HAVE_LIBC_MSVCRT)                 += file_open.o
 
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 26ccc27..96fe484 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -379,6 +379,7 @@ void av_register_all(void)
     REGISTER_PROTOCOL(UDP,              udp);
     REGISTER_PROTOCOL(UDPLITE,          udplite);
     REGISTER_PROTOCOL(UNIX,             unix);
+    REGISTER_PROTOCOL(ZIP,              zip);
 
     /* external libraries */
     REGISTER_DEMUXER (LIBGME,           libgme);
diff --git a/libavformat/zip.c b/libavformat/zip.c
new file mode 100644
index 0000000..c9d6679
--- /dev/null
+++ b/libavformat/zip.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2015 Lukasz Marek <lukasz.m.luki at gmail.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sys/stat.h>
+#include <zip.h>
+#include "libavutil/opt.h"
+#include "libavutil/avstring.h"
+#include "avformat.h"
+#include "internal.h"
+#include "url.h"
+
+typedef struct {
+    const AVClass *class;
+
+    struct zip *z;
+    struct zip_file *f;
+
+    char *password;
+    int file_index;
+    int64_t filesize;
+} ZIPContext;
+
+
+static int ffzip_close(URLContext *h)
+{
+    ZIPContext *zip = h->priv_data;
+    if (zip->f) {
+        zip_fclose(zip->f);
+        zip->f = NULL;
+    }
+    if (zip->z) {
+        zip_close(zip->z);
+        zip->z = NULL;
+    }
+    return 0;
+}
+
+static int ffzip_split_url(URLContext *h, const char *url, char **file)
+{
+    ZIPContext *zip = h->priv_data;
+    int ret = 0;
+    struct stat st;
+    char *filename, *pos;
+
+    *file = NULL;
+
+    if (strnlen(url, 7) < 7 || !av_strstart(url, "zip://", NULL))
+        return AVERROR(EINVAL);
+
+    filename = av_strdup(url + 6);
+    if (!filename)
+        return AVERROR(ENOMEM);
+
+    pos = filename;
+    while (pos) {
+        if (pos != filename)
+            *pos = 0;
+        if ((stat(filename, &st) == 0) && S_ISREG(st.st_mode)) {
+            av_log(h, AV_LOG_DEBUG, "Trying to open file: %s\n", filename);
+            zip->z = zip_open(filename, 0, NULL);
+            break;
+        }
+        if (pos != filename)
+            *pos = '/';
+        pos = strchr(pos + 1, '/');
+    }
+    if (!zip->z) {
+        ret = AVERROR(EIO);
+    } else if (pos != filename && pos[1]) {
+        *file = av_strdup(pos + 1);
+        if (!*file)
+            ret = AVERROR(ENOMEM);
+    }
+    av_free(filename);
+    return ret;
+}
+
+static int ffzip_open(URLContext *h, const char *url, int flags)
+{
+    ZIPContext *zip = h->priv_data;
+    struct zip_stat zip_st;
+    char *file;
+    int ret;
+
+    if ((ret = ffzip_split_url(h, url, &file)) < 0)
+        goto fail;
+
+    zip_set_default_password(zip->z, zip->password);
+    zip_stat_init(&zip_st);
+    zip->filesize = -1;
+    h->is_streamed = 1;
+
+    if (file) {
+        zip->f = zip_fopen(zip->z, file, 0);
+        if (!zip->f) {
+            ret = AVERROR(EIO);
+            goto fail;
+        }
+        if (!zip_stat(zip->z, file, 0, &zip_st))
+            zip->filesize = zip_st.size;
+        av_free(file);
+    } else if (zip_get_num_entries(zip->z, 0) == 1) {
+        zip->f = zip_fopen_index(zip->z, zip->file_index, 0);
+        if (!zip->f) {
+            ret = AVERROR(EIO);
+            goto fail;
+        }
+        if (!zip_stat_index(zip->z, zip->file_index, 0, &zip_st))
+            zip->filesize = zip_st.size;
+    }
+
+    return 0;
+  fail:
+    ffzip_close(h);
+    return ret;
+}
+
+static int ffzip_read(URLContext *h, unsigned char *buf, int size)
+{
+    ZIPContext *zip = h->priv_data;
+    int ret;
+    ret = zip_fread(zip->f, buf, size);
+    return ret < 0 ? AVERROR(EIO) : ret;
+}
+
+static int64_t ffzip_seek(URLContext *h, int64_t pos, int whence)
+{
+    ZIPContext *zip = h->priv_data;
+
+    if (whence == AVSEEK_SIZE && zip->filesize >= 0)
+        return zip->filesize;
+    return AVERROR(EIO);
+}
+
+#define OFFSET(x) offsetof(ZIPContext, x)
+#define D AV_OPT_FLAG_DECODING_PARAM
+#define E AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+    {"file_index", "set file index", OFFSET(file_index), AV_OPT_TYPE_INT, {.i64 = 0}, -1, INT_MAX, D|E },
+    {"password",   "set password", OFFSET(password), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E },
+    {NULL}
+};
+
+static const AVClass zip_context_class = {
+    .class_name     = "zip",
+    .item_name      = av_default_item_name,
+    .option         = options,
+    .version        = LIBAVUTIL_VERSION_INT,
+};
+
+URLProtocol ff_zip_protocol = {
+    .name                = "zip",
+    .url_open            = ffzip_open,
+    .url_read            = ffzip_read,
+    .url_seek            = ffzip_seek,
+    .url_close           = ffzip_close,
+    .priv_data_size      = sizeof(ZIPContext),
+    .priv_data_class     = &zip_context_class,
+};
-- 
1.9.1



More information about the ffmpeg-devel mailing list