On 01.04.2015 21:22, Alexander Strasser wrote:
On 2015-03-28 23:30 +0100, Lukasz Marek wrote:
W dniu sobota, 28 marca 2015 Peter Ross <pr...@xvid.org> napisaƂ(a):

   What about the following?

   ffplay zip://dir/a.zip/m.mkv  # open dir/a.zip, read file m.mkv inside
   ffplay -file m.mkv zip://dir/a.zip  # same effect as above
   ffplay zip://dir.zip/a.ass/m.txt # open dir.zip, read file a.ass/m.txt inside
   ffplay -file m.txt zip://dir.zip/a.ass # open dir.zip/a.ass, read file m.txt 
inside

   Patch that implements that on top of Lukasz's patch is attached.
Beware it is quickly implemented and only lightly tested, just to
show that it is possible to implement that behaviour. Do not expect
it to be beautiful and flawless.

   Also I didn't even attempt to work out details like option name and if
we should match first or last .zip occurrence when guessing.

I've attached another implementation based on libarchive. It is also just demo patch, not something that is ready to be merged.

I skipped totally the problem with selecting internal file. I just open the first available.

Libarchive allows:
1. Using protocols, so archive can be on remote host, tested via ftp and sftp (didn't check extracting from inner archive) 2. It provides archive_seek_data which seems to allow make this protocol seekable, but it is not working for me. Official documentation doesn't mention this function. Doxy in header is not much more helpful.

Libarchive does not allows:
1. Decompress encrypted archives (there is a ticket for that)
2. I cannot decompress rar archives (still better than libzip)

It still needs some tests and possibly digging in libarchive code.
Some contact with them may resolve some doubts.

Regarding selecting inner file, IMHO additional parameter and guessing by extension is the best choice until protocols support stat operation in efficient way. Of course assuming it should use protocols.

I will not work on this withing next week at least so if someone wants to continue then go ahead, just let me know please, so we don't duplicate the work again.
>From 71e69b5d3beed3429a310c413e4139f640e837e2 Mon Sep 17 00:00:00 2001
From: Lukasz Marek <lukasz.m.lu...@gmail.com>
Date: Fri, 20 Mar 2015 18:31:00 +0100
Subject: [PATCH] lavf: add zip protocol

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

diff --git a/configure b/configure
index 392946a..9cb4cfc 100755
--- a/configure
+++ b/configure
@@ -276,6 +276,7 @@ External library support:
   --disable-sdl            disable sdl [autodetect]
   --enable-x11grab         enable X11 grabbing (legacy) [no]
   --disable-xlib           disable xlib [autodetect]
+  --enable-libarchive      enable libarchive [no]
   --disable-zlib           disable zlib [autodetect]
 
 Toolchain options:
@@ -1406,6 +1407,7 @@ EXTERNAL_LIBRARY_LIST="
     libxcb_shape
     libxcb_xfixes
     libxvid
+    libarchive
     libzmq
     libzvbi
     lzma
@@ -2599,6 +2601,7 @@ udp_protocol_select="network"
 udplite_protocol_select="network"
 unix_protocol_deps="sys_un_h"
 unix_protocol_select="network"
+libarchive_protocol_deps="libarchive"
 
 # filters
 amovie_filter_deps="avcodec avformat"
@@ -4981,6 +4984,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 libarchive        && require_pkg_config libarchive archive.h archive_read_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..c971ef1 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_LIBARCHIVE_PROTOCOL)       += libarchive.o
+
 
 OBJS-$(HAVE_LIBC_MSVCRT)                 += file_open.o
 
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 26ccc27..9a9eef4 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(LIBARCHIVE,       libarchive);
 
     /* external libraries */
     REGISTER_DEMUXER (LIBGME,           libgme);
diff --git a/libavformat/libarchive.c b/libavformat/libarchive.c
new file mode 100644
index 0000000..675c43c
--- /dev/null
+++ b/libavformat/libarchive.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2015 Lukasz Marek <lukasz.m.l...@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 <archive.h>
+#include <archive_entry.h>
+#include "libavutil/opt.h"
+#include "libavutil/avstring.h"
+#include "libavutil/avassert.h"
+#include "avformat.h"
+#include "internal.h"
+#include "url.h"
+
+typedef struct {
+    const AVClass *class;
+
+    struct archive *arch;
+    struct archive_entry *entry;
+
+    URLContext *pb;
+    char buff[4096];
+} LibArchiveContext;
+
+
+static int libarchive_close(URLContext *h)
+{
+    LibArchiveContext *archive = h->priv_data;
+
+    ffurl_closep(&archive->pb);
+    return 0;
+}
+
+static ssize_t libarchive_read_data(struct archive *a, void *opaque, const void **buff)
+{
+    URLContext *h = opaque;
+    LibArchiveContext *archive = h->priv_data;
+    ssize_t ret;
+
+    *buff = archive->buff;
+    if ((ret = ffurl_read(archive->pb, archive->buff, sizeof(archive->buff))) < 0) {
+        av_log(h, AV_LOG_ERROR, "read cb error\n");
+        return ARCHIVE_FATAL;
+    }
+    return ret;
+}
+
+static int64_t libarchive_seek_data(struct archive *a, void *opaque, int64_t offset, int whence)
+{
+    URLContext *h = opaque;
+    LibArchiveContext *archive = h->priv_data;
+    int64_t ret;
+
+    av_log(h, AV_LOG_DEBUG, "seek %d %"PRId64"\n", whence, offset);
+
+    if ((ret = ffurl_seek(archive->pb, offset, whence)) < 0) {
+        av_log(h, AV_LOG_ERROR, "seek cb error\n");
+        return ARCHIVE_FATAL;
+    }
+    return ret;
+}
+
+static int libarchive_close_data(struct archive *a, void *opaque)
+{
+    URLContext *h = opaque;
+    LibArchiveContext *archive = h->priv_data;
+
+    ffurl_closep(&archive->pb);
+    av_freep(&archive->buff);
+
+    return ARCHIVE_OK;
+}
+
+static int libarchive_open(URLContext *h, const char *url, int flags)
+{
+    LibArchiveContext *archive = h->priv_data;
+    const char *file;
+    int ret;
+
+    if (!av_strstart(url, "libarchive://", &file))
+        return AVERROR(EINVAL);
+
+    if ((ret = ffurl_open(&archive->pb, file, AVIO_FLAG_READ, NULL, NULL)) < 0)
+        return ret;
+
+
+    archive->arch = archive_read_new();
+    if (!archive->arch) {
+        ret = AVERROR(ENOMEM);
+        goto fail;
+    }
+
+    h->is_streamed = 1;
+    if (!archive->pb->is_streamed) {
+        if (archive_read_set_seek_callback(archive->arch, libarchive_seek_data) != ARCHIVE_OK) {
+            ret = AVERROR_EXTERNAL;
+            goto fail;
+        }
+    }
+
+    if ((archive_read_support_filter_all(archive->arch) != ARCHIVE_OK) ||
+        (archive_read_support_format_all(archive->arch) != ARCHIVE_OK) ||
+        (archive_read_open(archive->arch, h, NULL, libarchive_read_data, libarchive_close_data) != ARCHIVE_OK)) {
+        ret = AVERROR_EXTERNAL;
+        goto fail;
+    }
+
+    //TODO: search for correct file
+    archive_read_next_header(archive->arch, &archive->entry);
+
+    return 0;
+  fail:
+    libarchive_close(h);
+    return ret;
+}
+
+static int libarchive_read(URLContext *h, unsigned char *buf, int size)
+{
+    LibArchiveContext *archive = h->priv_data;
+
+    ssize_t bytes_read = archive_read_data(archive->arch, buf, size);
+    if (bytes_read < 0) {
+        av_log(h, AV_LOG_ERROR, "Read error.\n");
+        return AVERROR(EIO);
+    }
+    return bytes_read;
+}
+
+#if 0
+static int64_t libarchive_seek(URLContext *h, int64_t pos, int whence)
+{
+    LibArchiveContext *archive = h->priv_data;
+    int64_t ret;
+
+    av_assert0(archive->entry);
+    switch (whence) {
+    case SEEK_SET:
+    case SEEK_CUR:
+    case SEEK_END:
+        ret = archive_seek_data(archive->arch, pos, whence);
+        if (ret < 0)
+            ret = AVERROR_EXTERNAL;
+        break;
+    case AVSEEK_SIZE:
+        ret = archive_entry_size(archive->entry);
+        break;
+    default:
+        ret = AVERROR(EINVAL);
+        break;
+    }
+    return ret;
+}
+#endif
+
+#define OFFSET(x) offsetof(LibArchiveContext, x)
+#define D AV_OPT_FLAG_DECODING_PARAM
+#define E AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+    {NULL}
+};
+
+static const AVClass libarchive_context_class = {
+    .class_name     = "libarchive",
+    .item_name      = av_default_item_name,
+    .option         = options,
+    .version        = LIBAVUTIL_VERSION_INT,
+};
+
+URLProtocol ff_libarchive_protocol = {
+    .name                = "libarchive",
+    .url_open            = libarchive_open,
+    .url_read            = libarchive_read,
+    //.url_seek            = libarchive_seek,
+    .url_close           = libarchive_close,
+    .priv_data_size      = sizeof(LibArchiveContext),
+    .priv_data_class     = &libarchive_context_class,
+};
-- 
1.9.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to