liblsmashの使い方
更新日: 2014年03月23日

・muxerとして使う /************************** * 多重化サンプルコード * * (エラーチェック省略) * **************************/ #include <lsmash.h> #define VIDEO_TRACK 0 #define AUDIO_TRACK 1 typedef struct { void *data; int size; int idr; uint64_t dts; uint64_t cts; } frame_t; /* エンコード * 入力データにDTSを与えて、エンコーダが出力データを返すときに与えられたDTSに、 * 並び替えによる遅延を加えたものをCTSとし、frame_t構造体に格納し返す */ static *frame_t encode_frame( uint32_t stream_id, uint64_t dts ) { frame_t *frame; /* エンコード処理色々 */ return frame; } int main( void ) { /* ROOT */ lsmash_root_t *root; /* ファイル */ lsmash_file_t *file; lsmash_file_parameters_t file_param; lsmash_brand_type major_brand = ISOM_BRAND_TYPE_MP42; lsmash_brand_type compatible_brands[2] = { ISOM_BRAND_TYPE_MP42, ISOM_BRAND_TYPE_ISOM }; /* ムービー */ lsmash_movie_parameters_t movie_param; /* トラック */ struct { int active; uint32_t id; uint32_t desc_index; uint32_t timebase; uint32_t sample_number; double dts; lsmash_track_parameters_t track_param; lsmash_media_parameters_t media_param; lsmash_sample_t *sample; } track[2] = { { 0 } }; /* トラック・ハンドラ */ lsmash_track_parameters_t *track_param; /* トラック・パラメータ */ lsmash_media_parameters_t *media_param; /* メディア・パラメータ */ /* 映像コーデック */ lsmash_video_summary_t *video_summary; uint32_t width = 1920; /* 幅 */ uint32_t height = 1080; /* 高さ */ uint32_t fps_num = 24000; /* フレームレート分母 */ uint32_t fps_den = 1001; /* フレームレート分子 */ uint8_t *sps; int sps_size; uint8_t *pps; int pps_size; lsmash_codec_specific_t *cs; lsmash_h264_specific_parameters_t *h264_param; /* 音声コーデック */ lsmash_audio_summary_t *audio_summary; uint32_t frequency = 48000; /* サンプリング周波数 */ uint32_t channels = 2; /* チャンネル数 */ uint32_t frame_length = 1024; /* 音声フレーム1つあたりのデコード時に出力されるPCMサンプル数 */ uint8_t *dsi; /* Decoder Specific Info */ int dsi_size; /* 多重化 */ int i = 0; double largest_dts = 0; uint32_t num_consecutive_sample_skip = 0; uint32_t num_active_input_tracks = 2; /* 出力ファイルを生成 */ root = lsmash_create_root(); lsmash_open_file( "output.mp4", 0, &file_param ); file_param.major_brand = major_brand; file_param.brands = compatible_brands; file_param.brand_count = sizeof(compatible_brands) / sizeof(compatible_brands[0]); file_param.minor_version = 0; file = lsmash_set_file( root, &file_param ); /* ムービーの設定 */ lsmash_initialize_movie_parameters( &movie_param ); lsmash_set_movie_parameters( root, &movie_param ); /* 映像トラックを生成 */ track[VIDEO_TRACK].id = lsmash_create_track( root, ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK ); /* 映像コーデックの設定 */ video_summary = (lsmash_video_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_VIDEO ); video_summary->sample_type = ISOM_CODEC_TYPE_AVC1_VIDEO; video_summary->width = width; video_summary->height = height; cs = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED ); h264_param = (lsmash_h264_specific_parameters_t *)cs->data.structured; h264_param->lengthSizeMinusOne = 3; /* 4バイト */ lsmash_append_h264_parameter_set( h264_param, H264_PARAMETER_SET_TYPE_SPS, sps, sps_size ); lsmash_append_h264_parameter_set( h264_param, H264_PARAMETER_SET_TYPE_PPS, pps, pps_size ); lsmash_add_codec_specific_data( (lsmash_summary_t *)video_summary, cs ); lsmash_destroy_codec_specific_data( cs ); cs = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED ); lsmash_add_codec_specific_data( (lsmash_summary_t *)video_summary, cs ); lsmash_destroy_codec_specific_data( cs ); track[VIDEO_TRACK].desc_index = lsmash_add_sample_entry( root, track[VIDEO_TRACK].id, video_summary ); /* 映像メディアの設定 */ track[VIDEO_TRACK].timebase = fps_den; media_param = &track[VIDEO_TRACK].media_param; lsmash_initialize_media_parameters( media_param ); media_param->timescale = fps_num; media_param->media_handler_name = "L-SMASH Video Handler"; lsmash_set_media_parameters( root, track[VIDEO_TRACK].id, media_param ); /* 映像トラックの設定 */ track_param = &track[VIDEO_TRACK].track_param; lsmash_initialize_track_parameters( track_param ); track_param->mode = ISOM_TRACK_ENABLED | ISOM_TRACK_IN_MOVIE | ISOM_TRACK_IN_PREVIEW; track_param->display_width = width << 16; track_param->display_height = height << 16; lsmash_set_track_parameters( root, track[VIDEO_TRACK].id, track_param ); /* 音声トラックを生成 */ track[AUDIO_TRACK].id = lsmash_create_track( root, ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK ); /* 音声コーデックの設定 */ audio_summary = (lsmash_audio_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_AUDIO ); audio_summary->sample_type = ISOM_CODEC_TYPE_MP4A_AUDIO; audio_summary->aot = MP4A_AUDIO_OBJECT_TYPE_AAC_LC; audio_summary->sbr_mode = MP4A_AAC_SBR_NOT_SPECIFIED; audio_summary->frequency = frequency; audio_summary->channels = channels; audio_summary->samples_in_frame = frame_length; /* 多重化には使われない */ cs = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED ); mp4sys_param = (lsmash_mp4sys_decoder_parameters_t *)cs->data.structured; mp4sys_param->objectTypeIndication = MP4SYS_OBJECT_TYPE_Audio_ISO_14496_3; mp4sys_param->streamType = MP4SYS_STREAM_TYPE_AudioStream; lsmash_set_mp4sys_decoder_specific_info( mp4sys_param, dsi, dsi_size ); lsmash_add_codec_specific_data( (lsmash_summary_t *)audio_summary, cs ); lsmash_destroy_codec_specific_data( cs ); track[AUDIO_TRACK].desc_index = lsmash_add_sample_entry( root, track[AUDIO_TRACK].id, audio_summary ); /* 音声メディアの設定 */ track[AUDIO_TRACK].timebase = frame_length; media_param = &track[AUDIO_TRACK].media_param; lsmash_initialize_media_parameters( media_param ); media_param->timescale = frequency; media_param->media_handler_name = "L-SMASH Audio Handler"; lsmash_set_media_parameters( root, track[AUDIO_TRACK].id, media_param ); /* 音声トラックの設定 */ track_param = &track[AUDIO_TRACK].track_param; lsmash_initialize_track_parameters( track_param ); track_param->mode = ISOM_TRACK_ENABLED | ISOM_TRACK_IN_MOVIE | ISOM_TRACK_IN_PREVIEW; lsmash_set_track_parameters( root, track[AUDIO_TRACK].id, track_param ); /* エンコードされたサンプルの多重化を開始 */ track[VIDEO_TRACK].active = 1; track[AUDIO_TRACK].active = 1; while( 1 ) { if( track[i].active ) { lsmash_sample_t *sample = track[i].sample; /* トラックがサンプルデータを保持していない場合、新しいサンプルデータを取得 */ if( !sample ) { /* エンコードされたフレーム・データを取得 */ uint64_t dts = (uint64_t)track[i].sample_number * track[i].timebase; frame_t *frame = encode_frame( i, dts ); if( !frame ) { /* このトラックにこれ以上、出力するサンプルがありません */ track[i].active = 0; if( --num_active_input_tracks == 0 ) break; /* 全てのトラックで、エンコードして出力すべきサンプルはありません */ } else { /* フレームサイズ分のサンプル・バッファを確保 */ sample = lsmash_create_sample( frame->size ); /* フレーム・データをサンプルにコピー */ memcpy( sample->data, frame->data, frame->size ); sample->length = frame->size; sample->index = track[i].desc_index; sample->dts = frame->dts; sample->cts = frame->cts; if( i == VIDEO_TRACK ) sample->prop.ra_flags = frame->idr ? ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC : 0; else sample->prop.ra_flags = ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC; track[i].dts = (double)sample->dts / track[i].timescale; track[i].sample = sample; } } if( sample ) { /* 条件を満たすなら、サンプルを出力先のサンプル・プールに追加 * サンプルはサンプル・プールからの出力時に自動的に解放される * lsmash_delete_sample( sample ) はlsmash_append_sample()した場合、不要 */ if( track[i].dts <= largest_dts || num_consecutive_sample_skip == num_active_input_tracks ) { lsmash_append_sample( root, track[i].id, sample ); track[i].sample = NULL; if( largest_dts < track[i].dts ) largest_dts = track[i].dts ); ++ track[i].sample_number; num_consecutive_sample_skip = 0; } else ++num_consecutive_sample_skip; /* サンプルの追加をスキップ */ } } if( ++i == 2 ) i = 0; /* 最初のトラックに戻る */ } /* サンプル・プールに残っている、まだ出力されてないサンプルを出力させる */ for( i = 0; i < 2; i++ ) lsmash_flush_pooled_samples( root, track[i].id, track[i].timebase ); /* 出力ファイルの構造情報を書き出し終了する */ lsmash_finish_movie( root, NULL ); /* 解放 */ lsmash_close_file( &file_param ); lsmash_destroy_root( root ); lsmash_cleanup_summary( (lsmash_summary_t *)video_summary ); lsmash_cleanup_summary( (lsmash_summary_t *)audio_summary ); return 0; }