[FFmpeg-devel] [PATCH] lavu: add stringinterp interface

Stefano Sabatini stefasab at gmail.com
Sat Dec 7 10:43:17 CET 2013


From: Clément Bœsch <u at pkh.me>

With very minor changes by Stefano Sabatini.

Based on thread:
From: Clément Bœsch <ubitux at gmail.com>
Subject: [FFmpeg-devel] [PATCH] WIP/lavu: add string interpolation helper.
Date: 2012-02-01 11:01:02 GMT

Signed-off-by: Stefano Sabatini <stefasab at gmail.com>

TODO: bump major, add APIchanges entry, mark as experimental?
---
 libavutil/Makefile       |   2 +
 libavutil/stringinterp.c | 207 +++++++++++++++++++++++++++++++++++++++++++++++
 libavutil/stringinterp.h |  66 +++++++++++++++
 3 files changed, 275 insertions(+)
 create mode 100644 libavutil/stringinterp.c
 create mode 100644 libavutil/stringinterp.h

diff --git a/libavutil/Makefile b/libavutil/Makefile
index 5e0c4ae..c30caae 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -110,6 +110,7 @@ OBJS = adler32.o                                                        \
        samplefmt.o                                                      \
        sha.o                                                            \
        sha512.o                                                         \
+       stringinterp.o                                                   \
        time.o                                                           \
        timecode.o                                                       \
        tree.o                                                           \
@@ -158,6 +159,7 @@ TESTPROGS = adler32                                                     \
             random_seed                                                 \
             rational                                                    \
             ripemd                                                      \
+            stringinterp                                                \
             sha                                                         \
             sha512                                                      \
             tree                                                        \
diff --git a/libavutil/stringinterp.c b/libavutil/stringinterp.c
new file mode 100644
index 0000000..d1d4fc1
--- /dev/null
+++ b/libavutil/stringinterp.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2012 Clément Bœsch
+ *
+ * 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
+ */
+
+/**
+ * @file
+ * string interpolation
+ */
+
+#include "avutil.h"
+#include "avstring.h"
+#include "stringinterp.h"
+
+struct node {
+    const char *key;
+    const char *value;
+    struct node *next;
+};
+
+typedef struct AVStringInterp {
+    struct node *hashtable[512];
+    char *buf;
+    size_t buf_size;
+} AVStringInterp;
+
+AVStringInterp *av_stringinterp_alloc(void)
+{
+    AVStringInterp *ctx = av_mallocz(sizeof(*ctx));
+
+    if (!ctx)
+        return NULL;
+    ctx->buf = av_malloc(128);
+    if (!ctx->buf) {
+        av_free(ctx);
+        return NULL;
+    }
+    ctx->buf_size = 128;
+    return ctx;
+}
+
+void av_stringinterp_free(AVStringInterp **ctx)
+{
+    int i;
+    AVStringInterp *s = *ctx;
+    for (i = 0; i < FF_ARRAY_ELEMS(s->hashtable); i++) {
+        struct node *tmp, *node = s->hashtable[i];
+        while (node) {
+            tmp = node;
+            node = node->next;
+            av_freep(&tmp);
+        }
+    }
+    av_freep(&s->buf);
+    av_freep(ctx);
+}
+
+static uint32_t get_hash(const char *key, size_t len, int tbl_len)
+{
+    size_t i;
+    uint32_t hash = 0;
+    for (i = 0; i < len; i++)
+        hash = (hash<<5) ^ (hash>>27) ^ key[i];
+    return hash % tbl_len;
+}
+
+static struct node *create_node(const char *key, const char *value)
+{
+    struct node *node = av_mallocz(sizeof(*node));
+    if (!node)
+        return NULL;
+    node->key   = key;
+    node->value = value;
+    return node;
+}
+
+int av_stringinterp_map(AVStringInterp *ctx, const char *key, const char *value)
+{
+    uint32_t id = get_hash(key, strlen(key), FF_ARRAY_ELEMS(ctx->hashtable));
+    struct node *node = ctx->hashtable[id];
+    struct node *insert_after = NULL;
+
+    while (node) {
+        if (!strcmp(key, node->key)) {
+            node->value = value;
+            return 0;
+        }
+        insert_after = node;
+        node = node->next;
+    }
+    node = create_node(key, value);
+    if (!node)
+        return AVERROR(ENOMEM);
+    if (insert_after)
+        insert_after->next = node;
+    else
+        ctx->hashtable[id] = node;
+    return 0;
+}
+
+static const char *get_value(AVStringInterp *ctx, const char *key)
+{
+    int id;
+    size_t keylen;
+    const char *p = strchr(key, ')');
+    struct node *node;
+
+    if (!p)
+        return NULL;
+    keylen = p - key;
+    id = get_hash(key, keylen, FF_ARRAY_ELEMS(ctx->hashtable));
+    for (node = ctx->hashtable[id]; node; node = node->next)
+        if (!strncmp(key, node->key, keylen))
+            return node->value;
+    return NULL;
+}
+
+#define APPEND_STRING(str, slen) do {               \
+    size_t new_size = pos + slen + 1;               \
+    if (new_size > ctx->buf_size) {                 \
+        char *ptr = av_realloc(ctx->buf, new_size); \
+        if (!ptr)                                   \
+            return NULL;                            \
+        ctx->buf      = ptr;                        \
+        ctx->buf_size = new_size;                   \
+    }                                               \
+    av_strlcpy(ctx->buf + pos, str, slen + 1);      \
+    pos += slen;                                    \
+} while (0)
+
+char *av_stringinterp_interpolate(AVStringInterp *ctx, const char *s)
+{
+    const char *p;
+    size_t pos = 0;
+
+    while (*s) {
+        if (s[0] == '%' && s[1] == '(') {
+            const char *value = get_value(ctx, s + 2);
+            if (value) {
+                APPEND_STRING(value, strlen(value));
+                s = strchr(s, ')') + 1;
+                continue;
+            }
+        }
+        p = strchr(s + 1, '%');
+        if (!p) {
+            APPEND_STRING(s, strlen(s));
+            break;
+        }
+        APPEND_STRING(s, p - s);
+        s = p;
+    }
+    return ctx->buf;
+}
+
+#ifdef TEST
+
+static void dump_table(AVStringInterp *ctx)
+{
+    int i;
+    printf("Hashtable dump:\n");
+    for (i = 0; i < FF_ARRAY_ELEMS(ctx->hashtable); i++) {
+        struct node *node = ctx->hashtable[i];
+        if (!node)
+            continue;
+        printf("  [%02d/%02ld]:", i, FF_ARRAY_ELEMS(ctx->hashtable));
+        while (node) {
+            printf(" \"%s\"=>\"%s\"", node->key, node->value);
+            node = node->next;
+        }
+        printf("\n");
+    }
+}
+
+int main(int ac, char **av)
+{
+    AVStringInterp *si = av_stringinterp_alloc();
+
+    av_stringinterp_map(si, "ts1",      "0.4123");
+    av_stringinterp_map(si, "ts2",      "54.153");
+    av_stringinterp_map(si, "filename", "FooBar");
+    av_stringinterp_map(si, "ext",      ".mpg");
+    av_stringinterp_map(si, "ext",      ".mp4");
+
+    dump_table(si);
+
+    printf("%s\n",
+           av_stringinterp_interpolate(si, "%(filename)_%(ts1)-%(ts2)_%(nokey)%(ext)"));
+    av_stringinterp_free(&si);
+    return 0;
+}
+#endif
diff --git a/libavutil/stringinterp.h b/libavutil/stringinterp.h
new file mode 100644
index 0000000..a2331ad
--- /dev/null
+++ b/libavutil/stringinterp.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012 Clément Bœsch
+ *
+ * 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
+ */
+
+/**
+ * @file
+ * string interpolation header
+ */
+
+#ifndef AVUTIL_STRINGINTERP_H
+#define AVUTIL_STRINGINTERP_H
+
+typedef struct AVStringInterp AVStringInterp;
+
+/**
+ * Allocate a new string interpolation context.
+ */
+AVStringInterp *av_stringinterp_alloc(void);
+
+/**
+ * Free a AVStringInterp context previously created with
+ * av_stringinterp_alloc().
+ */
+void av_stringinterp_free(AVStringInterp **ctx);
+
+/**
+ * Map a key string with a value string.
+ *
+ * If the key already exists, the value is replaced.
+ * @return 0 in case of success, a negative AVERROR code otherwise
+ * @note key and value are not duplicated, you must keep a reference
+ * to them.
+ */
+int av_stringinterp_map(AVStringInterp *ctx, const char *key, const char *value);
+
+/**
+ * Do the string interpolation.
+ *
+ * The value to interpolate must have the form "%(key)", where key is
+ * the name to be changed with the value previously stored in the
+ * AVStringInterp structure. In case the key is not recognized, it is
+ * ignored.
+ *
+ * @return a pointer to the printable string, or NULL in case of failure
+ * @note The returned buffer is kept in the AVStringInterp context, you must
+ *       not free it.
+ */
+char *av_stringinterp_interpolate(AVStringInterp *ctx, const char *s);
+
+#endif/* AVUTIL_STRINGINTERP_H */
-- 
1.8.1.2



More information about the ffmpeg-devel mailing list