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 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;
}
示例#3
0
int main( int argc, char *argv[] )
{
    if ( argc < 2 )
    {
        display_help();
        return -1;
    }
    else if( !strcasecmp( argv[1], "-h" ) || !strcasecmp( argv[1], "--help" ) )
    {
        display_help();
        return 0;
    }
    else if( !strcasecmp( argv[1], "-v" ) || !strcasecmp( argv[1], "--version" ) )
    {
        display_version();
        return 0;
    }
    int dump_box = 1;
    int chapter = 0;
    char *filename;
    lsmash_get_mainargs( &argc, &argv );
    if( argc > 2 )
    {
        if( !strcasecmp( argv[1], "--box" ) )
            DO_NOTHING;
        else if( !strcasecmp( argv[1], "--chapter" ) )
            chapter = 1;
        else if( !strcasecmp( argv[1], "--timestamp" ) )
            dump_box = 0;
        else
        {
            display_help();
            return -1;
        }
        filename = argv[2];
    }
    else
    {
        filename = argv[1];
    }
    /* Open the input file. */
    lsmash_root_t *root = lsmash_create_root();
    if( !root )
    {
        fprintf( stderr, "Failed to create a ROOT.\n" );
        return -1;
    }
    lsmash_file_parameters_t file_param = { 0 };
    if( lsmash_open_file( filename, 1, &file_param ) < 0 )
        return BOXDUMPER_ERR( "Failed to open an input file.\n" );
    if( dump_box )
        file_param.mode |= LSMASH_FILE_MODE_DUMP;
    lsmash_file_t *file = lsmash_set_file( root, &file_param );
    if( !file )
        return BOXDUMPER_ERR( "Failed to add a file into a ROOT.\n" );
    if( lsmash_read_file( file, &file_param ) < 0 )
        return BOXDUMPER_ERR( "Failed to read a file\n" );
    /* Dump the input file. */
    if( chapter )
    {
        if( lsmash_print_chapter_list( root ) )
            return BOXDUMPER_ERR( "Failed to extract chapter.\n" );
    }
    else if( dump_box )
    {
        if( lsmash_print_movie( root, "-" ) )
            return BOXDUMPER_ERR( "Failed to dump box structure.\n" );
    }
    else
    {
        lsmash_movie_parameters_t movie_param;
        lsmash_initialize_movie_parameters( &movie_param );
        lsmash_get_movie_parameters( root, &movie_param );
        uint32_t num_tracks = movie_param.number_of_tracks;
        for( uint32_t track_number = 1; track_number <= num_tracks; track_number++ )
        {
            uint32_t track_ID = lsmash_get_track_ID( root, track_number );
            if( !track_ID )
                return BOXDUMPER_ERR( "Failed to get track_ID.\n" );
            lsmash_media_parameters_t media_param;
            lsmash_initialize_media_parameters( &media_param );
            if( lsmash_get_media_parameters( root, track_ID, &media_param ) )
                return BOXDUMPER_ERR( "Failed to get media parameters.\n" );
            if( lsmash_construct_timeline( root, track_ID ) )
                return BOXDUMPER_ERR( "Failed to construct timeline.\n" );
            uint32_t timeline_shift;
            if( lsmash_get_composition_to_decode_shift_from_media_timeline( root, track_ID, &timeline_shift ) )
                return BOXDUMPER_ERR( "Failed to get timestamps.\n" );
            lsmash_media_ts_list_t ts_list;
            if( lsmash_get_media_timestamps( root, track_ID, &ts_list ) )
                return BOXDUMPER_ERR( "Failed to get timestamps.\n" );
            fprintf( stdout, "track_ID: %"PRIu32"\n", track_ID );
            fprintf( stdout, "Media timescale: %"PRIu32"\n", media_param.timescale );
            lsmash_media_ts_t *ts_array = ts_list.timestamp;
            if( !ts_array )
            {
                fprintf( stdout, "\n" );
                continue;
            }
            for( uint32_t i = 0; i < ts_list.sample_count; i++ )
                fprintf( stdout, "DTS = %"PRIu64", CTS = %"PRIu64"\n", ts_array[i].dts, ts_array[i].cts + timeline_shift );
            lsmash_free( ts_array );
            fprintf( stdout, "\n" );
        }
    }
    lsmash_destroy_root( root );
    return 0;
}
示例#4
0
int main( int argc, char *argv[] )
{
    if( argc < 2 )
        return print_help( -1 );
    int dump_box = 1;
    int chapter = 0;
    char *filename;
    if( argc > 2 )
    {
        if( !strcasecmp( argv[1], "--box" ) )
            DO_NOTHING;
        else if( !strcasecmp( argv[1], "--chapter" ) )
            chapter = 1;
        else if( !strcasecmp( argv[1], "--timestamp" ) )
            dump_box = 0;
        else
            return print_help( -1 );
        filename = argv[2];
    }
    else
    {
        if( !strcasecmp( argv[1], "-h" ) || !strcasecmp( argv[1], "--help" ) )
            return print_help( 0 );
        filename = argv[1];
    }
#ifdef _WIN32
    _setmode( _fileno(stdin), _O_BINARY );
#endif
    lsmash_file_mode mode = LSMASH_FILE_MODE_READ;
    if( dump_box )
        mode |= LSMASH_FILE_MODE_DUMP;
    lsmash_root_t *root = lsmash_open_movie( filename, mode );
    if( !root )
    {
        fprintf( stderr, "Failed to open input file.\n" );
        return -1;
    }
    if( chapter )
    {
        if( lsmash_print_chapter_list( root ) )
            return BOXDUMPER_ERR( "Failed to extract chapter.\n" );
    }
    else if( dump_box )
    {
        if( lsmash_print_movie( root, "-" ) )
            return BOXDUMPER_ERR( "Failed to dump box structure.\n" );
    }
    else
    {
        lsmash_movie_parameters_t movie_param;
        lsmash_initialize_movie_parameters( &movie_param );
        lsmash_get_movie_parameters( root, &movie_param );
        uint32_t num_tracks = movie_param.number_of_tracks;
        for( uint32_t track_number = 1; track_number <= num_tracks; track_number++ )
        {
            uint32_t track_ID = lsmash_get_track_ID( root, track_number );
            if( !track_ID )
                return BOXDUMPER_ERR( "Failed to get track_ID.\n" );
            lsmash_media_parameters_t media_param;
            lsmash_initialize_media_parameters( &media_param );
            if( lsmash_get_media_parameters( root, track_ID, &media_param ) )
                return BOXDUMPER_ERR( "Failed to get media parameters.\n" );
            if( lsmash_construct_timeline( root, track_ID ) )
                return BOXDUMPER_ERR( "Failed to construct timeline.\n" );
            uint32_t timeline_shift;
            if( lsmash_get_composition_to_decode_shift_from_media_timeline( root, track_ID, &timeline_shift ) )
                return BOXDUMPER_ERR( "Failed to get timestamps.\n" );
            lsmash_media_ts_list_t ts_list;
            if( lsmash_get_media_timestamps( root, track_ID, &ts_list ) )
                return BOXDUMPER_ERR( "Failed to get timestamps.\n" );
            fprintf( stdout, "track_ID: %"PRIu32"\n", track_ID );
            fprintf( stdout, "Media timescale: %"PRIu32"\n", media_param.timescale );
            lsmash_media_ts_t *ts_array = ts_list.timestamp;
            if( !ts_array )
            {
                fprintf( stdout, "\n" );
                continue;
            }
            for( uint32_t i = 0; i < ts_list.sample_count; i++ )
                fprintf( stdout, "DTS = %"PRIu64", CTS = %"PRIu64"\n", ts_array[i].dts, ts_array[i].cts + timeline_shift );
            free( ts_array );
            fprintf( stdout, "\n" );
        }
    }
    lsmash_destroy_root( root );
    return 0;
}