]> git.sesse.net Git - ffmpeg/blob - libavformat/hashenc.c
avformat/hashenc: rearrange options definition
[ffmpeg] / libavformat / hashenc.c
1 /*
2  * Hash/MD5 encoder (for codec/format testing)
3  * Copyright (c) 2009 Reimar Döffinger, based on crcenc (c) 2002 Fabrice Bellard
4  *
5  * This file is part of FFmpeg.
6  *
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.
11  *
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.
16  *
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
20  */
21
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"
27 #include "avformat.h"
28 #include "internal.h"
29
30 struct HashContext {
31     const AVClass *avclass;
32     struct AVHashContext *hash;
33     char *hash_name;
34     int format_version;
35 };
36
37 #define OFFSET(x) offsetof(struct HashContext, x)
38 #define ENC AV_OPT_FLAG_ENCODING_PARAM
39 #define HASH_OPT(defaulttype) \
40     { "hash", "set hash to use", OFFSET(hash_name), AV_OPT_TYPE_STRING, {.str = defaulttype}, 0, 0, ENC }
41 #define FORMAT_VERSION_OPT \
42     { "format_version", "file format version", OFFSET(format_version), AV_OPT_TYPE_INT, {.i64 = 2}, 1, 2, ENC }
43
44 #if CONFIG_HASH_MUXER
45 static const AVOption hash_options[] = {
46     HASH_OPT("sha256"),
47     { NULL },
48 };
49 #endif
50
51 #if CONFIG_FRAMEHASH_MUXER
52 static const AVOption framehash_options[] = {
53     HASH_OPT("sha256"),
54     FORMAT_VERSION_OPT,
55     { NULL },
56 };
57 #endif
58
59 #if CONFIG_MD5_MUXER
60 static const AVOption md5_options[] = {
61     HASH_OPT("md5"),
62     { NULL },
63 };
64 #endif
65
66 #if CONFIG_FRAMEMD5_MUXER
67 static const AVOption framemd5_options[] = {
68     HASH_OPT("md5"),
69     FORMAT_VERSION_OPT,
70     { NULL },
71 };
72 #endif
73
74 #if CONFIG_HASH_MUXER || CONFIG_MD5_MUXER
75 static int hash_write_header(struct AVFormatContext *s)
76 {
77     struct HashContext *c = s->priv_data;
78     int res = av_hash_alloc(&c->hash, c->hash_name);
79     if (res < 0)
80         return res;
81     av_hash_init(c->hash);
82     return 0;
83 }
84
85 static int hash_write_packet(struct AVFormatContext *s, AVPacket *pkt)
86 {
87     struct HashContext *c = s->priv_data;
88     av_hash_update(c->hash, pkt->data, pkt->size);
89     return 0;
90 }
91
92 static int hash_write_trailer(struct AVFormatContext *s)
93 {
94     struct HashContext *c = s->priv_data;
95     char buf[AV_HASH_MAX_SIZE*2+128];
96     snprintf(buf, sizeof(buf) - 200, "%s=", av_hash_get_name(c->hash));
97
98     av_hash_final_hex(c->hash, buf + strlen(buf), sizeof(buf) - strlen(buf));
99     av_strlcatf(buf, sizeof(buf), "\n");
100     avio_write(s->pb, buf, strlen(buf));
101     avio_flush(s->pb);
102
103     av_hash_freep(&c->hash);
104     return 0;
105 }
106 #endif
107
108 #if CONFIG_HASH_MUXER
109 static const AVClass hashenc_class = {
110     .class_name = "hash muxer",
111     .item_name  = av_default_item_name,
112     .option     = hash_options,
113     .version    = LIBAVUTIL_VERSION_INT,
114 };
115
116 AVOutputFormat ff_hash_muxer = {
117     .name              = "hash",
118     .long_name         = NULL_IF_CONFIG_SMALL("Hash testing"),
119     .priv_data_size    = sizeof(struct HashContext),
120     .audio_codec       = AV_CODEC_ID_PCM_S16LE,
121     .video_codec       = AV_CODEC_ID_RAWVIDEO,
122     .write_header      = hash_write_header,
123     .write_packet      = hash_write_packet,
124     .write_trailer     = hash_write_trailer,
125     .flags             = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT |
126                          AVFMT_TS_NEGATIVE,
127     .priv_class        = &hashenc_class,
128 };
129 #endif
130
131 #if CONFIG_MD5_MUXER
132 static const AVClass md5enc_class = {
133     .class_name = "MD5 muxer",
134     .item_name  = av_default_item_name,
135     .option     = md5_options,
136     .version    = LIBAVUTIL_VERSION_INT,
137 };
138
139 AVOutputFormat ff_md5_muxer = {
140     .name              = "md5",
141     .long_name         = NULL_IF_CONFIG_SMALL("MD5 testing"),
142     .priv_data_size    = sizeof(struct HashContext),
143     .audio_codec       = AV_CODEC_ID_PCM_S16LE,
144     .video_codec       = AV_CODEC_ID_RAWVIDEO,
145     .write_header      = hash_write_header,
146     .write_packet      = hash_write_packet,
147     .write_trailer     = hash_write_trailer,
148     .flags             = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT |
149                          AVFMT_TS_NEGATIVE,
150     .priv_class        = &md5enc_class,
151 };
152 #endif
153
154 #if CONFIG_FRAMEHASH_MUXER || CONFIG_FRAMEMD5_MUXER
155 static void framehash_print_extradata(struct AVFormatContext *s)
156 {
157     int i;
158
159     for (i = 0; i < s->nb_streams; i++) {
160         AVStream *st = s->streams[i];
161         AVCodecParameters *par = st->codecpar;
162         if (par->extradata) {
163             struct HashContext *c = s->priv_data;
164             char buf[AV_HASH_MAX_SIZE*2+1];
165
166             avio_printf(s->pb, "#extradata %d, %31d, ", i, par->extradata_size);
167             av_hash_init(c->hash);
168             av_hash_update(c->hash, par->extradata, par->extradata_size);
169             av_hash_final_hex(c->hash, buf, sizeof(buf));
170             avio_write(s->pb, buf, strlen(buf));
171             avio_printf(s->pb, "\n");
172         }
173     }
174 }
175
176 static int framehash_write_header(struct AVFormatContext *s)
177 {
178     struct HashContext *c = s->priv_data;
179     int res = av_hash_alloc(&c->hash, c->hash_name);
180     if (res < 0)
181         return res;
182     avio_printf(s->pb, "#format: frame checksums\n");
183     avio_printf(s->pb, "#version: %d\n", c->format_version);
184     avio_printf(s->pb, "#hash: %s\n", av_hash_get_name(c->hash));
185     framehash_print_extradata(s);
186     ff_framehash_write_header(s);
187     avio_printf(s->pb, "#stream#, dts,        pts, duration,     size, hash\n");
188     return 0;
189 }
190
191 static int framehash_write_packet(struct AVFormatContext *s, AVPacket *pkt)
192 {
193     struct HashContext *c = s->priv_data;
194     char buf[AV_HASH_MAX_SIZE*2+128];
195     int len;
196     av_hash_init(c->hash);
197     av_hash_update(c->hash, pkt->data, pkt->size);
198
199     snprintf(buf, sizeof(buf) - (AV_HASH_MAX_SIZE * 2 + 1), "%d, %10"PRId64", %10"PRId64", %8"PRId64", %8d, ",
200              pkt->stream_index, pkt->dts, pkt->pts, pkt->duration, pkt->size);
201     len = strlen(buf);
202     av_hash_final_hex(c->hash, buf + len, sizeof(buf) - len);
203     avio_write(s->pb, buf, strlen(buf));
204
205     if (c->format_version > 1 && pkt->side_data_elems) {
206         int i, j;
207         avio_printf(s->pb, ", S=%d", pkt->side_data_elems);
208         for (i = 0; i < pkt->side_data_elems; i++) {
209             av_hash_init(c->hash);
210             if (HAVE_BIGENDIAN && pkt->side_data[i].type == AV_PKT_DATA_PALETTE) {
211                 for (j = 0; j < pkt->side_data[i].size; j += sizeof(uint32_t)) {
212                     uint32_t data = AV_RL32(pkt->side_data[i].data + j);
213                     av_hash_update(c->hash, (uint8_t *)&data, sizeof(uint32_t));
214                 }
215             } else
216                 av_hash_update(c->hash, pkt->side_data[i].data, pkt->side_data[i].size);
217             snprintf(buf, sizeof(buf) - (AV_HASH_MAX_SIZE * 2 + 1), ", %8d, ", pkt->side_data[i].size);
218             len = strlen(buf);
219             av_hash_final_hex(c->hash, buf + len, sizeof(buf) - len);
220             avio_write(s->pb, buf, strlen(buf));
221         }
222     }
223
224     avio_printf(s->pb, "\n");
225     avio_flush(s->pb);
226     return 0;
227 }
228
229 static int framehash_write_trailer(struct AVFormatContext *s)
230 {
231     struct HashContext *c = s->priv_data;
232     av_hash_freep(&c->hash);
233     return 0;
234 }
235 #endif
236
237 #if CONFIG_FRAMEHASH_MUXER
238 static const AVClass framehash_class = {
239     .class_name = "frame hash muxer",
240     .item_name  = av_default_item_name,
241     .option     = framehash_options,
242     .version    = LIBAVUTIL_VERSION_INT,
243 };
244
245 AVOutputFormat ff_framehash_muxer = {
246     .name              = "framehash",
247     .long_name         = NULL_IF_CONFIG_SMALL("Per-frame hash testing"),
248     .priv_data_size    = sizeof(struct HashContext),
249     .audio_codec       = AV_CODEC_ID_PCM_S16LE,
250     .video_codec       = AV_CODEC_ID_RAWVIDEO,
251     .write_header      = framehash_write_header,
252     .write_packet      = framehash_write_packet,
253     .write_trailer     = framehash_write_trailer,
254     .flags             = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT |
255                          AVFMT_TS_NEGATIVE,
256     .priv_class        = &framehash_class,
257 };
258 #endif
259
260 #if CONFIG_FRAMEMD5_MUXER
261 static const AVClass framemd5_class = {
262     .class_name = "frame MD5 muxer",
263     .item_name  = av_default_item_name,
264     .option     = framemd5_options,
265     .version    = LIBAVUTIL_VERSION_INT,
266 };
267
268 AVOutputFormat ff_framemd5_muxer = {
269     .name              = "framemd5",
270     .long_name         = NULL_IF_CONFIG_SMALL("Per-frame MD5 testing"),
271     .priv_data_size    = sizeof(struct HashContext),
272     .audio_codec       = AV_CODEC_ID_PCM_S16LE,
273     .video_codec       = AV_CODEC_ID_RAWVIDEO,
274     .write_header      = framehash_write_header,
275     .write_packet      = framehash_write_packet,
276     .write_trailer     = framehash_write_trailer,
277     .flags             = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT |
278                          AVFMT_TS_NEGATIVE,
279     .priv_class        = &framemd5_class,
280 };
281 #endif