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 = avcodec_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 #ifdef FFCMP_HAVE_AVUTIL_FRAME_H
105 file->current_frame = av_frame_alloc();
107 file->current_frame = avcodec_alloc_frame();
109 if (!file->current_frame) {
110 fprintf(stderr, "Could not allocate frame.\n");
115 copy_packet.data -= decode_result;
116 copy_packet.size -= decode_result;
120 fprintf(stderr, "Warning: ignoring other frame.\n");
128 void help(char const * name)
130 fprintf(stderr, "Syntax: %s [options] file1 file2\n", name);
131 fprintf(stderr, "Options are:\n");
132 fprintf(stderr, "\t--audio-sample-tolerance, -t specify allowable absolute difference in audio sample value\n");
135 int main(int argc, char** argv)
137 int audio_sample_tolerance = 0;
139 int option_index = 0;
141 static struct option long_options[] = {
142 { "help", no_argument, 0, 'h' },
143 { "audio-sample-tolerance", required_argument, 0, 't' },
147 int c = getopt_long(argc, argv, "ht:", long_options, &option_index);
158 audio_sample_tolerance = atoi(optarg);
163 if (argc - optind < 2 || argc - optind >= 3) {
171 open_file(argv[optind]),
172 open_file(argv[optind + 1])
175 if (file[0].format_context->nb_streams != file[1].format_context->nb_streams) {
176 fprintf(stderr, "Files have different stream counts.\n");
180 for (int i = 0; i < file[0].format_context->nb_streams; ++i) {
181 if (file[0].format_context->streams[i]->codec->codec_type != file[1].format_context->streams[i]->codec->codec_type) {
182 fprintf(stderr, "Stream %d has different code type.\n", i);
189 read_frame(&file[0]),
193 if (done[0] != done[1]) {
194 fprintf(stderr, "Files are different lengths.\n");
198 while (file[0].n_complete_frames > 0 && file[1].n_complete_frames > 0) {
199 Frame frame = file[0].complete_frames[0];
200 AVStream* stream = file[0].format_context->streams[frame.stream_index];
203 file[0].format_context->streams[file[0].complete_frames[0].stream_index]->codec->sample_fmt !=
204 file[1].format_context->streams[file[1].complete_frames[0].stream_index]->codec->sample_fmt) {
205 fprintf(stderr, "Audio sample formats differ.\n");
210 file[0].format_context->streams[file[0].complete_frames[0].stream_index]->codec->channels !=
211 file[1].format_context->streams[file[1].complete_frames[0].stream_index]->codec->channels) {
212 fprintf(stderr, "Audio channel counts differ.\n");
217 file[0].complete_frames[0].frame->nb_samples !=
218 file[1].complete_frames[0].frame->nb_samples) {
219 fprintf(stderr, "Audio frame counts differ.\n");
223 int const size = av_samples_get_buffer_size(0, stream->codec->channels, frame.frame->nb_samples, stream->codec->sample_fmt, 1);
224 int const check = av_sample_fmt_is_planar(stream->codec->sample_fmt) ? stream->codec->channels : 1;
225 for (int i = 0; i < check; ++i) {
226 if (memcmp(file[0].complete_frames[0].frame->data[i], file[1].complete_frames[0].frame->data[i], size) != 0) {
228 int const channels = file[0].format_context->streams[file[0].complete_frames[0].stream_index]->codec->channels;
229 int const frames = frame.frame->nb_samples;
231 bool different = false;
232 switch (stream->codec->sample_fmt) {
233 case AV_SAMPLE_FMT_S16:
235 int16_t* p = (int16_t *) (file[0].complete_frames[0].frame->data[0]);
236 int16_t* q = (int16_t *) (file[1].complete_frames[0].frame->data[0]);
237 for (int i = 0; i < channels; ++i) {
238 for (int j = 0; j < frames; ++j) {
239 if (abs(*p - *q) > audio_sample_tolerance) {
241 fprintf(stderr, "\tsamples %d vs %d at channel %d frame %d\n", *p, *q, i, j);
250 fprintf(stderr, "Audio frames differ and could not be compared in detail.\n");
255 fprintf(stderr, "Audio frames %d differ.\n", file[0].complete_frame_index);
261 memmove(file[0].complete_frames, file[0].complete_frames + 1, (MAX_COMPLETE_FRAMES - 1) * sizeof(Frame));
262 memmove(file[1].complete_frames, file[1].complete_frames + 1, (MAX_COMPLETE_FRAMES - 1) * sizeof(Frame));
263 --file[0].n_complete_frames;
264 --file[1].n_complete_frames;
265 ++file[0].complete_frame_index;
266 ++file[1].complete_frame_index;