Пример #1
0
static int parse_tcfile( FILE *tcfile_in, timecode_hnd_t *h, video_info_t *info )
{
    char buff[256];
    int ret, tcfv, num, seq_num, timecodes_num;
    double *timecodes = NULL;
    double *fpss = NULL;

    ret = fscanf( tcfile_in, "# timecode format v%d", &tcfv );
    FAIL_IF_ERROR( ret != 1 || (tcfv != 1 && tcfv != 2), "unsupported timecode format\n" )

    if( tcfv == 1 )
    {
        uint64_t file_pos;
        double assume_fps, seq_fps;
        int start, end;
        int prev_start = -1, prev_end = -1;

        h->assume_fps = 0;
        for( num = 2; fgets( buff, sizeof(buff), tcfile_in ) != NULL; num++ )
        {
            if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
                continue;
            FAIL_IF_ERROR( sscanf( buff, "assume %lf", &h->assume_fps ) != 1 && sscanf( buff, "Assume %lf", &h->assume_fps ) != 1,
                           "tcfile parsing error: assumed fps not found\n" )
            break;
        }
        FAIL_IF_ERROR( h->assume_fps <= 0, "invalid assumed fps %.6f\n", h->assume_fps )

        file_pos = ftell( tcfile_in );
        h->stored_pts_num = 0;
        for( seq_num = 0; fgets( buff, sizeof(buff), tcfile_in ) != NULL; num++ )
        {
            if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
            {
                if( sscanf( buff, "# TDecimate Mode 3:  Last Frame = %d", &end ) == 1 )
                    h->stored_pts_num = end + 1;
                continue;
            }
            ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
            FAIL_IF_ERROR( ret != 3 && ret != EOF, "invalid input tcfile\n" )
            FAIL_IF_ERROR( start > end || start <= prev_start || end <= prev_end || seq_fps <= 0,
                           "invalid input tcfile at line %d: %s\n", num, buff )
            prev_start = start;
            prev_end = end;
            if( h->auto_timebase_den || h->auto_timebase_num )
                ++seq_num;
        }
        if( !h->stored_pts_num )
            h->stored_pts_num = end + 1;
        timecodes_num = h->stored_pts_num;
        fseek( tcfile_in, file_pos, SEEK_SET );

        timecodes = malloc( timecodes_num * sizeof(double) );
        if( !timecodes )
            return -1;
        if( h->auto_timebase_den || h->auto_timebase_num )
        {
            fpss = malloc( (seq_num + 1) * sizeof(double) );
            if( !fpss )
                goto fail;
        }

        assume_fps = correct_fps( h->assume_fps, h );
        if( assume_fps < 0 )
            goto fail;
        timecodes[0] = 0;
        for( num = seq_num = 0; num < timecodes_num - 1; )
        {
            fgets( buff, sizeof(buff), tcfile_in );
            if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
                continue;
            ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
            if( ret != 3 )
                start = end = timecodes_num - 1;
            for( ; num < start && num < timecodes_num - 1; num++ )
                timecodes[num + 1] = timecodes[num] + 1 / assume_fps;
            if( num < timecodes_num - 1 )
            {
                if( h->auto_timebase_den || h->auto_timebase_num )
                    fpss[seq_num++] = seq_fps;
                seq_fps = correct_fps( seq_fps, h );
                if( seq_fps < 0 )
                    goto fail;
                for( num = start; num <= end && num < timecodes_num - 1; num++ )
                    timecodes[num + 1] = timecodes[num] + 1 / seq_fps;
            }
        }
        if( h->auto_timebase_den || h->auto_timebase_num )
            fpss[seq_num] = h->assume_fps;

        if( h->auto_timebase_num && !h->auto_timebase_den )
        {
            double exponent;
            double assume_fps_sig, seq_fps_sig;
            if( try_mkv_timebase_den( fpss, h, seq_num + 1 ) < 0 )
                goto fail;
            fseek( tcfile_in, file_pos, SEEK_SET );
            assume_fps_sig = sigexp10( h->assume_fps, &exponent );
            assume_fps = MKV_TIMEBASE_DEN / ( round( MKV_TIMEBASE_DEN / assume_fps_sig ) / exponent );
            for( num = 0; num < timecodes_num - 1; )
            {
                fgets( buff, sizeof(buff), tcfile_in );
                if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
                    continue;
                ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
                if( ret != 3 )
                    start = end = timecodes_num - 1;
                seq_fps_sig = sigexp10( seq_fps, &exponent );
                seq_fps = MKV_TIMEBASE_DEN / ( round( MKV_TIMEBASE_DEN / seq_fps_sig ) / exponent );
                for( ; num < start && num < timecodes_num - 1; num++ )
                    timecodes[num + 1] = timecodes[num] + 1 / assume_fps;
                for( num = start; num <= end && num < timecodes_num - 1; num++ )
                    timecodes[num + 1] = timecodes[num] + 1 / seq_fps;
            }
        }
        if( fpss )
            free( fpss );

        h->assume_fps = assume_fps;
        h->last_timecode = timecodes[timecodes_num - 1];
    }
Пример #2
0
static int parse_tcfile( FILE *tcfile_in, timecode_hnd_t *h, video_info_t *info )
{
    char buff[256];
    int ret, tcfv, num, seq_num, timecodes_num;
    int64_t pts_seek_offset;
    double *timecodes = NULL;
    double *fpss = NULL;

    ret = fscanf( tcfile_in, "# timecode format v%d", &tcfv );
    if( ret != 1 || (tcfv != 1 && tcfv != 2) )
    {
        fprintf( stderr, "timecode [error]: unsupported timecode format\n" );
        return -1;
    }

    if( tcfv == 1 )
    {
        uint64_t file_pos;
        double assume_fps, seq_fps;
        int start, end = h->seek;
        int prev_start = -1, prev_end = -1;

        h->assume_fps = 0;
        for( num = 2; fgets( buff, sizeof(buff), tcfile_in ) != NULL; num++ )
        {
            if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
                continue;
            if( sscanf( buff, "assume %lf", &h->assume_fps ) != 1 && sscanf( buff, "Assume %lf", &h->assume_fps ) != 1 )
            {
                fprintf( stderr, "timecode [error]: tcfile parsing error: assumed fps not found\n" );
                return -1;
            }
            break;
        }
        if( h->assume_fps <= 0 )
        {
            fprintf( stderr, "timecode [error]: invalid assumed fps %.6f\n", h->assume_fps );
            return -1;
        }

        file_pos = ftell( tcfile_in );
        h->stored_pts_num = 0;
        for( seq_num = 0; fgets( buff, sizeof(buff), tcfile_in ) != NULL; num++ )
        {
            if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
            {
                if( sscanf( buff, "# TDecimate Mode 3:  Last Frame = %d", &end ) == 1 )
                    h->stored_pts_num = end + 1 - h->seek;
                continue;
            }
            ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
            if( ret != 3 && ret != EOF )
            {
                fprintf( stderr, "timecode [error]: invalid input tcfile\n" );
                return -1;
            }
            if( start > end || start <= prev_start || end <= prev_end || seq_fps <= 0 )
            {
                fprintf( stderr, "timecode [error]: invalid input tcfile at line %d: %s\n", num, buff );
                return -1;
            }
            prev_start = start;
            prev_end = end;
            if( h->auto_timebase_den || h->auto_timebase_num )
                ++seq_num;
        }
        if( !h->stored_pts_num )
            h->stored_pts_num = end + 1 - h->seek;
        timecodes_num = h->stored_pts_num + h->seek;
        fseek( tcfile_in, file_pos, SEEK_SET );

        timecodes = malloc( timecodes_num * sizeof(double) );
        if( !timecodes )
            return -1;
        if( h->auto_timebase_den || h->auto_timebase_num )
        {
            fpss = malloc( (seq_num + 1) * sizeof(double) );
            if( !fpss )
                goto fail;
        }

        assume_fps = correct_fps( h->assume_fps, h );
        if( assume_fps < 0 )
            goto fail;
        timecodes[0] = 0;
        for( num = seq_num = 0; num < timecodes_num - 1; )
        {
            fgets( buff, sizeof(buff), tcfile_in );
            if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
                continue;
            ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
            if( ret != 3 )
                start = end = timecodes_num - 1;
            if( h->auto_timebase_den || h->auto_timebase_num )
                fpss[seq_num++] = seq_fps;
            seq_fps = correct_fps( seq_fps, h );
            if( seq_fps < 0 )
                goto fail;
            for( ; num < start && num < timecodes_num - 1; num++ )
                timecodes[num + 1] = timecodes[num] + 1 / assume_fps;
            for( num = start; num <= end && num < timecodes_num - 1; num++ )
                timecodes[num + 1] = timecodes[num] + 1 / seq_fps;
        }
        if( h->auto_timebase_den || h->auto_timebase_num )
            fpss[seq_num] = h->assume_fps;

        if( h->auto_timebase_num && !h->auto_timebase_den )
        {
            double exponent;
            double assume_fps_sig, seq_fps_sig;
            if( try_mkv_timebase_den( fpss, h, seq_num + 1 ) < 0 )
                goto fail;
            fseek( tcfile_in, file_pos, SEEK_SET );
            assume_fps_sig = sigexp10( h->assume_fps, &exponent );
            assume_fps = MKV_TIMEBASE_DEN / ( round( MKV_TIMEBASE_DEN / assume_fps_sig ) / exponent );
            for( num = 0; num < timecodes_num - 1; )
            {
                fgets( buff, sizeof(buff), tcfile_in );
                if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
                    continue;
                ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
                if( ret != 3 )
                    start = end = timecodes_num - 1;
                seq_fps_sig = sigexp10( seq_fps, &exponent );
                seq_fps = MKV_TIMEBASE_DEN / ( round( MKV_TIMEBASE_DEN / seq_fps_sig ) / exponent );
                for( ; num < start && num < timecodes_num - 1; num++ )
                    timecodes[num + 1] = timecodes[num] + 1 / assume_fps;
                for( num = start; num <= end && num < timecodes_num - 1; num++ )
                    timecodes[num + 1] = timecodes[num] + 1 / seq_fps;
            }
        }
        if( fpss )
            free( fpss );

        h->assume_fps = assume_fps;
        h->last_timecode = timecodes[timecodes_num - 1];
    }
    else    /* tcfv == 2 */
    {
        uint64_t file_pos = ftell( tcfile_in );

        num = h->stored_pts_num = 0;
        while( fgets( buff, sizeof(buff), tcfile_in ) != NULL )
        {
            if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
            {
                if( !num )
                    file_pos = ftell( tcfile_in );
                continue;
            }
            if( num >= h->seek )
                ++h->stored_pts_num;
            ++num;
        }
        timecodes_num = h->stored_pts_num + h->seek;
        if( !timecodes_num )
        {
            fprintf( stderr, "timecode [error]: input tcfile doesn't have any timecodes!\n" );
            return -1;
        }
        fseek( tcfile_in, file_pos, SEEK_SET );

        timecodes = malloc( timecodes_num * sizeof(double) );
        if( !timecodes )
            return -1;

        fgets( buff, sizeof(buff), tcfile_in );
        ret = sscanf( buff, "%lf", &timecodes[0] );
        if( ret != 1 )
        {
            fprintf( stderr, "timecode [error]: invalid input tcfile for frame 0\n" );
            goto fail;
        }
        for( num = 1; num < timecodes_num; )
        {
            fgets( buff, sizeof(buff), tcfile_in );
            if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
                continue;
            ret = sscanf( buff, "%lf", &timecodes[num] );
            timecodes[num] *= 1e-3;         /* Timecode format v2 is expressed in milliseconds. */
            if( ret != 1 || timecodes[num] <= timecodes[num - 1] )
            {
                fprintf( stderr, "timecode [error]: invalid input tcfile for frame %d\n", num );
                goto fail;
            }
            ++num;
        }

        if( timecodes_num == 1 )
            h->timebase_den = info->fps_num;
        else if( h->auto_timebase_den )
        {
            fpss = malloc( (timecodes_num - 1) * sizeof(double) );
            if( !fpss )
                goto fail;
            for( num = 0; num < timecodes_num - 1; num++ )
            {
                fpss[num] = 1 / (timecodes[num + 1] - timecodes[num]);
                if( h->timebase_den >= 0 )
                {
                    int i = 1;
                    int fps_num, fps_den;
                    double exponent;
                    double fps_sig = sigexp10( fpss[num], &exponent );
                    while( 1 )
                    {
                        fps_den = i * h->timebase_num;
                        fps_num = round( fps_den * fps_sig ) * exponent;
                        if( fps_num < 0 || fabs( ((double)fps_num / fps_den) / exponent - fps_sig ) < DOUBLE_EPSILON )
                            break;
                        ++i;
                    }
                    h->timebase_den = fps_num > 0 && h->timebase_den ? lcm( h->timebase_den, fps_num ) : fps_num;
                    if( h->timebase_den < 0 )
                    {
                        h->auto_timebase_den = 0;
                        continue;
                    }
                }
            }
            if( h->auto_timebase_num && !h->auto_timebase_den )
                if( try_mkv_timebase_den( fpss, h, timecodes_num - 1 ) < 0 )
                    goto fail;
            free( fpss );
        }

        if( timecodes_num > 1 )
            h->assume_fps = 1 / (timecodes[timecodes_num - 1] - timecodes[timecodes_num - 2]);
        else
            h->assume_fps = (double)info->fps_num / info->fps_den;
        h->last_timecode = timecodes[timecodes_num - 1];
    }

    if( h->auto_timebase_den || h->auto_timebase_num )
    {
        x264_reduce_fraction( &h->timebase_num, &h->timebase_den );
        fprintf( stderr, "timecode [info]: automatic timebase generation %d/%d\n", h->timebase_num, h->timebase_den );
    }
    else if( h->timebase_den <= 0 )
    {
        fprintf( stderr, "timecode [error]: automatic timebase generation failed.\n"
                         "                  Specify an appropriate timebase manually.\n" );
        goto fail;
    }

    h->pts = malloc( h->stored_pts_num * sizeof(int64_t) );
    if( !h->pts )
        goto fail;
    pts_seek_offset = (int64_t)( timecodes[h->seek] * ((double)h->timebase_den / h->timebase_num) + 0.5 );
    h->pts[0] = 0;
    for( num = 1; num < h->stored_pts_num; num++ )
    {
        h->pts[num] = (int64_t)( timecodes[h->seek + num] * ((double)h->timebase_den / h->timebase_num) + 0.5 );
        h->pts[num] -= pts_seek_offset;
        if( h->pts[num] <= h->pts[num - 1] )
        {
            fprintf( stderr, "timecode [error]: invalid timebase or timecode for frame %d\n", num );
            goto fail;
        }
    }

    free( timecodes );
    return 0;

fail:
    if( timecodes )
        free( timecodes );
    if( fpss )
        free( fpss );
    return -1;
}