Beispiel #1
0
static int isom_add_chpl_entry( isom_chpl_t *chpl, isom_chapter_entry_t *chap_data )
{
    if( !chap_data->chapter_name
     || !chpl
     || !chpl->list )
        return LSMASH_ERR_FUNCTION_PARAM;
    isom_chpl_entry_t *data = lsmash_malloc( sizeof(isom_chpl_entry_t) );
    if( !data )
        return LSMASH_ERR_MEMORY_ALLOC;
    data->start_time          = chap_data->start_time;
    data->chapter_name_length = strlen( chap_data->chapter_name );
    data->chapter_name        = (char *)lsmash_malloc( data->chapter_name_length + 1 );
    if( !data->chapter_name )
    {
        lsmash_free( data );
        return LSMASH_ERR_MEMORY_ALLOC;
    }
    memcpy( data->chapter_name, chap_data->chapter_name, data->chapter_name_length );
    data->chapter_name[ data->chapter_name_length ] = '\0';
    if( lsmash_add_entry( chpl->list, data ) < 0 )
    {
        lsmash_free( data->chapter_name );
        lsmash_free( data );
        return LSMASH_ERR_MEMORY_ALLOC;
    }
    return 0;
}
Beispiel #2
0
static int dts_importer_probe( importer_t *importer )
{
    dts_importer_t *dts_imp = create_dts_importer( importer );
    if( !dts_imp )
        return LSMASH_ERR_MEMORY_ALLOC;
    lsmash_bits_t *bits = dts_imp->info.bits;
    lsmash_bs_t   *bs   = bits->bs;
    bs->buffer.max_size = DTS_MAX_EXSS_SIZE;
    importer->info = dts_imp;
    int err = dts_importer_get_next_accessunit_internal( importer );
    if( err < 0 )
        goto fail;
    lsmash_audio_summary_t *summary = dts_create_summary( &dts_imp->info );
    if( !summary )
    {
        err = LSMASH_ERR_NAMELESS;
        goto fail;
    }
    if( importer->status != IMPORTER_EOF )
        importer->status = IMPORTER_OK;
    dts_imp->au_number = 0;
    if( lsmash_add_entry( importer->summaries, summary ) < 0 )
    {
        lsmash_cleanup_summary( (lsmash_summary_t *)summary );
        err = LSMASH_ERR_MEMORY_ALLOC;
        goto fail;
    }
    return 0;
fail:
    remove_dts_importer( dts_imp );
    importer->info = NULL;
    return err;
}
Beispiel #3
0
static lsmash_video_summary_t *vc1_create_summary( vc1_info_t *info, vc1_sequence_header_t *sequence, uint32_t max_au_length )
{
    if( !info->sequence.present || !info->entry_point.present )
        return NULL;
    lsmash_video_summary_t *summary = (lsmash_video_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_VIDEO );
    if( !summary )
        return NULL;
    lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1,
                                                                           LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
    specific->data.unstructured = lsmash_create_vc1_specific_info( &info->dvc1_param, &specific->size );
    if( !specific->data.unstructured
     || lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
    {
        lsmash_cleanup_summary( (lsmash_summary_t *)summary );
        lsmash_destroy_codec_specific_data( specific );
        return NULL;
    }
    summary->sample_type           = ISOM_CODEC_TYPE_VC_1_VIDEO;
    summary->max_au_length         = max_au_length;
    summary->timescale             = sequence->framerate_numerator;
    summary->timebase              = sequence->framerate_denominator;
    summary->vfr                   = !sequence->framerate_flag;
    summary->sample_per_field      = 0;
    summary->width                 = sequence->disp_horiz_size;
    summary->height                = sequence->disp_vert_size;
    summary->par_h                 = sequence->aspect_width;
    summary->par_v                 = sequence->aspect_height;
    summary->color.primaries_index = sequence->color_prim;
    summary->color.transfer_index  = sequence->transfer_char;
    summary->color.matrix_index    = sequence->matrix_coef;
    return summary;
}
Beispiel #4
0
static int vc1_importer_probe( importer_t *importer )
{
    /* Find the first start code. */
    vc1_importer_t *vc1_imp = create_vc1_importer( importer );
    if( !vc1_imp )
        return LSMASH_ERR_MEMORY_ALLOC;
    lsmash_bs_t *bs = importer->bs;
    uint64_t first_ebdu_head_pos = 0;
    int err;
    while( 1 )
    {
        /* The first EBDU in decoding order of the stream shall have start code (0x000001). */
        if( 0x000001 == lsmash_bs_show_be24( bs, first_ebdu_head_pos ) )
            break;
        /* Invalid if encountered any value of non-zero before the first start code. */
        if( lsmash_bs_show_byte( bs, first_ebdu_head_pos ) )
        {
            err = LSMASH_ERR_INVALID_DATA;
            goto fail;
        }
        ++first_ebdu_head_pos;
    }
    /* OK. It seems the stream has a sequence header of VC-1. */
    importer->info = vc1_imp;
    vc1_info_t *info = &vc1_imp->info;
    lsmash_bs_read_seek( bs, first_ebdu_head_pos, SEEK_SET );
    info->ebdu_head_pos = first_ebdu_head_pos;
    if( (err = vc1_analyze_whole_stream( importer )) < 0 )
        goto fail;
    lsmash_video_summary_t *summary = vc1_create_summary( info, &vc1_imp->first_sequence, vc1_imp->max_au_length );
    if( !summary )
    {
        err = LSMASH_ERR_NAMELESS;
        goto fail;
    }
    if( lsmash_add_entry( importer->summaries, summary ) < 0 )
    {
        lsmash_cleanup_summary( (lsmash_summary_t *)summary );
        err = LSMASH_ERR_MEMORY_ALLOC;
        goto fail;
    }
    /* Go back to layer of the first EBDU. */
    importer->status = IMPORTER_OK;
    lsmash_bs_read_seek( bs, first_ebdu_head_pos, SEEK_SET );
    info->prev_bdu_type                  = 0xFF;    /* 0xFF is a forbidden value. */
    info->ebdu_head_pos                  = first_ebdu_head_pos;
    uint8_t *temp_access_unit            = info->access_unit.data;
    uint8_t *temp_incomplete_access_unit = info->access_unit.incomplete_data;
    memset( &info->access_unit, 0, sizeof(vc1_access_unit_t) );
    info->access_unit.data               = temp_access_unit;
    info->access_unit.incomplete_data    = temp_incomplete_access_unit;
    memset( &info->picture, 0, sizeof(vc1_picture_info_t) );
    return 0;
fail:
    remove_vc1_importer( vc1_imp );
    importer->info = NULL;
    lsmash_remove_entries( importer->summaries, lsmash_cleanup_summary );
    return err;
}
Beispiel #5
0
int lsmash_add_codec_specific_data( lsmash_summary_t *summary, lsmash_codec_specific_t *specific )
{
    if( !summary || !summary->opaque || !specific )
        return LSMASH_ERR_FUNCTION_PARAM;
    lsmash_codec_specific_t *dup = isom_duplicate_codec_specific_data( specific );
    if( !dup )
        return LSMASH_ERR_NAMELESS;
    if( lsmash_add_entry( &summary->opaque->list, dup ) < 0 )
    {
        lsmash_destroy_codec_specific_data( dup );
        return LSMASH_ERR_MEMORY_ALLOC;
    }
    return 0;
}
Beispiel #6
0
/* create AudioSpecificConfig as memory block from summary, and set it into that summary itself */
int lsmash_setup_AudioSpecificConfig( lsmash_audio_summary_t *summary )
{
    if( !summary || !summary->opaque )
        return LSMASH_ERR_FUNCTION_PARAM;
    /* Remove an old one. */
    for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
    {
        lsmash_codec_specific_t *cs = (lsmash_codec_specific_t *)entry->data;
        if( !cs || cs->type != LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG )
            continue;
        lsmash_remove_entry_direct( &summary->opaque->list, entry, lsmash_destroy_codec_specific_data );
    }
    /* Create and add a new one. */
    uint32_t data_length;
    uint8_t *data = mp4a_export_AudioSpecificConfig( summary->aot,
                                                     summary->frequency,
                                                     summary->channels,
                                                     summary->sbr_mode,
                                                     NULL,  /* FIXME */
                                                     0,     /* FIXME */
                                                     &data_length );
    if( !data )
        return LSMASH_ERR_NAMELESS;
    lsmash_codec_specific_t *cs = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG,
                                                                     LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
    if( !cs )
    {
        lsmash_free( data );
        return LSMASH_ERR_MEMORY_ALLOC;
    }
    lsmash_mp4sys_decoder_parameters_t *param = (lsmash_mp4sys_decoder_parameters_t *)cs->data.structured;
    param->objectTypeIndication = MP4SYS_OBJECT_TYPE_Audio_ISO_14496_3;
    param->streamType           = MP4SYS_STREAM_TYPE_AudioStream;
    int err = lsmash_set_mp4sys_decoder_specific_info( param, data, data_length );
    lsmash_free( data );
    if( err < 0 || (err = lsmash_add_entry( &summary->opaque->list, cs )) < 0 )
    {
        lsmash_destroy_codec_specific_data( cs );
        return err;
    }
    return 0;
}
Beispiel #7
0
static int wave_importer_probe( importer_t *importer )
{
    wave_importer_t *wave_imp = create_wave_importer( importer );
    if( !wave_imp )
        return LSMASH_ERR_MEMORY_ALLOC;
    int err = 0;
    uint32_t filesize;
    lsmash_bs_t *bs = importer->bs;
    if( lsmash_bs_get_be32( bs ) != LSMASH_4CC( 'R', 'I', 'F', 'F' )
     || ((filesize = lsmash_bs_get_le32( bs ) + 8) < WAVE_MIN_FILESIZE && filesize > 8)
     || lsmash_bs_get_be32( bs ) != LSMASH_4CC( 'W', 'A', 'V', 'E' ) )
    {
        err = LSMASH_ERR_INVALID_DATA;
        goto fail;
    }
    int fmt_chunk_present  = 0;
    int data_chunk_present = 0;
    while( !bs->eob && !(fmt_chunk_present && data_chunk_present) )
    {
        uint32_t ckID   = lsmash_bs_get_be32( bs );
        uint32_t ckSize = lsmash_bs_get_le32( bs );
        lsmash_bs_reset_counter( bs );
        switch( ckID )
        {
            case LSMASH_4CC( 'f', 'm', 't', ' ' ) :
                if( ckSize < 16 )
                {
                    err = LSMASH_ERR_INVALID_DATA;
                    goto fail;
                }
                if( (err = wave_parse_fmt_chunk( wave_imp, bs )) < 0 )
                    goto fail;
                fmt_chunk_present = 1;
                break;
            case LSMASH_4CC( 'd', 'a', 't', 'a' ) :
                if( !fmt_chunk_present )
                {
                    /* The 'fmt ' chunk must be present before the 'data' chunk. */
                    err = LSMASH_ERR_INVALID_DATA;
                    goto fail;
                }
                wave_imp->chunk.data_offset = lsmash_bs_get_stream_pos( bs );
                wave_imp->chunk.length      = ckSize;
                wave_imp->chunk.number      = 1;
                wave_imp->chunk.file        = importer->file;
                wave_imp->number_of_samples = ckSize / wave_imp->fmt.wfx.nBlockAlign;
                data_chunk_present = 1;
                break;
            default :
                break;
        }
        if( !data_chunk_present )
        {
            /* Skip the rest of this chunk.
             * Note that ckData is word-aligned even if ckSize is an odd number. */
            uint32_t skip_size = ckSize;
            if( skip_size & 1 )
                skip_size++;
            if( skip_size > lsmash_bs_count( bs ) )
            {
                skip_size -= lsmash_bs_count( bs );
                lsmash_bs_read_seek( bs, skip_size, SEEK_CUR );
            }
        }
    }
    if( !(fmt_chunk_present && data_chunk_present) )
    {
        err = LSMASH_ERR_INVALID_DATA;
        goto fail;
    }
    /* Make fake movie.
     * Treat WAVE file format as if it's QuickTime file format. */
    uint32_t track_ID;
    lsmash_movie_parameters_t movie_param = { 0 };
    lsmash_track_parameters_t track_param = { 0 };
    lsmash_media_parameters_t media_param = { 0 };
    importer->file->qt_compatible = 1;
    if( (err = lsmash_importer_make_fake_movie( importer )) < 0
     || (err = lsmash_importer_make_fake_track( importer, ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK, &track_ID )) < 0
     || (err = lsmash_get_movie_parameters( importer->root, &movie_param )) < 0
     || (err = lsmash_get_track_parameters( importer->root, track_ID, &track_param )) < 0
     || (err = lsmash_get_media_parameters( importer->root, track_ID, &media_param )) < 0 )
        goto fail;
    movie_param.timescale = wave_imp->fmt.wfx.nSamplesPerSec;
    media_param.timescale = wave_imp->fmt.wfx.nSamplesPerSec;
    if( (err = lsmash_set_movie_parameters( importer->root, &movie_param )) < 0
     || (err = lsmash_set_track_parameters( importer->root, track_ID, &track_param )) < 0
     || (err = lsmash_set_media_parameters( importer->root, track_ID, &media_param )) < 0 )
        goto fail;
    lsmash_audio_summary_t *summary = wave_create_summary( &wave_imp->fmt );
    if( !summary || lsmash_add_sample_entry( importer->root, track_ID, summary ) != 1 )
    {
        lsmash_cleanup_summary( (lsmash_summary_t *)summary );
        err = LSMASH_ERR_NAMELESS;
        goto fail;
    }
    if( (err = lsmash_add_entry( importer->summaries, summary )) < 0 )
    {
        lsmash_cleanup_summary( (lsmash_summary_t *)summary );
        goto fail;
    }
    importer->info   = wave_imp;
    importer->status = IMPORTER_OK;
    return 0;
fail:
    lsmash_importer_break_fake_movie( importer );
    remove_wave_importer( wave_imp );
    importer->file->qt_compatible = 0;
    importer->info = NULL;
    return err;
}
Beispiel #8
0
static lsmash_audio_summary_t *wave_create_summary( waveformat_extensible_t *fmt )
{
    lsmash_audio_summary_t *summary = (lsmash_audio_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_AUDIO );
    if( !summary )
        return NULL;
    waveformat_extended_t *wfx = &fmt->wfx;
    summary->sample_type      = QT_CODEC_TYPE_LPCM_AUDIO;
    summary->aot              = MP4A_AUDIO_OBJECT_TYPE_NULL;
    summary->frequency        = wfx->nSamplesPerSec;
    summary->channels         = wfx->nChannels;
    summary->sample_size      = wfx->wFormatTag == WAVE_FORMAT_TYPE_ID_EXTENSIBLE
                              ? fmt->Samples.wValidBitsPerSample
                              : wfx->wBitsPerSample;
    summary->samples_in_frame = 1000;   /* arbitrary */
    summary->sbr_mode         = MP4A_AAC_SBR_NOT_SPECIFIED;
    summary->bytes_per_frame  = wfx->nBlockAlign * summary->samples_in_frame;
    summary->max_au_length    = summary->bytes_per_frame;
    lsmash_codec_specific_t *cs = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS,
                                                                     LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
    if( !cs )
        goto fail;
    lsmash_qt_audio_format_specific_flags_t *lpcm = (lsmash_qt_audio_format_specific_flags_t *)cs->data.structured;
    if( (summary->sample_size & 7) == 0 )
        lpcm->format_flags |= QT_AUDIO_FORMAT_FLAG_PACKED;
    else
        lpcm->format_flags |= QT_AUDIO_FORMAT_FLAG_ALIGNED_HIGH;
    if( summary->sample_size > 8 )
        lpcm->format_flags |= QT_AUDIO_FORMAT_FLAG_SIGNED_INTEGER;
    if( lsmash_add_entry( &summary->opaque->list, cs ) < 0 )
    {
        lsmash_destroy_codec_specific_data( cs );
        goto fail;
    }
    if( wfx->wFormatTag == WAVE_FORMAT_TYPE_ID_EXTENSIBLE || wfx->nChannels > 2 )
    {
        cs = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT,
                                                LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
        if( !cs )
            goto fail;
        lsmash_qt_audio_channel_layout_t *layout = (lsmash_qt_audio_channel_layout_t *)cs->data.structured;
        if( wfx->wFormatTag == WAVE_FORMAT_TYPE_ID_EXTENSIBLE )
        {
            layout->channelLayoutTag = QT_CHANNEL_LAYOUT_USE_CHANNEL_BITMAP;
            layout->channelBitmap    = fmt->dwChannelMask;
        }
        else
        {
            layout->channelLayoutTag = QT_CHANNEL_LAYOUT_UNKNOWN | wfx->nChannels;
            layout->channelBitmap    = 0;
        }
        if( lsmash_add_entry( &summary->opaque->list, cs ) < 0 )
        {
            lsmash_destroy_codec_specific_data( cs );
            goto fail;
        }
    }
    return summary;
fail:
    lsmash_cleanup_summary( (lsmash_summary_t *)summary );
    return NULL;
}
Beispiel #9
0
static lsmash_audio_summary_t *dts_create_summary( dts_info_t *info )
{
    lsmash_audio_summary_t *summary = (lsmash_audio_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_AUDIO );
    if( !summary )
        return NULL;
    lsmash_dts_specific_parameters_t *param = &info->ddts_param;
    lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS,
                                                                           LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
    specific->data.unstructured = lsmash_create_dts_specific_info( param, &specific->size );
    if( !specific->data.unstructured
     || lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
    {
        lsmash_cleanup_summary( (lsmash_summary_t *)summary );
        lsmash_destroy_codec_specific_data( specific );
        return NULL;
    }
    /* The CODEC identifiers probably should not be the combination of 'mp4a' and
     * the objectTypeIndications for DTS audio since there is no public specification
     * which defines the encapsulation of the stream as the MPEG-4 Audio context yet.
     * In the world, there are muxers which is using such doubtful implementation.
     * The objectTypeIndications are registered at MP4RA, but this does not always
     * mean we can mux by using those objectTypeIndications.
     * If available, there shall be the specification which defines the existence of
     * DecoderSpecificInfo and its semantics, and what access unit consists of. */
    summary->sample_type = lsmash_dts_get_codingname( param );
    summary->aot         = MP4A_AUDIO_OBJECT_TYPE_NULL;     /* make no sense */
    summary->sbr_mode    = MP4A_AAC_SBR_NOT_SPECIFIED;      /* make no sense */
    switch( param->DTSSamplingFrequency )
    {
        case 12000 :    /* Invalid? (No reference in the spec) */
        case 24000 :
        case 48000 :
        case 96000 :
        case 192000 :
        case 384000 :   /* Invalid? (No reference in the spec) */
            summary->frequency = 48000;
            break;
        case 22050 :
        case 44100 :
        case 88200 :
        case 176400 :
        case 352800 :   /* Invalid? (No reference in the spec) */
            summary->frequency = 44100;
            break;
        case 8000 :     /* Invalid? (No reference in the spec) */
        case 16000 :
        case 32000 :
        case 64000 :
        case 128000 :
            summary->frequency = 32000;
            break;
        default :
            summary->frequency = 0;
            break;
    }
    summary->samples_in_frame = (summary->frequency * info->frame_duration) / param->DTSSamplingFrequency;
    summary->max_au_length    = DTS_MAX_CORE_SIZE + DTS_MAX_NUM_EXSS * DTS_MAX_EXSS_SIZE;
    summary->sample_size      = param->pcmSampleDepth;
    summary->channels         = dts_get_max_channel_count( info );
    return summary;
}