PR #23285 opened by James Almer (jamrial) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23285 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23285.patch
Add the same features as the framehash muxer. This makes it much more useful as it prints important information that some tests may need where framehash is not an option given it prints too many lines (e.g., samples with tons of frames where timestamps or packet flags are irrelevant, and just a single hash is enough). >From 781d913a104f7cc1a85d9707f90ffcae8cc2daa4 Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Sat, 30 May 2026 23:45:10 -0300 Subject: [PATCH 1/2] avcodec/dcadec: map Lw/Rw to FLC/FRC Some 7.1 DTS files seem to signal Lw/Rw channels that the decoder has been mapping to SL/SR, despite the macro for the mask being called 7_1_WIDE. This resulted in said samples reporting the same native layout as actual 7.1 samples with Lsr/Rsr/Lss/Rss (mapped to BL/BR/SL/SR). If we were to be strict, Lw/Rw would map to WR/WL, but that would result in an unusual native layout. Instead, lets map them to FLC/FRC, which will result in the more common 7.1(wide) native layout. Signed-off-by: James Almer <[email protected]> --- libavcodec/dcadec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavcodec/dcadec.c b/libavcodec/dcadec.c index f47a694746..7fbd2c6e3f 100644 --- a/libavcodec/dcadec.c +++ b/libavcodec/dcadec.c @@ -41,7 +41,7 @@ int ff_dca_set_channel_layout(AVCodecContext *avctx, int *ch_remap, int dca_mask static const uint8_t dca2wav_wide[28] = { 2, 0, 1, 4, 5, 3, 8, 4, 5, 9, 10, 6, 7, 12, - 13, 14, 3, 9, 10, 11, 12, 14, 16, 15, 17, 8, 4, 5, + 13, 14, 3, 6, 7, 11, 12, 14, 16, 15, 17, 8, 4, 5, }; DCAContext *s = avctx->priv_data; -- 2.52.0 >From d4ec2cea743fbee350b9281b49a180a70b59c623 Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Sun, 31 May 2026 00:01:19 -0300 Subject: [PATCH 2/2] avformat/hashenc: extend output of streamhash muxer Add the same features as the framehash muxer. This makes it much more useful as it prints important information that some tests may need where framehash is not an option given it prints too many lines (e.g., samples with tons of frames where timestamps or packet flags are irrelevant, and just a single hash is enough). Signed-off-by: James Almer <[email protected]> --- libavformat/hashenc.c | 95 +++++++++++++++++------------- tests/fate/dca.mak | 4 +- tests/ref/fate/dca-xll | 11 +++- tests/ref/fate/dca-xll-coded | 11 +++- tests/ref/fate/filter-channelsplit | 18 +++++- 5 files changed, 93 insertions(+), 46 deletions(-) diff --git a/libavformat/hashenc.c b/libavformat/hashenc.c index b108eca41b..4c58536313 100644 --- a/libavformat/hashenc.c +++ b/libavformat/hashenc.c @@ -34,6 +34,7 @@ struct HashContext { const AVClass *avclass; struct AVHashContext **hashes; char *hash_name; + int64_t *stream_sizes; int per_stream; int format_version; }; @@ -48,6 +49,7 @@ struct HashContext { #if CONFIG_HASH_MUXER || CONFIG_STREAMHASH_MUXER static const AVOption hash_streamhash_options[] = { HASH_OPT("sha256"), + FORMAT_VERSION_OPT, { NULL }, }; @@ -97,6 +99,13 @@ static int hash_init(struct AVFormatContext *s) av_hash_init(c->hashes[0]); return 0; } + +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); + return 0; +} #endif #if CONFIG_STREAMHASH_MUXER @@ -108,6 +117,9 @@ static int streamhash_init(struct AVFormatContext *s) c->hashes = av_calloc(s->nb_streams, sizeof(*c->hashes)); if (!c->hashes) return AVERROR(ENOMEM); + c->stream_sizes = av_calloc(s->nb_streams, sizeof(*c->stream_sizes)); + if (!c->stream_sizes) + return AVERROR(ENOMEM); for (i = 0; i < s->nb_streams; i++) { res = av_hash_alloc(&c->hashes[i], c->hash_name); if (res < 0) { @@ -117,25 +129,49 @@ static int streamhash_init(struct AVFormatContext *s) } return 0; } + +static int streamhash_write_packet(struct AVFormatContext *s, AVPacket *pkt) +{ + struct HashContext *c = s->priv_data; + av_hash_update(c->hashes[pkt->stream_index], pkt->data, pkt->size); + c->stream_sizes[pkt->stream_index] += pkt->size; + return 0; +} +#endif + +#if CONFIG_STREAMHASH_MUXER || CONFIG_FRAMEHASH_MUXER || CONFIG_FRAMEMD5_MUXER +static void hash_print_extradata(struct AVFormatContext *s) +{ + int i; + + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + AVCodecParameters *par = st->codecpar; + if (par->extradata) { + struct HashContext *c = s->priv_data; + char buf[AV_HASH_MAX_SIZE*2+1]; + + avio_printf(s->pb, "#extradata %d, %31d, ", i, par->extradata_size); + av_hash_init(c->hashes[0]); + av_hash_update(c->hashes[0], par->extradata, par->extradata_size); + av_hash_final_hex(c->hashes[0], buf, sizeof(buf)); + avio_write(s->pb, buf, strlen(buf)); + avio_printf(s->pb, "\n"); + } + } +} #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 streamhash_write_header(struct AVFormatContext *s) { struct HashContext *c = s->priv_data; - av_hash_update(c->hashes[c->per_stream ? pkt->stream_index : 0], pkt->data, pkt->size); + avio_printf(s->pb, "#format: stream checksums\n"); + avio_printf(s->pb, "#version: %d\n", c->format_version); + avio_printf(s->pb, "#hash: %s\n", av_hash_get_name(c->hashes[0])); + hash_print_extradata(s); + ff_framehash_write_header(s); + avio_printf(s->pb, "#stream#, size, hash\n"); return 0; } @@ -146,9 +182,7 @@ static int hash_write_trailer(struct AVFormatContext *s) 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])); + snprintf(buf, sizeof(buf) - 200, "%d, %11"PRId64", ", i, c->stream_sizes[i]); } else { snprintf(buf, sizeof(buf) - 200, "%s=", av_hash_get_name(c->hashes[i])); } @@ -171,6 +205,7 @@ static void hash_free(struct AVFormatContext *s) } } av_freep(&c->hashes); + av_freep(&c->stream_sizes); } #if CONFIG_HASH_MUXER @@ -222,7 +257,8 @@ const FFOutputFormat ff_streamhash_muxer = { .p.audio_codec = AV_CODEC_ID_PCM_S16LE, .p.video_codec = AV_CODEC_ID_RAWVIDEO, .init = streamhash_init, - .write_packet = hash_write_packet, + .write_header = streamhash_write_header, + .write_packet = streamhash_write_packet, .write_trailer = hash_write_trailer, .deinit = hash_free, .p.flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT | @@ -232,27 +268,6 @@ const FFOutputFormat ff_streamhash_muxer = { #endif #if CONFIG_FRAMEHASH_MUXER || CONFIG_FRAMEMD5_MUXER -static void framehash_print_extradata(struct AVFormatContext *s) -{ - int i; - - for (i = 0; i < s->nb_streams; i++) { - AVStream *st = s->streams[i]; - AVCodecParameters *par = st->codecpar; - if (par->extradata) { - struct HashContext *c = s->priv_data; - char buf[AV_HASH_MAX_SIZE*2+1]; - - avio_printf(s->pb, "#extradata %d, %31d, ", i, par->extradata_size); - av_hash_init(c->hashes[0]); - av_hash_update(c->hashes[0], par->extradata, par->extradata_size); - av_hash_final_hex(c->hashes[0], buf, sizeof(buf)); - avio_write(s->pb, buf, strlen(buf)); - avio_printf(s->pb, "\n"); - } - } -} - static int framehash_init(struct AVFormatContext *s) { int res; @@ -273,7 +288,7 @@ static int framehash_write_header(struct AVFormatContext *s) avio_printf(s->pb, "#format: frame checksums\n"); avio_printf(s->pb, "#version: %d\n", c->format_version); avio_printf(s->pb, "#hash: %s\n", av_hash_get_name(c->hashes[0])); - framehash_print_extradata(s); + hash_print_extradata(s); ff_framehash_write_header(s); avio_printf(s->pb, "#stream#, dts, pts, duration, size, hash\n"); return 0; diff --git a/tests/fate/dca.mak b/tests/fate/dca.mak index 609f924aa3..396faecf2d 100644 --- a/tests/fate/dca.mak +++ b/tests/fate/dca.mak @@ -71,10 +71,10 @@ fate-dca-core: CMP = oneoff fate-dca-core: REF = $(SAMPLES)/dts/dts.pcm FATE_DCA-$(call DEMDEC, DTS, DCA, ARESAMPLE_FILTER PCM_S24LE_ENCODER PCM_S24LE_MUXER) += fate-dca-xll -fate-dca-xll: CMD = md5 -i $(TARGET_SAMPLES)/dts/master_audio_7.1_24bit.dts -f s24le -af aresample +fate-dca-xll: CMD = fmtstdout "streamhash -hash md5" -i $(TARGET_SAMPLES)/dts/master_audio_7.1_24bit.dts -c:a pcm_s24le -af aresample FATE_DCA-$(call DEMDEC, DTS, DCA, ARESAMPLE_FILTER PCM_S24LE_ENCODER PCM_S24LE_MUXER) += fate-dca-xll-coded -fate-dca-xll-coded: CMD = md5 -channel_order coded -i $(TARGET_SAMPLES)/dts/master_audio_7.1_24bit.dts -f s24le -af aresample +fate-dca-xll-coded: CMD = fmtstdout "streamhash -hash md5" -channel_order coded -i $(TARGET_SAMPLES)/dts/master_audio_7.1_24bit.dts -c:a pcm_s24le -af aresample FATE_DCA-$(call PCM, DTS, DCA, ARESAMPLE_FILTER) += fate-dts_es fate-dts_es: CMD = pcm -i $(TARGET_SAMPLES)/dts/dts_es.dts diff --git a/tests/ref/fate/dca-xll b/tests/ref/fate/dca-xll index 75b5453a87..1cacc0ffae 100644 --- a/tests/ref/fate/dca-xll +++ b/tests/ref/fate/dca-xll @@ -1 +1,10 @@ -5eb9a95ddaf3c803e74443a49a691686 +#format: stream checksums +#version: 2 +#hash: MD5 +#tb 0: 1/48000 +#media_type 0: audio +#codec_id 0: pcm_s24le +#sample_rate 0: 48000 +#channel_layout_name 0: 7.1(wide) +#stream#, size, hash +0, 14401536, 5eb9a95ddaf3c803e74443a49a691686 diff --git a/tests/ref/fate/dca-xll-coded b/tests/ref/fate/dca-xll-coded index 42e17da0d7..15f601fb4f 100644 --- a/tests/ref/fate/dca-xll-coded +++ b/tests/ref/fate/dca-xll-coded @@ -1 +1,10 @@ -0ae67d520a46776046ab5ab7d1c6a387 +#format: stream checksums +#version: 2 +#hash: MD5 +#tb 0: 1/48000 +#media_type 0: audio +#codec_id 0: pcm_s24le +#sample_rate 0: 48000 +#channel_layout_name 0: 8 channels (FC+FL+FR+BL+BR+LFE+FLC+FRC) +#stream#, size, hash +0, 14401536, 0ae67d520a46776046ab5ab7d1c6a387 diff --git a/tests/ref/fate/filter-channelsplit b/tests/ref/fate/filter-channelsplit index 892801d94d..81ca60ab83 100644 --- a/tests/ref/fate/filter-channelsplit +++ b/tests/ref/fate/filter-channelsplit @@ -1,2 +1,16 @@ -0,a,SHA256=a4f03d92f82d074d20bcc49ffcbb28911ae85b097142249a890af59422eb0da8 -1,a,SHA256=c2f021f2b2faa1629674e6126ce5f997ef2034ecd3a15df595a98aefa40614e9 +#format: stream checksums +#version: 2 +#hash: SHA256 +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout_name 0: 1 channels (FL) +#tb 1: 1/44100 +#media_type 1: audio +#codec_id 1: pcm_s16le +#sample_rate 1: 44100 +#channel_layout_name 1: 1 channels (FR) +#stream#, size, hash +0, 529200, a4f03d92f82d074d20bcc49ffcbb28911ae85b097142249a890af59422eb0da8 +1, 529200, c2f021f2b2faa1629674e6126ce5f997ef2034ecd3a15df595a98aefa40614e9 -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
