2 * Hash/MD5 encoder (for codec/format testing)
3 * Copyright (c) 2009 Reimar Döffinger, based on crcenc (c) 2002 Fabrice Bellard
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "libavutil/avassert.h"
23 #include "libavutil/avstring.h"
24 #include "libavutil/hash.h"
25 #include "libavutil/intreadwrite.h"
26 #include "libavutil/opt.h"
31 const AVClass
*avclass
;
32 struct AVHashContext
**hashes
;
38 #define OFFSET(x) offsetof(struct HashContext, x)
39 #define ENC AV_OPT_FLAG_ENCODING_PARAM
40 #define HASH_OPT(defaulttype) \
41 { "hash", "set hash to use", OFFSET(hash_name), AV_OPT_TYPE_STRING, {.str = defaulttype}, 0, 0, ENC }
42 #define FORMAT_VERSION_OPT \
43 { "format_version", "file format version", OFFSET(format_version), AV_OPT_TYPE_INT, {.i64 = 2}, 1, 2, ENC }
46 static const AVOption hash_options
[] = {
52 #if CONFIG_FRAMEHASH_MUXER
53 static const AVOption framehash_options
[] = {
60 #if CONFIG_STREAMHASH_MUXER
61 static const AVOption streamhash_options
[] = {
68 static const AVOption md5_options
[] = {
74 #if CONFIG_FRAMEMD5_MUXER
75 static const AVOption framemd5_options
[] = {
82 #if CONFIG_HASH_MUXER || CONFIG_MD5_MUXER
83 static int hash_init(struct AVFormatContext
*s
)
86 struct HashContext
*c
= s
->priv_data
;
88 c
->hashes
= av_mallocz_array(1, sizeof(*c
->hashes
));
90 return AVERROR(ENOMEM
);
91 res
= av_hash_alloc(&c
->hashes
[0], c
->hash_name
);
94 av_hash_init(c
->hashes
[0]);
99 #if CONFIG_STREAMHASH_MUXER
100 static int streamhash_init(struct AVFormatContext
*s
)
103 struct HashContext
*c
= s
->priv_data
;
105 c
->hashes
= av_mallocz_array(s
->nb_streams
, sizeof(*c
->hashes
));
107 return AVERROR(ENOMEM
);
108 for (i
= 0; i
< s
->nb_streams
; i
++) {
109 res
= av_hash_alloc(&c
->hashes
[i
], c
->hash_name
);
113 av_hash_init(c
->hashes
[i
]);
119 #if CONFIG_HASH_MUXER || CONFIG_MD5_MUXER || CONFIG_STREAMHASH_MUXER
120 static char get_media_type_char(enum AVMediaType type
)
123 case AVMEDIA_TYPE_VIDEO
: return 'v';
124 case AVMEDIA_TYPE_AUDIO
: return 'a';
125 case AVMEDIA_TYPE_DATA
: return 'd';
126 case AVMEDIA_TYPE_SUBTITLE
: return 's';
127 case AVMEDIA_TYPE_ATTACHMENT
: return 't';
132 static int hash_write_packet(struct AVFormatContext
*s
, AVPacket
*pkt
)
134 struct HashContext
*c
= s
->priv_data
;
135 av_hash_update(c
->hashes
[c
->per_stream
? pkt
->stream_index
: 0], pkt
->data
, pkt
->size
);
139 static int hash_write_trailer(struct AVFormatContext
*s
)
141 struct HashContext
*c
= s
->priv_data
;
142 int num_hashes
= c
->per_stream
? s
->nb_streams
: 1;
143 for (int i
= 0; i
< num_hashes
; i
++) {
144 char buf
[AV_HASH_MAX_SIZE
*2+128];
146 AVStream
*st
= s
->streams
[i
];
147 snprintf(buf
, sizeof(buf
) - 200, "%d,%c,%s=", i
, get_media_type_char(st
->codecpar
->codec_type
),
148 av_hash_get_name(c
->hashes
[i
]));
150 snprintf(buf
, sizeof(buf
) - 200, "%s=", av_hash_get_name(c
->hashes
[i
]));
152 av_hash_final_hex(c
->hashes
[i
], buf
+ strlen(buf
), sizeof(buf
) - strlen(buf
));
153 av_strlcatf(buf
, sizeof(buf
), "\n");
154 avio_write(s
->pb
, buf
, strlen(buf
));
160 static void hash_free(struct AVFormatContext
*s
)
162 struct HashContext
*c
= s
->priv_data
;
164 int num_hashes
= c
->per_stream
? s
->nb_streams
: 1;
165 for (int i
= 0; i
< num_hashes
; i
++) {
166 av_hash_freep(&c
->hashes
[i
]);
169 av_freep(&c
->hashes
);
173 #if CONFIG_HASH_MUXER
174 static const AVClass hashenc_class
= {
175 .class_name
= "hash muxer",
176 .item_name
= av_default_item_name
,
177 .option
= hash_options
,
178 .version
= LIBAVUTIL_VERSION_INT
,
181 AVOutputFormat ff_hash_muxer
= {
183 .long_name
= NULL_IF_CONFIG_SMALL("Hash testing"),
184 .priv_data_size
= sizeof(struct HashContext
),
185 .audio_codec
= AV_CODEC_ID_PCM_S16LE
,
186 .video_codec
= AV_CODEC_ID_RAWVIDEO
,
188 .write_packet
= hash_write_packet
,
189 .write_trailer
= hash_write_trailer
,
191 .flags
= AVFMT_VARIABLE_FPS
| AVFMT_TS_NONSTRICT
|
193 .priv_class
= &hashenc_class
,
198 static const AVClass md5enc_class
= {
199 .class_name
= "MD5 muxer",
200 .item_name
= av_default_item_name
,
201 .option
= md5_options
,
202 .version
= LIBAVUTIL_VERSION_INT
,
205 AVOutputFormat ff_md5_muxer
= {
207 .long_name
= NULL_IF_CONFIG_SMALL("MD5 testing"),
208 .priv_data_size
= sizeof(struct HashContext
),
209 .audio_codec
= AV_CODEC_ID_PCM_S16LE
,
210 .video_codec
= AV_CODEC_ID_RAWVIDEO
,
212 .write_packet
= hash_write_packet
,
213 .write_trailer
= hash_write_trailer
,
215 .flags
= AVFMT_VARIABLE_FPS
| AVFMT_TS_NONSTRICT
|
217 .priv_class
= &md5enc_class
,
221 #if CONFIG_STREAMHASH_MUXER
222 static const AVClass streamhashenc_class
= {
223 .class_name
= "stream hash muxer",
224 .item_name
= av_default_item_name
,
225 .option
= streamhash_options
,
226 .version
= LIBAVUTIL_VERSION_INT
,
229 AVOutputFormat ff_streamhash_muxer
= {
230 .name
= "streamhash",
231 .long_name
= NULL_IF_CONFIG_SMALL("Per-stream hash testing"),
232 .priv_data_size
= sizeof(struct HashContext
),
233 .audio_codec
= AV_CODEC_ID_PCM_S16LE
,
234 .video_codec
= AV_CODEC_ID_RAWVIDEO
,
235 .init
= streamhash_init
,
236 .write_packet
= hash_write_packet
,
237 .write_trailer
= hash_write_trailer
,
239 .flags
= AVFMT_VARIABLE_FPS
| AVFMT_TS_NONSTRICT
|
241 .priv_class
= &streamhashenc_class
,
245 #if CONFIG_FRAMEHASH_MUXER || CONFIG_FRAMEMD5_MUXER
246 static void framehash_print_extradata(struct AVFormatContext
*s
)
250 for (i
= 0; i
< s
->nb_streams
; i
++) {
251 AVStream
*st
= s
->streams
[i
];
252 AVCodecParameters
*par
= st
->codecpar
;
253 if (par
->extradata
) {
254 struct HashContext
*c
= s
->priv_data
;
255 char buf
[AV_HASH_MAX_SIZE
*2+1];
257 avio_printf(s
->pb
, "#extradata %d, %31d, ", i
, par
->extradata_size
);
258 av_hash_init(c
->hashes
[0]);
259 av_hash_update(c
->hashes
[0], par
->extradata
, par
->extradata_size
);
260 av_hash_final_hex(c
->hashes
[0], buf
, sizeof(buf
));
261 avio_write(s
->pb
, buf
, strlen(buf
));
262 avio_printf(s
->pb
, "\n");
267 static int framehash_init(struct AVFormatContext
*s
)
270 struct HashContext
*c
= s
->priv_data
;
272 c
->hashes
= av_mallocz_array(1, sizeof(*c
->hashes
));
274 return AVERROR(ENOMEM
);
275 res
= av_hash_alloc(&c
->hashes
[0], c
->hash_name
);
281 static int framehash_write_header(struct AVFormatContext
*s
)
283 struct HashContext
*c
= s
->priv_data
;
284 avio_printf(s
->pb
, "#format: frame checksums\n");
285 avio_printf(s
->pb
, "#version: %d\n", c
->format_version
);
286 avio_printf(s
->pb
, "#hash: %s\n", av_hash_get_name(c
->hashes
[0]));
287 framehash_print_extradata(s
);
288 ff_framehash_write_header(s
);
289 avio_printf(s
->pb
, "#stream#, dts, pts, duration, size, hash\n");
293 static int framehash_write_packet(struct AVFormatContext
*s
, AVPacket
*pkt
)
295 struct HashContext
*c
= s
->priv_data
;
296 char buf
[AV_HASH_MAX_SIZE
*2+128];
298 av_hash_init(c
->hashes
[0]);
299 av_hash_update(c
->hashes
[0], pkt
->data
, pkt
->size
);
301 snprintf(buf
, sizeof(buf
) - (AV_HASH_MAX_SIZE
* 2 + 1), "%d, %10"PRId64
", %10"PRId64
", %8"PRId64
", %8d, ",
302 pkt
->stream_index
, pkt
->dts
, pkt
->pts
, pkt
->duration
, pkt
->size
);
304 av_hash_final_hex(c
->hashes
[0], buf
+ len
, sizeof(buf
) - len
);
305 avio_write(s
->pb
, buf
, strlen(buf
));
307 if (c
->format_version
> 1 && pkt
->side_data_elems
) {
309 avio_printf(s
->pb
, ", S=%d", pkt
->side_data_elems
);
310 for (i
= 0; i
< pkt
->side_data_elems
; i
++) {
311 av_hash_init(c
->hashes
[0]);
312 if (HAVE_BIGENDIAN
&& pkt
->side_data
[i
].type
== AV_PKT_DATA_PALETTE
) {
313 for (j
= 0; j
< pkt
->side_data
[i
].size
; j
+= sizeof(uint32_t)) {
314 uint32_t data
= AV_RL32(pkt
->side_data
[i
].data
+ j
);
315 av_hash_update(c
->hashes
[0], (uint8_t *)&data
, sizeof(uint32_t));
318 av_hash_update(c
->hashes
[0], pkt
->side_data
[i
].data
, pkt
->side_data
[i
].size
);
319 snprintf(buf
, sizeof(buf
) - (AV_HASH_MAX_SIZE
* 2 + 1), ", %8d, ", pkt
->side_data
[i
].size
);
321 av_hash_final_hex(c
->hashes
[0], buf
+ len
, sizeof(buf
) - len
);
322 avio_write(s
->pb
, buf
, strlen(buf
));
326 avio_printf(s
->pb
, "\n");
330 static void framehash_free(struct AVFormatContext
*s
)
332 struct HashContext
*c
= s
->priv_data
;
334 av_hash_freep(&c
->hashes
[0]);
335 av_freep(&c
->hashes
);
339 #if CONFIG_FRAMEHASH_MUXER
340 static const AVClass framehash_class
= {
341 .class_name
= "frame hash muxer",
342 .item_name
= av_default_item_name
,
343 .option
= framehash_options
,
344 .version
= LIBAVUTIL_VERSION_INT
,
347 AVOutputFormat ff_framehash_muxer
= {
349 .long_name
= NULL_IF_CONFIG_SMALL("Per-frame hash testing"),
350 .priv_data_size
= sizeof(struct HashContext
),
351 .audio_codec
= AV_CODEC_ID_PCM_S16LE
,
352 .video_codec
= AV_CODEC_ID_RAWVIDEO
,
353 .init
= framehash_init
,
354 .write_header
= framehash_write_header
,
355 .write_packet
= framehash_write_packet
,
356 .deinit
= framehash_free
,
357 .flags
= AVFMT_VARIABLE_FPS
| AVFMT_TS_NONSTRICT
|
359 .priv_class
= &framehash_class
,
363 #if CONFIG_FRAMEMD5_MUXER
364 static const AVClass framemd5_class
= {
365 .class_name
= "frame MD5 muxer",
366 .item_name
= av_default_item_name
,
367 .option
= framemd5_options
,
368 .version
= LIBAVUTIL_VERSION_INT
,
371 AVOutputFormat ff_framemd5_muxer
= {
373 .long_name
= NULL_IF_CONFIG_SMALL("Per-frame MD5 testing"),
374 .priv_data_size
= sizeof(struct HashContext
),
375 .audio_codec
= AV_CODEC_ID_PCM_S16LE
,
376 .video_codec
= AV_CODEC_ID_RAWVIDEO
,
377 .init
= framehash_init
,
378 .write_header
= framehash_write_header
,
379 .write_packet
= framehash_write_packet
,
380 .deinit
= framehash_free
,
381 .flags
= AVFMT_VARIABLE_FPS
| AVFMT_TS_NONSTRICT
|
383 .priv_class
= &framemd5_class
,