Example #1
0
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);
}
Example #2
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);
}
Example #3
0
/*
 * 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);
}
Example #4
0
/*
 * 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);
} 
Example #5
0
/*
 * 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);
}
Example #6
0
/*
 * 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;
}
Example #9
0
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;
}
Example #11
0
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;
}