[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