📄 mp4.c
字号:
p_data = block_FifoGet( p_input->p_fifo ); if( p_stream->fmt.i_codec == VLC_FOURCC( 'h', '2', '6', '4' ) ) { ConvertAVC1( p_mux, p_stream, p_data ); } else if( p_stream->fmt.i_codec == VLC_FOURCC( 's', 'u', 'b', 't' ) ) { p_data = ConvertSUBT( p_mux, p_stream, p_data ); } if( p_stream->fmt.i_cat != SPU_ES ) { /* Fix length of the sample */ if( p_input->p_fifo->i_depth > 0 ) { block_t *p_next = block_FifoShow( p_input->p_fifo ); int64_t i_diff = p_next->i_dts - p_data->i_dts; if( i_diff < I64C(1000000 ) ) /* protection */ { p_data->i_length = i_diff; } } if( p_data->i_length <= 0 ) { msg_Warn( p_mux, "i_length <= 0" ); p_stream->i_length_neg += p_data->i_length - 1; p_data->i_length = 1; } else if( p_stream->i_length_neg < 0 ) { int64_t i_recover = __MIN( p_data->i_length / 4, - p_stream->i_length_neg ); p_data->i_length -= i_recover; p_stream->i_length_neg += i_recover; } } /* Save starting time */ if( p_stream->i_entry_count == 0 ) { p_stream->i_dts_start = p_data->i_dts; /* Update global dts_start */ if( p_sys->i_dts_start <= 0 || p_stream->i_dts_start < p_sys->i_dts_start ) { p_sys->i_dts_start = p_stream->i_dts_start; } } if( p_stream->fmt.i_cat == SPU_ES && p_stream->i_entry_count > 0 ) { int64_t i_length = p_data->i_dts - p_stream->i_last_dts; if( i_length <= 0 ) { /* FIXME handle this broken case */ i_length = 1; } /* Fix last entry */ if( p_stream->entry[p_stream->i_entry_count-1].i_length <= 0 ) { p_stream->entry[p_stream->i_entry_count-1].i_length = i_length; } } /* add index entry */ p_stream->entry[p_stream->i_entry_count].i_pos = p_sys->i_pos; p_stream->entry[p_stream->i_entry_count].i_size = p_data->i_buffer; p_stream->entry[p_stream->i_entry_count].i_pts_dts= __MAX( p_data->i_pts - p_data->i_dts, 0 ); p_stream->entry[p_stream->i_entry_count].i_length = p_data->i_length; p_stream->entry[p_stream->i_entry_count].i_flags = p_data->i_flags; p_stream->i_entry_count++; /* XXX: -1 to always have 2 entry for easy adding of empty SPU */ if( p_stream->i_entry_count >= p_stream->i_entry_max - 1 ) { p_stream->i_entry_max += 1000; p_stream->entry = realloc( p_stream->entry, p_stream->i_entry_max * sizeof( mp4_entry_t ) ); } /* update */ p_stream->i_duration += p_data->i_length; p_sys->i_pos += p_data->i_buffer; /* Save the DTS */ p_stream->i_last_dts = p_data->i_dts; /* write data */ sout_AccessOutWrite( p_mux->p_access, p_data ); if( p_stream->fmt.i_cat == SPU_ES ) { int64_t i_length = p_stream->entry[p_stream->i_entry_count-1].i_length; if( i_length != 0 ) { /* TODO */ msg_Dbg( p_mux, "writing a empty subs" ) ; /* Append a idx entry */ p_stream->entry[p_stream->i_entry_count].i_pos = p_sys->i_pos; p_stream->entry[p_stream->i_entry_count].i_size = 3; p_stream->entry[p_stream->i_entry_count].i_pts_dts= 0; p_stream->entry[p_stream->i_entry_count].i_length = 0; p_stream->entry[p_stream->i_entry_count].i_flags = 0; /* XXX: No need to grow the entry here */ p_stream->i_entry_count++; /* Fix last dts */ p_stream->i_last_dts += i_length; /* Write a " " */ p_data = block_New( p_mux, 3 ); p_data->p_buffer[0] = 0; p_data->p_buffer[1] = 1; p_data->p_buffer[2] = ' '; p_sys->i_pos += p_data->i_buffer; sout_AccessOutWrite( p_mux->p_access, p_data ); } /* Fix duration */ p_stream->i_duration = p_stream->i_last_dts - p_stream->i_dts_start; } } return( VLC_SUCCESS );}/***************************************************************************** * *****************************************************************************/static block_t *ConvertSUBT( sout_mux_t *p_mux, mp4_stream_t *tk, block_t *p_block ){ p_block = block_Realloc( p_block, 2, p_block->i_buffer ); /* No trailling '\0' */ if( p_block->i_buffer > 2 && p_block->p_buffer[p_block->i_buffer-1] == '\0' ) p_block->i_buffer--; p_block->p_buffer[0] = ( (p_block->i_buffer - 2) >> 8 )&0xff; p_block->p_buffer[1] = ( (p_block->i_buffer - 2) )&0xff; return p_block;}static void ConvertAVC1( sout_mux_t *p_mux, mp4_stream_t *tk, block_t *p_block ){ uint8_t *last = p_block->p_buffer; /* Assume it starts with 0x00000001 */ uint8_t *dat = &p_block->p_buffer[4]; uint8_t *end = &p_block->p_buffer[p_block->i_buffer]; /* Replace the 4 bytes start code with 4 bytes size, * FIXME are all startcode 4 bytes ? (I don't think :( */ while( dat < end ) { int i_size; while( dat < end - 4 ) { if( dat[0] == 0x00 && dat[1] == 0x00 && dat[2] == 0x00 && dat[3] == 0x01 ) { break; } dat++; } if( dat >= end - 4 ) { dat = end; } /* Fix size */ i_size = dat - &last[4]; last[0] = ( i_size >> 24 )&0xff; last[1] = ( i_size >> 16 )&0xff; last[2] = ( i_size >> 8 )&0xff; last[3] = ( i_size )&0xff; if( (last[4]&0x1f) == 7 && tk->avc.i_sps <= 0 ) /* SPS */ { tk->avc.i_sps = i_size; tk->avc.sps = malloc( i_size ); memcpy( tk->avc.sps, &last[4], i_size ); tk->avc.i_profile = tk->avc.sps[1]; tk->avc.i_level = tk->avc.sps[3]; } else if( (last[4]&0x1f) == 8 && tk->avc.i_pps <= 0 ) /* PPS */ { tk->avc.i_pps = i_size; tk->avc.pps = malloc( i_size ); memcpy( tk->avc.pps, &last[4], i_size ); } last = dat; dat += 4; }}static int GetDescrLength( int i_size ){ if( i_size < 0x00000080 ) return 2 + i_size; else if( i_size < 0x00004000 ) return 3 + i_size; else if( i_size < 0x00200000 ) return 4 + i_size; else return 5 + i_size;}static bo_t *GetESDS( mp4_stream_t *p_stream ){ bo_t *esds; int i_stream_type; int i_object_type_indication; int i_decoder_specific_info_size; unsigned int i; int64_t i_bitrate_avg = 0; int64_t i_bitrate_max = 0; /* Compute avg/max bitrate */ for( i = 0; i < p_stream->i_entry_count; i++ ) { i_bitrate_avg += p_stream->entry[i].i_size; if( p_stream->entry[i].i_length > 0) { int64_t i_bitrate = I64C(8000000) * p_stream->entry[i].i_size / p_stream->entry[i].i_length; if( i_bitrate > i_bitrate_max ) i_bitrate_max = i_bitrate; } } if( p_stream->i_duration > 0 ) i_bitrate_avg = I64C(8000000) * i_bitrate_avg / p_stream->i_duration; else i_bitrate_avg = 0; if( i_bitrate_max <= 1 ) i_bitrate_max = 0x7fffffff; /* */ if( p_stream->fmt.i_extra > 0 ) { i_decoder_specific_info_size = GetDescrLength( p_stream->fmt.i_extra ); } else { i_decoder_specific_info_size = 0; } esds = box_full_new( "esds", 0, 0 ); /* ES_Descr */ bo_add_descr( esds, 0x03, 3 + GetDescrLength( 13 + i_decoder_specific_info_size ) + GetDescrLength( 1 ) ); bo_add_16be( esds, p_stream->i_track_id ); bo_add_8 ( esds, 0x1f ); // flags=0|streamPriority=0x1f /* DecoderConfigDescr */ bo_add_descr( esds, 0x04, 13 + i_decoder_specific_info_size ); switch( p_stream->fmt.i_codec ) { case VLC_FOURCC( 'm', 'p', '4', 'v' ): i_object_type_indication = 0x20; break; case VLC_FOURCC( 'm', 'p', 'g', 'v' ): /* FIXME MPEG-I=0x6b, MPEG-II = 0x60 -> 0x65 */ i_object_type_indication = 0x60; break; case VLC_FOURCC( 'm', 'p', '4', 'a' ): /* FIXME for mpeg2-aac == 0x66->0x68 */ i_object_type_indication = 0x40; break; case VLC_FOURCC( 'm', 'p', 'g', 'a' ): i_object_type_indication = p_stream->fmt.audio.i_rate < 32000 ? 0x69 : 0x6b; break; default: i_object_type_indication = 0x00; break; } i_stream_type = p_stream->fmt.i_cat == VIDEO_ES ? 0x04 : 0x05; bo_add_8 ( esds, i_object_type_indication ); bo_add_8 ( esds, ( i_stream_type << 2 ) | 1 ); bo_add_24be( esds, 1024 * 1024 ); // bufferSizeDB bo_add_32be( esds, i_bitrate_max ); // maxBitrate bo_add_32be( esds, i_bitrate_avg ); // avgBitrate if( p_stream->fmt.i_extra > 0 ) { int i; /* DecoderSpecificInfo */ bo_add_descr( esds, 0x05, p_stream->fmt.i_extra ); for( i = 0; i < p_stream->fmt.i_extra; i++ ) { bo_add_8( esds, ((uint8_t*)p_stream->fmt.p_extra)[i] ); } } /* SL_Descr mandatory */ bo_add_descr( esds, 0x06, 1 ); bo_add_8 ( esds, 0x02 ); // sl_predefined box_fix( esds ); return esds;}static bo_t *GetWaveTag( mp4_stream_t *p_stream ){ bo_t *wave; bo_t *box; wave = box_new( "wave" ); box = box_new( "frma" ); bo_add_fourcc( box, "mp4a" ); box_fix( box ); box_gather( wave, box ); box = box_new( "mp4a" ); bo_add_32be( box, 0 ); box_fix( box ); box_gather( wave, box ); box = GetESDS( p_stream ); box_fix( box ); box_gather( wave, box ); box = box_new( "srcq" ); bo_add_32be( box, 0x40 ); box_fix( box ); box_gather( wave, box ); /* wazza ? */ bo_add_32be( wave, 8 ); /* new empty box */ bo_add_32be( wave, 0 ); /* box label */ box_fix( wave ); return wave;}static bo_t *GetAvcCTag( mp4_stream_t *p_stream ){ bo_t *avcC; /* FIXME use better value */ avcC = box_new( "avcC" ); bo_add_8( avcC, 1 ); /* configuration version */ bo_add_8( avcC, p_stream->avc.i_profile ); bo_add_8( avcC, p_stream->avc.i_profile ); /* profile compatible ??? */ bo_add_8( avcC, p_stream->avc.i_level ); /* level, 5.1 */ bo_add_8( avcC, 0xff ); /* 0b11111100 | lengthsize = 0x11 */ bo_add_8( avcC, 0xe0 | (p_stream->avc.i_sps > 0 ? 1 : 0) ); /* 0b11100000 | sps_count */ if( p_stream->avc.i_sps > 0 ) { bo_add_16be( avcC, p_stream->avc.i_sps ); bo_add_mem( avcC, p_stream->avc.i_sps, p_stream->avc.sps ); } bo_add_8( avcC, (p_stream->avc.i_pps > 0 ? 1 : 0) ); /* pps_count */ if( p_stream->avc.i_pps > 0 ) { bo_add_16be( avcC, p_stream->avc.i_pps ); bo_add_mem( avcC, p_stream->avc.i_pps, p_stream->avc.pps ); } box_fix( avcC ); return avcC;}/* TODO: No idea about these values */static bo_t *GetSVQ3Tag( mp4_stream_t *p_stream ){ bo_t *smi = box_new( "SMI " ); if( p_stream->fmt.i_extra > 0x4e ) { uint8_t *p_end = &((uint8_t*)p_stream->fmt.p_extra)[p_stream->fmt.i_extra]; uint8_t *p = &((uint8_t*)p_stream->fmt.p_extra)[0x46]; while( p + 8 < p_end ) { int i_size = GetDWBE( p ); if( i_size <= 1 ) { /* FIXME handle 1 as long size */ break; } if( !strncmp( &p[4], "SMI ", 4 ) ) { bo_add_mem( smi, p_end - p - 8, &p[8] ); return smi; } p += i_size; } } /* Create a dummy one in fallback */ bo_add_fourcc( smi, "SEQH" ); bo_add_32be( smi, 0x5 ); bo_add_32be( smi, 0xe2c0211d ); bo_add_8( smi, 0xc0 ); box_fix( smi ); return smi;}static bo_t *GetUdtaTag( sout_mux_t *p_mux ){ sout_mux_sys_t *p_sys = p_mux->p_sys; bo_t *udta = box_new( "udta" ); vlc_meta_t *p_meta = p_mux->p_sout->p_meta; int i_track; /* Requirements */ for( i_track = 0; i_track < p_sys->i_nb_streams; i_track++ ) { mp4_stream_t *p_stream = p_sys->pp_streams[i_track]; if( p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','v') || p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','a') ) { bo_t *box = box_new( "\251req" ); /* String length */ bo_add_16be( box, sizeof("QuickTime 6.0 or greater") - 1); bo_add_16be( box, 0 ); bo_add_mem( box, sizeof("QuickTime 6.0 or greater") - 1, "QuickTime 6.0 or greater" ); box_fix( box ); box_gather( udta, box ); break; } } /* Encoder */ { bo_t *box = box_new( "\251enc" ); /* String length */ bo_add_16be( box, sizeof(PACKAGE_STRING " stream output") - 1); bo_add_16be( box, 0 ); bo_add_mem( box, sizeof(PACKAGE_STRING " stream output") - 1, PACKAGE_STRING " stream output" ); box_fix( box ); box_gather( udta, box ); } /* Misc atoms */ if( p_meta ) { int i; for( i = 0; i < p_meta->i_meta; i++ ) { bo_t *box = NULL; if( !strcmp( p_meta->name[i], VLC_META_TITLE ) ) box = box_new( "\251nam" ); else if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) ) box = box_new( "\251aut" ); else if( !strcmp( p_meta->name[i], VLC_META_ARTIST ) ) box = box_new( "\251ART" ); else if( !strcmp( p_meta->name[i], VLC_META_GENRE ) ) box = box_new( "\251gen" ); else if( !strcmp( p_meta->name[i], VLC_META_COPYRIGHT ) ) box = box_new( "\251cpy" ); else if( !strcmp( p_meta->name[i], VLC_META_DESCRIPTION ) ) box = box_new( "\251des" ); else if( !strcmp( p_meta->name[i], VLC_META_DATE ) ) box = box_new( "\251day" ); else if( !strcmp( p_meta->name[i], VLC_META_URL ) ) box = box_new( "\251url" ); if( box ) { bo_add_16be( box, strlen( p_meta->value[i] ) ); bo_add_16be( box, 0 ); bo_add_mem( box, strlen( p_meta->value[i] ), p_meta->value[i] ); box_fix( box ); box_gather( udta, box ); } } } box_fix( udta ); return udta;}static bo_t *GetSounBox( sout_mux_t *p_mux, mp4_stream_t *p_stream ){ sout_mux_sys_t *p_sys = p_mux->p_sys; vlc_bool_t b_descr = VLC_FALSE; bo_t *soun; char fcc[4] = " "; int i; switch( p_stream->fmt.i_codec ) { case VLC_FOURCC('m','p','4','a'): memcpy( fcc, "mp4a", 4 ); b_descr = VLC_TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -