#define _XOPEN_SOURCE 500 #include #include #include #include #include "video_decode.h" #include "util.h" static inline void pswap(void **p1, void **p2) { void *tmp; tmp = *p1; *p1 = *p2; *p2 = tmp; } /* print time in format: "hh:mm:ss.xxx" */ static void print_time(int64_t msec) { int hh = msec / 1000 / 60 / 60; msec -= hh * 1000 * 60 * 60; int mm = msec / 1000 / 60; msec -= mm * 1000 * 60; int ss = msec / 1000; msec -= ss * 1000; printf("%02d:%02d:%02d.%03jd", hh, mm, ss, msec); } static void start_new_szene(int64_t prev_szene_end, int64_t start) { static int prev_dts_start = 0; print_time(prev_dts_start); printf(" "); print_time(prev_szene_end - prev_dts_start); prev_dts_start = start; } static double frame_diff(struct video_frame *frame_a, struct video_frame *frame_b) { double average = 0; uint8_t *row_a = frame_a->data, *col_a = NULL; uint8_t *row_b = frame_b->data, *col_b = NULL; for (int y = 0; y < frame_a->height; ++y) { col_a = row_a; col_b = row_b; for (int x = 0; x < frame_a->width; ++x) { average += abs(*col_a - *col_b); col_a++; col_b++; } row_a += frame_a->stride; row_b += frame_b->stride; } return average / (frame_a->width * frame_a->height); } static double frame_average(struct video_frame *frame) { double average = 0; uint8_t *row = frame->data; uint8_t *col = NULL; for (int y = 0; y < frame->height; ++y) { col = row; for (int x = 0; x < frame->width; ++x) { average += *col; col++; } row += frame->stride; } return average / (frame->width * frame->height); } static void usage(void) { fprintf(stderr, "advtime [-a] [-d] FILE\n"); exit(EXIT_FAILURE); } int main(int argc, char **argv) { struct video_decode *vd; struct video_frame *frame_a = NULL, *frame_b = NULL; int ret, ch; int diff_flag = 0, average_flag = 0, frame_flag = 0, showcut_flag = 0; int64_t timestamp = 0; double diff = 0.0, old_diff = 0.0; char filename[BUFSIZ]; while ((ch = getopt(argc, argv, "adfs")) != -1) { switch (ch) { case 'a': average_flag = 1; break; case 'd': diff_flag = 1; break; case 'f': diff_flag = 1; break; case 's': showcut_flag = 1; break; default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc < 1) usage(); if (argc == 2 && strtol(argv[1], NULL, 10) > 0) timestamp = strtol(argv[1], NULL, 10); ret = video_decode_init(&vd, argv[0], timestamp); if (ret < 0) return -ret; ret = video_decode_get_frame(vd, &frame_a); if (ret < 0) return -ret; /* printf("fps: %d\n", vd->fmt_ctx->fps_probe_size); printf("streams: %d\n", vd->fmt_ctx->nb_streams); printf("filename: %s\n", vd->fmt_ctx->filename); printf("streams: %d\n", vd->fmt_ctx->streams[0]->duration); printf("duration: %d\n", vd->fmt_ctx->streams[1]->duration); printf("nb_frames: %d\n", vd->fmt_ctx->streams[0]->nb_frames); printf("avg frame rate: %f\n", av_q2d(vd->fmt_ctx->streams[0]->avg_frame_rate)); printf("real frame rate: %f\n", av_q2d(vd->fmt_ctx->streams[0]->r_frame_rate)); printf("first: %ji\n", vd->fmt_ctx->streams[0]->first_dts); printf("cur: %ji\n", vd->fmt_ctx->streams[0]->cur_dts); printf("reference: %ji\n", vd->fmt_ctx->streams[0]->reference_dts); */ for (int i = 0; video_decode_get_frame(vd, &frame_b) > 0; ++i) { if (frame_flag) /* print frame number */ printf("%d\t", i); if (average_flag) /* print frame average */ printf("%f", frame_average(frame_a)); if (average_flag && diff_flag) printf("\t"); if (diff_flag) { diff = frame_diff(frame_a, frame_b); // printf("%f", diff); // printf("\t%f", (diff - old_diff)); old_diff = diff; } if (diff > 40.0) { start_new_szene(frame_a->dts, frame_b->dts); if (!frame_flag && !average_flag) { printf("\n"); fflush(stdout); } if (showcut_flag == 1) { snprintf(filename, BUFSIZ, "img/%04i.pgm", i); frame_mix(frame_a, frame_b); if (pgm_save(frame_a->data, frame_a->stride, frame_a->width, frame_a->height, filename) < 0) exit(EXIT_FAILURE); } } if (frame_flag || average_flag) { printf("\n"); fflush(stdout); } pswap((void **)&frame_a, (void **)&frame_b); } if (diff_flag) { /* acutally we just finalize the last frame here */ start_new_szene(frame_a->dts, 0); printf("\n"); } video_decode_free_frame(&frame_a); video_decode_free_frame(&frame_b); video_decode_uninit(&vd); return EXIT_SUCCESS; }