コード例 #1
0
ファイル: file.c プロジェクト: darcyg/vapoursynth-plugins
int lsmash_switch_media_segment
(
    lsmash_root_t        *root,
    lsmash_file_t        *successor,
    lsmash_adhoc_remux_t *remux
)
{
    if( !root || !remux )
        return LSMASH_ERR_FUNCTION_PARAM;
    lsmash_file_t *predecessor = root->file;
    if( !predecessor || !successor
     || predecessor == successor
     || predecessor->root != successor->root
     || !predecessor->root || !successor->root
     || predecessor->root != root || successor->root != root
     ||  (successor->flags & LSMASH_FILE_MODE_INITIALIZATION)
     || !(successor->flags & LSMASH_FILE_MODE_MEDIA)
     || !(predecessor->flags & LSMASH_FILE_MODE_WRITE)      || !(successor->flags & LSMASH_FILE_MODE_WRITE)
     || !(predecessor->flags & LSMASH_FILE_MODE_BOX)        || !(successor->flags & LSMASH_FILE_MODE_BOX)
     || !(predecessor->flags & LSMASH_FILE_MODE_FRAGMENTED) || !(successor->flags & LSMASH_FILE_MODE_FRAGMENTED)
     || !(predecessor->flags & LSMASH_FILE_MODE_SEGMENT)    || !(successor->flags & LSMASH_FILE_MODE_SEGMENT)
     || (!(predecessor->flags & LSMASH_FILE_MODE_MEDIA) && !(predecessor->flags & LSMASH_FILE_MODE_INITIALIZATION)) )
        return LSMASH_ERR_FUNCTION_PARAM;
    int ret = isom_finish_final_fragment_movie( predecessor, remux );
    if( ret < 0 )
        return ret;
    if( predecessor->flags & LSMASH_FILE_MODE_INITIALIZATION )
    {
        if( predecessor->initializer != predecessor )
            return LSMASH_ERR_INVALID_DATA;
        successor->initializer = predecessor;
    }
    else
        successor->initializer = predecessor->initializer;
    if( !lsmash_get_entry_data( &successor->styp_list, 1 ) )
    {
        ret = isom_set_brands( successor, 0, 0, NULL, 0 );
        if( ret < 0 )
            return LSMASH_ERR_NAMELESS;
    }
    successor->fragment_count = predecessor->fragment_count;
    root->file = successor;
    return 0;
}
コード例 #2
0
ファイル: wave_imp.c プロジェクト: darcyg/vapoursynth-plugins
static int wave_importer_get_accessunit( importer_t *importer, uint32_t track_number, lsmash_sample_t **p_sample )
{
    if( !importer->info )
        return LSMASH_ERR_NAMELESS;
    if( track_number != 1 )
        return LSMASH_ERR_FUNCTION_PARAM;
    lsmash_audio_summary_t *summary = (lsmash_audio_summary_t *)lsmash_get_entry_data( importer->summaries, track_number );
    if( !summary )
        return LSMASH_ERR_NAMELESS;
    wave_importer_t *wave_imp = (wave_importer_t *)importer->info;
    importer_status current_status = importer->status;
    if( current_status == IMPORTER_ERROR )
        return LSMASH_ERR_NAMELESS;
    if( current_status == IMPORTER_EOF )
        return IMPORTER_EOF;
    if( wave_imp->number_of_samples / summary->samples_in_frame > wave_imp->au_number )
        wave_imp->au_length = summary->bytes_per_frame;
    else
    {
        wave_imp->au_length = wave_imp->fmt.wfx.nBlockAlign * (wave_imp->number_of_samples % summary->samples_in_frame);
        importer->status = IMPORTER_EOF;
        if( wave_imp->au_length == 0 )
            return IMPORTER_EOF;
    }
    lsmash_sample_t *sample = lsmash_create_sample( wave_imp->au_length );
    if( !sample )
        return LSMASH_ERR_MEMORY_ALLOC;
    *p_sample = sample;
    if( lsmash_bs_get_bytes_ex( importer->bs, wave_imp->au_length, sample->data ) != wave_imp->au_length )
    {
        importer->status = IMPORTER_ERROR;
        return LSMASH_ERR_INVALID_DATA;
    }
    sample->length        = wave_imp->au_length;
    sample->dts           = wave_imp->au_number ++ * summary->samples_in_frame;
    sample->cts           = sample->dts;
    sample->prop.ra_flags = ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC;
    return current_status;
}
コード例 #3
0
ファイル: dts_imp.c プロジェクト: arodland/l-smash
static int dts_importer_get_accessunit( importer_t *importer, uint32_t track_number, lsmash_sample_t **p_sample )
{
    if( !importer->info )
        return LSMASH_ERR_NAMELESS;
    if( track_number != 1 )
        return LSMASH_ERR_FUNCTION_PARAM;
    lsmash_audio_summary_t *summary = (lsmash_audio_summary_t *)lsmash_get_entry_data( importer->summaries, track_number );
    if( !summary )
        return LSMASH_ERR_NAMELESS;
    dts_importer_t *dts_imp = (dts_importer_t *)importer->info;
    dts_info_t     *info    = &dts_imp->info;
    importer_status current_status = importer->status;
    if( current_status == IMPORTER_ERROR )
        return LSMASH_ERR_NAMELESS;
    if( current_status == IMPORTER_EOF && dts_imp->au_length == 0 )
        return IMPORTER_EOF;
    if( current_status == IMPORTER_CHANGE )
        summary->max_au_length = 0;
    lsmash_sample_t *sample = lsmash_create_sample( dts_imp->au_length );
    if( !sample )
        return LSMASH_ERR_MEMORY_ALLOC;
    *p_sample = sample;
    memcpy( sample->data, dts_imp->au, dts_imp->au_length );
    sample->length                 = dts_imp->au_length;
    sample->dts                    = dts_imp->au_number++ * summary->samples_in_frame;
    sample->cts                    = sample->dts;
    sample->prop.ra_flags          = ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC;
    sample->prop.pre_roll.distance = !!(info->flags & DTS_EXT_SUBSTREAM_LBR_FLAG);  /* MDCT */
    if( importer->status == IMPORTER_EOF )
    {
        dts_imp->au_length = 0;
        return 0;
    }
    if( dts_importer_get_next_accessunit_internal( importer ) < 0 )
        importer->status = IMPORTER_ERROR;
    return current_status;
}
コード例 #4
0
ファイル: file.c プロジェクト: darcyg/vapoursynth-plugins
int isom_check_compatibility
(
    lsmash_file_t *file
)
{
    if( !file )
        return LSMASH_ERR_FUNCTION_PARAM;
    isom_clear_compat_flags( file );
    /* Get the brand container. */
    isom_ftyp_t *ftyp = file->ftyp ? file->ftyp : (isom_ftyp_t *)lsmash_get_entry_data( &file->styp_list, 1 );
    /* Check brand to decide mandatory boxes. */
    if( !ftyp )
    {
        /* No brand declaration means this file is a MP4 version 1 or QuickTime file format. */
        if( file->moov
         && file->moov->iods )
        {
            file->mp4_version1    = 1;
            file->isom_compatible = 1;
        }
        else
        {
            file->qt_compatible    = 1;
            file->undefined_64_ver = 1;
        }
        return 0;
    }
    for( uint32_t i = 0; i <= ftyp->brand_count; i++ )
    {
        uint32_t brand = (i == ftyp->brand_count ? ftyp->major_brand : ftyp->compatible_brands[i]);
        switch( brand )
        {
            case ISOM_BRAND_TYPE_QT :
                file->qt_compatible = 1;
                break;
            case ISOM_BRAND_TYPE_MP41 :
                file->mp4_version1 = 1;
                break;
            case ISOM_BRAND_TYPE_MP42 :
                file->mp4_version2 = 1;
                break;
            case ISOM_BRAND_TYPE_AVC1 :
            case ISOM_BRAND_TYPE_ISOM :
                file->max_isom_version = LSMASH_MAX( file->max_isom_version, 1 );
                file->min_isom_version = LSMASH_MIN( file->min_isom_version, 1 );
                break;
            case ISOM_BRAND_TYPE_ISO2 :
                file->max_isom_version = LSMASH_MAX( file->max_isom_version, 2 );
                file->min_isom_version = LSMASH_MIN( file->min_isom_version, 2 );
                break;
            case ISOM_BRAND_TYPE_ISO3 :
                file->max_isom_version = LSMASH_MAX( file->max_isom_version, 3 );
                file->min_isom_version = LSMASH_MIN( file->min_isom_version, 3 );
                break;
            case ISOM_BRAND_TYPE_ISO4 :
                file->max_isom_version = LSMASH_MAX( file->max_isom_version, 4 );
                file->min_isom_version = LSMASH_MIN( file->min_isom_version, 4 );
                break;
            case ISOM_BRAND_TYPE_ISO5 :
                file->max_isom_version = LSMASH_MAX( file->max_isom_version, 5 );
                file->min_isom_version = LSMASH_MIN( file->min_isom_version, 5 );
                break;
            case ISOM_BRAND_TYPE_ISO6 :
                file->max_isom_version = LSMASH_MAX( file->max_isom_version, 6 );
                file->min_isom_version = LSMASH_MIN( file->min_isom_version, 6 );
                break;
            case ISOM_BRAND_TYPE_ISO7 :
                file->max_isom_version = LSMASH_MAX( file->max_isom_version, 7 );
                file->min_isom_version = LSMASH_MIN( file->min_isom_version, 7 );
                break;
            case ISOM_BRAND_TYPE_M4A :
            case ISOM_BRAND_TYPE_M4B :
            case ISOM_BRAND_TYPE_M4P :
            case ISOM_BRAND_TYPE_M4V :
                file->itunes_movie = 1;
                break;
            case ISOM_BRAND_TYPE_3GP4 :
                file->max_3gpp_version = LSMASH_MAX( file->max_3gpp_version, 4 );
                break;
            case ISOM_BRAND_TYPE_3GP5 :
                file->max_3gpp_version = LSMASH_MAX( file->max_3gpp_version, 5 );
                break;
            case ISOM_BRAND_TYPE_3GE6 :
            case ISOM_BRAND_TYPE_3GG6 :
            case ISOM_BRAND_TYPE_3GP6 :
            case ISOM_BRAND_TYPE_3GR6 :
            case ISOM_BRAND_TYPE_3GS6 :
                file->max_3gpp_version = LSMASH_MAX( file->max_3gpp_version, 6 );
                break;
            case ISOM_BRAND_TYPE_3GP7 :
                file->max_3gpp_version = LSMASH_MAX( file->max_3gpp_version, 7 );
                break;
            case ISOM_BRAND_TYPE_3GP8 :
                file->max_3gpp_version = LSMASH_MAX( file->max_3gpp_version, 8 );
                break;
            case ISOM_BRAND_TYPE_3GE9 :
            case ISOM_BRAND_TYPE_3GF9 :
            case ISOM_BRAND_TYPE_3GG9 :
            case ISOM_BRAND_TYPE_3GH9 :
            case ISOM_BRAND_TYPE_3GM9 :
            case ISOM_BRAND_TYPE_3GP9 :
            case ISOM_BRAND_TYPE_3GR9 :
            case ISOM_BRAND_TYPE_3GS9 :
            case ISOM_BRAND_TYPE_3GT9 :
                file->max_3gpp_version = LSMASH_MAX( file->max_3gpp_version, 9 );
                break;
            default :
                break;
        }
        switch( brand )
        {
            case ISOM_BRAND_TYPE_AVC1 :
            case ISOM_BRAND_TYPE_ISO2 :
            case ISOM_BRAND_TYPE_ISO3 :
            case ISOM_BRAND_TYPE_ISO4 :
            case ISOM_BRAND_TYPE_ISO5 :
            case ISOM_BRAND_TYPE_ISO6 :
                file->avc_extensions = 1;
                break;
            case ISOM_BRAND_TYPE_3GP4 :
            case ISOM_BRAND_TYPE_3GP5 :
            case ISOM_BRAND_TYPE_3GP6 :
            case ISOM_BRAND_TYPE_3GP7 :
            case ISOM_BRAND_TYPE_3GP8 :
            case ISOM_BRAND_TYPE_3GP9 :
                file->forbid_tref = 1;
                break;
            case ISOM_BRAND_TYPE_3GH9 :
            case ISOM_BRAND_TYPE_3GM9 :
            case ISOM_BRAND_TYPE_DASH :
            case ISOM_BRAND_TYPE_DSMS :
            case ISOM_BRAND_TYPE_LMSG :
            case ISOM_BRAND_TYPE_MSDH :
            case ISOM_BRAND_TYPE_MSIX :
            case ISOM_BRAND_TYPE_SIMS :
                file->media_segment = 1;
                break;
            default :
                break;
        }
    }
    file->isom_compatible = !file->qt_compatible
                          || file->mp4_version1
                          || file->mp4_version2
                          || file->itunes_movie
                          || file->max_3gpp_version;
    file->undefined_64_ver = file->qt_compatible || file->itunes_movie;
    if( file->flags & LSMASH_FILE_MODE_WRITE )
    {
        /* Media Segment is incompatible with ISO Base Media File Format version 4 or former must be compatible with
         * version 6 or later since it requires default-base-is-moof and Track Fragment Base Media Decode Time Box. */
        if( file->media_segment && (file->min_isom_version < 5 || (file->max_isom_version && file->max_isom_version < 6)) )
            return LSMASH_ERR_INVALID_DATA;
        file->allow_moof_base = (file->max_isom_version >= 5 && file->min_isom_version >= 5)
                             || (file->max_isom_version == 0 && file->min_isom_version == UINT8_MAX && file->media_segment);
    }
    return 0;
}
コード例 #5
0
ファイル: chapter.c プロジェクト: darcyg/vapoursynth-plugins
int lsmash_create_reference_chapter_track( lsmash_root_t *root, uint32_t track_ID, char *file_name )
{
    if( isom_check_initializer_present( root ) < 0 )
        goto error_message;
    lsmash_file_t *file = root->file;
    if( !file
     || !file->moov
     || !file->moov->mvhd )
        goto error_message;
    if( file->forbid_tref || (!file->qt_compatible && !file->itunes_movie) )
    {
        lsmash_log( NULL, LSMASH_LOG_ERROR, "reference chapter is not available for this file.\n" );
        goto error_message;
    }
    FILE *chapter = NULL;       /* shut up 'uninitialized' warning */
    /* Create a Track Reference Box. */
    isom_trak_t *trak = isom_get_trak( file, track_ID );
    if( !trak )
    {
        lsmash_log( NULL, LSMASH_LOG_ERROR, "the specified track ID to apply the chapter doesn't exist.\n" );
        goto error_message;
    }
    if( !trak->tref && !isom_add_tref( trak ) )
        goto error_message;
    /* Create a track_ID for a new chapter track. */
    uint32_t *id = (uint32_t *)lsmash_malloc( sizeof(uint32_t) );
    if( !id )
        goto error_message;
    uint32_t chapter_track_ID = *id = file->moov->mvhd->next_track_ID;
    /* Create a Track Reference Type Box. */
    isom_tref_type_t *chap = isom_add_track_reference_type( trak->tref, QT_TREF_TYPE_CHAP );
    if( !chap )
    {
        lsmash_free( id );
        goto error_message;
    }
    chap->ref_count = 1;
    chap->track_ID  = id;
    /* Create a reference chapter track. */
    if( chapter_track_ID != lsmash_create_track( root, ISOM_MEDIA_HANDLER_TYPE_TEXT_TRACK ) )
        goto error_message;
    /* Set track parameters. */
    lsmash_track_parameters_t track_param;
    lsmash_initialize_track_parameters( &track_param );
    track_param.mode = ISOM_TRACK_IN_MOVIE | ISOM_TRACK_IN_PREVIEW;
    if( lsmash_set_track_parameters( root, chapter_track_ID, &track_param ) < 0 )
        goto fail;
    /* Set media parameters. */
    uint64_t media_timescale = lsmash_get_media_timescale( root, track_ID );
    if( !media_timescale )
        goto fail;
    lsmash_media_parameters_t media_param;
    lsmash_initialize_media_parameters( &media_param );
    media_param.timescale    = media_timescale;
    media_param.ISO_language = file->max_3gpp_version >= 6 || file->itunes_movie ? ISOM_LANGUAGE_CODE_UNDEFINED : 0;
    media_param.MAC_language = 0;
    if( lsmash_set_media_parameters( root, chapter_track_ID, &media_param ) < 0 )
        goto fail;
    /* Create a sample description. */
    lsmash_codec_type_t sample_type = file->max_3gpp_version >= 6 || file->itunes_movie
                                    ? ISOM_CODEC_TYPE_TX3G_TEXT
                                    : QT_CODEC_TYPE_TEXT_TEXT;
    lsmash_summary_t summary = { .sample_type = sample_type, .data_ref_index = 1 };
    uint32_t sample_entry = lsmash_add_sample_entry( root, chapter_track_ID, &summary );
    if( !sample_entry )
        goto fail;
    /* Check each line format. */
    fn_get_chapter_data fnc = isom_check_chap_line( file_name );
    if( !fnc )
        goto fail;
    /* Open chapter format file. */
    chapter = lsmash_fopen( file_name, "rb" );
    if( !chapter )
    {
        lsmash_log( NULL, LSMASH_LOG_ERROR, "failed to open the chapter file \"%s\".\n", file_name );
        goto fail;
    }
    /* Parse the file and write text samples. */
    isom_chapter_entry_t data;
    while( !fnc( chapter, &data ) )
    {
        /* set start_time */
        data.start_time = data.start_time * 1e-9 * media_timescale + 0.5;
        /* write a text sample here */
        int is_qt_text = lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_TEXT_TEXT );
        uint16_t name_length = strlen( data.chapter_name );
        lsmash_sample_t *sample = lsmash_create_sample( 2 + name_length + 12 * is_qt_text );
        if( !sample )
        {
            lsmash_free( data.chapter_name );
            goto fail;
        }
        sample->data[0] = (name_length >> 8) & 0xff;
        sample->data[1] =  name_length       & 0xff;
        memcpy( sample->data + 2, data.chapter_name, name_length );
        if( is_qt_text )
        {
            /* QuickTime Player requires Text Encoding Attribute Box ('encd') if media language is ISO language codes : undefined.
             * Also this box can avoid garbling if the QuickTime text sample is encoded by Unicode characters.
             * Note: 3GPP Timed Text supports only UTF-8 or UTF-16, so this box isn't needed. */
            static const uint8_t encd[12] =
                {
                    0x00, 0x00, 0x00, 0x0C,     /* size: 12 */
                    0x65, 0x6E, 0x63, 0x64,     /* type: 'encd' */
                    0x00, 0x00, 0x01, 0x00      /* Unicode Encoding */
                };
            memcpy( sample->data + 2 + name_length, encd, 12 );
        }
        sample->dts           = data.start_time;
        sample->cts           = data.start_time;
        sample->prop.ra_flags = ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC;
        sample->index         = sample_entry;
        if( lsmash_append_sample( root, chapter_track_ID, sample ) < 0 )
        {
            lsmash_free( data.chapter_name );
            goto fail;
        }
        lsmash_freep( &data.chapter_name );
    }
    if( lsmash_flush_pooled_samples( root, chapter_track_ID, 0 ) < 0 )
        goto fail;
    isom_trak_t *chapter_trak = isom_get_trak( file, chapter_track_ID );
    if( !chapter_trak )
        goto fail;
    fclose( chapter );
    chapter_trak->is_chapter       = 1;
    chapter_trak->related_track_ID = track_ID;
    return 0;
fail:
    if( chapter )
        fclose( chapter );
    /* Remove chapter track reference. */
    if( trak->tref->ref_list.tail )
        isom_remove_box_by_itself( trak->tref->ref_list.tail->data );
    if( trak->tref->ref_list.entry_count == 0 )
        isom_remove_box_by_itself( trak->tref );
    /* Remove the reference chapter track attached at tail of the list. */
    if( file->moov->trak_list.tail )
        isom_remove_box_by_itself( file->moov->trak_list.tail->data );
error_message:
    lsmash_log( NULL, LSMASH_LOG_ERROR, "failed to set reference chapter.\n" );
    return LSMASH_ERR_NAMELESS;
}

uint32_t lsmash_count_tyrant_chapter( lsmash_root_t *root )
{
    if( isom_check_initializer_present( root ) < 0
     && root->file->initializer->moov
     && root->file->initializer->moov->udta
     && root->file->initializer->moov->udta->chpl
     && root->file->initializer->moov->udta->chpl->list )
        return root->file->initializer->moov->udta->chpl->list->entry_count;
    return 0;
}

char *lsmash_get_tyrant_chapter( lsmash_root_t *root, uint32_t index, double *timestamp )
{
    if( isom_check_initializer_present( root ) < 0 )
        return NULL;
    lsmash_file_t *file = root->file->initializer;
    if( !file->moov
     || !file->moov->mvhd
     || !file->moov->udta
     || !file->moov->udta->chpl )
        return NULL;
    isom_chpl_t *chpl = file->moov->udta->chpl;
    isom_chpl_entry_t *data = (isom_chpl_entry_t *)lsmash_get_entry_data( chpl->list, index );
    if( !data )
        return NULL;
    double timescale = chpl->version ? 10000000.0 : file->moov->mvhd->timescale;
    *timestamp = data->start_time / timescale;
    if( !memcmp( data->chapter_name, UTF8_BOM, UTF8_BOM_LENGTH ) )
        return data->chapter_name + UTF8_BOM_LENGTH;
    return data->chapter_name;
}


int lsmash_print_chapter_list( lsmash_root_t *root )
{
    if( isom_check_initializer_present( root ) < 0
     || !(root->file->initializer->flags & LSMASH_FILE_MODE_READ) )
        return LSMASH_ERR_FUNCTION_PARAM;
    lsmash_file_t *file = root->file->initializer;
    if( file->moov
     && file->moov->udta
     && file->moov->udta->chpl )
    {
        isom_chpl_t *chpl = file->moov->udta->chpl;
        uint32_t timescale;
        if( !chpl->version )
        {
            if( !file->moov
             && !file->moov->mvhd )
                return LSMASH_ERR_NAMELESS;
            timescale = file->moov->mvhd->timescale;
        }
        else
            timescale = 10000000;
        uint32_t i = 1;
        for( lsmash_entry_t *entry = chpl->list->head; entry; entry = entry->next )
        {
            isom_chpl_entry_t *data = (isom_chpl_entry_t *)entry->data;
            int64_t start_time = data->start_time / timescale;
            int hh =  start_time / 3600;
            int mm = (start_time /   60) % 60;
            int ss =  start_time         % 60;
            int ms = ((data->start_time / (double)timescale) - hh * 3600 - mm * 60 - ss) * 1e3 + 0.5;
            if( !memcmp( data->chapter_name, UTF8_BOM, UTF8_BOM_LENGTH ) )    /* detect BOM */
            {
                data->chapter_name += UTF8_BOM_LENGTH;
#ifdef _WIN32
                if( i == 1 )
                    printf( UTF8_BOM );    /* add BOM on Windows */
#endif
            }
            printf( "CHAPTER%02"PRIu32"=%02d:%02d:%02d.%03d\n", i, hh, mm, ss, ms );
            printf( "CHAPTER%02"PRIu32"NAME=%s\n", i++, data->chapter_name );
        }
        return 0;
    }
    lsmash_log( NULL, LSMASH_LOG_ERROR, "this file doesn't have a chapter list.\n" );
    return LSMASH_ERR_NAMELESS;
}