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.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 <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 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel