📄 mp4.c
字号:
static bo_t *GetTextBox( sout_mux_t *p_mux, mp4_stream_t *p_stream ){ bo_t *text = box_new( "text" ); int i; for( i = 0; i < 6; i++ ) { bo_add_8( text, 0 ); // reserved; } bo_add_16be( text, 1 ); // data-reference-index bo_add_32be( text, 0 ); // display flags bo_add_32be( text, 0 ); // justification for( i = 0; i < 3; i++ ) { bo_add_16be( text, 0 ); // back ground color } bo_add_16be( text, 0 ); // box text bo_add_16be( text, 0 ); // box text bo_add_16be( text, 0 ); // box text bo_add_16be( text, 0 ); // box text bo_add_64be( text, 0 ); // reserved for( i = 0; i < 3; i++ ) { bo_add_16be( text, 0xff ); // foreground color } bo_add_8 ( text, 9 ); bo_add_mem( text, 9, (uint8_t*)"Helvetica" ); box_fix( text ); return text;}static bo_t *GetStblBox( sout_mux_t *p_mux, mp4_stream_t *p_stream ){ sout_mux_sys_t *p_sys = p_mux->p_sys; unsigned int i_chunk, i_stsc_last_val, i_stsc_entries, i, i_index; bo_t *stbl, *stsd, *stts, *stco, *stsc, *stsz, *stss; uint32_t i_timescale; int64_t i_dts, i_dts_q; stbl = box_new( "stbl" ); /* sample description */ stsd = box_full_new( "stsd", 0, 0 ); bo_add_32be( stsd, 1 ); if( p_stream->fmt.i_cat == AUDIO_ES ) { bo_t *soun = GetSounBox( p_mux, p_stream ); box_gather( stsd, soun ); } else if( p_stream->fmt.i_cat == VIDEO_ES ) { bo_t *vide = GetVideBox( p_mux, p_stream ); box_gather( stsd, vide ); } else if( p_stream->fmt.i_cat == SPU_ES ) { box_gather( stsd, GetTextBox( p_mux, p_stream ) ); } box_fix( stsd ); /* chunk offset table */ if( p_sys->i_pos >= (((uint64_t)0x1) << 32) ) { /* 64 bits version */ p_stream->b_stco64 = VLC_TRUE; stco = box_full_new( "co64", 0, 0 ); } else { /* 32 bits version */ p_stream->b_stco64 = VLC_FALSE; stco = box_full_new( "stco", 0, 0 ); } bo_add_32be( stco, 0 ); // entry-count (fixed latter) /* sample to chunk table */ stsc = box_full_new( "stsc", 0, 0 ); bo_add_32be( stsc, 0 ); // entry-count (fixed latter) for( i_chunk = 0, i_stsc_last_val = 0, i_stsc_entries = 0, i = 0; i < p_stream->i_entry_count; i_chunk++ ) { int i_first = i; if( p_stream->b_stco64 ) bo_add_64be( stco, p_stream->entry[i].i_pos ); else bo_add_32be( stco, p_stream->entry[i].i_pos ); while( i < p_stream->i_entry_count ) { if( i + 1 < p_stream->i_entry_count && p_stream->entry[i].i_pos + p_stream->entry[i].i_size != p_stream->entry[i + 1].i_pos ) { i++; break; } i++; } /* Add entry to the stsc table */ if( i_stsc_last_val != i - i_first ) { bo_add_32be( stsc, 1 + i_chunk ); // first-chunk bo_add_32be( stsc, i - i_first ) ; // samples-per-chunk bo_add_32be( stsc, 1 ); // sample-descr-index i_stsc_last_val = i - i_first; i_stsc_entries++; } } /* Fix stco entry count */ bo_fix_32be( stco, 12, i_chunk ); msg_Dbg( p_mux, "created %d chunks (stco)", i_chunk ); box_fix( stco ); /* Fix stsc entry count */ bo_fix_32be( stsc, 12, i_stsc_entries ); box_fix( stsc ); /* add stts */ stts = box_full_new( "stts", 0, 0 ); bo_add_32be( stts, 0 ); // entry-count (fixed latter) if( p_stream->fmt.i_cat == AUDIO_ES ) i_timescale = p_stream->fmt.audio.i_rate; else i_timescale = 1001; /* first, create quantified length */ for( i = 0, i_dts = 0, i_dts_q = 0; i < p_stream->i_entry_count; i++ ) { int64_t i_dts_deq = i_dts_q * I64C(1000000) / (int64_t)i_timescale; int64_t i_delta = p_stream->entry[i].i_length + i_dts - i_dts_deq; i_dts += p_stream->entry[i].i_length; p_stream->entry[i].i_length = i_delta * (int64_t)i_timescale / I64C(1000000); i_dts_q += p_stream->entry[i].i_length; } /* then write encoded table */ for( i = 0, i_index = 0; i < p_stream->i_entry_count; i_index++) { int i_first = i; int64_t i_delta = p_stream->entry[i].i_length; while( i < p_stream->i_entry_count ) { i++; if( i >= p_stream->i_entry_count || p_stream->entry[i].i_length != i_delta ) { break; } } bo_add_32be( stts, i - i_first ); // sample-count bo_add_32be( stts, i_delta ); // sample-delta } bo_fix_32be( stts, 12, i_index ); box_fix( stts ); /* FIXME add ctts ?? FIXME */ stsz = box_full_new( "stsz", 0, 0 ); bo_add_32be( stsz, 0 ); // sample-size bo_add_32be( stsz, p_stream->i_entry_count ); // sample-count for( i = 0; i < p_stream->i_entry_count; i++ ) { bo_add_32be( stsz, p_stream->entry[i].i_size ); // sample-size } box_fix( stsz ); /* create stss table */ stss = NULL; for( i = 0, i_index = 0; i < p_stream->i_entry_count; i++ ) { if( p_stream->entry[i].i_flags & BLOCK_FLAG_TYPE_I ) { if( stss == NULL ) { stss = box_full_new( "stss", 0, 0 ); bo_add_32be( stss, 0 ); /* fixed later */ } bo_add_32be( stss, 1 + i ); i_index++; } } if( stss ) { bo_fix_32be( stss, 12, i_index ); box_fix( stss ); } /* Now gather all boxes into stbl */ box_gather( stbl, stsd ); box_gather( stbl, stts ); if( stss ) { box_gather( stbl, stss ); } box_gather( stbl, stsc ); box_gather( stbl, stsz ); p_stream->i_stco_pos = stbl->i_buffer + 16; box_gather( stbl, stco ); /* finish stbl */ box_fix( stbl ); return stbl;}static int64_t get_timestamp();static uint32_t mvhd_matrix[9] = { 0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000 };static bo_t *GetMoovBox( sout_mux_t *p_mux ){ sout_mux_sys_t *p_sys = p_mux->p_sys; bo_t *moov, *mvhd; int i_trak, i; uint32_t i_movie_timescale = 90000; int64_t i_movie_duration = 0; moov = box_new( "moov" ); /* Create general info */ for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ ) { mp4_stream_t *p_stream = p_sys->pp_streams[i_trak]; i_movie_duration = __MAX( i_movie_duration, p_stream->i_duration ); } msg_Dbg( p_mux, "movie duration %ds", (uint32_t)( i_movie_duration / (mtime_t)1000000 ) ); i_movie_duration = i_movie_duration * i_movie_timescale / 1000000; /* *** add /moov/mvhd *** */ if( !p_sys->b_64_ext ) { mvhd = box_full_new( "mvhd", 0, 0 ); bo_add_32be( mvhd, get_timestamp() ); // creation time bo_add_32be( mvhd, get_timestamp() ); // modification time bo_add_32be( mvhd, i_movie_timescale); // timescale bo_add_32be( mvhd, i_movie_duration ); // duration } else { mvhd = box_full_new( "mvhd", 1, 0 ); bo_add_64be( mvhd, get_timestamp() ); // creation time bo_add_64be( mvhd, get_timestamp() ); // modification time bo_add_32be( mvhd, i_movie_timescale); // timescale bo_add_64be( mvhd, i_movie_duration ); // duration } bo_add_32be( mvhd, 0x10000 ); // rate bo_add_16be( mvhd, 0x100 ); // volume bo_add_16be( mvhd, 0 ); // reserved for( i = 0; i < 2; i++ ) { bo_add_32be( mvhd, 0 ); // reserved } for( i = 0; i < 9; i++ ) { bo_add_32be( mvhd, mvhd_matrix[i] );// matrix } for( i = 0; i < 6; i++ ) { bo_add_32be( mvhd, 0 ); // pre-defined } /* Next available track id */ bo_add_32be( mvhd, p_sys->i_nb_streams + 1 ); // next-track-id box_fix( mvhd ); box_gather( moov, mvhd ); for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ ) { mp4_stream_t *p_stream; uint32_t i_timescale; bo_t *trak, *tkhd, *edts, *elst, *mdia, *mdhd, *hdlr; bo_t *minf, *dinf, *dref, *url, *stbl; p_stream = p_sys->pp_streams[i_trak]; if( p_stream->fmt.i_cat == AUDIO_ES ) i_timescale = p_stream->fmt.audio.i_rate; else i_timescale = 1001; /* *** add /moov/trak *** */ trak = box_new( "trak" ); /* *** add /moov/trak/tkhd *** */ if( !p_sys->b_64_ext ) { if( p_sys->b_mov ) tkhd = box_full_new( "tkhd", 0, 0x0f ); else tkhd = box_full_new( "tkhd", 0, 1 ); bo_add_32be( tkhd, get_timestamp() ); // creation time bo_add_32be( tkhd, get_timestamp() ); // modification time bo_add_32be( tkhd, p_stream->i_track_id ); bo_add_32be( tkhd, 0 ); // reserved 0 bo_add_32be( tkhd, p_stream->i_duration * (int64_t)i_movie_timescale / (mtime_t)1000000 ); // duration } else { if( p_sys->b_mov ) tkhd = box_full_new( "tkhd", 1, 0x0f ); else tkhd = box_full_new( "tkhd", 1, 1 ); bo_add_64be( tkhd, get_timestamp() ); // creation time bo_add_64be( tkhd, get_timestamp() ); // modification time bo_add_32be( tkhd, p_stream->i_track_id ); bo_add_32be( tkhd, 0 ); // reserved 0 bo_add_64be( tkhd, p_stream->i_duration * (int64_t)i_movie_timescale / (mtime_t)1000000 ); // duration } for( i = 0; i < 2; i++ ) { bo_add_32be( tkhd, 0 ); // reserved } bo_add_16be( tkhd, 0 ); // layer bo_add_16be( tkhd, 0 ); // pre-defined // volume bo_add_16be( tkhd, p_stream->fmt.i_cat == AUDIO_ES ? 0x100 : 0 ); bo_add_16be( tkhd, 0 ); // reserved for( i = 0; i < 9; i++ ) { bo_add_32be( tkhd, mvhd_matrix[i] ); // matrix } if( p_stream->fmt.i_cat == AUDIO_ES ) { bo_add_32be( tkhd, 0 ); // width (presentation) bo_add_32be( tkhd, 0 ); // height(presentation) } else if( p_stream->fmt.i_cat == VIDEO_ES ) { int i_width = p_stream->fmt.video.i_width << 16; if( p_stream->fmt.video.i_aspect > 0 ) { i_width = (int64_t)p_stream->fmt.video.i_aspect * ((int64_t)p_stream->fmt.video.i_height << 16) / VOUT_ASPECT_FACTOR; } // width (presentation) bo_add_32be( tkhd, i_width ); // height(presentation) bo_add_32be( tkhd, p_stream->fmt.video.i_height << 16 ); } else { int i_width = 320 << 16; int i_height = 200; int i; for( i = 0; i < p_sys->i_nb_streams; i++ ) { mp4_stream_t *tk = p_sys->pp_streams[i]; if( tk->fmt.i_cat == VIDEO_ES ) { if( p_stream->fmt.video.i_aspect ) i_width = (int64_t)p_stream->fmt.video.i_aspect * ((int64_t)p_stream->fmt.video.i_height<<16) / VOUT_ASPECT_FACTOR; else i_width = p_stream->fmt.video.i_width << 16; i_height = p_stream->fmt.video.i_height; break; } } bo_add_32be( tkhd, i_width ); // width (presentation) bo_add_32be( tkhd, i_height << 16 ); // height(presentation) } box_fix( tkhd ); box_gather( trak, tkhd ); /* *** add /moov/trak/edts and elst */ edts = box_new( "edts" ); elst = box_full_new( "elst", p_sys->b_64_ext ? 1 : 0, 0 ); if( p_stream->i_dts_start > p_sys->i_dts_start ) { bo_add_32be( elst, 2 ); if( p_sys->b_64_ext ) { bo_add_64be( elst, (p_stream->i_dts_start-p_sys->i_dts_start) * i_movie_timescale / I64C(1000000) ); bo_add_64be( elst, -1 ); } else { bo_add_32be( elst, (p_stream->i_dts_start-p_sys->i_dts_start) * i_movie_timescale / I64C(1000000) ); bo_add_32be( elst, -1 ); } bo_add_16be( elst, 1 ); bo_add_16be( elst, 0 ); } else { bo_add_32be( elst, 1 ); } if( p_sys->b_64_ext ) { bo_add_64be( elst, p_stream->i_duration * i_movie_timescale / I64C(1000000) ); bo_add_64be( elst, 0 ); } else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -