diff mbox series

[FFmpeg-devel,share,a,stupid,and,fun] avformat: add a fileptr protocol

Message ID tencent_2713349C41CB99A62ED083E6CAA7E02AA606@qq.com
State New
Headers show
Series [FFmpeg-devel,share,a,stupid,and,fun] avformat: add a fileptr protocol
Related show

Checks

Context Check Description
andriy/make_x86 fail Make failed
andriy/make_ppc success Make finished
andriy/make_fate_ppc success Make fate finished
andriy/makeppc warning New warnings during build

Commit Message

zhilizhao(赵志立) Oct. 14, 2021, 11:06 a.m. UTC
Just share a patch, not meant for merge.

Basically, the patch adds a new protocol which looks like fd:// or pipe:,
but deals with FILE *.

You may ask why? It’s useless if the FILE *ptr is a regular one, unless
combined with

     FILE *
     open_memstream(char **bufp, size_t *sizep);

     FILE *
     fmemopen(void *restrict *buf, size_t size, const char * restrict mode);

Then you can read or write to memory directly. For example:
diff mbox series

Patch

diff --git a/fftools/ffplay.c b/fftools/ffplay.c
index ccea0e4578..e59d524602 100644
--- a/fftools/ffplay.c
+++ b/fftools/ffplay.c
@@ -3554,7 +3554,16 @@  static void opt_input_file(void *optctx, const char *filename)
     }
     if (!strcmp(filename, "-"))
         filename = "pipe:";
-    input_filename = filename;
+
+    // This part is stupid
+    FILE *file = fopen(filename, "rb");
+    uint8_t *buf = malloc(128 << 20);
+    size_t size = fread(buf, 1, 128 << 20, file);
+    fclose(file);
+
+    // This part is interesting
+    file = fmemopen(buf, size, "rb");
+    asprintf(&input_filename, "fileptr:%p", file);
 }

 static int opt_codec(void *optctx, const char *opt, const char *arg)

For writing to memory, we have avio_open_dyn_buf(). For reading from meory, we have
data_uri. avio callback can handle all kinds of cases. Still, I think the
polymorphism of FILE * is interesting.

—
 libavformat/Makefile    |  1 +
 libavformat/file.c      | 84 +++++++++++++++++++++++++++++++++++++++++
 libavformat/protocols.c |  1 +
 3 files changed, 86 insertions(+)

diff --git a/libavformat/Makefile b/libavformat/Makefile
index 8a1b40aafe..047ad55462 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -637,6 +637,7 @@  OBJS-$(CONFIG_MD5_PROTOCOL)              += md5proto.o
 OBJS-$(CONFIG_MMSH_PROTOCOL)             += mmsh.o mms.o asf.o
 OBJS-$(CONFIG_MMST_PROTOCOL)             += mmst.o mms.o asf.o
 OBJS-$(CONFIG_PIPE_PROTOCOL)             += file.o
+OBJS-$(CONFIG_FILEPTR_PROTOCOL)          += file.o
 OBJS-$(CONFIG_PROMPEG_PROTOCOL)          += prompeg.o
 OBJS-$(CONFIG_RTMP_PROTOCOL)             += rtmpproto.o rtmpdigest.o rtmppkt.o
 OBJS-$(CONFIG_RTMPE_PROTOCOL)            += rtmpproto.o rtmpdigest.o rtmppkt.o
diff --git a/libavformat/file.c b/libavformat/file.c
index 9c23f680cd..bdf56a8473 100644
--- a/libavformat/file.c
+++ b/libavformat/file.c
@@ -412,3 +412,87 @@  const URLProtocol ff_pipe_protocol = {
 };
 
 #endif /* CONFIG_PIPE_PROTOCOL */
+
+#if CONFIG_FILEPTR_PROTOCOL
+
+typedef struct FilePtrContext {
+    const AVClass *class;
+    FILE *file;
+} FilePtrContext;
+
+static int fileptr_open(URLContext *h, const char *filename, int flags)
+{
+    FilePtrContext *c = h->priv_data;
+    FILE *file;
+    av_strstart(filename, "fileptr:", &filename);
+
+    file = (FILE *)strtoll(filename, NULL, 0);
+    if(!file) {
+        av_log(h, AV_LOG_INFO, "no FILE *, open stdin/stdout instead\n");
+        if (flags & AVIO_FLAG_WRITE) {
+            file = stdout;
+        } else {
+            file = stdin;
+        }
+    }
+
+    c->file = file;
+    return 0;
+}
+
+static int fileptr_read(URLContext *h, unsigned char *buf, int size)
+{
+    FilePtrContext *c = h->priv_data;
+    int ret;
+
+    ret = fread(buf, 1, size, c->file);
+    if (!ret) {
+        if (feof(c->file))
+            return AVERROR_EOF;
+        else
+            return AVERROR(EIO);
+    }
+
+    return ret;
+}
+
+static int fileptr_write(URLContext *h, const unsigned char *buf, int size)
+{
+    FilePtrContext *c = h->priv_data;
+    int ret;
+
+    ret = fwrite(buf, 1, size, c->file);
+    if (ret != size)
+        return AVERROR(EIO);
+
+    return ret;
+}
+
+static int64_t fileptr_seek(URLContext *h, int64_t pos, int whence)
+{
+    FilePtrContext *c = h->priv_data;
+    int ret;
+    ret = fseeko(c->file, pos, whence);
+    if (ret == -1) {
+        return AVERROR(errno);
+    }
+    return ftello(c->file);
+}
+
+static const AVClass fileptr_class = {
+    .class_name = "fileptr",
+    .item_name = av_default_item_name,
+    .version = LIBAVUTIL_VERSION_INT,
+};
+
+const URLProtocol ff_fileptr_protocol = {
+    .name                = "fileptr",
+    .url_open            = fileptr_open,
+    .url_read            = fileptr_read,
+    .url_write           = fileptr_write,
+    .url_seek            = fileptr_seek,
+    .priv_data_size      = sizeof(FilePtrContext),
+    .priv_data_class     = &fileptr_class,
+};
+
+#endif
\ No newline at end of file
diff --git a/libavformat/protocols.c b/libavformat/protocols.c
index b108aa6c7e..26c065e665 100644
--- a/libavformat/protocols.c
+++ b/libavformat/protocols.c
@@ -73,6 +73,7 @@  extern const URLProtocol ff_libsrt_protocol;
 extern const URLProtocol ff_libssh_protocol;
 extern const URLProtocol ff_libsmbclient_protocol;
 extern const URLProtocol ff_libzmq_protocol;
+extern const URLProtocol ff_fileptr_protocol;
 
 #include "libavformat/protocol_list.c"