[FFmpeg-devel] [PATCH] Add a generic hash API.

Reimar Döffinger Reimar.Doeffinger at gmx.de
Fri May 10 20:23:32 CEST 2013


Also use this API in framemd5.

Signed-off-by: Reimar Döffinger <Reimar.Doeffinger at gmx.de>
---
 libavformat/md5enc.c |   61 ++++++++++++++------
 libavutil/Makefile   |    1 +
 libavutil/hash.c     |  154 ++++++++++++++++++++++++++++++++++++++++++++++++++
 libavutil/hash.h     |   78 +++++++++++++++++++++++++
 4 files changed, 276 insertions(+), 18 deletions(-)
 create mode 100644 libavutil/hash.c
 create mode 100644 libavutil/hash.h

diff --git a/libavformat/md5enc.c b/libavformat/md5enc.c
index d5c1fdd..b88e6df 100644
--- a/libavformat/md5enc.c
+++ b/libavformat/md5enc.c
@@ -19,21 +19,28 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#include "libavutil/md5.h"
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/hash.h"
+#include "libavutil/opt.h"
 #include "avformat.h"
 #include "internal.h"
 
 struct MD5Context {
-    struct AVMD5 *md5;
+    const AVClass *avclass;
+    struct AVHashContext *hash;
+    char *hash_name;
 };
 
 static void md5_finish(struct AVFormatContext *s, char *buf)
 {
     struct MD5Context *c = s->priv_data;
-    uint8_t md5[16];
+    uint8_t md5[32];
     int i, offset = strlen(buf);
-    av_md5_final(c->md5, md5);
-    for (i = 0; i < sizeof(md5); i++) {
+    int len = av_hash_get_size(c->hash);
+    av_assert0(len > 0 && len <= sizeof(md5));
+    av_hash_final(c->hash, md5);
+    for (i = 0; i < len; i++) {
         snprintf(buf + offset, 3, "%02"PRIx8, md5[i]);
         offset += 2;
     }
@@ -44,32 +51,48 @@ static void md5_finish(struct AVFormatContext *s, char *buf)
     avio_flush(s->pb);
 }
 
+#define OFFSET(x) offsetof(struct MD5Context, x)
+#define ENC AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption hash_options[] = {
+    { "hash", "set hash to use", OFFSET(hash_name), AV_OPT_TYPE_STRING, {.str = "md5"}, 0, 0, ENC },
+    { NULL },
+};
+
+static const AVClass hashenc_class = {
+    .class_name = "hash encoder class",
+    .item_name  = av_default_item_name,
+    .option     = hash_options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
 #if CONFIG_MD5_MUXER
 static int write_header(struct AVFormatContext *s)
 {
     struct MD5Context *c = s->priv_data;
-    c->md5 = av_md5_alloc();
-    if (!c->md5)
-        return AVERROR(ENOMEM);
-    av_md5_init(c->md5);
+    int res = av_hash_alloc(&c->hash, c->hash_name);
+    if (res < 0)
+        return res;
+    av_hash_init(c->hash);
     return 0;
 }
 
 static int write_packet(struct AVFormatContext *s, AVPacket *pkt)
 {
     struct MD5Context *c = s->priv_data;
-    av_md5_update(c->md5, pkt->data, pkt->size);
+    av_hash_update(c->hash, pkt->data, pkt->size);
     return 0;
 }
 
 static int write_trailer(struct AVFormatContext *s)
 {
     struct MD5Context *c = s->priv_data;
-    char buf[64] = "MD5=";
+    char buf[128];
+    av_strlcpy(buf, av_hash_get_name(c->hash), sizeof(buf) - 100);
+    av_strlcat(buf, "=", sizeof(buf) - 100);
 
     md5_finish(s, buf);
 
-    av_freep(&c->md5);
+    av_hash_freep(&c->hash);
     return 0;
 }
 
@@ -83,6 +106,7 @@ AVOutputFormat ff_md5_muxer = {
     .write_packet      = write_packet,
     .write_trailer     = write_trailer,
     .flags             = AVFMT_NOTIMESTAMPS,
+    .priv_class        = &hashenc_class,
 };
 #endif
 
@@ -90,9 +114,9 @@ AVOutputFormat ff_md5_muxer = {
 static int framemd5_write_header(struct AVFormatContext *s)
 {
     struct MD5Context *c = s->priv_data;
-    c->md5 = av_md5_alloc();
-    if (!c->md5)
-        return AVERROR(ENOMEM);
+    int res = av_hash_alloc(&c->hash, c->hash_name);
+    if (res < 0)
+        return res;
     return ff_framehash_write_header(s);
 }
 
@@ -100,8 +124,8 @@ static int framemd5_write_packet(struct AVFormatContext *s, AVPacket *pkt)
 {
     struct MD5Context *c = s->priv_data;
     char buf[256];
-    av_md5_init(c->md5);
-    av_md5_update(c->md5, pkt->data, pkt->size);
+    av_hash_init(c->hash);
+    av_hash_update(c->hash, pkt->data, pkt->size);
 
     snprintf(buf, sizeof(buf) - 64, "%d, %10"PRId64", %10"PRId64", %8d, %8d, ",
              pkt->stream_index, pkt->dts, pkt->pts, pkt->duration, pkt->size);
@@ -112,7 +136,7 @@ static int framemd5_write_packet(struct AVFormatContext *s, AVPacket *pkt)
 static int framemd5_write_trailer(struct AVFormatContext *s)
 {
     struct MD5Context *c = s->priv_data;
-    av_freep(&c->md5);
+    av_hash_freep(&c->hash);
     return 0;
 }
 
@@ -127,5 +151,6 @@ AVOutputFormat ff_framemd5_muxer = {
     .write_trailer     = framemd5_write_trailer,
     .flags             = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT |
                          AVFMT_TS_NEGATIVE,
+    .priv_class        = &hashenc_class,
 };
 #endif
diff --git a/libavutil/Makefile b/libavutil/Makefile
index b7664f7..f40f6fb 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -81,6 +81,7 @@ OBJS = adler32.o                                                        \
        file.o                                                           \
        float_dsp.o                                                      \
        frame.o                                                          \
+       hash.o                                                           \
        hmac.o                                                           \
        imgutils.o                                                       \
        intfloat_readwrite.o                                             \
diff --git a/libavutil/hash.c b/libavutil/hash.c
new file mode 100644
index 0000000..481010d
--- /dev/null
+++ b/libavutil/hash.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2013 Reimar Döffinger <Reimar.Doeffinger at gmx.de>
+ *
+ * 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 <stdint.h>
+#include "hash.h"
+
+#include "adler32.h"
+#include "crc.h"
+#include "md5.h"
+#include "murmur3.h"
+#include "sha.h"
+
+#include "avstring.h"
+#include "error.h"
+#include "intreadwrite.h"
+#include "mem.h"
+
+enum hashtype {
+    MD5,
+    MURMUR3,
+    SHA160,
+    SHA224,
+    SHA256,
+    CRC32,
+    ADLER32,
+    NUM_HASHES
+};
+
+typedef struct AVHashContext {
+    void *ctx;
+    enum hashtype type;
+    const AVCRC *crctab;
+    uint32_t crc;
+} AVHashContext;
+
+struct {
+    const char *name;
+    int size;
+} hashdesc[] = {
+    [MD5]     = {"MD5",     16},
+    [MURMUR3] = {"murmur3", 16},
+    [SHA160]  = {"SHA160",  20},
+    [SHA224]  = {"SHA240",  28},
+    [SHA256]  = {"SHA256",  32},
+    [CRC32]   = {"CRC32",    4},
+    [ADLER32] = {"adler32",  4},
+};
+
+const char *av_hash_names(int i)
+{
+    if (i < 0 || i >= NUM_HASHES) return NULL;
+    return hashdesc[i].name;
+}
+
+const char *av_hash_get_name(const AVHashContext *ctx)
+{
+    return hashdesc[ctx->type].name;
+}
+
+int av_hash_get_size(const AVHashContext *ctx)
+{
+    return hashdesc[ctx->type].size;
+}
+
+int av_hash_alloc(AVHashContext **ctx, const char *name)
+{
+    AVHashContext *res;
+    int i;
+    *ctx = NULL;
+    for (i = 0; i < NUM_HASHES; i++)
+        if (av_strcasecmp(name, hashdesc[i].name) == 0)
+            break;
+    if (i >= NUM_HASHES) return AVERROR(EINVAL);
+    res = av_mallocz(sizeof(*res));
+    if (!res) return AVERROR(ENOMEM);
+    res->type = i;
+    switch (i) {
+    case MD5:     res->ctx = av_md5_alloc(); break;
+    case MURMUR3: res->ctx = av_murmur3_alloc(); break;
+    case SHA160:
+    case SHA224:
+    case SHA256:  res->ctx = av_sha_alloc(); break;
+    case CRC32:   res->crctab = av_crc_get_table(AV_CRC_32_IEEE); break;
+    case ADLER32: break;
+    }
+    if (i != ADLER32 && i != CRC32 && !res->ctx) {
+        av_free(res);
+        return AVERROR(ENOMEM);
+    }
+    *ctx = res;
+    return 0;
+}
+
+void av_hash_init(AVHashContext *ctx)
+{
+    switch (ctx->type) {
+    case MD5:     av_md5_init(ctx->ctx); break;
+    case MURMUR3: av_murmur3_init(ctx->ctx); break;
+    case SHA160:  av_sha_init(ctx->ctx, 160); break;
+    case SHA224:  av_sha_init(ctx->ctx, 224); break;
+    case SHA256:  av_sha_init(ctx->ctx, 256); break;
+    case CRC32:
+    case ADLER32: ctx->crc = 0; break;
+    }
+}
+
+void av_hash_update(AVHashContext *ctx, const uint8_t *src, int len)
+{
+    switch (ctx->type) {
+    case MD5:     av_md5_update(ctx->ctx, src, len); break;
+    case MURMUR3: av_murmur3_update(ctx->ctx, src, len); break;
+    case SHA160:
+    case SHA224:
+    case SHA256:  av_sha_update(ctx->ctx, src, len); break;
+    case CRC32:   ctx->crc = av_crc(ctx->crctab, ctx->crc, src, len); break;
+    case ADLER32: ctx->crc = av_adler32_update(ctx->crc, src, len); break;
+    }
+}
+
+void av_hash_final(AVHashContext *ctx, uint8_t *dst)
+{
+    switch (ctx->type) {
+    case MD5:     av_md5_final(ctx->ctx, dst); break;
+    case MURMUR3: av_murmur3_final(ctx->ctx, dst); break;
+    case SHA160:
+    case SHA224:
+    case SHA256:  av_sha_final(ctx->ctx, dst); break;
+    case CRC32:
+    case ADLER32: AV_WL32(dst, ctx->crc); break;
+    }
+}
+
+void av_hash_freep(AVHashContext **ctx)
+{
+    if (*ctx)
+        av_freep(&(*ctx)->ctx);
+    av_freep(ctx);
+}
diff --git a/libavutil/hash.h b/libavutil/hash.h
new file mode 100644
index 0000000..7ecb3e7
--- /dev/null
+++ b/libavutil/hash.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2013 Reimar Döffinger <Reimar.Doeffinger at gmx.de>
+ *
+ * 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
+ */
+
+#ifndef AVUTIL_HASH_H
+#define AVUTIL_HASH_H
+
+#include <stdint.h>
+
+struct AVHashContext;
+
+/**
+ * Allocate a hash context for the algorithm specified by name.
+ *
+ * @return  >= 0 for success, a negative error code for failure
+ * @note  The context is not initialized, you must call av_hash_init().
+ */
+int av_hash_alloc(struct AVHashContext **ctx, const char *name);
+
+/**
+ * Get the names of available hash algorithms.
+ *
+ * This function can be used to enumerate the algorithms.
+ *
+ * @param i  index of the hash algorithm, starting from 0
+ * @return   a pointer to a static string or NULL if i is out of range
+ */
+const char *av_hash_names(int i);
+
+/**
+ * Get the name of the algorithm corresponding to the given hash context.
+ */
+const char *av_hash_get_name(const struct AVHashContext *ctx);
+
+/**
+ * Get the size of the resulting hash value in bytes.
+ *
+ * The pointer passed to av_hash_final have space for at least this many bytes.
+ */
+int av_hash_get_size(const struct AVHashContext *ctx);
+
+/**
+ * Initialize or reset a hash context.
+ */
+void av_hash_init(struct AVHashContext *ctx);
+
+/**
+ * Update a hash context with additional data.
+ */
+void av_hash_update(struct AVHashContext *ctx, const uint8_t *src, int len);
+
+/**
+ * Finalize a hash context and compute the actual hash value.
+ */
+void av_hash_final(struct AVHashContext *ctx, uint8_t *dst);
+
+/**
+ * Free hash context.
+ */
+void av_hash_freep(struct AVHashContext **ctx);
+
+#endif /* AVUTIL_HASH_H */
-- 
1.7.10.4



More information about the ffmpeg-devel mailing list