X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fmux%2Fmp4.c;h=b65a539cf1d6ef96467164f8f5059c712accaec3;hb=425521e9cd087612afb46c93d7427d531929e2a4;hp=c85ad5d7fa27624d868345ef673ce61d3fe37092;hpb=e7042bde8e2c7152526d144f722eaa122aff7766;p=vlc diff --git a/modules/mux/mp4.c b/modules/mux/mp4.c index c85ad5d7fa..b65a539cf1 100644 --- a/modules/mux/mp4.c +++ b/modules/mux/mp4.c @@ -1,25 +1,25 @@ /***************************************************************************** * mp4.c: mp4/mov muxer ***************************************************************************** - * Copyright (C) 2001, 2002, 2003, 2006 the VideoLAN team + * Copyright (C) 2001, 2002, 2003, 2006 VLC authors and VideoLAN * $Id$ * * Authors: Laurent Aimar * Gildas Bazin * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** @@ -164,6 +164,8 @@ static bo_t *GetMoovBox(sout_mux_t *p_mux); static block_t *ConvertSUBT(block_t *); static block_t *ConvertAVC1(block_t *); +static const char avc1_start_code[4] = { 0, 0, 0, 1 }; + /***************************************************************************** * Open: *****************************************************************************/ @@ -236,15 +238,11 @@ static void Close(vlc_object_t *p_this) { sout_mux_t *p_mux = (sout_mux_t*)p_this; sout_mux_sys_t *p_sys = p_mux->p_sys; - block_t *p_hdr; - bo_t bo, *moov; - vlc_value_t val; - - uint64_t i_moov_pos; msg_Dbg(p_mux, "Close"); /* Update mdat size */ + bo_t bo; bo_init(&bo); if (p_sys->i_pos - p_sys->i_mdat_pos >= (((uint64_t)1)<<32)) { /* Extended size */ @@ -257,29 +255,26 @@ static void Close(vlc_object_t *p_this) bo_add_32be (&bo, p_sys->i_pos - p_sys->i_mdat_pos - 8); bo_add_fourcc(&bo, "mdat"); } - p_hdr = bo.b; - p_hdr->i_buffer = bo.len; + bo.b->i_buffer = bo.len; sout_AccessOutSeek(p_mux->p_access, p_sys->i_mdat_pos); - sout_AccessOutWrite(p_mux->p_access, p_hdr); + sout_AccessOutWrite(p_mux->p_access, bo.b); /* Create MOOV header */ - i_moov_pos = p_sys->i_pos; - moov = GetMoovBox(p_mux); + uint64_t i_moov_pos = p_sys->i_pos; + bo_t *moov = GetMoovBox(p_mux); /* Check we need to create "fast start" files */ - var_Get(p_this, SOUT_CFG_PREFIX "faststart", &val); - p_sys->b_fast_start = val.b_bool; + p_sys->b_fast_start = var_GetBool(p_this, SOUT_CFG_PREFIX "faststart"); while (p_sys->b_fast_start) { /* Move data to the end of the file so we can fit the moov header * at the start */ - block_t *p_buf; - int64_t i_chunk, i_size = p_sys->i_pos - p_sys->i_mdat_pos; + int64_t i_size = p_sys->i_pos - p_sys->i_mdat_pos; int i_moov_size = moov->len; while (i_size > 0) { - i_chunk = __MIN(32768, i_size); - p_buf = block_Alloc(i_chunk); + int64_t i_chunk = __MIN(32768, i_size); + block_t *p_buf = block_Alloc(i_chunk); sout_AccessOutSeek(p_mux->p_access, p_sys->i_mdat_pos + i_size - i_chunk); if (sout_AccessOutRead(p_mux->p_access, p_buf) < i_chunk) { @@ -304,21 +299,18 @@ static void Close(vlc_object_t *p_this) moov->len = p_stream->i_stco_pos; for (unsigned i = 0; i < p_stream->i_entry_count; ) { + mp4_entry_t *entry = p_stream->entry; if (p_stream->b_stco64) - bo_add_64be(moov, p_stream->entry[i].i_pos + i_moov_size); + bo_add_64be(moov, entry[i].i_pos + i_moov_size); else - bo_add_32be(moov, p_stream->entry[i].i_pos + i_moov_size); + bo_add_32be(moov, entry[i].i_pos + i_moov_size); - 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) { + for (; i < p_stream->i_entry_count; i++) + if (i >= p_stream->i_entry_count - 1 || + entry[i].i_pos + entry[i].i_size != entry[i+1].i_pos) { i++; break; } - - i++; - } } } @@ -443,34 +435,29 @@ static int Mux(sout_mux_t *p_mux) sout_mux_sys_t *p_sys = p_mux->p_sys; for (;;) { - sout_input_t *p_input; - mp4_stream_t *p_stream; - block_t *p_data; - mtime_t i_dts; - - int i_stream = sout_MuxGetStream(p_mux, 2, &i_dts); + int i_stream = sout_MuxGetStream(p_mux, 2, NULL); if (i_stream < 0) return(VLC_SUCCESS); - p_input = p_mux->pp_inputs[i_stream]; - p_stream = (mp4_stream_t*)p_input->p_sys; + sout_input_t *p_input = p_mux->pp_inputs[i_stream]; + mp4_stream_t *p_stream = (mp4_stream_t*)p_input->p_sys; -again: - p_data = block_FifoGet(p_input->p_fifo); - if (p_stream->fmt.i_codec == VLC_CODEC_H264) - p_data = ConvertAVC1(p_data); - else if (p_stream->fmt.i_codec == VLC_CODEC_SUBT) - p_data = ConvertSUBT(p_data); - if (p_data == NULL) - goto again; + block_t *p_data; + do { + p_data = block_FifoGet(p_input->p_fifo); + if (p_stream->fmt.i_codec == VLC_CODEC_H264) + p_data = ConvertAVC1(p_data); + else if (p_stream->fmt.i_codec == VLC_CODEC_SUBT) + p_data = ConvertSUBT(p_data); + } while (!p_data); if (p_stream->fmt.i_cat != SPU_ES) { /* Fix length of the sample */ if (block_FifoCount(p_input->p_fifo) > 0) { block_t *p_next = block_FifoShow(p_input->p_fifo); - int64_t i_diff = p_next->i_dts - p_data->i_dts; + int64_t i_diff = p_next->i_dts - p_data->i_dts; - if (i_diff < INT64_C(1000000)) /* protection */ + if (i_diff < CLOCK_FREQ) /* protection */ p_data->i_length = i_diff; } if (p_data->i_length <= 0) { @@ -505,14 +492,15 @@ again: 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; + mp4_entry_t *e = &p_stream->entry[p_stream->i_entry_count]; + e->i_pos = p_sys->i_pos; + e->i_size = p_data->i_buffer; + e->i_pts_dts = p_data->i_pts - p_data->i_dts; + if (e->i_pts_dts < 0) + e->i_pts_dts = 0; + e->i_length = p_data->i_length; + e->i_flags = p_data->i_flags; p_stream->i_entry_count++; /* XXX: -1 to always have 2 entry for easy adding of empty SPU */ @@ -540,11 +528,12 @@ again: msg_Dbg(p_mux, "writing an empty sub") ; /* 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; + mp4_entry_t *e = &p_stream->entry[p_stream->i_entry_count]; + e->i_pos = p_sys->i_pos; + e->i_size = 3; + e->i_pts_dts= 0; + e->i_length = 0; + e->i_flags = 0; /* XXX: No need to grow the entry here */ p_stream->i_entry_count++; @@ -598,10 +587,8 @@ static block_t *ConvertAVC1(block_t *p_block) /* Replace the 4 bytes start code with 4 bytes size, * FIXME are all startcodes 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) + if (!memcmp(dat, avc1_start_code, 4)) break; dat++; } @@ -609,7 +596,7 @@ static block_t *ConvertAVC1(block_t *p_block) dat = end; /* Fix size */ - i_size = dat - &last[4]; + int i_size = dat - &last[4]; last[0] = (i_size >> 24)&0xff; last[1] = (i_size >> 16)&0xff; last[2] = (i_size >> 8)&0xff; @@ -627,9 +614,6 @@ static block_t *ConvertAVC1(block_t *p_block) 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; int64_t i_bitrate_avg = 0; int64_t i_bitrate_max = 0; @@ -651,7 +635,7 @@ static bo_t *GetESDS(mp4_stream_t *p_stream) i_bitrate_max = 0x7fffffff; /* */ - i_decoder_specific_info_size = (p_stream->fmt.i_extra > 0) ? 5 + p_stream->fmt.i_extra : 0; + int i_decoder_specific_info_size = (p_stream->fmt.i_extra > 0) ? 5 + p_stream->fmt.i_extra : 0; esds = box_full_new("esds", 0, 0); @@ -663,6 +647,7 @@ static bo_t *GetESDS(mp4_stream_t *p_stream) /* DecoderConfigDescr */ bo_add_descr(esds, 0x04, 13 + i_decoder_specific_info_size); + int i_object_type_indication; switch(p_stream->fmt.i_codec) { case VLC_CODEC_MP4V: @@ -684,7 +669,7 @@ static bo_t *GetESDS(mp4_stream_t *p_stream) i_object_type_indication = 0x00; break; } - i_stream_type = p_stream->fmt.i_cat == VIDEO_ES ? 0x04 : 0x05; + int 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); @@ -704,8 +689,6 @@ static bo_t *GetESDS(mp4_stream_t *p_stream) bo_add_descr(esds, 0x06, 1); bo_add_8 (esds, 0x02); // sl_predefined - box_fix(esds); - return esds; } @@ -718,29 +701,23 @@ static bo_t *GetWaveTag(mp4_stream_t *p_stream) 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; } @@ -759,8 +736,6 @@ static bo_t *GetDamrTag(mp4_stream_t *p_stream) bo_add_16be(damr, 0x83ff); /* Mode set (all modes for AMR_WB) */ bo_add_16be(damr, 0x1); /* Mode change period (no restriction) */ - box_fix(damr); - return damr; } @@ -774,8 +749,6 @@ static bo_t *GetD263Tag(void) bo_add_16be(d263, 0xa); bo_add_8(d263, 0); - box_fix(d263); - return d263; } @@ -793,27 +766,23 @@ static bo_t *GetAvcCTag(mp4_stream_t *p_stream) int i_buffer = p_stream->fmt.i_extra; while (i_buffer > 3) { - /* seek startcode */ - while (p_buffer[0] != 0 || p_buffer[1] != 0 || p_buffer[2] != 1) { + while (memcmp(p_buffer, &avc1_start_code[1], 3)) { i_buffer--; p_buffer++; } const int i_nal_type = p_buffer[3]&0x1f; - int i_size = 0; int i_startcode = 0; - - for (int i_offset = 1; i_offset+2 < i_buffer ; i_offset++) { - if (p_buffer[i_offset] == 0 && p_buffer[i_offset+1] == 0 && - p_buffer[i_offset+2] == 1) { + for (int i_offset = 1; i_offset+2 < i_buffer ; i_offset++) + if (!memcmp(&p_buffer[i_offset], &avc1_start_code[1], 3)) { /* we found another startcode */ i_startcode = i_offset; while (p_buffer[i_startcode-1] == 0 && i_startcode > 0) i_startcode--; break; } - } - i_size = i_startcode ? i_startcode : i_buffer; + + int i_size = i_startcode ? i_startcode : i_buffer; if (i_nal_type == 7) { p_sps = &p_buffer[3]; @@ -847,7 +816,6 @@ static bo_t *GetAvcCTag(mp4_stream_t *p_stream) bo_add_16be(avcC, i_pps_size); bo_add_mem(avcC, i_pps_size, p_pps); } - box_fix(avcC); return avcC; } @@ -878,7 +846,6 @@ static bo_t *GetSVQ3Tag(mp4_stream_t *p_stream) bo_add_32be(smi, 0x5); bo_add_32be(smi, 0xe2c0211d); bo_add_8(smi, 0xc0); - box_fix(smi); return smi; } @@ -891,16 +858,15 @@ static bo_t *GetUdtaTag(sout_mux_t *p_mux) /* Requirements */ for (int i_track = 0; i_track < p_sys->i_nb_streams; i_track++) { mp4_stream_t *p_stream = p_sys->pp_streams[i_track]; + vlc_fourcc_t codec = p_stream->fmt.i_codec; - if (p_stream->fmt.i_codec == VLC_CODEC_MP4V || - p_stream->fmt.i_codec == VLC_CODEC_MP4A) { + if (codec == VLC_CODEC_MP4V || codec == VLC_CODEC_MP4A) { 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, (uint8_t *)"QuickTime 6.0 or greater"); - box_fix(box); box_gather(udta, box); break; } @@ -914,7 +880,6 @@ static bo_t *GetUdtaTag(sout_mux_t *p_mux) bo_add_16be(box, 0); bo_add_mem(box, sizeof(PACKAGE_STRING " stream output") - 1, (uint8_t*)PACKAGE_STRING " stream output"); - box_fix(box); box_gather(udta, box); } #if 0 @@ -930,7 +895,6 @@ static bo_t *GetUdtaTag(sout_mux_t *p_mux) bo_add_16be(box, 0); \ bo_add_mem(box, strlen(vlc_meta_Get(p_meta, vlc_meta_##type)), \ (uint8_t*)(vlc_meta_Get(p_meta, vlc_meta_##type))); \ - box_fix(box); \ box_gather(udta, box); \ } } @@ -944,51 +908,32 @@ static bo_t *GetUdtaTag(sout_mux_t *p_mux) #undef ADD_META_BOX } #endif - 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; - bool b_descr = false; - bo_t *soun; - char fcc[4] = " "; - - switch(p_stream->fmt.i_codec) - { - case VLC_CODEC_MP4A: - memcpy(fcc, "mp4a", 4); - b_descr = true; - break; - - case VLC_CODEC_AMR_NB: - case VLC_CODEC_AMR_WB: - memcpy(fcc, (char*)&p_stream->fmt.i_codec, 4); - b_descr = true; - break; - - case VLC_CODEC_MPGA: - if (p_sys->b_mov) + bool b_descr = true; + vlc_fourcc_t codec = p_stream->fmt.i_codec; + char fcc[4]; + vlc_fourcc_to_char(codec, fcc); + + if (codec == VLC_CODEC_MPGA) { + if (p_sys->b_mov) { + b_descr = false; memcpy(fcc, ".mp3", 4); - else { + } else memcpy(fcc, "mp4a", 4); - b_descr = true; - } - break; - - default: - memcpy(fcc, (char*)&p_stream->fmt.i_codec, 4); - break; } - soun = box_new(fcc); + bo_t *soun = box_new(fcc); for (int 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_CODEC_MP4A) + if (p_sys->b_mov && codec == VLC_CODEC_MP4A) bo_add_16be(soun, 1); // version 1; else bo_add_16be(soun, 0); // version 0; @@ -1018,67 +963,39 @@ static bo_t *GetSounBox(sout_mux_t *p_mux, mp4_stream_t *p_stream) if (b_descr) { bo_t *box; - if (p_sys->b_mov && p_stream->fmt.i_codec == VLC_CODEC_MP4A) + if (p_sys->b_mov && codec == VLC_CODEC_MP4A) box = GetWaveTag(p_stream); - else if (p_stream->fmt.i_codec == VLC_CODEC_AMR_NB) + else if (codec == VLC_CODEC_AMR_NB) box = GetDamrTag(p_stream); else box = GetESDS(p_stream); - box_fix(box); box_gather(soun, box); } - box_fix(soun); - return soun; } static bo_t *GetVideBox(mp4_stream_t *p_stream) { - bo_t *vide; - char fcc[4] = " "; + char fcc[4]; switch(p_stream->fmt.i_codec) { case VLC_CODEC_MP4V: - case VLC_CODEC_MPGV: - memcpy(fcc, "mp4v", 4); - break; - - case VLC_CODEC_MJPG: - memcpy(fcc, "mjpa", 4); - break; - - case VLC_CODEC_SVQ1: - memcpy(fcc, "SVQ1", 4); - break; - - case VLC_CODEC_SVQ3: - memcpy(fcc, "SVQ3", 4); - break; - - case VLC_CODEC_H263: - memcpy(fcc, "s263", 4); - break; - - case VLC_CODEC_H264: - memcpy(fcc, "avc1", 4); - break; - - case VLC_CODEC_YV12: - memcpy(fcc, "yv12", 4); - break; - - case VLC_CODEC_YUYV: - memcpy(fcc, "yuy2", 4); - break; - + case VLC_CODEC_MPGV: memcpy(fcc, "mp4v", 4); break; + case VLC_CODEC_MJPG: memcpy(fcc, "mjpa", 4); break; + case VLC_CODEC_SVQ1: memcpy(fcc, "SVQ1", 4); break; + case VLC_CODEC_SVQ3: memcpy(fcc, "SVQ3", 4); break; + case VLC_CODEC_H263: memcpy(fcc, "s263", 4); break; + case VLC_CODEC_H264: memcpy(fcc, "avc1", 4); break; + case VLC_CODEC_YV12: memcpy(fcc, "yv12", 4); break; + case VLC_CODEC_YUYV: memcpy(fcc, "yuy2", 4); break; default: - memcpy(fcc, (char*)&p_stream->fmt.i_codec, 4); + vlc_fourcc_to_char(p_stream->fmt.i_codec, fcc); break; } - vide = box_new(fcc); + bo_t *vide = box_new(fcc); for (int i = 0; i < 6; i++) bo_add_8(vide, 0); // reserved; bo_add_16be(vide, 1); // data-reference-index @@ -1109,42 +1026,22 @@ static bo_t *GetVideBox(mp4_stream_t *p_stream) { case VLC_CODEC_MP4V: case VLC_CODEC_MPGV: - { - bo_t *esds = GetESDS(p_stream); - - box_fix(esds); - box_gather(vide, esds); - } + box_gather(vide, GetESDS(p_stream)); break; case VLC_CODEC_H263: - { - bo_t *d263 = GetD263Tag(); - - box_fix(d263); - box_gather(vide, d263); - } + box_gather(vide, GetD263Tag()); break; case VLC_CODEC_SVQ3: - { - bo_t *esds = GetSVQ3Tag(p_stream); - - box_fix(esds); - box_gather(vide, esds); - } + box_gather(vide, GetSVQ3Tag(p_stream)); break; case VLC_CODEC_H264: box_gather(vide, GetAvcCTag(p_stream)); break; - - default: - break; } - box_fix(vide); - return vide; } @@ -1173,36 +1070,25 @@ static bo_t *GetTextBox(void) 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_t *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_stream); - box_gather(stsd, vide); - } else if (p_stream->fmt.i_cat == SPU_ES) { + if (p_stream->fmt.i_cat == AUDIO_ES) + box_gather(stsd, GetSounBox(p_mux, p_stream)); + else if (p_stream->fmt.i_cat == VIDEO_ES) + box_gather(stsd, GetVideBox(p_stream)); + else if (p_stream->fmt.i_cat == SPU_ES) box_gather(stsd, GetTextBox()); - } - box_fix(stsd); /* chunk offset table */ + bo_t *stco; if (p_sys->i_pos >= (((uint64_t)0x1) << 32)) { /* 64 bits version */ p_stream->b_stco64 = true; @@ -1215,29 +1101,27 @@ static bo_t *GetStblBox(sout_mux_t *p_mux, mp4_stream_t *p_stream) bo_add_32be(stco, 0); // entry-count (fixed latter) /* sample to chunk table */ - stsc = box_full_new("stsc", 0, 0); + bo_t *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++) { + unsigned i_chunk = 0; + unsigned i_stsc_last_val = 0, i_stsc_entries = 0; + for (unsigned i = 0; i < p_stream->i_entry_count; i_chunk++) { + mp4_entry_t *entry = p_stream->entry; int i_first = i; if (p_stream->b_stco64) - bo_add_64be(stco, p_stream->entry[i].i_pos); + bo_add_64be(stco, entry[i].i_pos); else - bo_add_32be(stco, p_stream->entry[i].i_pos); + bo_add_32be(stco, 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) { + for (; i < p_stream->i_entry_count; i++) + if (i >= p_stream->i_entry_count - 1 || + entry[i].i_pos + entry[i].i_size != 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 @@ -1251,62 +1135,48 @@ static bo_t *GetStblBox(sout_mux_t *p_mux, mp4_stream_t *p_stream) /* 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_t *stts = box_full_new("stts", 0, 0); bo_add_32be(stts, 0); // entry-count (fixed latter) + uint32_t i_timescale; 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 * INT64_C(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; + i_timescale = CLOCK_FREQ; - p_stream->entry[i].i_length = - i_delta * (int64_t)i_timescale / INT64_C(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++) { + unsigned i_index = 0; + for (unsigned i = 0; i < p_stream->i_entry_count; i_index++) { + p_stream->entry[i].i_length = p_stream->entry[i].i_length + * (int64_t)i_timescale / CLOCK_FREQ; 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) + for (; 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_t *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 (unsigned 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++) + bo_t *stss = NULL; + i_index = 0; + for (unsigned i = 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); @@ -1316,12 +1186,12 @@ static bo_t *GetStblBox(sout_mux_t *p_mux, mp4_stream_t *p_stream) i_index++; } - if (stss) { + if (stss) bo_fix_32be(stss, 12, i_index); - box_fix(stss); - } /* Now gather all boxes into stbl */ + bo_t *stbl = box_new("stbl"); + box_gather(stbl, stsd); box_gather(stbl, stts); if (stss) @@ -1331,9 +1201,6 @@ static bo_t *GetStblBox(sout_mux_t *p_mux, mp4_stream_t *p_stream) p_stream->i_stco_pos = stbl->len + 16; box_gather(stbl, stco); - /* finish stbl */ - box_fix(stbl); - return stbl; } @@ -1359,10 +1226,9 @@ static bo_t *GetMoovBox(sout_mux_t *p_mux) 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)); + msg_Dbg(p_mux, "movie duration %"PRId64"s", i_movie_duration / CLOCK_FREQ); - i_movie_duration = i_movie_duration * i_movie_timescale / 1000000; + i_movie_duration = i_movie_duration * i_movie_timescale / CLOCK_FREQ; /* *** add /moov/mvhd *** */ if (!p_sys->b_64_ext) { @@ -1391,27 +1257,22 @@ static bo_t *GetMoovBox(sout_mux_t *p_mux) /* 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 (int 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]; + mp4_stream_t *p_stream = p_sys->pp_streams[i_trak]; + uint32_t i_timescale; if (p_stream->fmt.i_cat == AUDIO_ES) i_timescale = p_stream->fmt.audio.i_rate; else - i_timescale = 1001; + i_timescale = CLOCK_FREQ; /* *** add /moov/trak *** */ - trak = box_new("trak"); + bo_t *trak = box_new("trak"); /* *** add /moov/trak/tkhd *** */ + bo_t *tkhd; if (!p_sys->b_64_ext) { if (p_sys->b_mov) tkhd = box_full_new("tkhd", 0, 0x0f); @@ -1423,8 +1284,7 @@ static bo_t *GetMoovBox(sout_mux_t *p_mux) 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 + (int64_t)i_movie_timescale / CLOCK_FREQ); // duration } else { if (p_sys->b_mov) tkhd = box_full_new("tkhd", 1, 0x0f); @@ -1436,8 +1296,7 @@ static bo_t *GetMoovBox(sout_mux_t *p_mux) 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 + (int64_t)i_movie_timescale / CLOCK_FREQ); // duration } for (int i = 0; i < 2; i++) @@ -1484,22 +1343,21 @@ static bo_t *GetMoovBox(sout_mux_t *p_mux) 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); + bo_t *edts = box_new("edts"); + bo_t *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 / INT64_C(1000000)); + i_movie_timescale / CLOCK_FREQ); bo_add_64be(elst, -1); } else { bo_add_32be(elst, (p_stream->i_dts_start-p_sys->i_dts_start) * - i_movie_timescale / INT64_C(1000000)); + i_movie_timescale / CLOCK_FREQ); bo_add_32be(elst, -1); } bo_add_16be(elst, 1); @@ -1509,39 +1367,38 @@ static bo_t *GetMoovBox(sout_mux_t *p_mux) } if (p_sys->b_64_ext) { bo_add_64be(elst, p_stream->i_duration * - i_movie_timescale / INT64_C(1000000)); + i_movie_timescale / CLOCK_FREQ); bo_add_64be(elst, 0); } else { bo_add_32be(elst, p_stream->i_duration * - i_movie_timescale / INT64_C(1000000)); + i_movie_timescale / CLOCK_FREQ); bo_add_32be(elst, 0); } bo_add_16be(elst, 1); bo_add_16be(elst, 0); - box_fix(elst); box_gather(edts, elst); - box_fix(edts); box_gather(trak, edts); /* *** add /moov/trak/mdia *** */ - mdia = box_new("mdia"); + bo_t *mdia = box_new("mdia"); /* media header */ + bo_t *mdhd; if (!p_sys->b_64_ext) { mdhd = box_full_new("mdhd", 0, 0); bo_add_32be(mdhd, i_timestamp); // creation time bo_add_32be(mdhd, i_timestamp); // modification time bo_add_32be(mdhd, i_timescale); // timescale bo_add_32be(mdhd, p_stream->i_duration * (int64_t)i_timescale / - (mtime_t)1000000); // duration + CLOCK_FREQ); // duration } else { mdhd = box_full_new("mdhd", 1, 0); bo_add_64be(mdhd, i_timestamp); // creation time bo_add_64be(mdhd, i_timestamp); // modification time bo_add_32be(mdhd, i_timescale); // timescale bo_add_64be(mdhd, p_stream->i_duration * (int64_t)i_timescale / - (mtime_t)1000000); // duration + CLOCK_FREQ); // duration } if (p_stream->fmt.psz_language) { @@ -1565,11 +1422,10 @@ static bo_t *GetMoovBox(sout_mux_t *p_mux) } else bo_add_16be(mdhd, 0 ); // language bo_add_16be(mdhd, 0 ); // predefined - box_fix(mdhd); box_gather(mdia, mdhd); /* handler reference */ - hdlr = box_full_new("hdlr", 0, 0); + bo_t *hdlr = box_full_new("hdlr", 0, 0); if (p_sys->b_mov) bo_add_fourcc(hdlr, "mhlr"); // media handler @@ -1600,11 +1456,10 @@ static bo_t *GetMoovBox(sout_mux_t *p_mux) if (!p_sys->b_mov) bo_add_8(hdlr, 0); /* asciiz string for .mp4, yes that's BRAIN DAMAGED F**K MP4 */ - box_fix(hdlr); box_gather(mdia, hdlr); /* minf*/ - minf = box_new("minf"); + bo_t *minf = box_new("minf"); /* add smhd|vmhd */ if (p_stream->fmt.i_cat == AUDIO_ES) { @@ -1613,7 +1468,6 @@ static bo_t *GetMoovBox(sout_mux_t *p_mux) smhd = box_full_new("smhd", 0, 0); bo_add_16be(smhd, 0); // balance bo_add_16be(smhd, 0); // reserved - box_fix(smhd); box_gather(minf, smhd); } else if (p_stream->fmt.i_cat == VIDEO_ES) { @@ -1623,7 +1477,6 @@ static bo_t *GetMoovBox(sout_mux_t *p_mux) bo_add_16be(vmhd, 0); // graphicsmode for (int i = 0; i < 3; i++) bo_add_16be(vmhd, 0); // opcolor - box_fix(vmhd); box_gather(minf, vmhd); } else if (p_stream->fmt.i_cat == SPU_ES) { @@ -1635,47 +1488,39 @@ static bo_t *GetMoovBox(sout_mux_t *p_mux) bo_add_16be(gmin, 0); // opcolor bo_add_16be(gmin, 0); // balance bo_add_16be(gmin, 0); // reserved - box_fix(gmin); box_gather(gmhd, gmin); - box_fix(gmhd); box_gather(minf, gmhd); } /* dinf */ - dinf = box_new("dinf"); - dref = box_full_new("dref", 0, 0); + bo_t *dinf = box_new("dinf"); + bo_t *dref = box_full_new("dref", 0, 0); bo_add_32be(dref, 1); - url = box_full_new("url ", 0, 0x01); - box_fix(url); + bo_t *url = box_full_new("url ", 0, 0x01); box_gather(dref, url); - box_fix(dref); box_gather(dinf, dref); /* append dinf to mdia */ - box_fix(dinf); box_gather(minf, dinf); /* add stbl */ - stbl = GetStblBox(p_mux, p_stream); + bo_t *stbl = GetStblBox(p_mux, p_stream); /* append stbl to minf */ p_stream->i_stco_pos += minf->len; box_gather(minf, stbl); /* append minf to mdia */ - box_fix(minf); p_stream->i_stco_pos += mdia->len; box_gather(mdia, minf); /* append mdia to trak */ - box_fix(mdia); p_stream->i_stco_pos += trak->len; box_gather(trak, mdia); /* append trak to moov */ - box_fix(trak); p_stream->i_stco_pos += moov->len; box_gather(moov, trak); } @@ -1793,6 +1638,7 @@ static void box_fix(bo_t *box) static void box_gather (bo_t *box, bo_t *box2) { + box_fix(box2); box->b = block_Realloc(box->b, 0, box->len + box2->len); memcpy(&box->b->p_buffer[box->len], box2->b->p_buffer, box2->len); box->len += box2->len;