📄 mp4.c
字号:
break; case VLC_FOURCC('m','p','g','a'): if( p_sys->b_mov ) memcpy( fcc, ".mp3", 4 ); else { memcpy( fcc, "mp4a", 4 ); b_descr = VLC_TRUE; } break; default: memcpy( fcc, (char*)&p_stream->fmt.i_codec, 4 ); break; } soun = box_new( fcc ); for( i = 0; i < 6; i++ ) { bo_add_8( soun, 0 ); // reserved; } bo_add_16be( soun, 1 ); // data-reference-index /* SoundDescription */ if( p_sys->b_mov && p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','a') ) { bo_add_16be( soun, 1 ); // version 1; } else { bo_add_16be( soun, 0 ); // version 0; } bo_add_16be( soun, 0 ); // revision level (0) bo_add_32be( soun, 0 ); // vendor // channel-count bo_add_16be( soun, p_stream->fmt.audio.i_channels ); // sample size bo_add_16be( soun, p_stream->fmt.audio.i_bitspersample ? p_stream->fmt.audio.i_bitspersample : 16 ); bo_add_16be( soun, -2 ); // compression id bo_add_16be( soun, 0 ); // packet size (0) bo_add_16be( soun, p_stream->fmt.audio.i_rate ); // sampleratehi bo_add_16be( soun, 0 ); // sampleratelo /* Extended data for SoundDescription V1 */ if( p_sys->b_mov && p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','a') ) { /* samples per packet */ bo_add_32be( soun, p_stream->fmt.audio.i_frame_length ); bo_add_32be( soun, 1536 ); /* bytes per packet */ bo_add_32be( soun, 2 ); /* bytes per frame */ /* bytes per sample */ bo_add_32be( soun, 2 /*p_stream->fmt.audio.i_bitspersample/8 */); } /* Add an ES Descriptor */ if( b_descr ) { bo_t *box; if( p_sys->b_mov && p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','a') ) { box = GetWaveTag( p_stream ); } else { box = GetESDS( p_stream ); } box_fix( box ); box_gather( soun, box ); } box_fix( soun ); return soun;}static bo_t *GetVideBox( sout_mux_t *p_mux, mp4_stream_t *p_stream ){ bo_t *vide; char fcc[4] = " "; int i; switch( p_stream->fmt.i_codec ) { case VLC_FOURCC('m','p','4','v'): case VLC_FOURCC('m','p','g','v'): memcpy( fcc, "mp4v", 4 ); break; case VLC_FOURCC('M','J','P','G'): memcpy( fcc, "mjpa", 4 ); break; case VLC_FOURCC('S','V','Q','1'): memcpy( fcc, "SVQ1", 4 ); break; case VLC_FOURCC('S','V','Q','3'): memcpy( fcc, "SVQ3", 4 ); break; case VLC_FOURCC('h','2','6','4'): memcpy( fcc, "avc1", 4 ); break; default: memcpy( fcc, (char*)&p_stream->fmt.i_codec, 4 ); break; } vide = box_new( fcc ); for( i = 0; i < 6; i++ ) { bo_add_8( vide, 0 ); // reserved; } bo_add_16be( vide, 1 ); // data-reference-index bo_add_16be( vide, 0 ); // predefined; bo_add_16be( vide, 0 ); // reserved; for( i = 0; i < 3; i++ ) { bo_add_32be( vide, 0 ); // predefined; } bo_add_16be( vide, p_stream->fmt.video.i_width ); // i_width bo_add_16be( vide, p_stream->fmt.video.i_height ); // i_height bo_add_32be( vide, 0x00480000 ); // h 72dpi bo_add_32be( vide, 0x00480000 ); // v 72dpi bo_add_32be( vide, 0 ); // data size, always 0 bo_add_16be( vide, 1 ); // frames count per sample // compressor name; for( i = 0; i < 32; i++ ) { bo_add_8( vide, 0 ); } bo_add_16be( vide, 0x18 ); // depth bo_add_16be( vide, 0xffff ); // predefined /* add an ES Descriptor */ switch( p_stream->fmt.i_codec ) { case VLC_FOURCC('m','p','4','v'): case VLC_FOURCC('m','p','g','v'): { bo_t *esds = GetESDS( p_stream ); box_fix( esds ); box_gather( vide, esds ); } break; case VLC_FOURCC('S','V','Q','3'): { bo_t *esds = GetSVQ3Tag( p_stream ); box_fix( esds ); box_gather( vide, esds ); } break; case VLC_FOURCC('h','2','6','4'): box_gather( vide, GetAvcCTag( p_stream ) ); break; default: break; } box_fix( vide ); return vide;}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, "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 }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -