int main(void) { int n1, d1; /* numerator, denominator of first fraction */ int n2, d2; /* numerator, denominator of second fraction */ char op; /* arithmetic operator + - * or / */ char again; /* y or n depending on user's desire to continue */ int n_ans, /* numerator, denominator of answer */ d_ans; /* While the user wants to continue, gets and solves arithmetic problems with common fractions. */ do { /* Gets a fraction problem */ scan_fraction(&n1, &d1); op = get_operator(); scan_fraction(&n2, &d2); /* Computes the result */ switch (op) { case '+': add_fractions(n1, d1, n2, d2, &n_ans, &d_ans); break; case '-': add_fractions(n1, d1, -n2, d2, &n_ans, &d_ans); break; case '*': multiply_fractions(n1, d1, n2, d2, &n_ans, &d_ans); break; case '/': multiply_fractions(n1, d1, d2, n2, &n_ans, &d_ans); } reduce_fraction(&n_ans, &d_ans); /* Displays problem and result */ printf("\n"); print_fraction(n1, d1); printf(" %c ", op); print_fraction(n2, d2); printf(" = "); print_fraction(n_ans, d_ans); /* Asks user about doing another problem */ printf("\nDo another problem? (y/n) > "); scanf(" %c", &again); } while (again == 'Y' || again == 'y'); return(0); }
/* * c) Subtract the fraction f2 from the fraction f1. */ void test_part_c(void){ struct fraction diff, f1, f2; printf("Enter first fraction (a/b): "); scanf("%d / %d", &f1.numerator, &f1.denominator); printf("Enter second fraction (a/b): "); scanf("%d / %d", &f2.numerator, &f2.denominator); diff = subtract_fractions(f1, f2); diff = reduce_fraction(diff); printf("Difference of the fractions: %d/%d\n", diff.numerator, diff.denominator); }
/* * b) Add the fractions f1 and f2. */ void test_part_b(void){ struct fraction sum, f1, f2; printf("Enter first fraction (a/b): "); scanf("%d / %d", &f1.numerator, &f1.denominator); printf("Enter second fraction (a/b): "); scanf("%d / %d", &f2.numerator, &f2.denominator); sum = add_fractions(f1, f2); sum = reduce_fraction(sum); printf("Sum of the fractions: %d/%d\n", sum.numerator, sum.denominator); }
/* * e) Divide the fraction f1 by the fraction f2. */ void test_part_e(void){ struct fraction quotient, f1, f2; printf("Enter first fraction (a/b): "); scanf("%d / %d", &f1.numerator, &f1.denominator); printf("Enter second fraction (a/b): "); scanf("%d / %d", &f2.numerator, &f2.denominator); quotient = divide_fractions(f1, f2); quotient = reduce_fraction(quotient); printf("Product of the fractions: %d/%d\n", quotient.numerator, quotient.denominator); }
/* * d) Multiply the fractions f1 and f2. */ void test_part_d(void){ struct fraction product, f1, f2; printf("Enter first fraction (a/b): "); scanf("%d / %d", &f1.numerator, &f1.denominator); printf("Enter second fraction (a/b): "); scanf("%d / %d", &f2.numerator, &f2.denominator); product = multiply_fractions(f1, f2); product = reduce_fraction(product); printf("Product of the fractions: %d/%d\n", product.numerator, product.denominator); }
/* * a) Reduce the fraction f to lowest terms. Hint: To reduce a fraction to * lowest terms, first compute the greatest common divisor (GCD) of the * numerator and denominator. Then divide both the numerator and denominator * by the GCD. */ void test_part_a(void){ struct fraction f; printf("Enter an unreduced fraction (a/b): "); scanf("%d / %d", &f.numerator, &f.denominator); #ifdef DEBUG printf("Unreduced fraction: %d/%d\n", f.numerator, f.denominator); #endif f = reduce_fraction(f); printf("Reduced fraction: %d/%d\n", f.numerator, f.denominator); return; }
/** * Divides the destination fraction by the source fraction. * * @param p0 the destination fraction * @param p1 the source fraction */ void calculate_fraction_divide(void* p0, void* p1) { log_terminated_message((void*) DEBUG_LEVEL_LOG_MODEL, (void*) L"Calculate fraction divide."); // The destination numerator and denominator. void* dn = *NULL_POINTER_MEMORY_MODEL; void* dd = *NULL_POINTER_MEMORY_MODEL; // The source numerator and denominator. void* sn = *NULL_POINTER_MEMORY_MODEL; void* sd = *NULL_POINTER_MEMORY_MODEL; // Get destination numerator and denominator. copy_array_forward((void*) &dn, p0, (void*) POINTER_PRIMITIVE_MEMORY_ABSTRACTION, (void*) PRIMITIVE_MEMORY_MODEL_COUNT, (void*) VALUE_PRIMITIVE_MEMORY_NAME, (void*) NUMERATOR_FRACTION_MEMORY_NAME); copy_array_forward((void*) &dd, p0, (void*) POINTER_PRIMITIVE_MEMORY_ABSTRACTION, (void*) PRIMITIVE_MEMORY_MODEL_COUNT, (void*) VALUE_PRIMITIVE_MEMORY_NAME, (void*) DENOMINATOR_FRACTION_MEMORY_NAME); // Get source numerator and denominator. copy_array_forward((void*) &sn, p1, (void*) POINTER_PRIMITIVE_MEMORY_ABSTRACTION, (void*) PRIMITIVE_MEMORY_MODEL_COUNT, (void*) VALUE_PRIMITIVE_MEMORY_NAME, (void*) NUMERATOR_FRACTION_MEMORY_NAME); copy_array_forward((void*) &sd, p1, (void*) POINTER_PRIMITIVE_MEMORY_ABSTRACTION, (void*) PRIMITIVE_MEMORY_MODEL_COUNT, (void*) VALUE_PRIMITIVE_MEMORY_NAME, (void*) DENOMINATOR_FRACTION_MEMORY_NAME); // Multiply destination- and source numerators and denominators CROSS-WISE. calculate_integer_multiply(dn, sd); calculate_integer_multiply(dd, sn); reduce_fraction(p0); }
int libavsmash_video_setup_timestamp_info ( libavsmash_video_decode_handler_t *vdhp, libavsmash_video_output_handler_t *vohp, int64_t *framerate_num, int64_t *framerate_den ) { int err = -1; uint64_t media_timescale = lsmash_get_media_timescale( vdhp->root, vdhp->track_id ); uint64_t media_duration = lsmash_get_media_duration_from_media_timeline( vdhp->root, vdhp->track_id ); if( media_duration == 0 ) media_duration = INT32_MAX; if( vdhp->sample_count == 1 ) { /* Calculate average framerate. */ reduce_fraction( &media_timescale, &media_duration ); *framerate_num = (int64_t)media_timescale; *framerate_den = (int64_t)media_duration; err = 0; goto setup_finish; } lw_log_handler_t *lhp = &vdhp->config.lh; lsmash_media_ts_list_t ts_list; if( lsmash_get_media_timestamps( vdhp->root, vdhp->track_id, &ts_list ) < 0 ) { lw_log_show( lhp, LW_LOG_ERROR, "Failed to get timestamps." ); goto setup_finish; } if( ts_list.sample_count != vdhp->sample_count ) { lw_log_show( lhp, LW_LOG_ERROR, "Failed to count number of video samples." ); goto setup_finish; } uint32_t composition_sample_delay; if( lsmash_get_max_sample_delay( &ts_list, &composition_sample_delay ) < 0 ) { lsmash_delete_media_timestamps( &ts_list ); lw_log_show( lhp, LW_LOG_ERROR, "Failed to get composition delay." ); goto setup_finish; } if( composition_sample_delay ) { /* Consider composition order for keyframe detection. * Note: sample number for L-SMASH is 1-origin. */ vdhp->order_converter = (order_converter_t *)lw_malloc_zero( (ts_list.sample_count + 1) * sizeof(order_converter_t) ); if( !vdhp->order_converter ) { lsmash_delete_media_timestamps( &ts_list ); lw_log_show( lhp, LW_LOG_ERROR, "Failed to allocate memory." ); goto setup_finish; } for( uint32_t i = 0; i < ts_list.sample_count; i++ ) ts_list.timestamp[i].dts = i + 1; lsmash_sort_timestamps_composition_order( &ts_list ); for( uint32_t i = 0; i < ts_list.sample_count; i++ ) vdhp->order_converter[i + 1].composition_to_decoding = (uint32_t)ts_list.timestamp[i].dts; } /* Calculate average framerate. */ uint64_t largest_cts = ts_list.timestamp[0].cts; uint64_t second_largest_cts = 0; uint64_t first_duration = ts_list.timestamp[1].cts - ts_list.timestamp[0].cts; uint64_t composition_timebase = first_duration; int strict_cfr = 1; for( uint32_t i = 1; i < ts_list.sample_count; i++ ) { uint64_t duration = ts_list.timestamp[i].cts - ts_list.timestamp[i - 1].cts; if( duration == 0 ) { lsmash_delete_media_timestamps( &ts_list ); lw_log_show( lhp, LW_LOG_WARNING, "Detected CTS duplication at frame %" PRIu32, i ); err = 0; goto setup_finish; } if( strict_cfr && duration != first_duration ) strict_cfr = 0; composition_timebase = get_gcd( composition_timebase, duration ); second_largest_cts = largest_cts; largest_cts = ts_list.timestamp[i].cts; } uint64_t reduce = reduce_fraction( &media_timescale, &composition_timebase ); uint64_t composition_duration = ((largest_cts - ts_list.timestamp[0].cts) + (largest_cts - second_largest_cts)) / reduce; lsmash_delete_media_timestamps( &ts_list ); double avg_frame_rate = (vdhp->sample_count * ((double)media_timescale / composition_duration)); if( strict_cfr || !lw_try_rational_framerate( avg_frame_rate, framerate_num, framerate_den, composition_timebase ) ) { uint64_t num = (uint64_t)(avg_frame_rate * composition_timebase + 0.5); uint64_t den = composition_timebase; if( num && den ) reduce_fraction( &num, &den ); else { num = 1; den = 1; } *framerate_num = (int64_t)num; *framerate_den = (int64_t)den; } err = 0; setup_finish:; if( vohp->vfr2cfr ) { /* Override average framerate by specified output constant framerate. */ *framerate_num = (int64_t)vohp->cfr_num; *framerate_den = (int64_t)vohp->cfr_den; vohp->frame_count = ((double)vohp->cfr_num / vohp->cfr_den) * ((double)media_duration / media_timescale) + 0.5; } else vohp->frame_count = libavsmash_video_get_sample_count( vdhp ); uint32_t min_cts_sample_number = get_decoding_sample_number( vdhp->order_converter, 1 ); vdhp->config.error = lsmash_get_cts_from_media_timeline( vdhp->root, vdhp->track_id, min_cts_sample_number, &vdhp->min_cts ); return err; }
static void ipu_set_upscale_bilinear_coef(struct ipu *ipu, const struct fraction *frac, unsigned int reg) { unsigned int add = frac->denom, i; struct fraction weight_frac = { .num = 0, .denom = frac->num }; usleep(20000); /* a 20ms sleep seems necessary */ write_reg(ipu, reg, 0x1); for (i = 0; i < frac->num; i++) { unsigned int weight = 512 - 512 * weight_frac.num / weight_frac.denom; unsigned int offset = 0; weight_frac.num += add; if (weight_frac.num >= weight_frac.denom) { offset = 1; weight_frac.num -= weight_frac.denom; } uint32_t value = ((weight & 0x7FF) << 6) | (offset << 1); usleep(20000); /* a 20ms sleep seems necessary */ write_reg(ipu, reg, value); } } /* * Sets up the IPU to downscale an image with bilinear resampling. * If the scaling fraction >= 1/2, each input pixel is used at least once. * If the scaling fraction < 1/2, not all input pixels are used, and it is * possible that the pixels read from each group of input pixels are more * to the left than expected. This is due to the scaling coefficients not * supporting specifying an offset for the first pixel, only those after it. * * The input pixels to use for each output pixel are calculated from the * middle of each output pixel. * * IN: * ipu: Pointer to IPU registers. * frac: Pointer to downscaling fraction. src * frac->num / frac->denom * == dst. * reg: The register number to write. This is either REG_HRSZ_COEF_LUT or * REG_VRSZ_COEF_LUT. */ static void ipu_set_downscale_bilinear_coef(struct ipu *ipu, const struct fraction *frac, unsigned int reg) { unsigned int add = frac->denom * 2, i; struct fraction weight_frac = { .num = frac->denom, .denom = frac->num * 2 }; usleep(20000); /* a 20ms sleep seems necessary */ write_reg(ipu, reg, 0x1); for (i = 0; i < frac->num; i++) { weight_frac.num = weight_frac.denom / 2 + (weight_frac.num - weight_frac.denom / 2) % weight_frac.denom; /* * Here, "input pixel 1.0" means half of 0 and half of 1; * "input pixel 0.5" means all of 0; and * "input pixel 1.49" means almost all of 1. */ unsigned int weight = 512 - (512 * (weight_frac.num - weight_frac.denom / 2) / weight_frac.denom); weight_frac.num += add; unsigned int offset = (weight_frac.num - weight_frac.denom / 2) / weight_frac.denom; uint32_t value = ((weight & 0x7FF) << 6) | (offset << 1); usleep(20000); /* a 20ms sleep seems necessary */ write_reg(ipu, reg, value); } } static void ipu_set_bilinear_resize_coef(struct ipu *ipu, const struct fraction *frac, unsigned int reg) { if (frac->num >= frac->denom) { ipu_set_upscale_bilinear_coef(ipu, frac, reg); } else { ipu_set_downscale_bilinear_coef(ipu, frac, reg); } } static void ipu_set_nearest_resize_coef(struct ipu *ipu, const struct fraction *frac, unsigned int reg) { unsigned int add = frac->denom, i; struct fraction weight_frac = { .num = 0, .denom = frac->num }; usleep(20000); /* a 20ms sleep seems necessary */ write_reg(ipu, reg, 0x1); for (i = 0; i < frac->num; i++) { const unsigned int weight = 512; unsigned int offset = 0; weight_frac.num += add; offset = weight_frac.num / weight_frac.denom; weight_frac.num %= weight_frac.denom; uint32_t value = (weight << 6) | (offset << 1); usleep(20000); /* a 20ms sleep seems necessary */ write_reg(ipu, reg, value); } } static void ipu_set_resize_params(struct ipu *ipu, enum ipu_resize_algorithm algorithm, unsigned int srcW, unsigned int srcH, unsigned int dstW, unsigned int dstH, unsigned int bytes_per_pixel) { struct fraction fracW = { .num = dstW, .denom = srcW }, fracH = { .num = dstH, .denom = srcH }; uint32_t coef_index = 0; reduce_fraction(&fracW); reduce_fraction(&fracH); printf("Width resizing fraction: %2u/%2u\n", fracW.num, fracW.denom); printf("Height resizing fraction: %2u/%2u\n", fracH.num, fracH.denom); /* Calculate valid W/H parameters */ dstW = calc_size(srcW, &fracW); dstH = calc_size(srcH, &fracH); printf("New output size: %ux%u\n", dstW, dstH); set_bit(ipu, REG_CTRL, (srcW != dstW ? IPU_CTRL_HRSZ_EN : 0) | (srcH != dstH ? IPU_CTRL_VRSZ_EN : 0)); if (srcW != dstW) coef_index = (fracW.num - 1) << 16; if (srcH != dstH) coef_index |= fracH.num - 1; /* Set the LUT index register */ write_reg(ipu, REG_RSZ_COEF_INDEX, coef_index); /* Set the input/output height/width */ write_reg(ipu, REG_IN_FM_GS, ((srcW * bytes_per_pixel) << IN_FM_W_SFT) | (srcH << IN_FM_H_SFT)); write_reg(ipu, REG_OUT_GS, ((dstW * bytes_per_pixel) << IN_FM_W_SFT) | (dstH << IN_FM_H_SFT)); /* Set the input/output stride */ write_reg(ipu, REG_Y_STRIDE, ipu->src_stride); write_reg(ipu, REG_OUT_STRIDE, ipu->dst_stride); if (srcW != dstW) { /* Set the horizontal resize coefficients */ switch (algorithm) { case IPU_NEAREST_NEIGHBOR: ipu_set_nearest_resize_coef(ipu, &fracW, REG_HRSZ_COEF_LUT); break; case IPU_BILINEAR: ipu_set_bilinear_resize_coef(ipu, &fracW, REG_HRSZ_COEF_LUT); break; } } if (srcH != dstH) { /* Set the vertical resize coefficients */ switch (algorithm) { case IPU_NEAREST_NEIGHBOR: ipu_set_nearest_resize_coef(ipu, &fracH, REG_VRSZ_COEF_LUT); break; case IPU_BILINEAR: ipu_set_bilinear_resize_coef(ipu, &fracH, REG_VRSZ_COEF_LUT); break; } } }
static void setup_timestamp_info( libavsmash_video_decode_handler_t *hp, VideoInfo *vi, uint64_t media_timescale, IScriptEnvironment *env ) { if( vi->num_frames == 1 ) { /* Calculate average framerate. */ uint64_t media_duration = lsmash_get_media_duration_from_media_timeline( hp->root, hp->track_ID ); if( media_duration == 0 ) media_duration = INT32_MAX; reduce_fraction( &media_timescale, &media_duration ); vi->fps_numerator = (unsigned int)media_timescale; vi->fps_denominator = (unsigned int)media_duration; return; } lsmash_media_ts_list_t ts_list; if( lsmash_get_media_timestamps( hp->root, hp->track_ID, &ts_list ) ) env->ThrowError( "LSMASHVideoSource: failed to get timestamps." ); if( ts_list.sample_count != vi->num_frames ) env->ThrowError( "LSMASHVideoSource: failed to count number of video samples." ); uint32_t composition_sample_delay; if( lsmash_get_max_sample_delay( &ts_list, &composition_sample_delay ) ) { lsmash_delete_media_timestamps( &ts_list ); env->ThrowError( "LSMASHVideoSource: failed to get composition delay." ); } if( composition_sample_delay ) { /* Consider composition order for keyframe detection. * Note: sample number for L-SMASH is 1-origin. */ hp->order_converter = (order_converter_t *)malloc( (ts_list.sample_count + 1) * sizeof(order_converter_t) ); if( !hp->order_converter ) { lsmash_delete_media_timestamps( &ts_list ); env->ThrowError( "LSMASHVideoSource: failed to allocate memory." ); } for( uint32_t i = 0; i < ts_list.sample_count; i++ ) ts_list.timestamp[i].dts = i + 1; lsmash_sort_timestamps_composition_order( &ts_list ); for( uint32_t i = 0; i < ts_list.sample_count; i++ ) hp->order_converter[i + 1].composition_to_decoding = (uint32_t)ts_list.timestamp[i].dts; } /* Calculate average framerate. */ uint64_t largest_cts = ts_list.timestamp[1].cts; uint64_t second_largest_cts = ts_list.timestamp[0].cts; uint64_t composition_timebase = ts_list.timestamp[1].cts - ts_list.timestamp[0].cts; for( uint32_t i = 2; i < ts_list.sample_count; i++ ) { if( ts_list.timestamp[i].cts == ts_list.timestamp[i - 1].cts ) { lsmash_delete_media_timestamps( &ts_list ); return; } composition_timebase = get_gcd( composition_timebase, ts_list.timestamp[i].cts - ts_list.timestamp[i - 1].cts ); second_largest_cts = largest_cts; largest_cts = ts_list.timestamp[i].cts; } uint64_t reduce = reduce_fraction( &media_timescale, &composition_timebase ); uint64_t composition_duration = ((largest_cts - ts_list.timestamp[0].cts) + (largest_cts - second_largest_cts)) / reduce; lsmash_delete_media_timestamps( &ts_list ); vi->fps_numerator = (unsigned int)((vi->num_frames * ((double)media_timescale / composition_duration)) * composition_timebase + 0.5); vi->fps_denominator = (unsigned int)composition_timebase; }
void lwlibav_setup_timestamp_info ( lwlibav_file_handler_t *lwhp, lwlibav_video_decode_handler_t *vdhp, lwlibav_video_output_handler_t *vohp, int64_t *framerate_num, int64_t *framerate_den ) { AVStream *video_stream = vdhp->format->streams[ vdhp->stream_index ]; if( vdhp->frame_count == 1 || lwhp->raw_demuxer || ((lwhp->format_flags & AVFMT_TS_DISCONT) && !(vdhp->lw_seek_flags & SEEK_DTS_BASED)) || !(vdhp->lw_seek_flags & (SEEK_DTS_BASED | SEEK_PTS_BASED | SEEK_PTS_GENERATED)) ) { *framerate_num = (int64_t)video_stream->avg_frame_rate.num; *framerate_den = (int64_t)video_stream->avg_frame_rate.den; return; } video_frame_info_t *info = vdhp->frame_list; int64_t first_ts; int64_t largest_ts; int64_t second_largest_ts; uint64_t first_duration; uint64_t stream_timebase; int strict_cfr; if( !(lwhp->format_flags & AVFMT_TS_DISCONT) && (vdhp->lw_seek_flags & (SEEK_PTS_BASED | SEEK_PTS_GENERATED)) ) { first_ts = info[1].pts; largest_ts = first_ts; second_largest_ts = first_ts; first_duration = info[2].pts - info[1].pts; stream_timebase = first_duration; strict_cfr = (first_duration != 0); for( uint32_t i = 2; i <= vdhp->frame_count; i++ ) { uint64_t duration = info[i].pts - info[i - 1].pts; if( duration == 0 ) { if( vdhp->lh.show_log ) vdhp->lh.show_log( &vdhp->lh, LW_LOG_WARNING, "Detected PTS %"PRId64" duplication at frame %"PRIu32, info[i].pts, i ); goto fail; } if( strict_cfr && duration != first_duration ) strict_cfr = 0; stream_timebase = get_gcd( stream_timebase, duration ); second_largest_ts = largest_ts; largest_ts = info[i].pts; } } else { uint32_t prev; uint32_t curr; if( vdhp->order_converter ) { prev = vdhp->order_converter[1].decoding_to_presentation; curr = vdhp->order_converter[2].decoding_to_presentation; } else { prev = 1; curr = 2; } first_ts = info[prev].dts; largest_ts = first_ts; second_largest_ts = first_ts; first_duration = info[curr].dts - info[prev].dts; stream_timebase = first_duration; strict_cfr = (first_duration != 0); for( uint32_t i = 2; i <= vdhp->frame_count; i++ ) { if( vdhp->order_converter ) { prev = vdhp->order_converter[i - 1].decoding_to_presentation; curr = vdhp->order_converter[i ].decoding_to_presentation; } else { prev = i - 1; curr = i; } uint64_t duration = info[curr].dts - info[prev].dts; if( duration == 0 ) { if( vdhp->lh.show_log ) vdhp->lh.show_log( &vdhp->lh, LW_LOG_WARNING, "Detected DTS %"PRId64" duplication at frame %"PRIu32, info[curr].dts, curr ); goto fail; } if( strict_cfr && duration != first_duration ) strict_cfr = 0; stream_timebase = get_gcd( stream_timebase, duration ); second_largest_ts = largest_ts; largest_ts = info[curr].dts; } } stream_timebase *= video_stream->time_base.num; uint64_t stream_timescale = video_stream->time_base.den; uint64_t reduce = reduce_fraction( &stream_timescale, &stream_timebase ); uint64_t stream_duration = (((largest_ts - first_ts) + (largest_ts - second_largest_ts)) * video_stream->time_base.num) / reduce; double stream_framerate = (vohp->frame_count - (vohp->repeat_correction_ts ? 1 : 0)) * ((double)stream_timescale / stream_duration); if( strict_cfr || !lw_try_rational_framerate( stream_framerate, framerate_num, framerate_den, stream_timebase ) ) { if( stream_timebase > INT_MAX || (uint64_t)(stream_framerate * stream_timebase + 0.5) > INT_MAX ) goto fail; uint64_t num = (uint64_t)(stream_framerate * stream_timebase + 0.5); uint64_t den = stream_timebase; if( num && den ) reduce_fraction( &num, &den ); else if( video_stream->avg_frame_rate.num == 0 || video_stream->avg_frame_rate.den == 0 ) { num = 1; den = 1; } else goto fail; *framerate_num = (int64_t)num; *framerate_den = (int64_t)den; } return; fail: *framerate_num = (int64_t)video_stream->avg_frame_rate.num; *framerate_den = (int64_t)video_stream->avg_frame_rate.den; return; }