int main (int argc, char *argv[]) { GCContext gc_context; GMainLoop *mainLoop; GKeyFile *keyFile; GThread *displayThread; GThread *inputControllerThread; GThread *x11EventThread; int i; GCConfig config = { .movie_path = DEFAULT_MOVIE_PATH, .mask_path = DEFAULT_MASK_PATH, .controller_path = DEFAULT_CONTROLLER_PATH, .seconds_per_frame = DEFAULT_SECONDS_PER_FRAME, .easing_factor = DEFAULT_EASING_FACTOR, .frames_per_tick = 0, .diameter_controller = 0, .diameter_rim = 0, .ctr = 0, .fpr = 0, .number_of_frames = 0, .fullscreen = TRUE, .timeZone = NULL, }; Movie movie = { .planes = NULL, .frame_offset = 0, .fd_movie = -1, .frame = { .pitches = { FRAME_PITCH, 0, 0 } }, .fd_mask = -1, .mask = { .pitches = { MASK_PITCH, 0, 0 } }, .pre_load_surface = VDP_INVALID_HANDLE, .play_direction = DIRECTION_FORWARD, .ticks = 0, .new_frame = FALSE, .ease_to = TRUE, }; keyFile = g_key_file_new(); if (argc > 1 && g_key_file_load_from_file(keyFile, argv[1], G_KEY_FILE_NONE, NULL)) { if (g_key_file_has_group(keyFile, "MAIN")) { if (g_key_file_has_key(keyFile, "MAIN", "utc_offset", NULL)) config.timeZone = g_time_zone_new(g_key_file_get_string(keyFile, "MAIN", "utc_offset", NULL)); if (g_key_file_has_key(keyFile, "MAIN", "ease_to_time", NULL)) movie.ease_to = g_key_file_get_boolean(keyFile, "MAIN", "ease_to_time", NULL); } if (g_key_file_has_group(keyFile, "MOVIE")) { if (g_key_file_has_key(keyFile, "MOVIE", "file", NULL)) config.movie_path = g_key_file_get_string(keyFile, "MOVIE", "file", NULL); if (g_key_file_has_key(keyFile, "MOVIE", "mask", NULL)) config.mask_path = g_key_file_get_string(keyFile, "MOVIE", "mask", NULL); if (g_key_file_has_key(keyFile, "MOVIE", "seconds_per_frame", NULL)) config.seconds_per_frame = (float)g_key_file_get_double(keyFile, "MOVIE", "seconds_per_frame", NULL); if (g_key_file_has_key(keyFile, "MOVIE", "easing_factor", NULL)) config.easing_factor = (float)g_key_file_get_integer(keyFile, "MOVIE", "easing_factor", NULL); } if (g_key_file_has_group(keyFile, "CONTROLLER")) { if (g_key_file_has_key(keyFile, "CONTROLLER", "path", NULL)) config.controller_path = g_key_file_get_string(keyFile, "CONTROLLER", "path", NULL); if (g_key_file_has_key(keyFile, "CONTROLLER", "diameter_controller", NULL)) config.diameter_controller = (float)g_key_file_get_double(keyFile, "CONTROLLER", "diameter_controller", NULL); if (g_key_file_has_key(keyFile, "CONTROLLER", "diameter_rim", NULL)) config.diameter_rim = (float)g_key_file_get_double(keyFile, "CONTROLLER", "diameter_rim", NULL); if (g_key_file_has_key(keyFile, "CONTROLLER", "ctr", NULL)) config.ctr = (float)g_key_file_get_double(keyFile, "CONTROLLER", "ctr", NULL); if (g_key_file_has_key(keyFile, "CONTROLLER", "fpr", NULL)) config.fpr = (float)g_key_file_get_double(keyFile, "CONTROLLER", "fpr", NULL); if (g_key_file_has_key(keyFile, "CONTROLLER", "frames_per_tick", NULL)) config.frames_per_tick = (float)g_key_file_get_double(keyFile, "CONTROLLER", "frames_per_tick", NULL); } if (g_key_file_has_group(keyFile, "SCREEN")) { if (g_key_file_has_key(keyFile, "SCREEN", "fullscreen", NULL)) config.fullscreen = g_key_file_get_boolean(keyFile, "SCREEN", "fullscreen", NULL); } g_key_file_free(keyFile); } if (!config.timeZone) config.timeZone = g_time_zone_new_local(); if (!config.frames_per_tick && !(config.frames_per_tick = frames_per_tick(config.diameter_controller, config.diameter_rim, config.ctr, config.fpr))) { g_warning("No valid tick settings, using default frames per tick: %f", DEFAULT_FRAMES_PER_TICK); config.frames_per_tick = DEFAULT_FRAMES_PER_TICK; } config.movie_size = get_file_size(config.movie_path); config.number_of_frames = config.movie_size / FRAME_SIZE; mainLoop = g_main_loop_new(NULL, FALSE); gc_context.g_main_loop = mainLoop; gc_context.g_main_context = g_main_loop_get_context(mainLoop); gc_context.window_size.width = MOVIE_WIDTH; gc_context.window_size.height = MOVIE_HEIGHT; gc_context.exit = FALSE; gc_context.movie_context = &movie; gc_context.config = &config; g_message("movie file: %s", config.movie_path); g_message("movie size: %lu", config.movie_size); g_message("movie frames: %lu", config.number_of_frames); g_message("movie mask file: %s", config.mask_path); g_message("frames per minute: %f", get_frames_per_minute(&gc_context)); g_message("frames per day: %lu", get_frames_per_day(&gc_context)); g_message("frames per tick: %f", config.frames_per_tick); g_message("number of days: %d", get_number_of_days(&gc_context)); g_message("current day: %d", get_current_day(&gc_context)); if (movie.ease_to) { movie.ease_to_frame = get_frame_offset(&gc_context, GO_TO_RAND_DAY, DAY_OFFSET_NOW); g_message("ease to frame: %lu", movie.ease_to_frame); } x11_init(&gc_context); vdpau_init(&gc_context); load_movie(&gc_context); load_mask(&gc_context); g_cond_init(&movie.tick_cond); g_mutex_init(&movie.tick_lock); g_mutex_init(&movie.frame_lock); displayThread = g_thread_new("Display thread", display_thread, (gpointer)&gc_context); inputControllerThread = g_thread_new("Input controller thread", input_controller_thread, (gpointer)&gc_context); x11EventThread = g_thread_new("X11 Event thread", x11_event_thread, (gpointer)&gc_context); g_main_loop_run(mainLoop); gc_context.exit = TRUE; g_thread_join(displayThread); g_thread_join(inputControllerThread); g_thread_join(x11EventThread); g_cond_clear(&movie.tick_cond); g_mutex_clear(&movie.tick_lock); g_mutex_clear(&movie.frame_lock); g_time_zone_unref(config.timeZone); }
// This function must be called before // any other decoding functions int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int thread_count) { // Initialize the avcodec library and register codecs av_log_set_level(AV_LOG_QUIET); avcodec_register_all(); av_init_packet(&pkt); #ifdef HAVE_VDPAU if (perf_lvl & HARDWARE_ACCELERATION) { switch (videoFormat) { case VIDEO_FORMAT_H264: decoder = avcodec_find_decoder_by_name("h264_vdpau"); break; case VIDEO_FORMAT_H265: decoder = avcodec_find_decoder_by_name("hevc_vdpau"); break; } if (decoder != NULL) decoder_system = VDPAU; } #endif if (decoder == NULL) { decoder_system = SOFTWARE; switch (videoFormat) { case VIDEO_FORMAT_H264: decoder = avcodec_find_decoder_by_name("h264"); break; case VIDEO_FORMAT_H265: decoder = avcodec_find_decoder_by_name("hevc"); break; } if (decoder == NULL) { printf("Couldn't find decoder\n"); return -1; } } decoder_ctx = avcodec_alloc_context3(decoder); if (decoder_ctx == NULL) { printf("Couldn't allocate context"); return -1; } if (perf_lvl & DISABLE_LOOP_FILTER) // Skip the loop filter for performance reasons decoder_ctx->skip_loop_filter = AVDISCARD_ALL; if (perf_lvl & LOW_LATENCY_DECODE) // Use low delay single threaded encoding decoder_ctx->flags |= CODEC_FLAG_LOW_DELAY; if (perf_lvl & SLICE_THREADING) decoder_ctx->thread_type = FF_THREAD_SLICE; else { decoder_ctx->flags2 |= CODEC_FLAG2_FAST; decoder_ctx->delay = 0; decoder_ctx->thread_type = FF_THREAD_FRAME; } decoder_ctx->thread_count = thread_count; decoder_ctx->width = width; decoder_ctx->height = height; decoder_ctx->pix_fmt = AV_PIX_FMT_YUV420P; int err = avcodec_open2(decoder_ctx, decoder, NULL); if (err < 0) { printf("Couldn't open codec"); return err; } dec_frame = av_frame_alloc(); if (dec_frame == NULL) { printf("Couldn't allocate frame"); return -1; } #ifdef HAVE_VDPAU if (decoder_system == VDPAU) vdpau_init(decoder_ctx, width, height); #endif return 0; }