summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2018-02-13 10:32:18 +0000
committerCarl Hetherington <cth@carlh.net>2018-02-13 10:32:18 +0000
commit39dfbac23f0b044b3597d86ed2ca0a05251dd14c (patch)
tree0244103367e4511821308eba9112b8c1a9b959a8
parent699f178779fdccd89a823ca2b61fc6fe476dfee1 (diff)
Proper inspection of audio frames; support for audio tolerance.
-rw-r--r--ffcmp.c97
1 files changed, 93 insertions, 4 deletions
diff --git a/ffcmp.c b/ffcmp.c
index 786ad949..0ba9af80 100644
--- a/ffcmp.c
+++ b/ffcmp.c
@@ -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);
+ }
}
}