Attached is a patch that implements a protocol identified as 'ghost:'.
This protocol behaves as a file, except that all writes occur to a
phantom file in memory. Upon closing the file, the protocol runs MD5
over the phantom file and prints it to stdout, much like the existing
MD5 protocol.
Why add this? Run the following:
make fate-v410enc V=2
This will show you the long command used to run the test. On my system,
it's:
/home/melanson/libav/build/avconv -nostats -threads 1 -thread_type
frame+slice -f image2 -vcodec pgmyuv -i
/home/melanson/libav/build/tests/vsynth1/%02d.pgm -flags +bitexact
-vcodec v410 -f avi md5:
which produces an MD5 of 979c9a9a09e8eaaf6467b8c22c0ac8bb (presently
checked in as tests/ref/fate/v410enc). However, if you output the
foregoing command to an actual file, the MD5 is different
(fdc56004a19afe46541aa09183eb78a2). The discrepancy comes about because
the AVI muxer needs to seek backward in the course of normal writing and
the MD5 protocol doesn't allow this.
To re-iterate: FATE is generating an incorrect file. As the QA bore on
the project, I just can't let this stand. This ghost protocol is one
possible solution. Another is simply writing the file to disk, which has
its own problems.
The ghost protocol is incomplete and experimental, but it works in the
foregoing example. If replacing 'md5:' with 'ghost:' in that command
line, you will get the correct MD5.
I wanted to get feedback before I put any more time into this.
Thanks,
--
-Mike Melanson
>From d48418214ea04c66ccd74f70e57f730a36f01bd1 Mon Sep 17 00:00:00 2001
From: Mike Melanson <[email protected]>
Date: Fri, 30 Dec 2011 20:26:01 -0800
Subject: [PATCH] Experimental ghost: protocol
---
libavformat/Makefile | 1 +
libavformat/allformats.c | 1 +
libavformat/ghostproto.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 161 insertions(+), 0 deletions(-)
create mode 100644 libavformat/ghostproto.c
diff --git a/libavformat/Makefile b/libavformat/Makefile
index de44050..11c6f38 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -337,6 +337,7 @@ OBJS-$(CONFIG_MMSH_PROTOCOL) += mmsh.o mms.o
asf.o
OBJS-$(CONFIG_MMST_PROTOCOL) += mmst.o mms.o asf.o
OBJS-$(CONFIG_MD5_PROTOCOL) += md5proto.o
OBJS-$(CONFIG_PIPE_PROTOCOL) += file.o
+OBJS-$(CONFIG_GHOST_PROTOCOL) += ghostproto.o
# external or internal rtmp
RTMP-OBJS-$(CONFIG_LIBRTMP) = librtmp.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 1debddb..a57a94e 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -244,6 +244,7 @@ void av_register_all(void)
REGISTER_PROTOCOL (CONCAT, concat);
REGISTER_PROTOCOL (CRYPTO, crypto);
REGISTER_PROTOCOL (FILE, file);
+ REGISTER_PROTOCOL (GHOST, ghost);
REGISTER_PROTOCOL (GOPHER, gopher);
REGISTER_PROTOCOL (HTTP, http);
REGISTER_PROTOCOL (HTTPPROXY, httpproxy);
diff --git a/libavformat/ghostproto.c b/libavformat/ghostproto.c
new file mode 100644
index 0000000..7d81e1a
--- /dev/null
+++ b/libavformat/ghostproto.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2011 Mike Melanson
+ *
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include "libavutil/avstring.h"
+#include "libavutil/md5.h"
+#include "libavutil/mem.h"
+#include "libavutil/error.h"
+#include "avformat.h"
+#include "avio.h"
+
+typedef struct
+{
+ uint8_t *bytes;
+ int alloc_size;
+ int file_size;
+ int index;
+ int flags;
+} ghost_file;
+
+#define GHOST_PAGE_SIZE (1024 * 1024)
+
+static int ghost_open(URLContext *h, const char *filename, int flags)
+{
+ ghost_file *ghost = (ghost_file *)h->priv_data;
+
+ ghost->flags = flags;
+ ghost->index = 0;
+ ghost->file_size = 0;
+ ghost->alloc_size = GHOST_PAGE_SIZE;
+ ghost->bytes = av_mallocz(ghost->alloc_size);
+
+ if (!ghost->bytes)
+ {
+ av_log(NULL, AV_LOG_ERROR, "No memory for ghost file\n");
+ return -1;
+ }
+
+ if (!(flags & AVIO_FLAG_WRITE))
+ return AVERROR(EINVAL);
+
+ return 0;
+}
+
+#if 0
+static int ghost_read(URLContext *h, unsigned char *buf, int size)
+{
+ ghost_file *ghost = (ghost_file *)h->priv_data;
+ int read_size;
+
+ if (ghost->index + size < ghost->alloc_size)
+ read_size = size;
+ else
+ read_size = ghost->alloc_size - size;
+
+ memcpy(buf, ghost->bytes + ghost->index, read_size);
+ ghost->index += read_size;
+ return read_size;
+}
+#endif
+
+
+static int ghost_write(URLContext *h, const unsigned char *buf, int size)
+{
+ ghost_file *ghost = (ghost_file *)h->priv_data;
+
+ if (ghost->index + size < ghost->alloc_size)
+ {
+ /* need more space for writing; round up to the nearest page */
+ ghost->alloc_size += size + (GHOST_PAGE_SIZE - 1);
+ ghost->alloc_size &= ~(GHOST_PAGE_SIZE - 1);
+ ghost->bytes = av_realloc(ghost->bytes, ghost->alloc_size);
+ if (!ghost->bytes)
+ {
+ av_log(NULL, AV_LOG_ERROR, "No memory for ghost file\n");
+ return -1;
+ }
+ }
+ memcpy(ghost->bytes + ghost->index, buf, size);
+ ghost->index += size;
+ if (ghost->index > ghost->file_size)
+ ghost->file_size = ghost->index;
+ return size;
+}
+
+
+static int64_t ghost_seek(URLContext *h, int64_t pos, int whence)
+{
+ ghost_file *ghost = (ghost_file *)h->priv_data;
+ int64_t ret = 0;
+
+ if (whence & AVSEEK_SIZE)
+ ret = ghost->file_size;
+ else if (whence == SEEK_SET)
+ {
+ if (pos >= ghost->file_size)
+ ret = ghost->file_size;
+ else if (pos < 0)
+ ret = ghost->index = 0;
+ else
+ ret = ghost->index = pos;
+ }
+else
+ av_log(NULL, AV_LOG_ERROR, "help! seek mode %d not implemented\n", whence);
+
+ ghost->index = ret;
+ return ret;
+}
+
+
+static int ghost_close(URLContext *h)
+{
+ ghost_file *ghost = (ghost_file *)h->priv_data;
+ uint8_t md5[16], buf[64];
+ int i, err = 0;
+ struct AVMD5 *md5_ctx;
+
+ md5_ctx = av_malloc(av_md5_size);
+ av_md5_init(md5_ctx);
+ av_md5_update(md5_ctx, ghost->bytes, ghost->file_size);
+ av_md5_final(md5_ctx, md5);
+
+ for (i = 0; i < sizeof(md5); i++)
+ snprintf(buf + i*2, 3, "%02x", md5[i]);
+ buf[i*2] = '\n';
+
+ if (fwrite(buf, 1, i*2+1, stdout) < i*2+1)
+ err = AVERROR(errno);
+
+ return err;
+}
+
+
+URLProtocol ff_ghost_protocol = {
+ .name = "ghost",
+ .url_open = ghost_open,
+// .url_read = ghost_read,
+ .url_write = ghost_write,
+ .url_seek = ghost_seek,
+ .url_close = ghost_close,
+ .priv_data_size = sizeof(ghost_file),
+};
--
1.7.4.1
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel