1/* 2 * 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/opt.h" 26#include "avformat.h" 27#include "internal.h" 28 29struct MD5Context { 30 const AVClass *avclass; 31 struct AVHashContext *hash; 32 char *hash_name; 33}; 34 35static void md5_finish(struct AVFormatContext *s, char *buf) 36{ 37 struct MD5Context *c = s->priv_data; 38 uint8_t md5[AV_HASH_MAX_SIZE]; 39 int i, offset = strlen(buf); 40 int len = av_hash_get_size(c->hash); 41 av_assert0(len > 0 && len <= sizeof(md5)); 42 av_hash_final(c->hash, md5); 43 for (i = 0; i < len; i++) { 44 snprintf(buf + offset, 3, "%02"PRIx8, md5[i]); 45 offset += 2; 46 } 47 buf[offset] = '\n'; 48 buf[offset+1] = 0; 49 50 avio_write(s->pb, buf, strlen(buf)); 51 avio_flush(s->pb); 52} 53 54#define OFFSET(x) offsetof(struct MD5Context, x) 55#define ENC AV_OPT_FLAG_ENCODING_PARAM 56static const AVOption hash_options[] = { 57 { "hash", "set hash to use", OFFSET(hash_name), AV_OPT_TYPE_STRING, {.str = "md5"}, 0, 0, ENC }, 58 { NULL }, 59}; 60 61static const AVClass md5enc_class = { 62 .class_name = "hash encoder class", 63 .item_name = av_default_item_name, 64 .option = hash_options, 65 .version = LIBAVUTIL_VERSION_INT, 66}; 67 68#if CONFIG_MD5_MUXER 69static int write_header(struct AVFormatContext *s) 70{ 71 struct MD5Context *c = s->priv_data; 72 int res = av_hash_alloc(&c->hash, c->hash_name); 73 if (res < 0) 74 return res; 75 av_hash_init(c->hash); 76 return 0; 77} 78 79static int write_packet(struct AVFormatContext *s, AVPacket *pkt) 80{ 81 struct MD5Context *c = s->priv_data; 82 av_hash_update(c->hash, pkt->data, pkt->size); 83 return 0; 84} 85 86static int write_trailer(struct AVFormatContext *s) 87{ 88 struct MD5Context *c = s->priv_data; 89 char buf[256]; 90 av_strlcpy(buf, av_hash_get_name(c->hash), sizeof(buf) - 200); 91 av_strlcat(buf, "=", sizeof(buf) - 200); 92 93 md5_finish(s, buf); 94 95 av_hash_freep(&c->hash); 96 return 0; 97} 98 99AVOutputFormat ff_md5_muxer = { 100 .name = "md5", 101 .long_name = NULL_IF_CONFIG_SMALL("MD5 testing"), 102 .priv_data_size = sizeof(struct MD5Context), 103 .audio_codec = AV_CODEC_ID_PCM_S16LE, 104 .video_codec = AV_CODEC_ID_RAWVIDEO, 105 .write_header = write_header, 106 .write_packet = write_packet, 107 .write_trailer = write_trailer, 108 .flags = AVFMT_NOTIMESTAMPS, 109 .priv_class = &md5enc_class, 110}; 111#endif 112 113#if CONFIG_FRAMEMD5_MUXER 114static int framemd5_write_header(struct AVFormatContext *s) 115{ 116 struct MD5Context *c = s->priv_data; 117 int res = av_hash_alloc(&c->hash, c->hash_name); 118 if (res < 0) 119 return res; 120 avio_printf(s->pb, "#format: frame checksums\n"); 121 avio_printf(s->pb, "#version: 1\n"); 122 avio_printf(s->pb, "#hash: %s\n", av_hash_get_name(c->hash)); 123 ff_framehash_write_header(s); 124 avio_printf(s->pb, "#stream#, dts, pts, duration, size, hash\n"); 125 return 0; 126} 127 128static int framemd5_write_packet(struct AVFormatContext *s, AVPacket *pkt) 129{ 130 struct MD5Context *c = s->priv_data; 131 char buf[256]; 132 av_hash_init(c->hash); 133 av_hash_update(c->hash, pkt->data, pkt->size); 134 135 snprintf(buf, sizeof(buf) - 64, "%d, %10"PRId64", %10"PRId64", %8d, %8d, ", 136 pkt->stream_index, pkt->dts, pkt->pts, pkt->duration, pkt->size); 137 md5_finish(s, buf); 138 return 0; 139} 140 141static int framemd5_write_trailer(struct AVFormatContext *s) 142{ 143 struct MD5Context *c = s->priv_data; 144 av_hash_freep(&c->hash); 145 return 0; 146} 147 148static const AVClass framemd5_class = { 149 .class_name = "frame hash encoder class", 150 .item_name = av_default_item_name, 151 .option = hash_options, 152 .version = LIBAVUTIL_VERSION_INT, 153}; 154 155AVOutputFormat ff_framemd5_muxer = { 156 .name = "framemd5", 157 .long_name = NULL_IF_CONFIG_SMALL("Per-frame MD5 testing"), 158 .priv_data_size = sizeof(struct MD5Context), 159 .audio_codec = AV_CODEC_ID_PCM_S16LE, 160 .video_codec = AV_CODEC_ID_RAWVIDEO, 161 .write_header = framemd5_write_header, 162 .write_packet = framemd5_write_packet, 163 .write_trailer = framemd5_write_trailer, 164 .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT | 165 AVFMT_TS_NEGATIVE, 166 .priv_class = &framemd5_class, 167}; 168#endif 169