コード例 #1
0
ファイル: dts_imp.c プロジェクト: arodland/l-smash
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;
}
コード例 #2
0
ファイル: vc1_imp.c プロジェクト: arodland/l-smash
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;
}
コード例 #3
0
ファイル: vc1_imp.c プロジェクト: arodland/l-smash
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;
}
コード例 #4
0
ファイル: mp4_lsmash.c プロジェクト: 0x0B501E7E/x264
static void remove_mp4_hnd( hnd_t handle )
{
    mp4_hnd_t *p_mp4 = handle;
    if( !p_mp4 )
        return;
    lsmash_cleanup_summary( (lsmash_summary_t *)p_mp4->summary );
    lsmash_close_file( &p_mp4->file_param );
    lsmash_destroy_root( p_mp4->p_root );
    free( p_mp4->p_sei_buffer );
    free( p_mp4 );
}
コード例 #5
0
ファイル: wave_imp.c プロジェクト: darcyg/vapoursynth-plugins
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;
}
コード例 #6
0
ファイル: wave_imp.c プロジェクト: darcyg/vapoursynth-plugins
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;
}
コード例 #7
0
bool fcMP4Muxer::mux(const Params &params)
{
    lsmash_root_t               *root;
    lsmash_file_parameters_t    mp4_stream;
    lsmash_file_parameters_t    h264_stream;
    lsmash_brand_type           major_brand = ISOM_BRAND_TYPE_MP42;
    lsmash_brand_type           compatible_brands[2] = { ISOM_BRAND_TYPE_MP42, ISOM_BRAND_TYPE_ISOM };
    uint32_t                    fps_num = params.frame_rate;
    uint32_t                    fps_den = 1;

    // 出力 mp4
    root = lsmash_create_root();
    if (lsmash_open_file(params.out_mp4_path, 0, &mp4_stream) != 0) {
        return false;
    }
    mp4_stream.major_brand = major_brand;
    mp4_stream.brands = compatible_brands;
    mp4_stream.brand_count = sizeof(compatible_brands) / sizeof(compatible_brands[0]);
    mp4_stream.minor_version = 0;
    lsmash_set_file(root, &mp4_stream);

    lsmash_movie_parameters_t movie_param;
    lsmash_initialize_movie_parameters(&movie_param);
    lsmash_set_movie_parameters(root, &movie_param);


    int track_number = 1;
    MP4TrackData track_data[2];
    int num_track_data = 0;

    if (params.in_h264_path) {
        importer_t *h264_importer = lsmash_importer_open(params.in_h264_path, "H.264");
        if (h264_importer == nullptr) { return false; }

        int h264_track_id = lsmash_create_track(root, ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK);

        lsmash_track_parameters_t track_param;
        lsmash_initialize_track_parameters(&track_param);
        (int&)track_param.mode = ISOM_TRACK_IN_MOVIE | ISOM_TRACK_IN_PREVIEW;

        int sample_entry = 0;
        lsmash_summary_t *summary = lsmash_duplicate_summary(h264_importer, track_number);
        auto video_summary = (lsmash_video_summary_t*)summary;
        track_param.display_width = video_summary->width << 16;
        track_param.display_height = video_summary->height << 16;
        lsmash_set_track_parameters(root, h264_track_id, &track_param);
        sample_entry = lsmash_add_sample_entry(root, h264_track_id, summary);

        auto& td = track_data[num_track_data++];
        td.importer = h264_importer;
        td.summary = summary;
        td.sample_entry = sample_entry;
        td.track_number = track_number;
        td.track_id = h264_track_id;
        td.timescale = video_summary->timescale;
        td.timebase = video_summary->timebase;

        lsmash_media_parameters_t media_param;
        lsmash_initialize_media_parameters(&media_param);
        media_param.timescale = td.timescale;
        lsmash_set_media_parameters(root, h264_track_id, &media_param);
    }

    if (params.in_aac_path) {
        importer_t *aac_importer = lsmash_importer_open(params.in_aac_path, "adts");
        if (aac_importer == nullptr) { return false; }

        int aac_track_id = lsmash_create_track(root, ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK);

        lsmash_track_parameters_t track_param;
        lsmash_initialize_track_parameters(&track_param);
        (int&)track_param.mode = ISOM_TRACK_IN_MOVIE | ISOM_TRACK_IN_PREVIEW;

        int sample_entry = 0;
        lsmash_summary_t *summary = lsmash_duplicate_summary(aac_importer, track_number);
        auto audio_summary = (lsmash_audio_summary_t*)summary;
        lsmash_set_track_parameters(root, aac_track_id, &track_param);
        sample_entry = lsmash_add_sample_entry(root, aac_track_id, summary);

        auto& td = track_data[num_track_data++];
        td.importer = aac_importer;
        td.summary = summary;
        td.sample_entry = sample_entry;
        td.track_number = track_number;
        td.track_id = aac_track_id;
        td.timescale = audio_summary->frequency;
        td.timebase = 1;

        lsmash_media_parameters_t media_param;
        lsmash_initialize_media_parameters(&media_param);
        media_param.timescale = td.timescale;
        lsmash_set_media_parameters(root, aac_track_id, &media_param);
    }

    double largest_dts = 0.0;
    uint32_t num_consecutive_sample_skip = 0;
    for (int ti = 0;;) {
        auto &td = track_data[ti];

        if (!td.sample) {
            int ret = lsmash_importer_get_access_unit(td.importer, td.track_number, &td.sample);
            if (ret <= -1) // error
            {
                lsmash_delete_sample(td.sample);
                break;
            }
            else if (ret == 1) /* a change of stream's properties */
            {
                lsmash_cleanup_summary(td.summary);
                td.summary = lsmash_duplicate_summary(td.importer, td.track_number);
                td.sample_entry = lsmash_add_sample_entry(root, td.track_id, td.summary);
                if (!td.sample_entry) { break; }
            }
            else if (ret == 2) /* EOF */
            {
                lsmash_delete_sample(td.sample);
                break;
            }

            if (td.sample)
            {
                td.sample->index = td.sample_entry;
                td.sample->dts *= td.timebase;
                td.sample->cts *= td.timebase;
                td.dts = (double)td.sample->dts / td.timescale;
            }
        }

        if (td.sample) {
            if (td.dts <= largest_dts || num_consecutive_sample_skip == num_track_data)
            {
                uint64_t sample_size = td.sample->length;
                uint64_t sample_dts = td.sample->dts;
                uint64_t sample_cts = td.sample->cts;
                if (lsmash_append_sample(root, td.track_id, td.sample)) {
                    return false;
                }
                td.prev_dts = sample_dts;
                td.sample = nullptr;
                largest_dts = std::max<double>(largest_dts, td.dts);
                num_consecutive_sample_skip = 0;
            }
            else {
                // skip
                ++num_consecutive_sample_skip;
            }
        }

        ti = (ti + 1) % num_track_data;
    }

    for (int i = 0; i < num_track_data; ++i) {
        lsmash_flush_pooled_samples(root, track_data[i].track_id, fps_den);
        lsmash_cleanup_summary(track_data[i].summary);
        lsmash_importer_close(track_data[i].importer);
    }


    lsmash_finish_movie(root, nullptr);
    lsmash_close_file(&mp4_stream);
    lsmash_destroy_root(root);

    return true;
}
コード例 #8
0
ファイル: dts_imp.c プロジェクト: arodland/l-smash
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;
}