diff options
| author | Carl Hetherington <cth@carlh.net> | 2018-02-13 10:32:18 +0000 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2018-02-13 10:32:18 +0000 |
| commit | 39dfbac23f0b044b3597d86ed2ca0a05251dd14c (patch) | |
| tree | 0244103367e4511821308eba9112b8c1a9b959a8 | |
| parent | 699f178779fdccd89a823ca2b61fc6fe476dfee1 (diff) | |
Proper inspection of audio frames; support for audio tolerance.
| -rw-r--r-- | ffcmp.c | 97 |
1 files changed, 93 insertions, 4 deletions
@@ -1,5 +1,6 @@ #include <libavformat/avformat.h> #include <libavutil/frame.h> +#include <getopt.h> #include <stdbool.h> #define MAX_COMPLETE_FRAMES 64 @@ -112,13 +113,51 @@ read_frame(File* file) return false; } +void help(char const * name) +{ + fprintf(stderr, "Syntax: %s [options] file1 file2\n", name); + fprintf(stderr, "Options are:\n"); + fprintf(stderr, "\t--audio-sample-tolerance, -t specify allowable absolute difference in audio sample value\n"); +} + int main(int argc, char** argv) { + int audio_sample_tolerance = 0; + + int option_index = 0; + while (true) { + static struct option long_options[] = { + { "help", no_argument, 0, 'h' }, + { "audio-sample-tolerance", required_argument, 0, 't' }, + { 0, 0, 0, 0 } + }; + + int c = getopt_long(argc, argv, "ht:", long_options, &option_index); + + if (c == -1) { + break; + } + + switch (c) { + case 'h': + help(argv[0]); + break; + case 't': + audio_sample_tolerance = atoi(optarg); + break; + } + } + + if (argc - optind < 2 || argc - optind >= 3) { + help(argv[0]); + exit(EXIT_FAILURE); + } + av_register_all(); File file[2] = { - open_file(argv[1]), - open_file(argv[2]) + open_file(argv[optind]), + open_file(argv[optind + 1]) }; if (file[0].format_context->nb_streams != file[1].format_context->nb_streams) { @@ -148,12 +187,62 @@ int main(int argc, char** argv) Frame frame = file[0].complete_frames[0]; AVStream* stream = file[0].format_context->streams[frame.stream_index]; + if ( + file[0].format_context->streams[file[0].complete_frames[0].stream_index]->codec->sample_fmt != + file[1].format_context->streams[file[1].complete_frames[0].stream_index]->codec->sample_fmt) { + fprintf(stderr, "Audio sample formats differ.\n"); + exit(EXIT_FAILURE); + } + + if ( + file[0].format_context->streams[file[0].complete_frames[0].stream_index]->codec->channels != + file[1].format_context->streams[file[1].complete_frames[0].stream_index]->codec->channels) { + fprintf(stderr, "Audio channel counts differ.\n"); + exit(EXIT_FAILURE); + } + + if ( + file[0].complete_frames[0].frame->nb_samples != + file[1].complete_frames[0].frame->nb_samples) { + fprintf(stderr, "Audio frame counts differ.\n"); + exit(EXIT_FAILURE); + } + int const size = av_samples_get_buffer_size(0, stream->codec->channels, frame.frame->nb_samples, stream->codec->sample_fmt, 1); int const check = av_sample_fmt_is_planar(stream->codec->sample_fmt) ? stream->codec->channels : 1; for (int i = 0; i < check; ++i) { if (memcmp(file[0].complete_frames[0].frame->data[i], file[1].complete_frames[0].frame->data[i], size) != 0) { - fprintf(stderr, "Audio frames %d differ.\n", file[0].complete_frame_index); - exit(EXIT_FAILURE); + + int const channels = file[0].format_context->streams[file[0].complete_frames[0].stream_index]->codec->channels; + int const frames = frame.frame->nb_samples; + + bool different = false; + switch (stream->codec->sample_fmt) { + case AV_SAMPLE_FMT_S16: + { + int16_t* p = (int16_t *) (file[0].complete_frames[0].frame->data[0]); + int16_t* q = (int16_t *) (file[1].complete_frames[0].frame->data[0]); + for (int i = 0; i < channels; ++i) { + for (int j = 0; j < frames; ++j) { + if (abs(*p - *q) > audio_sample_tolerance) { + different = true; + fprintf(stderr, "\tsamples %d vs %d at channel %d frame %d\n", *p, *q, i, j); + } + ++p; + ++q; + } + } + break; + } + default: + fprintf(stderr, "Audio frames differ and could not be compared in detail.\n"); + break; + } + + if (different) { + fprintf(stderr, "Audio frames %d differ.\n", file[0].complete_frame_index); + exit(EXIT_FAILURE); + } } } |
