Exemple #1
0
static void bs_alloc( lsmash_bs_t *bs, size_t alloc )
{
    if( (bs->buffer.alloc >= alloc) || bs->error )
        return;
    if( !bs->buffer.internal )
    {
        /* We cannot re-allocate the memory block. */
        bs->error = 1;
        return;
    }
    alloc += (1 << 16);
    alloc  = LSMASH_MAX( alloc, bs->buffer.max_size );
    uint8_t *data;
    if( !bs->buffer.data )
        data = lsmash_malloc( alloc );
    else
        data = lsmash_realloc( bs->buffer.data, alloc );
    if( !data )
    {
        bs_buffer_free( bs );
        bs->error = 1;
        return;
    }
    bs->buffer.internal = 1;
    bs->buffer.data     = data;
    bs->buffer.alloc    = alloc;
}
Exemple #2
0
/* TODO: Support offset > INT64_MAX */
int64_t lsmash_bs_read_seek( lsmash_bs_t *bs, int64_t offset, int whence )
{
    if( whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END )
        return LSMASH_ERR_FUNCTION_PARAM;
    if( whence == SEEK_CUR )
        offset -= lsmash_bs_get_remaining_buffer_size( bs );
    /* Check whether we can seek on the buffer. */
    if( !bs->buffer.unseekable )
    {
        assert( bs->offset >= bs->buffer.store );
        uint64_t dst_offset = bs_estimate_seek_offset( bs, offset, whence );
        uint64_t offset_s = bs->offset - bs->buffer.store;
        uint64_t offset_e = bs->offset;
        if( bs->unseekable || (dst_offset >= offset_s && dst_offset < offset_e) )
        {
            /* OK, we can. So, seek on the buffer. */
            bs->buffer.pos = dst_offset - offset_s;
            bs->eob        = 0;
            return lsmash_bs_get_stream_pos( bs );
        }
    }
    if( bs->unseekable )
        return LSMASH_ERR_NAMELESS;
    /* Try to seek the stream. */
    int64_t ret = bs->seek( bs->stream, offset, whence );
    if( ret < 0 )
        return ret;
    bs->offset  = ret;
    bs->written = LSMASH_MAX( bs->written, bs->offset );
    bs->eof     = 0;
    bs->eob     = 0;
    /* The data on the buffer is invalid. */
    lsmash_bs_empty( bs );
    return ret;
}
Exemple #3
0
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;
}
Exemple #4
0
lsmash_file_t *lsmash_set_file
(
    lsmash_root_t            *root,
    lsmash_file_parameters_t *param
)
{
    if( !root || !param )
        return NULL;
    lsmash_file_t *file = isom_add_file( root );
    if( !file )
        return NULL;
    lsmash_bs_t *bs = lsmash_bs_create();
    if( !bs )
        goto fail;
    file->bs                  = bs;
    file->flags               = param->mode;
    file->bs->stream          = param->opaque;
    file->bs->read            = param->read;
    file->bs->write           = param->write;
    file->bs->seek            = param->seek;
    file->bs->unseekable      = (param->seek == NULL);
    file->bs->buffer.max_size = param->max_read_size;
    file->max_chunk_duration  = param->max_chunk_duration;
    file->max_async_tolerance = LSMASH_MAX( param->max_async_tolerance, 2 * param->max_chunk_duration );
    file->max_chunk_size      = param->max_chunk_size;
    if( (file->flags & LSMASH_FILE_MODE_WRITE)
     && (file->flags & LSMASH_FILE_MODE_BOX) )
    {
        /* Construction of Segment Index Box requires seekability at our current implementation.
         * If segment is not so large, data rearrangement can be avoided by buffering i.e. the
         * seekability is not essential, but at present we don't support buffering of all materials
         * within segment. */
        if( (file->flags & LSMASH_FILE_MODE_INDEX) && file->bs->unseekable )
            goto fail;
        /* Establish the fragment handler if required. */
        if( file->flags & LSMASH_FILE_MODE_FRAGMENTED )
        {
            file->fragment = lsmash_malloc_zero( sizeof(isom_fragment_manager_t) );
            if( !file->fragment )
                goto fail;
            file->fragment->first_moof_pos = FIRST_MOOF_POS_UNDETERMINED;
            file->fragment->pool = lsmash_create_entry_list();
            if( !file->fragment->pool )
                goto fail;
        }
        else if( file->bs->unseekable )
            /* For unseekable output operations, LSMASH_FILE_MODE_FRAGMENTED shall be set. */
            goto fail;
        /* Establish file types. */
        if( isom_set_brands( file, param->major_brand,
                                   param->minor_version,
                                   param->brands, param->brand_count ) < 0 )
            goto fail;
        /* Create the movie header if the initialization of the streams is required. */
        if( (file->flags & LSMASH_FILE_MODE_INITIALIZATION) && !isom_movie_create( file ) )
            goto fail;
    }
    if( !root->file )
        root->file = file;
    return file;
fail:
    isom_remove_box_by_itself( file );
    return NULL;
}
Exemple #5
0
static int vc1_analyze_whole_stream
(
    importer_t *importer
)
{
    /* Parse all EBDU in the stream for preparation of calculating timestamps. */
    uint32_t cts_alloc = (1 << 12) * sizeof(uint64_t);
    uint64_t *cts = lsmash_malloc( cts_alloc );
    if( !cts )
        return LSMASH_ERR_MEMORY_ALLOC; /* Failed to allocate CTS list */
    uint32_t num_access_units  = 0;
    uint32_t num_consecutive_b = 0;
    lsmash_class_t *logger = &(lsmash_class_t){ "VC-1" };
    lsmash_log( &logger, LSMASH_LOG_INFO, "Analyzing stream as VC-1\r" );
    vc1_importer_t *vc1_imp = (vc1_importer_t *)importer->info;
    vc1_info_t     *info    = &vc1_imp->info;
    importer->status = IMPORTER_OK;
    int err;
    while( importer->status != IMPORTER_EOF )
    {
#if 0
        lsmash_log( &logger, LSMASH_LOG_INFO, "Analyzing stream as VC-1: %"PRIu32"\n", num_access_units + 1 );
#endif
        if( (err = vc1_importer_get_access_unit_internal( importer, 1 )) < 0 )
            goto fail;
        vc1_importer_check_eof( importer, &info->access_unit );
        /* In the case where B-pictures exist
         * Decode order
         *      I[0]P[1]P[2]B[3]B[4]P[5]...
         * DTS
         *        0   1   2   3   4   5 ...
         * Composition order
         *      I[0]P[1]B[3]B[4]P[2]P[5]...
         * CTS
         *        1   2   3   4   5   6 ...
         * We assumes B or BI-pictures always be present in the stream here. */
        if( !info->access_unit.disposable )
        {
            /* Apply CTS of the last B-picture plus 1 to the last non-B-picture. */
            if( num_access_units > num_consecutive_b )
                cts[ num_access_units - num_consecutive_b - 1 ] = num_access_units;
            num_consecutive_b = 0;
        }
        else    /* B or BI-picture */
        {
            /* B and BI-pictures shall be output or displayed in the same order as they are encoded. */
            cts[ num_access_units ] = num_access_units;
            ++num_consecutive_b;
            info->dvc1_param.bframe_present = 1;
        }
        if( cts_alloc <= num_access_units * sizeof(uint64_t) )
        {
            uint32_t alloc = 2 * num_access_units * sizeof(uint64_t);
            uint64_t *temp = lsmash_realloc( cts, alloc );
            if( !temp )
            {
                err = LSMASH_ERR_MEMORY_ALLOC;
                goto fail;  /* Failed to re-allocate CTS list */
            }
            cts = temp;
            cts_alloc = alloc;
        }
        vc1_imp->max_au_length = LSMASH_MAX( info->access_unit.data_length, vc1_imp->max_au_length );
        ++num_access_units;
    }
    if( num_access_units > num_consecutive_b )
        cts[ num_access_units - num_consecutive_b - 1 ] = num_access_units;
    else
    {
        err = LSMASH_ERR_INVALID_DATA;
        goto fail;
    }
    /* Construct timestamps. */
    lsmash_media_ts_t *timestamp = lsmash_malloc( num_access_units * sizeof(lsmash_media_ts_t) );
    if( !timestamp )
    {
        err = LSMASH_ERR_MEMORY_ALLOC;
        goto fail;  /* Failed to allocate timestamp list */
    }
    for( uint32_t i = 1; i < num_access_units; i++ )
        if( cts[i] < cts[i - 1] )
        {
            vc1_imp->composition_reordering_present = 1;
            break;
        }
    if( vc1_imp->composition_reordering_present )
        for( uint32_t i = 0; i < num_access_units; i++ )
        {
            timestamp[i].cts = cts[i];
            timestamp[i].dts = i;
        }
    else
        for( uint32_t i = 0; i < num_access_units; i++ )
            timestamp[i].cts = timestamp[i].dts = i;
    lsmash_free( cts );
    lsmash_log_refresh_line( &logger );
#if 0
    for( uint32_t i = 0; i < num_access_units; i++ )
        fprintf( stderr, "Timestamp[%"PRIu32"]: DTS=%"PRIu64", CTS=%"PRIu64"\n", i, timestamp[i].dts, timestamp[i].cts );
#endif
    vc1_imp->ts_list.sample_count = num_access_units;
    vc1_imp->ts_list.timestamp    = timestamp;
    return 0;
fail:
    lsmash_log_refresh_line( &logger );
    lsmash_free( cts );
    return err;
}