mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-01-24 13:56:33 +02:00
avformat/hashenc: add streamhash muxer
Implemented as a variant of the hash muxer, reusing most functions, and making use of the previously introduced array of hashes. Signed-off-by: Moritz Barsnick <barsnick@gmx.net> Reviewed-by: James Almer <jamrial@gmail.com> Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
This commit is contained in:
parent
666b427881
commit
2f87c9f646
@ -10,6 +10,7 @@ version <next>:
|
|||||||
- IMM5 video decoder
|
- IMM5 video decoder
|
||||||
- ZeroMQ protocol
|
- ZeroMQ protocol
|
||||||
- support Sipro ACELP.KELVIN decoding
|
- support Sipro ACELP.KELVIN decoding
|
||||||
|
- streamhash muxer
|
||||||
|
|
||||||
|
|
||||||
version 4.2:
|
version 4.2:
|
||||||
|
@ -2064,6 +2064,53 @@ Specify whether to remove all fragments when finished. Default 0 (do not remove)
|
|||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
|
@anchor{streamhash}
|
||||||
|
@section streamhash
|
||||||
|
|
||||||
|
Per stream hash testing format.
|
||||||
|
|
||||||
|
This muxer computes and prints a cryptographic hash of all the input frames,
|
||||||
|
on a per-stream basis. This can be used for equality checks without having
|
||||||
|
to do a complete binary comparison.
|
||||||
|
|
||||||
|
By default audio frames are converted to signed 16-bit raw audio and
|
||||||
|
video frames to raw video before computing the hash, but the output
|
||||||
|
of explicit conversions to other codecs can also be used. Timestamps
|
||||||
|
are ignored. It uses the SHA-256 cryptographic hash function by default,
|
||||||
|
but supports several other algorithms.
|
||||||
|
|
||||||
|
The output of the muxer consists of one line per stream of the form:
|
||||||
|
@var{streamindex},@var{streamtype},@var{algo}=@var{hash}, where
|
||||||
|
@var{streamindex} is the index of the mapped stream, @var{streamtype} is a
|
||||||
|
single characer indicating the type of stream, @var{algo} is a short string
|
||||||
|
representing the hash function used, and @var{hash} is a hexadecimal number
|
||||||
|
representing the computed hash.
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item hash @var{algorithm}
|
||||||
|
Use the cryptographic hash function specified by the string @var{algorithm}.
|
||||||
|
Supported values include @code{MD5}, @code{murmur3}, @code{RIPEMD128},
|
||||||
|
@code{RIPEMD160}, @code{RIPEMD256}, @code{RIPEMD320}, @code{SHA160},
|
||||||
|
@code{SHA224}, @code{SHA256} (default), @code{SHA512/224}, @code{SHA512/256},
|
||||||
|
@code{SHA384}, @code{SHA512}, @code{CRC32} and @code{adler32}.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@subsection Examples
|
||||||
|
|
||||||
|
To compute the SHA-256 hash of the input converted to raw audio and
|
||||||
|
video, and store it in the file @file{out.sha256}:
|
||||||
|
@example
|
||||||
|
ffmpeg -i INPUT -f streamhash out.sha256
|
||||||
|
@end example
|
||||||
|
|
||||||
|
To print an MD5 hash to stdout use the command:
|
||||||
|
@example
|
||||||
|
ffmpeg -i INPUT -f streamhash -hash md5 -
|
||||||
|
@end example
|
||||||
|
|
||||||
|
See also the @ref{hash} and @ref{framehash} muxers.
|
||||||
|
|
||||||
@anchor{fifo}
|
@anchor{fifo}
|
||||||
@section fifo
|
@section fifo
|
||||||
|
|
||||||
|
@ -494,6 +494,7 @@ OBJS-$(CONFIG_SRT_DEMUXER) += srtdec.o subtitles.o
|
|||||||
OBJS-$(CONFIG_SRT_MUXER) += srtenc.o
|
OBJS-$(CONFIG_SRT_MUXER) += srtenc.o
|
||||||
OBJS-$(CONFIG_STL_DEMUXER) += stldec.o subtitles.o
|
OBJS-$(CONFIG_STL_DEMUXER) += stldec.o subtitles.o
|
||||||
OBJS-$(CONFIG_STR_DEMUXER) += psxstr.o
|
OBJS-$(CONFIG_STR_DEMUXER) += psxstr.o
|
||||||
|
OBJS-$(CONFIG_STREAMHASH_MUXER) += hashenc.o
|
||||||
OBJS-$(CONFIG_STREAM_SEGMENT_MUXER) += segment.o
|
OBJS-$(CONFIG_STREAM_SEGMENT_MUXER) += segment.o
|
||||||
OBJS-$(CONFIG_SUBVIEWER1_DEMUXER) += subviewer1dec.o subtitles.o
|
OBJS-$(CONFIG_SUBVIEWER1_DEMUXER) += subviewer1dec.o subtitles.o
|
||||||
OBJS-$(CONFIG_SUBVIEWER_DEMUXER) += subviewerdec.o subtitles.o
|
OBJS-$(CONFIG_SUBVIEWER_DEMUXER) += subviewerdec.o subtitles.o
|
||||||
|
@ -393,6 +393,7 @@ extern AVInputFormat ff_srt_demuxer;
|
|||||||
extern AVOutputFormat ff_srt_muxer;
|
extern AVOutputFormat ff_srt_muxer;
|
||||||
extern AVInputFormat ff_str_demuxer;
|
extern AVInputFormat ff_str_demuxer;
|
||||||
extern AVInputFormat ff_stl_demuxer;
|
extern AVInputFormat ff_stl_demuxer;
|
||||||
|
extern AVOutputFormat ff_streamhash_muxer;
|
||||||
extern AVInputFormat ff_subviewer1_demuxer;
|
extern AVInputFormat ff_subviewer1_demuxer;
|
||||||
extern AVInputFormat ff_subviewer_demuxer;
|
extern AVInputFormat ff_subviewer_demuxer;
|
||||||
extern AVInputFormat ff_sup_demuxer;
|
extern AVInputFormat ff_sup_demuxer;
|
||||||
|
@ -31,6 +31,7 @@ struct HashContext {
|
|||||||
const AVClass *avclass;
|
const AVClass *avclass;
|
||||||
struct AVHashContext **hashes;
|
struct AVHashContext **hashes;
|
||||||
char *hash_name;
|
char *hash_name;
|
||||||
|
int per_stream;
|
||||||
int format_version;
|
int format_version;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -56,6 +57,13 @@ static const AVOption framehash_options[] = {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_STREAMHASH_MUXER
|
||||||
|
static const AVOption streamhash_options[] = {
|
||||||
|
HASH_OPT("sha256"),
|
||||||
|
{ NULL },
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
#if CONFIG_MD5_MUXER
|
#if CONFIG_MD5_MUXER
|
||||||
static const AVOption md5_options[] = {
|
static const AVOption md5_options[] = {
|
||||||
HASH_OPT("md5"),
|
HASH_OPT("md5"),
|
||||||
@ -76,6 +84,7 @@ static int hash_init(struct AVFormatContext *s)
|
|||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
struct HashContext *c = s->priv_data;
|
struct HashContext *c = s->priv_data;
|
||||||
|
c->per_stream = 0;
|
||||||
c->hashes = av_mallocz_array(1, sizeof(c->hashes));
|
c->hashes = av_mallocz_array(1, sizeof(c->hashes));
|
||||||
if (!c->hashes)
|
if (!c->hashes)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
@ -85,24 +94,66 @@ static int hash_init(struct AVFormatContext *s)
|
|||||||
av_hash_init(c->hashes[0]);
|
av_hash_init(c->hashes[0]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_STREAMHASH_MUXER
|
||||||
|
static int streamhash_init(struct AVFormatContext *s)
|
||||||
|
{
|
||||||
|
int res, i;
|
||||||
|
struct HashContext *c = s->priv_data;
|
||||||
|
c->per_stream = 1;
|
||||||
|
c->hashes = av_mallocz_array(s->nb_streams, sizeof(c->hashes));
|
||||||
|
if (!c->hashes)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
for (i = 0; i < s->nb_streams; i++) {
|
||||||
|
res = av_hash_alloc(&c->hashes[i], c->hash_name);
|
||||||
|
if (res < 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
av_hash_init(c->hashes[i]);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_HASH_MUXER || CONFIG_MD5_MUXER || CONFIG_STREAMHASH_MUXER
|
||||||
|
static char get_media_type_char(enum AVMediaType type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case AVMEDIA_TYPE_VIDEO: return 'v';
|
||||||
|
case AVMEDIA_TYPE_AUDIO: return 'a';
|
||||||
|
case AVMEDIA_TYPE_DATA: return 'd';
|
||||||
|
case AVMEDIA_TYPE_SUBTITLE: return 's';
|
||||||
|
case AVMEDIA_TYPE_ATTACHMENT: return 't';
|
||||||
|
default: return '?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int hash_write_packet(struct AVFormatContext *s, AVPacket *pkt)
|
static int hash_write_packet(struct AVFormatContext *s, AVPacket *pkt)
|
||||||
{
|
{
|
||||||
struct HashContext *c = s->priv_data;
|
struct HashContext *c = s->priv_data;
|
||||||
av_hash_update(c->hashes[0], pkt->data, pkt->size);
|
av_hash_update(c->hashes[c->per_stream ? pkt->stream_index : 0], pkt->data, pkt->size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hash_write_trailer(struct AVFormatContext *s)
|
static int hash_write_trailer(struct AVFormatContext *s)
|
||||||
{
|
{
|
||||||
struct HashContext *c = s->priv_data;
|
struct HashContext *c = s->priv_data;
|
||||||
char buf[AV_HASH_MAX_SIZE*2+128];
|
int num_hashes = c->per_stream ? s->nb_streams : 1;
|
||||||
snprintf(buf, sizeof(buf) - 200, "%s=", av_hash_get_name(c->hashes[0]));
|
for (int i = 0; i < num_hashes; i++) {
|
||||||
|
char buf[AV_HASH_MAX_SIZE*2+128];
|
||||||
av_hash_final_hex(c->hashes[0], buf + strlen(buf), sizeof(buf) - strlen(buf));
|
if (c->per_stream) {
|
||||||
av_strlcatf(buf, sizeof(buf), "\n");
|
AVStream *st = s->streams[i];
|
||||||
avio_write(s->pb, buf, strlen(buf));
|
snprintf(buf, sizeof(buf) - 200, "%d,%c,%s=", i, get_media_type_char(st->codecpar->codec_type),
|
||||||
avio_flush(s->pb);
|
av_hash_get_name(c->hashes[i]));
|
||||||
|
} else {
|
||||||
|
snprintf(buf, sizeof(buf) - 200, "%s=", av_hash_get_name(c->hashes[i]));
|
||||||
|
}
|
||||||
|
av_hash_final_hex(c->hashes[i], buf + strlen(buf), sizeof(buf) - strlen(buf));
|
||||||
|
av_strlcatf(buf, sizeof(buf), "\n");
|
||||||
|
avio_write(s->pb, buf, strlen(buf));
|
||||||
|
avio_flush(s->pb);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -110,8 +161,12 @@ static int hash_write_trailer(struct AVFormatContext *s)
|
|||||||
static void hash_free(struct AVFormatContext *s)
|
static void hash_free(struct AVFormatContext *s)
|
||||||
{
|
{
|
||||||
struct HashContext *c = s->priv_data;
|
struct HashContext *c = s->priv_data;
|
||||||
if (c->hashes)
|
if (c->hashes) {
|
||||||
av_hash_freep(&c->hashes[0]);
|
int num_hashes = c->per_stream ? s->nb_streams : 1;
|
||||||
|
for (int i = 0; i < num_hashes; i++) {
|
||||||
|
av_hash_freep(&c->hashes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
av_freep(&c->hashes);
|
av_freep(&c->hashes);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -164,6 +219,30 @@ AVOutputFormat ff_md5_muxer = {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_STREAMHASH_MUXER
|
||||||
|
static const AVClass streamhashenc_class = {
|
||||||
|
.class_name = "stream hash muxer",
|
||||||
|
.item_name = av_default_item_name,
|
||||||
|
.option = streamhash_options,
|
||||||
|
.version = LIBAVUTIL_VERSION_INT,
|
||||||
|
};
|
||||||
|
|
||||||
|
AVOutputFormat ff_streamhash_muxer = {
|
||||||
|
.name = "streamhash",
|
||||||
|
.long_name = NULL_IF_CONFIG_SMALL("Per-stream hash testing"),
|
||||||
|
.priv_data_size = sizeof(struct HashContext),
|
||||||
|
.audio_codec = AV_CODEC_ID_PCM_S16LE,
|
||||||
|
.video_codec = AV_CODEC_ID_RAWVIDEO,
|
||||||
|
.init = streamhash_init,
|
||||||
|
.write_packet = hash_write_packet,
|
||||||
|
.write_trailer = hash_write_trailer,
|
||||||
|
.deinit = hash_free,
|
||||||
|
.flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT |
|
||||||
|
AVFMT_TS_NEGATIVE,
|
||||||
|
.priv_class = &streamhashenc_class,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
#if CONFIG_FRAMEHASH_MUXER || CONFIG_FRAMEMD5_MUXER
|
#if CONFIG_FRAMEHASH_MUXER || CONFIG_FRAMEMD5_MUXER
|
||||||
static void framehash_print_extradata(struct AVFormatContext *s)
|
static void framehash_print_extradata(struct AVFormatContext *s)
|
||||||
{
|
{
|
||||||
@ -190,6 +269,7 @@ static int framehash_init(struct AVFormatContext *s)
|
|||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
struct HashContext *c = s->priv_data;
|
struct HashContext *c = s->priv_data;
|
||||||
|
c->per_stream = 0;
|
||||||
c->hashes = av_mallocz_array(1, sizeof(c->hashes));
|
c->hashes = av_mallocz_array(1, sizeof(c->hashes));
|
||||||
if (!c->hashes)
|
if (!c->hashes)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
|
@ -32,8 +32,8 @@
|
|||||||
// Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium)
|
// Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium)
|
||||||
// Also please add any ticket numbers that you believe might be affected here
|
// Also please add any ticket numbers that you believe might be affected here
|
||||||
#define LIBAVFORMAT_VERSION_MAJOR 58
|
#define LIBAVFORMAT_VERSION_MAJOR 58
|
||||||
#define LIBAVFORMAT_VERSION_MINOR 32
|
#define LIBAVFORMAT_VERSION_MINOR 33
|
||||||
#define LIBAVFORMAT_VERSION_MICRO 104
|
#define LIBAVFORMAT_VERSION_MICRO 100
|
||||||
|
|
||||||
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
|
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
|
||||||
LIBAVFORMAT_VERSION_MINOR, \
|
LIBAVFORMAT_VERSION_MINOR, \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user