1 #include <libavformat/avformat.h>
2 #ifdef FFCMP_HAVE_AVUTIL_FRAME_H
3 #include <libavutil/frame.h>
5 #include <libavcodec/avcodec.h>
10 #define MAX_COMPLETE_FRAMES 64
20 AVFormatContext* format_context;
23 AVFrame* current_frame;
24 Frame complete_frames[MAX_COMPLETE_FRAMES];
25 int n_complete_frames;
26 int complete_frame_index;
30 open_file(char* filename)
34 file.format_context = avformat_alloc_context();
35 if (!file.format_context) {
36 fprintf(stderr, "Could not create format context.\n");
39 int e = avformat_open_input(&file.format_context, filename, 0, 0);
41 fprintf(stderr, "Failed to open %s\n", filename);
44 for (int i = 0; i < file.format_context->nb_streams; ++i) {
45 file.codec = avcodec_find_decoder(file.format_context->streams[i]->codec->codec_id);
47 fprintf(stderr, "Could not find codec.\n");
50 if (avcodec_open2(file.format_context->streams[i]->codec, file.codec, 0) < 0) {
51 fprintf(stderr, "Could not open codec.\n");
56 #ifdef FFCMP_HAVE_AVUTIL_FRAME_H
57 file.current_frame = av_frame_alloc();
59 file.current_frame = av_alloc_frame();
61 if (!file.current_frame) {
62 fprintf(stderr, "Could not allocate frame.\n");
66 file.n_complete_frames = 0;
67 file.complete_frame_index = 0;
73 read_frame(File* file)
75 int r = av_read_frame(file->format_context, &file->packet);
76 if (r == AVERROR_EOF) {
81 fprintf(stderr, "Failed to read frame.\n");
85 switch (file->format_context->streams[file->packet.stream_index]->codec->codec_type) {
86 case AVMEDIA_TYPE_VIDEO:
87 fprintf(stderr, "Warning: ignoring video frame.\n");
89 case AVMEDIA_TYPE_AUDIO:
91 AVPacket copy_packet = file->packet;
92 while (copy_packet.size > 0) {
94 int decode_result = avcodec_decode_audio4(file->format_context->streams[file->packet.stream_index]->codec, file->current_frame, &frame_finished, ©_packet);
95 if (decode_result < 0) {
96 fprintf(stderr, "Failed to decode audio.\n");
100 if (frame_finished) {
101 file->complete_frames[file->n_complete_frames].frame = file->current_frame;
102 file->complete_frames[file->n_complete_frames].stream_index = file->packet.stream_index;
103 ++file->n_complete_frames;
104 file->current_frame = av_frame_alloc();
105 if (!file->current_frame) {
106 fprintf(stderr, "Could not allocate frame.\n");
111 copy_packet.data -= decode_result;
112 copy_packet.size -= decode_result;
116 fprintf(stderr, "Warning: ignoring other frame.\n");
124 void help(char const * name)
126 fprintf(stderr, "Syntax: %s [options] file1 file2\n", name);
127 fprintf(stderr, "Options are:\n");
128 fprintf(stderr, "\t--audio-sample-tolerance, -t specify allowable absolute difference in audio sample value\n");
131 int main(int argc, char** argv)
133 int audio_sample_tolerance = 0;
135 int option_index = 0;
137 static struct option long_options[] = {
138 { "help", no_argument, 0, 'h' },
139 { "audio-sample-tolerance", required_argument, 0, 't' },
143 int c = getopt_long(argc, argv, "ht:", long_options, &option_index);
154 audio_sample_tolerance = atoi(optarg);
159 if (argc - optind < 2 || argc - optind >= 3) {
167 open_file(argv[optind]),
168 open_file(argv[optind + 1])
171 if (file[0].format_context->nb_streams != file[1].format_context->nb_streams) {
172 fprintf(stderr, "Files have different stream counts.\n");
176 for (int i = 0; i < file[0].format_context->nb_streams; ++i) {
177 if (file[0].format_context->streams[i]->codec->codec_type != file[1].format_context->streams[i]->codec->codec_type) {
178 fprintf(stderr, "Stream %d has different code type.\n", i);
185 read_frame(&file[0]),
189 if (done[0] != done[1]) {
190 fprintf(stderr, "Files are different lengths.\n");
194 while (file[0].n_complete_frames > 0 && file[1].n_complete_frames > 0) {
195 Frame frame = file[0].complete_frames[0];
196 AVStream* stream = file[0].format_context->streams[frame.stream_index];
199 file[0].format_context->streams[file[0].complete_frames[0].stream_index]->codec->sample_fmt !=
200 file[1].format_context->streams[file[1].complete_frames[0].stream_index]->codec->sample_fmt) {
201 fprintf(stderr, "Audio sample formats differ.\n");
206 file[0].format_context->streams[file[0].complete_frames[0].stream_index]->codec->channels !=
207 file[1].format_context->streams[file[1].complete_frames[0].stream_index]->codec->channels) {
208 fprintf(stderr, "Audio channel counts differ.\n");
213 file[0].complete_frames[0].frame->nb_samples !=
214 file[1].complete_frames[0].frame->nb_samples) {
215 fprintf(stderr, "Audio frame counts differ.\n");
219 int const size = av_samples_get_buffer_size(0, stream->codec->channels, frame.frame->nb_samples, stream->codec->sample_fmt, 1);
220 int const check = av_sample_fmt_is_planar(stream->codec->sample_fmt) ? stream->codec->channels : 1;
221 for (int i = 0; i < check; ++i) {
222 if (memcmp(file[0].complete_frames[0].frame->data[i], file[1].complete_frames[0].frame->data[i], size) != 0) {
224 int const channels = file[0].format_context->streams[file[0].complete_frames[0].stream_index]->codec->channels;
225 int const frames = frame.frame->nb_samples;
227 bool different = false;
228 switch (stream->codec->sample_fmt) {
229 case AV_SAMPLE_FMT_S16:
231 int16_t* p = (int16_t *) (file[0].complete_frames[0].frame->data[0]);
232 int16_t* q = (int16_t *) (file[1].complete_frames[0].frame->data[0]);
233 for (int i = 0; i < channels; ++i) {
234 for (int j = 0; j < frames; ++j) {
235 if (abs(*p - *q) > audio_sample_tolerance) {
237 fprintf(stderr, "\tsamples %d vs %d at channel %d frame %d\n", *p, *q, i, j);
246 fprintf(stderr, "Audio frames differ and could not be compared in detail.\n");
251 fprintf(stderr, "Audio frames %d differ.\n", file[0].complete_frame_index);
257 memmove(file[0].complete_frames, file[0].complete_frames + 1, (MAX_COMPLETE_FRAMES - 1) * sizeof(Frame));
258 memmove(file[1].complete_frames, file[1].complete_frames + 1, (MAX_COMPLETE_FRAMES - 1) * sizeof(Frame));
259 --file[0].n_complete_frames;
260 --file[1].n_complete_frames;
261 ++file[0].complete_frame_index;
262 ++file[1].complete_frame_index;