image_t * get_next_frame (bool_t store_wfa, int enlarge_factor, int smoothing, const char *reference_frame, format_e format, video_t *video, dectimer_t *timer, wfa_t *orig_wfa, bitfile_t *input) /* * Get next frame of the WFA 'video' from stream 'input'. * 'orig_wfa' is the constant part of the WFA used by all frames. * Depending on values of 'enlarge_factor' and 'smoothing' enlarge and * smooth image, respectively. * If 'store_wfa' is TRUE, then store WFA structure of reference frames * (used by analysis tool xwfa). * If 'reference_frame' is not NULL, then load image 'reference_frame' * from disk. * 'format' gives the color format to be used (either 4:2:0 or 4:4:4). * If 'timer' is not NULL, then accumulate running time statistics. * * Return value: * pointer to decoded frame * * Side effects: * 'video' and 'timer' struct are modified. */ { image_t *frame = NULL; /* current frame */ image_t *sframe = NULL; /* current smoothed frame */ bool_t current_frame_is_future_frame = NO; if (video->future_display == video->display) { /* * Future frame is already computed since it has been used * as reference frame. So just return the stored frame. */ if (video->frame) /* discard current frame */ free_image (video->frame); video->frame = video->future; video->future = NULL; if (video->sframe) /* discard current (smoothed) frame */ free_image (video->sframe); video->sframe = video->sfuture; video->sfuture = NULL; if (store_wfa) copy_wfa (video->wfa, video->wfa_future); video->display++; if (!store_wfa) video->wfa = NULL; } else { do /* compute next frame(s) */ { unsigned frame_number; /* current frame number */ clock_t ptimer; unsigned int stop_timer [3]; wfa_t *tmp_wfa = NULL; if (!store_wfa) video->wfa = orig_wfa; else { tmp_wfa = alloc_wfa (NO); copy_wfa (tmp_wfa, video->wfa); copy_wfa (video->wfa, orig_wfa); } /* * First step: read WFA from disk */ prg_timer (&ptimer, START); frame_number = read_next_wfa (video->wfa, input); stop_timer [0] = prg_timer (&ptimer, STOP); if (timer) { timer->input [video->wfa->frame_type] += stop_timer [0]; timer->frames [video->wfa->frame_type]++; } /* * Read reference frame from disk if required * (i.e., 1st frame is of type B or P) */ if (video->display == 0 && video->wfa->frame_type != I_FRAME) { if (!reference_frame) error ("First frame is %c-frame but no " "reference frame is given.", video->wfa->frame_type == B_FRAME ? 'B' : 'P'); video->frame = read_image_file (reference_frame); video->sframe = NULL; } /* * Depending on current frame type update past and future frames */ if (video->wfa->frame_type == I_FRAME) { if (video->past) /* discard past frame */ free_image (video->past); video->past = NULL; if (video->future) /* discard future frame */ free_image (video->future); video->future = NULL; if (video->sfuture) /* discard (smoothed) future frame */ free_image (video->sfuture); video->sfuture = NULL; if (video->frame) /* discard current frame */ free_image (video->frame); video->frame = NULL; if (video->sframe) /* discard current (smoothed) frame */ free_image (video->sframe); video->sframe = NULL; } else if (video->wfa->frame_type == P_FRAME) { if (video->past) /* discard past frame */ free_image (video->past); video->past = video->frame; /* past <- current frame */ video->frame = NULL; if (video->sframe) /* discard current (smoothed) frame */ free_image (video->sframe); video->sframe = NULL; if (store_wfa) copy_wfa (video->wfa_past, tmp_wfa); if (video->future) /* discard future frame */ free_image (video->future); video->future = NULL; if (video->sfuture) /* discard (smoothed) future frame */ free_image (video->sfuture); video->sfuture = NULL; } else /* B_FRAME */ { if (current_frame_is_future_frame) { if (video->future) /* discard future frame */ free_image (video->future); video->future = frame; /* future <- current frame */ if (video->sfuture) /* discard (smoothed) future frame */ free_image (video->sfuture); video->sfuture = sframe; /* future <- current (smoothed) */ if (store_wfa) copy_wfa (video->wfa_future, tmp_wfa); if (video->frame) /* discard current frame */ free_image (video->frame); video->frame = NULL; if (video->sframe) /* discard current (smoothed) frame */ free_image (video->sframe); video->sframe = NULL; frame = NULL; sframe = NULL; } else { if (video->wfa->wfainfo->B_as_past_ref == YES) { if (video->past) /* discard past frame */ free_image (video->past); video->past = video->frame; /* past <- current frame */ video->frame = NULL; if (video->sframe) /* discard current (smoothed) frame */ free_image (video->sframe); video->sframe = NULL; if (store_wfa) copy_wfa (video->wfa_past, tmp_wfa); } else { if (video->frame) /* discard current */ free_image (video->frame); video->frame = NULL; if (video->sframe) /* discard current (smoothed) frame */ free_image (video->sframe); video->sframe = NULL; } } } if (tmp_wfa) free_wfa (tmp_wfa); current_frame_is_future_frame = NO; /* * Second step: decode image * Optionally enlarge image if specified by option 'enlarge_factor'. */ { unsigned orig_width, orig_height; stop_timer [0] = stop_timer [1] = stop_timer [2] = 0; enlarge_image (enlarge_factor, format, (video->wfa->wfainfo->color && format == FORMAT_4_2_0) ? video->wfa->tree [video->wfa->tree [video->wfa->root_state][0]][0] : -1, video->wfa); if (enlarge_factor > 0) { orig_width = video->wfa->wfainfo->width << enlarge_factor; orig_height = video->wfa->wfainfo->height << enlarge_factor; } else { orig_width = video->wfa->wfainfo->width >> - enlarge_factor; orig_height = video->wfa->wfainfo->height >> - enlarge_factor; if (orig_width & 1) orig_width++; if (orig_height & 1) orig_height++; } frame = decode_image (orig_width, orig_height, format, timer != NULL ? stop_timer : NULL, video->wfa); if (timer) { timer->preprocessing [video->wfa->frame_type] += stop_timer [0]; timer->decoder [video->wfa->frame_type] += stop_timer [1]; timer->cleanup [video->wfa->frame_type] += stop_timer [2]; } } /* * Third step: restore motion compensation */ if (video->wfa->frame_type != I_FRAME) { prg_timer (&ptimer, START); restore_mc (enlarge_factor, frame, video->past, video->future, video->wfa); stop_timer [0] = prg_timer (&ptimer, STOP); if (timer) timer->motion [video->wfa->frame_type] += stop_timer [0]; } /* * Fourth step: smooth image along partitioning borders */ prg_timer (&ptimer, START); if (smoothing < 0) /* smoothing not changed by user */ smoothing = video->wfa->wfainfo->smoothing; if (smoothing > 0 && smoothing <= 100) { sframe = clone_image (frame); smooth_image (smoothing, video->wfa, sframe); } else sframe = NULL; stop_timer [0] = prg_timer (&ptimer, STOP); if (timer) timer->smooth [video->wfa->frame_type] += stop_timer [0]; if (frame_number == video->display) { video->display++; video->frame = frame; video->sframe = sframe; frame = NULL; sframe = NULL; } else if (frame_number > video->display) { video->future_display = frame_number; current_frame_is_future_frame = YES; } if (!store_wfa) remove_states (video->wfa->basis_states, video->wfa); } while (!video->frame); if (!store_wfa) video->wfa = NULL; } return video->sframe ? video->sframe : video->frame; }
image_t * decode_image (unsigned orig_width, unsigned orig_height, format_e format, unsigned *dec_timer, const wfa_t *wfa) /* * Compute image which is represented by the given 'wfa'. * 'orig_width'x'orig_height' gives the resolution of the image at * coding time. Use 4:2:0 subsampling or 4:4:4 'format' for color images. * If 'dec_timer' is given, accumulate running time statistics. * * Return value: * pointer to decoded image * * Side effects: * '*dectimer' is changed if 'dectimer' != NULL. */ { unsigned root_state [3]; /* root of bintree for each band */ unsigned width, height; /* computed image size */ image_t *frame; /* regenerated frame */ word_t **images; /* pointer to array of pointers to state images */ u_word_t *offsets; /* pointer to array of state image offsets */ unsigned max_level; /* max. level of state with approx. */ unsigned state; clock_t ptimer; prg_timer (&ptimer, START); /* * Compute root of bintree for each color band */ if (wfa->wfainfo->color) { root_state [Y] = wfa->tree [wfa->tree [wfa->root_state][0]][0]; root_state [Cb] = wfa->tree [wfa->tree [wfa->root_state][0]][1]; root_state [Cr] = wfa->tree [wfa->tree [wfa->root_state][1]][0]; } else root_state [GRAY] = wfa->root_state; /* * Compute maximum level of a linear combination */ for (max_level = 0, state = wfa->basis_states; state < wfa->states; state++) if (isedge (wfa->into [state][0][0]) || isedge (wfa->into [state][1][0])) max_level = max (max_level, wfa->level_of_state [state]); /* * Allocate frame buffer for decoded image */ compute_actual_size (format == FORMAT_4_2_0 ? root_state [Y] : MAXSTATES, &width, &height, wfa); width = max (width, orig_width); height = max (height, orig_height); frame = alloc_image (width, height, wfa->wfainfo->color, format); /* * Allocate buffers for intermediate state images */ if (wfa->wfainfo->color) { wfa->level_of_state [wfa->root_state] = 128; wfa->level_of_state [wfa->tree[wfa->root_state][0]] = 128; wfa->level_of_state [wfa->tree[wfa->root_state][1]] = 128; } alloc_state_images (&images, &offsets, frame, root_state, 0, max_level, format, wfa); if (dec_timer) dec_timer [0] += prg_timer (&ptimer, STOP); /* * Decode all state images, forming the complete image. */ prg_timer (&ptimer, START); compute_state_images (max_level, images, offsets, wfa); if (dec_timer) dec_timer [1] += prg_timer (&ptimer, STOP); /* * Cleanup buffers used for intermediate state images */ prg_timer (&ptimer, START); free_state_images (max_level, frame->color, images, offsets, root_state, 0, format, wfa); /* * Crop decoded image if the image size differs. */ if (orig_width != width || orig_height != height) { frame->height = orig_height; frame->width = orig_width; if (orig_width != width) { color_e band; /* current color band */ word_t *src, *dst; /* source and destination pointers */ unsigned y; /* current row */ for (band = first_band (frame->color); band <= last_band (frame->color); band++) { src = dst = frame->pixels [band]; for (y = orig_height; y; y--) { memmove (dst, src, orig_width * sizeof (word_t)); dst += orig_width; src += width; } if (format == FORMAT_4_2_0 && band == Y) { orig_width >>= 1; orig_height >>= 1; width >>= 1; } }
static void video_decoder (const char *wfa_name, const char *image_name, bool_t panel, bool_t double_resolution, int fps, fiasco_d_options_t *options) { do { unsigned width, height, frames, n; fiasco_decoder_t *decoder_state; char *filename; char *basename; /* basename of decoded frame */ char *suffix; /* suffix of decoded frame */ unsigned frame_time; if (!(decoder_state = fiasco_decoder_new (wfa_name, options))) error (fiasco_get_error_message ()); if (fps <= 0) /* then use value of FIASCO file */ fps = fiasco_decoder_get_rate (decoder_state); frame_time = fps ? (1000 / fps) : (1000 / 25); if (!(width = fiasco_decoder_get_width (decoder_state))) error (fiasco_get_error_message ()); if (!(height = fiasco_decoder_get_height (decoder_state))) error (fiasco_get_error_message ()); if (!(frames = fiasco_decoder_get_length (decoder_state))) error (fiasco_get_error_message ()); get_output_template (image_name, wfa_name, fiasco_decoder_is_color (decoder_state), &basename, &suffix); filename = Calloc (strlen (basename) + strlen (suffix) + 2 + 10 + (int) (log10 (frames) + 1), sizeof (char)); for (n = 0; n < frames; n++) { clock_t fps_timer; /* frames per second timer struct */ prg_timer (&fps_timer, START); if (image_name) /* just write frame to disk */ { if (frames == 1) /* just one image */ { if (streq (image_name, "-")) strcpy (filename, "-"); else sprintf (filename, "%s.%s", basename, suffix); } else { fprintf (stderr, "Decoding frame %d to file `%s.%0*d.%s\n", n, basename, (int) (log10 (frames - 1) + 1), n, suffix); sprintf (filename, "%s.%0*d.%s", basename, (int) (log10 (frames - 1) + 1), n, suffix); } if (!fiasco_decoder_write_frame (decoder_state, filename)) error (fiasco_get_error_message ()); } } free (filename); fiasco_decoder_delete (decoder_state); } while (panel); }