@ -31,6 +31,7 @@ struct HashContext {
const AVClass * avclass ;
struct AVHashContext * * hashes ;
char * hash_name ;
int per_stream ;
int format_version ;
} ;
@ -56,6 +57,13 @@ static const AVOption framehash_options[] = {
} ;
# endif
# if CONFIG_STREAMHASH_MUXER
static const AVOption streamhash_options [ ] = {
HASH_OPT ( " sha256 " ) ,
{ NULL } ,
} ;
# endif
# if CONFIG_MD5_MUXER
static const AVOption md5_options [ ] = {
HASH_OPT ( " md5 " ) ,
@ -76,6 +84,7 @@ static int hash_init(struct AVFormatContext *s)
{
int res ;
struct HashContext * c = s - > priv_data ;
c - > per_stream = 0 ;
c - > hashes = av_mallocz_array ( 1 , sizeof ( c - > hashes ) ) ;
if ( ! c - > hashes )
return AVERROR ( ENOMEM ) ;
@ -85,24 +94,66 @@ static int hash_init(struct AVFormatContext *s)
av_hash_init ( c - > hashes [ 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 )
{
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 ;
}
static int hash_write_trailer ( struct AVFormatContext * s )
{
struct HashContext * c = s - > priv_data ;
char buf [ AV_HASH_MAX_SIZE * 2 + 128 ] ;
snprintf ( buf , sizeof ( buf ) - 200 , " %s= " , av_hash_get_name ( c - > hashes [ 0 ] ) ) ;
av_hash_final_hex ( c - > hashes [ 0 ] , buf + strlen ( buf ) , sizeof ( buf ) - strlen ( buf ) ) ;
av_strlcatf ( buf , sizeof ( buf ) , " \n " ) ;
avio_write ( s - > pb , buf , strlen ( buf ) ) ;
avio_flush ( s - > pb ) ;
int num_hashes = c - > per_stream ? s - > nb_streams : 1 ;
for ( int i = 0 ; i < num_hashes ; i + + ) {
char buf [ AV_HASH_MAX_SIZE * 2 + 128 ] ;
if ( c - > per_stream ) {
AVStream * st = s - > streams [ i ] ;
snprintf ( buf , sizeof ( buf ) - 200 , " %d,%c,%s= " , i , get_media_type_char ( st - > codecpar - > codec_type ) ,
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 ;
}
@ -110,8 +161,12 @@ static int hash_write_trailer(struct AVFormatContext *s)
static void hash_free ( struct AVFormatContext * s )
{
struct HashContext * c = s - > priv_data ;
if ( c - > hashes )
av_hash_freep ( & c - > hashes [ 0 ] ) ;
if ( c - > hashes ) {
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 ) ;
}
# endif
@ -164,6 +219,30 @@ AVOutputFormat ff_md5_muxer = {
} ;
# 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
static void framehash_print_extradata ( struct AVFormatContext * s )
{
@ -190,6 +269,7 @@ static int framehash_init(struct AVFormatContext *s)
{
int res ;
struct HashContext * c = s - > priv_data ;
c - > per_stream = 0 ;
c - > hashes = av_mallocz_array ( 1 , sizeof ( c - > hashes ) ) ;
if ( ! c - > hashes )
return AVERROR ( ENOMEM ) ;