Projects
Multimedia
bento4
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 14
View file
bento4.changes
Changed
@@ -1,4 +1,9 @@ ------------------------------------------------------------------- +Tue Nov 12 12:10:33 UTC 2019 - Luigi Baldoni <aloisio@gmx.com> + +- Update to version 1.5.1-629 + +------------------------------------------------------------------- Sun Jan 13 09:15:40 UTC 2019 - aloisio@gmx.com - Update to version 1.5.1-628
View file
bento4.spec
Changed
@@ -16,10 +16,10 @@ # -%define _over 1.5.1-628 -%define _libver 1_5_1r628 +%define _over 1.5.1-629 +%define _libver 1_5_1r629 Name: bento4 -Version: 1.5.1r628 +Version: 1.5.1r629 Release: 0 Summary: C++ toolkit for all your MP4 and MPEG DASH media format needs License: GPL-2.0-or-later
View file
bento4-1.5.1r628.tar.gz/Build/Makefiles/TopLevel.mak -> bento4-1.5.1r629.tar.gz/Build/Makefiles/TopLevel.mak
Changed
@@ -47,9 +47,9 @@ .PHONY: Setup Setup: mkdir $(OUTPUT_DIR) - + # ------- Apps ----------- -ALL_APPS = mp4dump mp4info mp42aac mp42ts aac2mp4 mp4decrypt mp4encrypt mp4edit mp4extract mp4rtphintinfo mp4tag mp4dcfpackager mp4fragment mp4compact mp4split mp4mux avcinfo hevcinfo mp42hevc mp42hls +ALL_APPS = mp4dump mp4info mp42aac mp42ts aac2mp4 mp4decrypt mp4encrypt mp4edit mp4extract mp4rtphintinfo mp4tag mp4dcfpackager mp4fragment mp4compact mp4split mp4mux avcinfo hevcinfo mp42hevc mp42hls mp4iframeindex export ALL_APPS ################################################################## @@ -72,7 +72,7 @@ sdk: lib apps $(TITLE) @$(INVOKE_SUBMAKE) -f $(BUILD_ROOT)/Makefiles/SDK.mak - + mp4dump: lib $(TITLE) @$(INVOKE_SUBMAKE) -f $(BUILD_ROOT)/Makefiles/Mp4Dump.mak @@ -132,7 +132,7 @@ mp4compact: lib $(TITLE) @$(INVOKE_SUBMAKE) -f $(BUILD_ROOT)/Makefiles/Mp4Compact.mak - + mp4mux: lib $(TITLE) @$(INVOKE_SUBMAKE) -f $(BUILD_ROOT)/Makefiles/Mp4Mux.mak
View file
bento4-1.5.1r628.tar.gz/Source/C++/Apps/Mp42Hls/Mp42Hls.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Apps/Mp42Hls/Mp42Hls.cpp
Changed
@@ -562,7 +562,7 @@ PreventStartCodeEmulation(nalu+nalu_length_size, nalu_length, escaped_nalu); // the size may have changed - // FIXME: this could overflow if nalu_length_size is too small + // TODO: this could overflow if nalu_length_size is too small switch (nalu_length_size) { case 1: nalu[0] = (AP4_UI08)(escaped_nalu.GetDataSize()&0xFF); @@ -2108,6 +2108,12 @@ if (Stats.segments_total_duration != 0.0) { average_iframe_bitrate = 8.0*(double)Stats.iframes_total_size/Stats.segments_total_duration; } + + double frame_rate = 0.0; + if (Stats.segments_total_duration != 0.0) { + frame_rate = (double)video_track->GetSampleCount()/((double)video_track->GetMediaDuration()/(double)video_track->GetMediaTimeScale()); + } + printf( "{\n" ); @@ -2117,13 +2123,15 @@ " \"avg_segment_bitrate\": %f,\n" " \"max_segment_bitrate\": %f,\n" " \"avg_iframe_bitrate\": %f,\n" - " \"max_iframe_bitrate\": %f\n" + " \"max_iframe_bitrate\": %f,\n" + " \"frame_rate\": %f\n" " }", (double)movie->GetDurationMs()/1000.0, average_segment_bitrate, Stats.max_segment_bitrate, average_iframe_bitrate, - Stats.max_iframe_bitrate + Stats.max_iframe_bitrate, + frame_rate ); if (audio_track) { AP4_String codec;
View file
bento4-1.5.1r628.tar.gz/Source/C++/Apps/Mp4Fragment/Mp4Fragment.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Apps/Mp4Fragment/Mp4Fragment.cpp
Changed
@@ -2,7 +2,7 @@ | | AP4 - MP4 Fragmenter | -| Copyright 2002-2015 Axiomatic Systems, LLC +| Copyright 2002-2019 Axiomatic Systems, LLC | | | This file is part of Bento4/AP4 (MP4 Atom Processing Library). @@ -37,9 +37,9 @@ /*---------------------------------------------------------------------- | constants +---------------------------------------------------------------------*/ -#define BANNER "MP4 Fragmenter - Version 1.6.0\n"\ +#define BANNER "MP4 Fragmenter - Version 1.6.1\n"\ "(Bento4 Version " AP4_VERSION_STRING ")\n"\ - "(c) 2002-2015 Axiomatic Systems, LLC" + "(c) 2002-2019 Axiomatic Systems, LLC" /*---------------------------------------------------------------------- | constants @@ -86,8 +86,8 @@ " --index (re)create the segment index\n" " --trim trim excess media in longer tracks\n" " --no-tfdt don't add 'tfdt' boxes in the fragments (may be needed for legacy Smooth Streaming clients)\n" - " --tfdt-start <start> Value of the first tfdt timestamp, expressed either as a floating point number in seconds)\n" - " --sequence-number-start <start> Value of the first segment sequence number (default: 1)\n" + " --tfdt-start <start> value of the first tfdt timestamp, expressed as a floating point number in seconds\n" + " --sequence-number-start <start> value of the first segment sequence number (default: 1)\n" " --force-i-frame-sync <auto|all> treat all I-frames as sync samples (for open-gop sequences)\n" " 'auto' only forces the flag if an open-gop source is detected, 'all' forces the flag in all cases\n" " --copy-udta copy the moov/udta atom from input to output\n" @@ -644,7 +644,7 @@ AP4_Array<AP4_TrunAtom::Entry> trun_entries; fragment->m_MdatSize = AP4_ATOM_HEADER_SIZE; AP4_UI32 constant_sample_duration = 0; - bool all_segment_durations_equal = true; + bool all_sample_durations_equal = true; for (;;) { // if we have one non-zero CTS delta, we'll need to express it if (cursor->m_Sample.GetCtsDelta()) { @@ -674,12 +674,12 @@ fragment->m_Duration += trun_entry.sample_duration; // check if the durations are all the same - if (all_segment_durations_equal) { + if (all_sample_durations_equal) { if (constant_sample_duration == 0) { constant_sample_duration = trun_entry.sample_duration; } else { if (constant_sample_duration != trun_entry.sample_duration) { - all_segment_durations_equal = false; + all_sample_durations_equal = false; } } } @@ -705,11 +705,11 @@ } if (Options.verbosity > 2) { printf(" %d samples\n", sample_count); - printf(" constant sample duration: %s\n", all_segment_durations_equal?"yes":"no"); + printf(" constant sample duration: %s\n", all_sample_durations_equal?"yes":"no"); } // update the 'trun' flags if needed - if (all_segment_durations_equal) { + if (all_sample_durations_equal) { tfhd->SetDefaultSampleDuration(constant_sample_duration); tfhd->UpdateFlags(tfhd->GetFlags() | AP4_TFHD_FLAG_DEFAULT_SAMPLE_DURATION_PRESENT); } else { @@ -771,9 +771,11 @@ AP4_Position sidx_position = 0; output_stream.Tell(sidx_position); if (create_segment_index) { + AP4_UI32 sidx_timescale = timescale ? timescale : indexed_cursor->m_Track->GetMediaTimeScale(); + AP4_UI64 earliest_presentation_time = (AP4_UI64)(Options.tfdt_start * (double)sidx_timescale); sidx = new AP4_SidxAtom(indexed_cursor->m_Track->GetId(), - timescale ? timescale : indexed_cursor->m_Track->GetMediaTimeScale(), - 0, + sidx_timescale, + earliest_presentation_time, 0); // reserve space for the entries now, but they will be computed and updated later sidx->SetReferenceCount(indexed_segments.ItemCount());
View file
bento4-1.5.1r628.tar.gz/Source/C++/Apps/Mp4Mux/Mp4Mux.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Apps/Mp4Mux/Mp4Mux.cpp
Changed
@@ -2,7 +2,7 @@ | | AP4 - Elementary Stream Muliplexer | -| Copyright 2002-2016 Axiomatic Systems, LLC +| Copyright 2002-2019 Axiomatic Systems, LLC | | | This file is part of Bento4/AP4 (MP4 Atom Processing Library). @@ -39,11 +39,12 @@ /*---------------------------------------------------------------------- | constants +---------------------------------------------------------------------*/ -#define BANNER "MP4 Elementary Stream Multiplexer - Version 1.1\n"\ +#define BANNER "MP4 Elementary Stream Multiplexer - Version 2.0\n"\ "(Bento4 Version " AP4_VERSION_STRING ")\n"\ - "(c) 2002-20016 Axiomatic Systems, LLC" + "(c) 2002-20019 Axiomatic Systems, LLC" const unsigned int AP4_MUX_DEFAULT_VIDEO_FRAME_RATE = 24; +const unsigned int AP4_MUX_READ_BUFFER_SIZE = 65536; /*---------------------------------------------------------------------- | globals @@ -301,7 +302,7 @@ } // read some data and feed the parser - AP4_UI08 input_buffer[4096]; + AP4_UI08 input_buffer[AP4_MUX_READ_BUFFER_SIZE]; AP4_Size to_read = parser.GetBytesFree(); if (to_read) { AP4_Size bytes_read = 0; @@ -381,7 +382,7 @@ AP4_AvcFrameParser parser; for (;;) { bool eos; - unsigned char input_buffer[4096]; + unsigned char input_buffer[AP4_MUX_READ_BUFFER_SIZE]; AP4_Size bytes_in_buffer = 0; result = input->ReadPartial(input_buffer, sizeof(input_buffer), bytes_in_buffer); if (AP4_SUCCEEDED(result)) { @@ -602,7 +603,7 @@ AP4_HevcFrameParser parser; for (;;) { bool eos; - unsigned char input_buffer[4096]; + unsigned char input_buffer[AP4_MUX_READ_BUFFER_SIZE]; AP4_Size bytes_in_buffer = 0; result = input->ReadPartial(input_buffer, sizeof(input_buffer), bytes_in_buffer); if (AP4_SUCCEEDED(result)) { @@ -716,8 +717,8 @@ AP4_UI32 min_spatial_segmentation = 0; // TBD (should read from VUI if present) AP4_UI08 parallelism_type = 0; // unknown AP4_UI08 chroma_format = sps->chroma_format_idc; - AP4_UI08 luma_bit_depth = 8; // FIXME: hardcoded temporarily, should be read from the bitstream - AP4_UI08 chroma_bit_depth = 8; // FIXME: hardcoded temporarily, should be read from the bitstream + AP4_UI08 luma_bit_depth = 8; // hardcoded temporarily, should be read from the bitstream + AP4_UI08 chroma_bit_depth = 8; // hardcoded temporarily, should be read from the bitstream AP4_UI16 average_frame_rate = 0; // unknown AP4_UI08 constant_frame_rate = 0; // unknown AP4_UI08 num_temporal_layers = 0; // unknown
View file
bento4-1.5.1r628.tar.gz/Source/C++/Codecs/Ap4HevcParser.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Codecs/Ap4HevcParser.cpp
Changed
@@ -243,11 +243,15 @@ /* abs_delta_rps_minus1 = */ ReadGolomb(bits); if (delta_idx_minus1+1 > stRpsIdx) return AP4_ERROR_INVALID_FORMAT; // should not happen unsigned int RefRpsIdx = stRpsIdx - (delta_idx_minus1 + 1); - unsigned int NumDeltaPocs = sps->short_term_ref_pic_sets[RefRpsIdx].num_negative_pics + sps->short_term_ref_pic_sets[RefRpsIdx].num_positive_pics; + unsigned int NumDeltaPocs = sps->short_term_ref_pic_sets[RefRpsIdx].num_delta_pocs; for (unsigned j=0; j<=NumDeltaPocs; j++) { unsigned int used_by_curr_pic_flag /*[j]*/ = bits.ReadBit(); + unsigned int use_delta_flag /*[j]*/ = 1; if (!used_by_curr_pic_flag /*[j]*/) { - /* use_delta_flag[j] = */ bits.ReadBit(); + use_delta_flag /*[j]*/ = bits.ReadBit(); + } + if (used_by_curr_pic_flag /*[j]*/ || use_delta_flag /*[j]*/) { + rps->num_delta_pocs++; } } } else { @@ -256,6 +260,7 @@ if (rps->num_negative_pics > 16 || rps->num_positive_pics > 16) { return AP4_ERROR_INVALID_FORMAT; } + rps->num_delta_pocs = rps->num_negative_pics + rps->num_positive_pics; for (unsigned int i=0; i<rps->num_negative_pics; i++) { rps->delta_poc_s0_minus1[i] = ReadGolomb(bits); rps->used_by_curr_pic_s0_flag[i] = bits.ReadBit();
View file
bento4-1.5.1r628.tar.gz/Source/C++/Codecs/Ap4HevcParser.h -> bento4-1.5.1r629.tar.gz/Source/C++/Codecs/Ap4HevcParser.h
Changed
@@ -161,6 +161,7 @@ unsigned int used_by_curr_pic_s1_flag[16]; unsigned int num_negative_pics; unsigned int num_positive_pics; + unsigned int num_delta_pocs; } AP4_HevcShortTermRefPicSet; /*----------------------------------------------------------------------
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4Atom.h -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4Atom.h
Changed
@@ -495,6 +495,8 @@ const AP4_Atom::Type AP4_ATOM_TYPE_DTSH = AP4_ATOM_TYPE('d','t','s','h'); const AP4_Atom::Type AP4_ATOM_TYPE_DTSL = AP4_ATOM_TYPE('d','t','s','l'); const AP4_Atom::Type AP4_ATOM_TYPE_DTSE = AP4_ATOM_TYPE('d','t','s','e'); +const AP4_Atom::Type AP4_ATOM_TYPE_FLAC = AP4_ATOM_TYPE('f','L','a','C'); +const AP4_Atom::Type AP4_ATOM_TYPE_OPUS = AP4_ATOM_TYPE('O','p','u','s'); const AP4_Atom::Type AP4_ATOM_TYPE_MFRA = AP4_ATOM_TYPE('m','f','r','a'); const AP4_Atom::Type AP4_ATOM_TYPE_TFRA = AP4_ATOM_TYPE('t','f','r','a'); const AP4_Atom::Type AP4_ATOM_TYPE_MFRO = AP4_ATOM_TYPE('m','f','r','o');
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4AtomFactory.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4AtomFactory.cpp
Changed
@@ -197,6 +197,12 @@ stream.GetSize(stream_size); if (stream_size >= start) { size = stream_size - start; + + if (size <= 0xFFFFFFFF) { + size_32 = (AP4_UI32)size; + } else { + size_32 = 1; // signal a large atom + } } } else if (size == 1) { // 64-bit size @@ -206,6 +212,10 @@ return AP4_ERROR_INVALID_FORMAT; } stream.ReadUI64(size); + if (size < 16) { + stream.Seek(start); + return AP4_ERROR_INVALID_FORMAT; + } if (size <= 0xFFFFFFFF) { force_64 = true; } @@ -321,6 +331,8 @@ case AP4_ATOM_TYPE_DTSH: case AP4_ATOM_TYPE_DTSL: case AP4_ATOM_TYPE_DTSE: + case AP4_ATOM_TYPE_FLAC: + case AP4_ATOM_TYPE_OPUS: atom = new AP4_AudioSampleEntry(type, size_32, stream, *this); break;
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4AvccAtom.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4AvccAtom.cpp
Changed
@@ -85,8 +85,8 @@ cursor += 2+AP4_BytesToInt16BE(&payload[cursor]); if (cursor > payload_size) return NULL; } + if (cursor+1 > payload_size) return NULL; unsigned int num_pic_params = payload[cursor++]; - if (cursor > payload_size) return NULL; for (unsigned int i=0; i<num_pic_params; i++) { if (cursor+2 > payload_size) return NULL; cursor += 2+AP4_BytesToInt16BE(&payload[cursor]);
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4CommonEncryption.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4CommonEncryption.cpp
Changed
@@ -2327,6 +2327,36 @@ } /*---------------------------------------------------------------------- +| AP4_CencDecryptingProcessor:GetKeyForTrak ++---------------------------------------------------------------------*/ +const AP4_DataBuffer* +AP4_CencDecryptingProcessor::GetKeyForTrak(AP4_UI32 track_id, AP4_ProtectedSampleDescription* sample_description) +{ + // look for the key by track ID + const AP4_DataBuffer* key = m_KeyMap->GetKey(track_id); + if (!key) { + // no key found by track ID, look for a key by KID + if (sample_description) { + AP4_ProtectionSchemeInfo* scheme_info = sample_description->GetSchemeInfo(); + if (scheme_info) { + AP4_ContainerAtom* schi = scheme_info->GetSchiAtom(); + if (schi) { + AP4_TencAtom* tenc = AP4_DYNAMIC_CAST(AP4_TencAtom, schi->FindChild("tenc")); + if (tenc) { + const AP4_UI08* kid = tenc->GetDefaultKid(); + if (kid) { + key = m_KeyMap->GetKeyByKid(kid); + } + } + } + } + } + } + + return key; +} + +/*---------------------------------------------------------------------- | AP4_CencDecryptingProcessor:CreateTrackHandler +---------------------------------------------------------------------*/ AP4_Processor::TrackHandler* @@ -2363,8 +2393,8 @@ } if (sample_entries.ItemCount() == 0) return NULL; - // look for the key by track ID - const AP4_DataBuffer* key = m_KeyMap->GetKey(trak->GetId()); + // get the key for this track + const AP4_DataBuffer* key = GetKeyForTrak(trak->GetId(), sample_descs.ItemCount() ? sample_descs[0] : NULL); // create a decrypter with this key if (key) { @@ -2385,7 +2415,7 @@ | AP4_CencDecryptingProcessor::CreateFragmentHandler +---------------------------------------------------------------------*/ AP4_Processor::FragmentHandler* -AP4_CencDecryptingProcessor::CreateFragmentHandler(AP4_TrakAtom* /*trak*/, +AP4_CencDecryptingProcessor::CreateFragmentHandler(AP4_TrakAtom* trak, AP4_TrexAtom* trex, AP4_ContainerAtom* traf, AP4_ByteStream& moof_data, @@ -2410,11 +2440,11 @@ sample_description = track_decrypter->GetSampleDescription(index-1); } if (sample_description == NULL) return NULL; + + // get the key for this track + key = GetKeyForTrak(tfhd->GetTrackId(), sample_description); } - // get the matching key by track ID - key = m_KeyMap->GetKey(tfhd->GetTrackId()); - break; } }
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4CommonEncryption.h -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4CommonEncryption.h
Changed
@@ -664,7 +664,10 @@ AP4_ByteStream& moof_data, AP4_Position moof_offset); -protected: +protected: + // methods + const AP4_DataBuffer* GetKeyForTrak(AP4_UI32 track_id, AP4_ProtectedSampleDescription* sample_description); + // members AP4_BlockCipherFactory* m_BlockCipherFactory; const AP4_ProtectionKeyMap* m_KeyMap;
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4DecoderConfigDescriptor.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4DecoderConfigDescriptor.cpp
Changed
@@ -74,11 +74,8 @@ header_size, payload_size) { - // record the start position - AP4_Position start; - stream.Tell(start); - // read descriptor fields + if (payload_size < 13) return; stream.ReadUI08(m_ObjectTypeIndication); unsigned char bits; stream.ReadUI08(bits); @@ -87,9 +84,12 @@ stream.ReadUI24(m_BufferSize); stream.ReadUI32(m_MaxBitrate); stream.ReadUI32(m_AverageBitrate); - + payload_size -= 13; + // read other descriptors - AP4_SubStream* substream = new AP4_SubStream(stream, start+13, payload_size-13); + AP4_Position offset; + stream.Tell(offset); + AP4_SubStream* substream = new AP4_SubStream(stream, offset, payload_size); AP4_Descriptor* descriptor = NULL; while (AP4_DescriptorFactory::CreateDescriptorFromStream(*substream, descriptor)
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4DescriptorFactory.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4DescriptorFactory.cpp
Changed
@@ -78,55 +78,57 @@ } while (--max && (ext&0x80)); // create the descriptor - switch (tag) { - case AP4_DESCRIPTOR_TAG_OD: - case AP4_DESCRIPTOR_TAG_MP4_OD: - descriptor = new AP4_ObjectDescriptor(stream, tag, header_size, payload_size); - break; - - case AP4_DESCRIPTOR_TAG_IOD: - case AP4_DESCRIPTOR_TAG_MP4_IOD: - descriptor = new AP4_InitialObjectDescriptor(stream, tag, header_size, payload_size); - break; - - case AP4_DESCRIPTOR_TAG_ES_ID_INC: - descriptor = new AP4_EsIdIncDescriptor(stream, header_size, payload_size); - break; - - case AP4_DESCRIPTOR_TAG_ES_ID_REF: - descriptor = new AP4_EsIdRefDescriptor(stream, header_size, payload_size); - break; - - case AP4_DESCRIPTOR_TAG_ES: - descriptor = new AP4_EsDescriptor(stream, header_size, payload_size); - break; - - case AP4_DESCRIPTOR_TAG_DECODER_CONFIG: - descriptor = new AP4_DecoderConfigDescriptor(stream, header_size, payload_size); - break; - - case AP4_DESCRIPTOR_TAG_DECODER_SPECIFIC_INFO: - descriptor = new AP4_DecoderSpecificInfoDescriptor(stream, header_size, payload_size); - break; - - case AP4_DESCRIPTOR_TAG_SL_CONFIG: - if (payload_size != 1) return AP4_ERROR_INVALID_FORMAT; - descriptor = new AP4_SLConfigDescriptor(header_size); - break; - - case AP4_DESCRIPTOR_TAG_IPMP_DESCRIPTOR_POINTER: - descriptor = new AP4_IpmpDescriptorPointer(stream, header_size, payload_size); - break; - - case AP4_DESCRIPTOR_TAG_IPMP_DESCRIPTOR: - descriptor = new AP4_IpmpDescriptor(stream, header_size, payload_size); - break; - - default: - descriptor = new AP4_UnknownDescriptor(stream, tag, header_size, payload_size); - break; + if (payload_size) { + switch (tag) { + case AP4_DESCRIPTOR_TAG_OD: + case AP4_DESCRIPTOR_TAG_MP4_OD: + descriptor = new AP4_ObjectDescriptor(stream, tag, header_size, payload_size); + break; + + case AP4_DESCRIPTOR_TAG_IOD: + case AP4_DESCRIPTOR_TAG_MP4_IOD: + descriptor = new AP4_InitialObjectDescriptor(stream, tag, header_size, payload_size); + break; + + case AP4_DESCRIPTOR_TAG_ES_ID_INC: + descriptor = new AP4_EsIdIncDescriptor(stream, header_size, payload_size); + break; + + case AP4_DESCRIPTOR_TAG_ES_ID_REF: + descriptor = new AP4_EsIdRefDescriptor(stream, header_size, payload_size); + break; + + case AP4_DESCRIPTOR_TAG_ES: + descriptor = new AP4_EsDescriptor(stream, header_size, payload_size); + break; + + case AP4_DESCRIPTOR_TAG_DECODER_CONFIG: + descriptor = new AP4_DecoderConfigDescriptor(stream, header_size, payload_size); + break; + + case AP4_DESCRIPTOR_TAG_DECODER_SPECIFIC_INFO: + descriptor = new AP4_DecoderSpecificInfoDescriptor(stream, header_size, payload_size); + break; + + case AP4_DESCRIPTOR_TAG_SL_CONFIG: + if (payload_size != 1) return AP4_ERROR_INVALID_FORMAT; + descriptor = new AP4_SLConfigDescriptor(header_size); + break; + + case AP4_DESCRIPTOR_TAG_IPMP_DESCRIPTOR_POINTER: + descriptor = new AP4_IpmpDescriptorPointer(stream, header_size, payload_size); + break; + + case AP4_DESCRIPTOR_TAG_IPMP_DESCRIPTOR: + descriptor = new AP4_IpmpDescriptor(stream, header_size, payload_size); + break; + + default: + descriptor = new AP4_UnknownDescriptor(stream, tag, header_size, payload_size); + break; + } } - + // skip to the end of the descriptor stream.Seek(offset+header_size+payload_size);
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4ElstAtom.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4ElstAtom.cpp
Changed
@@ -68,10 +68,24 @@ AP4_ByteStream& stream) : AP4_Atom(AP4_ATOM_TYPE_ELST, size, version, flags) { + // read the number of entries AP4_UI32 entry_count; stream.ReadUI32(entry_count); + + // compute bounds + AP4_UI32 max_entries; + if (version == 0) { + max_entries = (size - (AP4_FULL_ATOM_HEADER_SIZE + 4)) / 12; + } else { + max_entries = (size - (AP4_FULL_ATOM_HEADER_SIZE + 4)) / 20; + } + if (entry_count > max_entries) { + entry_count = max_entries; + } + + // read the entries m_Entries.EnsureCapacity(entry_count); - for (AP4_UI32 i=0; i<entry_count; i++) { + for (AP4_UI32 i=0; i < entry_count; i++) { AP4_UI16 media_rate; AP4_UI16 zero; if (version == 0) {
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4EsDescriptor.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4EsDescriptor.cpp
Changed
@@ -63,24 +63,28 @@ AP4_Size payload_size) : AP4_Descriptor(AP4_DESCRIPTOR_TAG_ES, header_size, payload_size) { - AP4_Position start; - stream.Tell(start); - // read descriptor fields + if (payload_size < 3) return; stream.ReadUI16(m_EsId); unsigned char bits; stream.ReadUI08(bits); + payload_size -= 3; m_Flags = (bits>>5)&7; m_StreamPriority = bits&0x1F; if (m_Flags & AP4_ES_DESCRIPTOR_FLAG_STREAM_DEPENDENCY) { + if (payload_size < 2) return; stream.ReadUI16(m_DependsOn); + payload_size -= 2; } else { m_DependsOn = 0; } if (m_Flags & AP4_ES_DESCRIPTOR_FLAG_URL) { unsigned char url_length; + if (payload_size < 1) return; stream.ReadUI08(url_length); + --payload_size; if (url_length) { + if (payload_size < url_length) return; char* url = new char[url_length+1]; if (url) { stream.Read(url, url_length); @@ -88,10 +92,13 @@ m_Url = url; delete[] url; } + payload_size -= url_length; } } if (m_Flags & AP4_ES_DESCRIPTOR_FLAG_URL) { + if (payload_size < 2) return; stream.ReadUI16(m_OcrEsId); + payload_size -= 2; } else { m_OcrEsId = 0; } @@ -99,8 +106,7 @@ // read other descriptors AP4_Position offset; stream.Tell(offset); - AP4_SubStream* substream = new AP4_SubStream(stream, offset, - payload_size-AP4_Size(offset-start)); + AP4_SubStream* substream = new AP4_SubStream(stream, offset, payload_size); AP4_Descriptor* descriptor = NULL; while (AP4_DescriptorFactory::CreateDescriptorFromStream(*substream, descriptor)
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4FileWriter.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4FileWriter.cpp
Changed
@@ -117,7 +117,7 @@ movie->GetMoovAtom()->Write(stream); // create and write the media data (mdat) - // FIXME: this only supports 32-bit mdat size + // TODO: this only supports 32-bit mdat size stream.WriteUI32((AP4_UI32)mdat_size); stream.WriteUI32(AP4_ATOM_TYPE_MDAT);
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4LinearReader.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4LinearReader.cpp
Changed
@@ -41,8 +41,7 @@ | AP4_LinearReader::AP4_LinearReader +---------------------------------------------------------------------*/ AP4_LinearReader::AP4_LinearReader(AP4_Movie& movie, - AP4_ByteStream* fragment_stream, - AP4_Size max_buffer) : + AP4_ByteStream* fragment_stream) : m_Movie(movie), m_Fragment(NULL), m_FragmentStream(fragment_stream), @@ -50,7 +49,6 @@ m_NextFragmentPosition(0), m_BufferFullness(0), m_BufferFullnessPeak(0), - m_MaxBufferFullness(max_buffer), m_Mfra(NULL) { m_HasFragments = movie.HasFragments(); @@ -404,11 +402,7 @@ AP4_Result AP4_LinearReader::Advance(bool read_data) { - // first, check if we have space to advance - if (m_BufferFullness >= m_MaxBufferFullness) { - return AP4_ERROR_NOT_ENOUGH_SPACE; - } - + AP4_UI64 min_offset = (AP4_UI64)(-1); Tracker* next_tracker = NULL; for (;;) {
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4LinearReader.h -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4LinearReader.h
Changed
@@ -50,14 +50,12 @@ const unsigned int AP4_LINEAR_READER_INITIALIZED = 1; const unsigned int AP4_LINEAR_READER_FLAG_EOS = 2; -const unsigned int AP4_LINEAR_READER_DEFAULT_BUFFER_SIZE = 16*1024*1024; - /*---------------------------------------------------------------------- | AP4_LinearReader +---------------------------------------------------------------------*/ class AP4_LinearReader { public: - AP4_LinearReader(AP4_Movie& movie, AP4_ByteStream* fragment_stream = NULL, AP4_Size max_buffer=AP4_LINEAR_READER_DEFAULT_BUFFER_SIZE); + AP4_LinearReader(AP4_Movie& movie, AP4_ByteStream* fragment_stream = NULL); virtual ~AP4_LinearReader(); AP4_Result EnableTrack(AP4_UI32 track_id); @@ -184,7 +182,6 @@ AP4_Array<Tracker*> m_Trackers; AP4_Size m_BufferFullness; AP4_Size m_BufferFullnessPeak; - AP4_Size m_MaxBufferFullness; AP4_ContainerAtom* m_Mfra; };
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4Mpeg2Ts.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4Mpeg2Ts.cpp
Changed
@@ -282,6 +282,12 @@ bool with_pcr, AP4_ByteStream& output) { + // ISO/IEC 13818-1 section 2.7.5 says a DTS shall appear only if the + // decoding time differs from the presentation time. + if (with_dts && (dts == pts)) { + with_dts = false; + } + unsigned int pes_header_size = 14+(with_dts?5:0); AP4_BitWriter pes_header(pes_header_size);
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4ObjectDescriptor.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4ObjectDescriptor.cpp
Changed
@@ -71,20 +71,23 @@ AP4_Size payload_size) : AP4_Descriptor(tag, header_size, payload_size) { - AP4_Position start; - stream.Tell(start); - // read descriptor fields unsigned short bits; + if (payload_size < 2) return; stream.ReadUI16(bits); + payload_size -= 2; m_ObjectDescriptorId = (bits>>6); m_UrlFlag = ((bits&(1<<5))!=0); if (m_UrlFlag) { unsigned char url_length; + if (payload_size < 1) return; stream.ReadUI08(url_length); + --payload_size; char url[256]; + if (payload_size < url_length) return; stream.Read(url, url_length); + payload_size -= url_length; url[url_length] = '\0'; m_Url = url; } @@ -92,8 +95,7 @@ // read other descriptors AP4_Position offset; stream.Tell(offset); - AP4_SubStream* substream = new AP4_SubStream(stream, offset, - payload_size-AP4_Size(offset-start)); + AP4_SubStream* substream = new AP4_SubStream(stream, offset, payload_size); AP4_Descriptor* descriptor = NULL; while (AP4_DescriptorFactory::CreateDescriptorFromStream(*substream, descriptor) @@ -223,36 +225,40 @@ m_VisualProfileLevelIndication(0), m_GraphicsProfileLevelIndication(0) { - AP4_Position start; - stream.Tell(start); - // read descriptor fields unsigned short bits; + if (payload_size < 2) return; stream.ReadUI16(bits); + payload_size -= 2; m_ObjectDescriptorId = (bits>>6); m_UrlFlag = ((bits&(1<<5))!=0); m_IncludeInlineProfileLevelFlag = ((bits&(1<<4))!=0); - + if (m_UrlFlag) { unsigned char url_length; + if (payload_size < 1) return; stream.ReadUI08(url_length); + --payload_size; char url[256]; + if (payload_size < url_length) return; stream.Read(url, url_length); + payload_size -= url_length; url[url_length] = '\0'; m_Url = url; } else { + if (payload_size < 5) return; stream.ReadUI08(m_OdProfileLevelIndication); stream.ReadUI08(m_SceneProfileLevelIndication); stream.ReadUI08(m_AudioProfileLevelIndication); stream.ReadUI08(m_VisualProfileLevelIndication); - stream.ReadUI08(m_GraphicsProfileLevelIndication); + stream.ReadUI08(m_GraphicsProfileLevelIndication); + payload_size -= 5; } // read other descriptors AP4_Position offset; stream.Tell(offset); - AP4_SubStream* substream = new AP4_SubStream(stream, offset, - payload_size-AP4_Size(offset-start)); + AP4_SubStream* substream = new AP4_SubStream(stream, offset, payload_size); AP4_Descriptor* descriptor = NULL; while (AP4_DescriptorFactory::CreateDescriptorFromStream(*substream, descriptor)
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4Results.h -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4Results.h
Changed
@@ -55,7 +55,6 @@ const int AP4_ERROR_INVALID_RTP_PACKET_EXTRA_DATA = -20; const int AP4_ERROR_BUFFER_TOO_SMALL = -21; const int AP4_ERROR_NOT_ENOUGH_DATA = -22; -const int AP4_ERROR_NOT_ENOUGH_SPACE = -23; /*---------------------------------------------------------------------- | utility functions
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4Sample.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4Sample.cpp
Changed
@@ -143,8 +143,17 @@ // check the size if (m_Size < size+offset) return AP4_FAILURE; + // check if there's enough data in the stream + AP4_LargeSize stream_size = 0; + AP4_Result result = m_DataStream->GetSize(stream_size); + if (AP4_SUCCEEDED(result)) { + if (size + offset > stream_size) { + return AP4_ERROR_OUT_OF_RANGE; + } + } + // set the buffer size - AP4_Result result = data.SetDataSize(size); + result = data.SetDataSize(size); if (AP4_FAILED(result)) return result; // get the data from the stream
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4SampleDescription.h -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4SampleDescription.h
Changed
@@ -95,6 +95,8 @@ const AP4_UI32 AP4_SAMPLE_FORMAT_VC_1 = AP4_ATOM_TYPE('v','c','-','1'); const AP4_UI32 AP4_SAMPLE_FORMAT_XML_ = AP4_ATOM_TYPE('x','m','l',' '); const AP4_UI32 AP4_SAMPLE_FORMAT_STPP = AP4_ATOM_TYPE('s','t','p','p'); +const AP4_UI32 AP4_SAMPLE_FORMAT_FLAC = AP4_ATOM_TYPE('f','L','a','C'); +const AP4_UI32 AP4_SAMPLE_FORMAT_OPUS = AP4_ATOM_TYPE('O','p','u','s'); const char* AP4_GetFormatName(AP4_UI32 format);
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4SegmentBuilder.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4SegmentBuilder.cpp
Changed
@@ -2,7 +2,7 @@ | | AP4 - Segment Builder | -| Copyright 2002-2014 Axiomatic Systems, LLC +| Copyright 2002-2019 Axiomatic Systems, LLC | | | This file is part of Bento4/AP4 (MP4 Atom Processing Library). @@ -46,7 +46,8 @@ /*---------------------------------------------------------------------- | constants +---------------------------------------------------------------------*/ -const AP4_UI32 AP4_SEGMENT_BUILDER_DEFAULT_TIMESCALE = 1000; +const AP4_UI32 AP4_SEGMENT_BUILDER_DEFAULT_TIMESCALE = 1000; +const unsigned int AP4_STREAM_FEEDER_DEFAULT_BUFFER_SIZE = 65536; /*---------------------------------------------------------------------- | AP4_SegmentBuilder::AP4_SegmentBuilder @@ -87,28 +88,6 @@ } /*---------------------------------------------------------------------- -| AP4_FeedSegmentBuilder::AP4_FeedSegmentBuilder -+---------------------------------------------------------------------*/ -AP4_FeedSegmentBuilder::AP4_FeedSegmentBuilder(AP4_Track::Type track_type, - AP4_UI32 track_id, - AP4_UI64 media_time_origin) : - AP4_SegmentBuilder(track_type, track_id, media_time_origin) -{ -} - -/*---------------------------------------------------------------------- -| AP4_AvcSegmentBuilder::AP4_AvcSegmentBuilder -+---------------------------------------------------------------------*/ -AP4_AvcSegmentBuilder::AP4_AvcSegmentBuilder(AP4_UI32 track_id, - double frames_per_second, - AP4_UI64 media_time_origin) : - AP4_FeedSegmentBuilder(AP4_Track::TYPE_VIDEO, track_id, media_time_origin), - m_FramesPerSecond(frames_per_second) -{ - m_Timescale = (unsigned int)(frames_per_second*1000.0); -} - -/*---------------------------------------------------------------------- | AP4_SegmentBuilder::WriteMediaSegment +---------------------------------------------------------------------*/ AP4_Result @@ -118,7 +97,7 @@ if (m_TrackType == AP4_Track::TYPE_VIDEO) { tfhd_flags |= AP4_TFHD_FLAG_DEFAULT_SAMPLE_FLAGS_PRESENT; } - + // setup the moof structure AP4_ContainerAtom* moof = new AP4_ContainerAtom(AP4_ATOM_TYPE_MOOF); AP4_MfhdAtom* mfhd = new AP4_MfhdAtom(sequence_number); @@ -167,7 +146,7 @@ trun_entry.sample_duration = m_Samples[i].GetDuration(); trun_entry.sample_size = m_Samples[i].GetSize(); trun_entry.sample_composition_time_offset = m_Samples[i].GetCtsDelta(); - + mdat_size += trun_entry.sample_size; } @@ -211,69 +190,32 @@ } /*---------------------------------------------------------------------- -| AP4_AvcSegmentBuilder::Feed +| AP4_FeedSegmentBuilder::AP4_FeedSegmentBuilder +---------------------------------------------------------------------*/ -AP4_Result -AP4_AvcSegmentBuilder::Feed(const void* data, - AP4_Size data_size, - AP4_Size& bytes_consumed) +AP4_FeedSegmentBuilder::AP4_FeedSegmentBuilder(AP4_Track::Type track_type, + AP4_UI32 track_id, + AP4_UI64 media_time_origin) : + AP4_SegmentBuilder(track_type, track_id, media_time_origin) { - AP4_Result result; - - AP4_AvcFrameParser::AccessUnitInfo access_unit_info; - result = m_FrameParser.Feed(data, data_size, bytes_consumed, access_unit_info, data == NULL); - if (AP4_FAILED(result)) return result; - - // check if we have an access unit - if (access_unit_info.nal_units.ItemCount()) { - // compute the total size of the sample data - unsigned int sample_data_size = 0; - for (unsigned int i=0; i<access_unit_info.nal_units.ItemCount(); i++) { - sample_data_size += 4+access_unit_info.nal_units[i]->GetDataSize(); - } - - // format the sample data - AP4_MemoryByteStream* sample_data = new AP4_MemoryByteStream(sample_data_size); - for (unsigned int i=0; i<access_unit_info.nal_units.ItemCount(); i++) { - sample_data->WriteUI32(access_unit_info.nal_units[i]->GetDataSize()); - sample_data->Write(access_unit_info.nal_units[i]->GetData(), access_unit_info.nal_units[i]->GetDataSize()); - } - - // compute the timestamp in a drift-less manner - AP4_UI32 duration = 0; - AP4_UI64 dts = 0; - if (m_Timescale !=0 && m_FramesPerSecond != 0.0) { - AP4_UI64 this_sample_time = m_MediaStartTime+m_MediaDuration; - AP4_UI64 next_sample_time = (AP4_UI64)((double)m_Timescale*(double)(m_SampleStartNumber+m_Samples.ItemCount()+1)/m_FramesPerSecond); - duration = (AP4_UI32)(next_sample_time-this_sample_time); - dts = (AP4_UI64)((double)m_Timescale/m_FramesPerSecond*(double)m_Samples.ItemCount()); - } +} - // create a new sample and add it to the list - AP4_Sample sample(*sample_data, 0, sample_data_size, duration, 0, dts, 0, access_unit_info.is_idr); - AddSample(sample); - sample_data->Release(); - - // remember the sample order - m_SampleOrders.Append(SampleOrder(access_unit_info.decode_order, access_unit_info.display_order)); - - // free the memory buffers - for (unsigned int i=0; i<access_unit_info.nal_units.ItemCount(); i++) { - delete access_unit_info.nal_units[i]; - } - access_unit_info.nal_units.Clear(); - - return 1; // one access unit returned - } - - return AP4_SUCCESS; +/*---------------------------------------------------------------------- +| AP4_VideoSegmentBuilder::AP4_VideoSegmentBuilder ++---------------------------------------------------------------------*/ +AP4_VideoSegmentBuilder::AP4_VideoSegmentBuilder(AP4_UI32 track_id, + double frames_per_second, + AP4_UI64 media_time_origin) : + AP4_FeedSegmentBuilder(AP4_Track::TYPE_VIDEO, track_id, media_time_origin), + m_FramesPerSecond(frames_per_second) +{ + m_Timescale = (unsigned int)(frames_per_second*1000.0); } /*---------------------------------------------------------------------- -| AP4_AvcSegmentBuilder::SortSamples +| AP4_VideoSegmentBuilder::SortSamples +---------------------------------------------------------------------*/ void -AP4_AvcSegmentBuilder::SortSamples(SampleOrder* array, unsigned int n) +AP4_VideoSegmentBuilder::SortSamples(SampleOrder* array, unsigned int n) { if (n < 2) { return; @@ -299,10 +241,82 @@ } /*---------------------------------------------------------------------- -| AP4_AvcSegmentBuilder::WriteMediaSegment +| AP4_VideoSegmentBuilder::WriteVideoInitSegment ++---------------------------------------------------------------------*/ +AP4_Result +AP4_VideoSegmentBuilder::WriteVideoInitSegment(AP4_ByteStream& stream, + AP4_SampleDescription* sample_description, + unsigned int width, + unsigned int height, + AP4_UI32 brand) +{ + // create the output file object + AP4_Movie* output_movie = new AP4_Movie(AP4_SEGMENT_BUILDER_DEFAULT_TIMESCALE); + + // create an mvex container + AP4_ContainerAtom* mvex = new AP4_ContainerAtom(AP4_ATOM_TYPE_MVEX); + AP4_MehdAtom* mehd = new AP4_MehdAtom(0); + mvex->AddChild(mehd); + + // create a sample table (with no samples) to hold the sample description + AP4_SyntheticSampleTable* sample_table = new AP4_SyntheticSampleTable(); + sample_table->AddSampleDescription(sample_description, true); + + // create the track + AP4_Track* output_track = new AP4_Track(AP4_Track::TYPE_VIDEO, + sample_table, + m_TrackId, + AP4_SEGMENT_BUILDER_DEFAULT_TIMESCALE, + 0, + m_Timescale, + 0, + m_TrackLanguage.GetChars(), + width << 16, + height << 16); + output_movie->AddTrack(output_track); + + // add a trex entry to the mvex container + AP4_TrexAtom* trex = new AP4_TrexAtom(m_TrackId, + 1, + 0, + 0, + 0); + mvex->AddChild(trex); + + // update the mehd duration + // TBD mehd->SetDuration(0); + + // the mvex container to the moov container + output_movie->GetMoovAtom()->AddChild(mvex); + + // write the ftyp atom + AP4_Array<AP4_UI32> brands; + brands.Append(AP4_FILE_BRAND_ISOM); + brands.Append(AP4_FILE_BRAND_MP42); + brands.Append(AP4_FILE_BRAND_MP41); + brands.Append(brand); + + AP4_FtypAtom* ftyp = new AP4_FtypAtom(AP4_FILE_BRAND_MP42, 1, &brands[0], brands.ItemCount()); + ftyp->Write(stream); + delete ftyp; + + // write the moov atom + AP4_Result result = output_movie->GetMoovAtom()->Write(stream); + if (AP4_FAILED(result)) { + return result; + } + + // cleanup + delete output_movie; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_VideoSegmentBuilder::WriteMediaSegment +---------------------------------------------------------------------*/ AP4_Result -AP4_AvcSegmentBuilder::WriteMediaSegment(AP4_ByteStream& stream, unsigned int sequence_number) +AP4_VideoSegmentBuilder::WriteMediaSegment(AP4_ByteStream& stream, unsigned int sequence_number) { if (m_SampleOrders.ItemCount() > 1) { // rebase the decode order @@ -352,13 +366,80 @@ } /*---------------------------------------------------------------------- -| AP4_AvcSegmentBuilder::WriteInitSegment +| AP4_AvcSegmentBuilder::AP4_AvcSegmentBuilder ++---------------------------------------------------------------------*/ +AP4_AvcSegmentBuilder::AP4_AvcSegmentBuilder(AP4_UI32 track_id, + double frames_per_second, + AP4_UI64 media_time_origin) : + AP4_VideoSegmentBuilder(track_id, frames_per_second, media_time_origin) +{ +} + +/*---------------------------------------------------------------------- +| AP4_AvcSegmentBuilder::Feed +---------------------------------------------------------------------*/ AP4_Result -AP4_AvcSegmentBuilder::WriteInitSegment(AP4_ByteStream& stream) +AP4_AvcSegmentBuilder::Feed(const void* data, + AP4_Size data_size, + AP4_Size& bytes_consumed) { AP4_Result result; + AP4_AvcFrameParser::AccessUnitInfo access_unit_info; + result = m_FrameParser.Feed(data, data_size, bytes_consumed, access_unit_info, data == NULL); + if (AP4_FAILED(result)) return result; + + // check if we have an access unit + if (access_unit_info.nal_units.ItemCount()) { + // compute the total size of the sample data + unsigned int sample_data_size = 0; + for (unsigned int i=0; i<access_unit_info.nal_units.ItemCount(); i++) { + sample_data_size += 4+access_unit_info.nal_units[i]->GetDataSize(); + } + + // format the sample data + AP4_MemoryByteStream* sample_data = new AP4_MemoryByteStream(sample_data_size); + for (unsigned int i=0; i<access_unit_info.nal_units.ItemCount(); i++) { + sample_data->WriteUI32(access_unit_info.nal_units[i]->GetDataSize()); + sample_data->Write(access_unit_info.nal_units[i]->GetData(), access_unit_info.nal_units[i]->GetDataSize()); + } + + // compute the timestamp in a drift-less manner + AP4_UI32 duration = 0; + AP4_UI64 dts = 0; + if (m_Timescale !=0 && m_FramesPerSecond != 0.0) { + AP4_UI64 this_sample_time = m_MediaStartTime+m_MediaDuration; + AP4_UI64 next_sample_time = (AP4_UI64)((double)m_Timescale*(double)(m_SampleStartNumber+m_Samples.ItemCount()+1)/m_FramesPerSecond); + duration = (AP4_UI32)(next_sample_time-this_sample_time); + dts = (AP4_UI64)((double)m_Timescale/m_FramesPerSecond*(double)m_Samples.ItemCount()); + } + + // create a new sample and add it to the list + AP4_Sample sample(*sample_data, 0, sample_data_size, duration, 0, dts, 0, access_unit_info.is_idr); + AddSample(sample); + sample_data->Release(); + + // remember the sample order + m_SampleOrders.Append(SampleOrder(access_unit_info.decode_order, access_unit_info.display_order)); + + // free the memory buffers + for (unsigned int i=0; i<access_unit_info.nal_units.ItemCount(); i++) { + delete access_unit_info.nal_units[i]; + } + access_unit_info.nal_units.Clear(); + + return 1; // one access unit returned + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_AvcSegmentBuilder::WriteInitSegment ++---------------------------------------------------------------------*/ +AP4_Result +AP4_AvcSegmentBuilder::WriteInitSegment(AP4_ByteStream& stream) +{ // compute the track parameters AP4_AvcSequenceParameterSet* sps = NULL; for (unsigned int i=0; i<=AP4_AVC_SPS_MAX_ID; i++) { @@ -404,69 +485,184 @@ 4, sps_array, pps_array); + + // let the base class finish the work + return AP4_VideoSegmentBuilder::WriteVideoInitSegment(stream, + sample_description, + video_width, + video_height, + AP4_FILE_BRAND_AVC1); +} + +/*---------------------------------------------------------------------- +| AP4_HevcSegmentBuilder::AP4_HevcSegmentBuilder ++---------------------------------------------------------------------*/ +AP4_HevcSegmentBuilder::AP4_HevcSegmentBuilder(AP4_UI32 track_id, + double frames_per_second, + AP4_UI32 video_format, + AP4_UI64 media_time_origin) : + AP4_VideoSegmentBuilder(track_id, frames_per_second, media_time_origin), + m_VideoFormat(video_format) +{ +} + +/*---------------------------------------------------------------------- +| AP4_HevcSegmentBuilder::Feed ++---------------------------------------------------------------------*/ +AP4_Result +AP4_HevcSegmentBuilder::Feed(const void* data, + AP4_Size data_size, + AP4_Size& bytes_consumed) +{ + AP4_Result result; - // create the output file object - AP4_Movie* output_movie = new AP4_Movie(AP4_SEGMENT_BUILDER_DEFAULT_TIMESCALE); - - // create an mvex container - AP4_ContainerAtom* mvex = new AP4_ContainerAtom(AP4_ATOM_TYPE_MVEX); - AP4_MehdAtom* mehd = new AP4_MehdAtom(0); - mvex->AddChild(mehd); - - // create a sample table (with no samples) to hold the sample description - AP4_SyntheticSampleTable* sample_table = new AP4_SyntheticSampleTable(); - sample_table->AddSampleDescription(sample_description, true); - - // create the track - AP4_Track* output_track = new AP4_Track(AP4_Track::TYPE_VIDEO, - sample_table, - m_TrackId, - AP4_SEGMENT_BUILDER_DEFAULT_TIMESCALE, - 0, - m_Timescale, - 0, - m_TrackLanguage.GetChars(), - video_width << 16, - video_height << 16); - output_movie->AddTrack(output_track); - - // add a trex entry to the mvex container - AP4_TrexAtom* trex = new AP4_TrexAtom(m_TrackId, - 1, - 0, - 0, - 0); - mvex->AddChild(trex); - - // update the mehd duration - // TBD mehd->SetDuration(0); - - // the mvex container to the moov container - output_movie->GetMoovAtom()->AddChild(mvex); - - // write the ftyp atom - AP4_Array<AP4_UI32> brands; - brands.Append(AP4_FILE_BRAND_ISOM); - brands.Append(AP4_FILE_BRAND_MP42); - brands.Append(AP4_FILE_BRAND_MP41); - - AP4_FtypAtom* ftyp = new AP4_FtypAtom(AP4_FILE_BRAND_MP42, 1, &brands[0], brands.ItemCount()); - ftyp->Write(stream); - delete ftyp; + AP4_HevcFrameParser::AccessUnitInfo access_unit_info; + result = m_FrameParser.Feed(data, data_size, bytes_consumed, access_unit_info, data == NULL); + if (AP4_FAILED(result)) return result; - // write the moov atom - result = output_movie->GetMoovAtom()->Write(stream); - if (AP4_FAILED(result)) { - return result; + // check if we have an access unit + if (access_unit_info.nal_units.ItemCount()) { + // compute the total size of the sample data + unsigned int sample_data_size = 0; + for (unsigned int i=0; i<access_unit_info.nal_units.ItemCount(); i++) { + sample_data_size += 4+access_unit_info.nal_units[i]->GetDataSize(); + } + + // format the sample data + AP4_MemoryByteStream* sample_data = new AP4_MemoryByteStream(sample_data_size); + for (unsigned int i=0; i<access_unit_info.nal_units.ItemCount(); i++) { + sample_data->WriteUI32(access_unit_info.nal_units[i]->GetDataSize()); + sample_data->Write(access_unit_info.nal_units[i]->GetData(), access_unit_info.nal_units[i]->GetDataSize()); + } + + // compute the timestamp in a drift-less manner + AP4_UI32 duration = 0; + AP4_UI64 dts = 0; + if (m_Timescale !=0 && m_FramesPerSecond != 0.0) { + AP4_UI64 this_sample_time = m_MediaStartTime+m_MediaDuration; + AP4_UI64 next_sample_time = (AP4_UI64)((double)m_Timescale*(double)(m_SampleStartNumber+m_Samples.ItemCount()+1)/m_FramesPerSecond); + duration = (AP4_UI32)(next_sample_time-this_sample_time); + dts = (AP4_UI64)((double)m_Timescale/m_FramesPerSecond*(double)m_Samples.ItemCount()); + } + + // create a new sample and add it to the list + AP4_Sample sample(*sample_data, 0, sample_data_size, duration, 0, dts, 0, access_unit_info.is_random_access); + AddSample(sample); + sample_data->Release(); + + // remember the sample order + m_SampleOrders.Append(SampleOrder(access_unit_info.decode_order, access_unit_info.display_order)); + + // free the memory buffers + for (unsigned int i=0; i<access_unit_info.nal_units.ItemCount(); i++) { + delete access_unit_info.nal_units[i]; + } + access_unit_info.nal_units.Clear(); + + return 1; // one access unit returned } - // cleanup - delete output_movie; - return AP4_SUCCESS; } /*---------------------------------------------------------------------- +| AP4_HevcSegmentBuilder::WriteInitSegment ++---------------------------------------------------------------------*/ +AP4_Result +AP4_HevcSegmentBuilder::WriteInitSegment(AP4_ByteStream& stream) +{ + // check that we have at least one SPS + AP4_HevcSequenceParameterSet* sps = NULL; + for (unsigned int i=0; i<=AP4_HEVC_SPS_MAX_ID; i++) { + sps = m_FrameParser.GetSequenceParameterSets()[i]; + if (sps) break; + } + if (sps == NULL) { + return AP4_ERROR_INVALID_FORMAT; + } + unsigned int video_width = 0; + unsigned int video_height = 0; + sps->GetInfo(video_width, video_height); + + // collect parameters from the first SPS entry + // TODO: synthesize from multiple SPS entries if we have more than one + AP4_UI08 general_profile_space = sps->profile_tier_level.general_profile_space; + AP4_UI08 general_tier_flag = sps->profile_tier_level.general_tier_flag; + AP4_UI08 general_profile = sps->profile_tier_level.general_profile_idc; + AP4_UI32 general_profile_compatibility_flags = sps->profile_tier_level.general_profile_compatibility_flags; + AP4_UI64 general_constraint_indicator_flags = sps->profile_tier_level.general_constraint_indicator_flags; + AP4_UI08 general_level = sps->profile_tier_level.general_level_idc; + AP4_UI32 min_spatial_segmentation = 0; // TBD (should read from VUI if present) + AP4_UI08 parallelism_type = 0; // unknown + AP4_UI08 chroma_format = sps->chroma_format_idc; + AP4_UI08 luma_bit_depth = 8; // hardcoded temporarily, should be read from the bitstream + AP4_UI08 chroma_bit_depth = 8; // hardcoded temporarily, should be read from the bitstream + AP4_UI16 average_frame_rate = 0; // unknown + AP4_UI08 constant_frame_rate = 0; // unknown + AP4_UI08 num_temporal_layers = 0; // unknown + AP4_UI08 temporal_id_nested = 0; // unknown + AP4_UI08 nalu_length_size = 4; + + // collect the VPS, SPS and PPS into arrays + AP4_Array<AP4_DataBuffer> vps_array; + for (unsigned int i=0; i<=AP4_HEVC_VPS_MAX_ID; i++) { + if (m_FrameParser.GetVideoParameterSets()[i]) { + vps_array.Append(m_FrameParser.GetVideoParameterSets()[i]->raw_bytes); + } + } + AP4_Array<AP4_DataBuffer> sps_array; + for (unsigned int i=0; i<=AP4_HEVC_SPS_MAX_ID; i++) { + if (m_FrameParser.GetSequenceParameterSets()[i]) { + sps_array.Append(m_FrameParser.GetSequenceParameterSets()[i]->raw_bytes); + } + } + AP4_Array<AP4_DataBuffer> pps_array; + for (unsigned int i=0; i<=AP4_HEVC_PPS_MAX_ID; i++) { + if (m_FrameParser.GetPictureParameterSets()[i]) { + pps_array.Append(m_FrameParser.GetPictureParameterSets()[i]->raw_bytes); + } + } + + // setup the video the sample descripton + AP4_UI08 parameters_completeness = (m_VideoFormat == AP4_SAMPLE_FORMAT_HVC1 ? 1 : 0); + AP4_HevcSampleDescription* sample_description = + new AP4_HevcSampleDescription(m_VideoFormat, + video_width, + video_height, + 24, + "HEVC Coding", + general_profile_space, + general_tier_flag, + general_profile, + general_profile_compatibility_flags, + general_constraint_indicator_flags, + general_level, + min_spatial_segmentation, + parallelism_type, + chroma_format, + luma_bit_depth, + chroma_bit_depth, + average_frame_rate, + constant_frame_rate, + num_temporal_layers, + temporal_id_nested, + nalu_length_size, + vps_array, + parameters_completeness, + sps_array, + parameters_completeness, + pps_array, + parameters_completeness); + + // let the base class finish the work + return AP4_VideoSegmentBuilder::WriteVideoInitSegment(stream, + sample_description, + video_width, + video_height, + AP4_FILE_BRAND_HVC1); +} + +/*---------------------------------------------------------------------- | AP4_AacSegmentBuilder::AP4_AacSegmentBuilder +---------------------------------------------------------------------*/ AP4_AacSegmentBuilder::AP4_AacSegmentBuilder(AP4_UI32 track_id, AP4_UI64 media_time_origin) : @@ -550,7 +746,6 @@ bytes_consumed += can_feed; } } - return AP4_SUCCESS; } @@ -621,3 +816,62 @@ return result; } + +/*---------------------------------------------------------------------- +| AP4_StreamFeeder::AP4_StreamFeeder ++---------------------------------------------------------------------*/ +AP4_StreamFeeder::AP4_StreamFeeder(AP4_ByteStream* source, AP4_FeedSegmentBuilder& builder) : + m_Source(source), + m_Builder(builder), + m_FeedBuffer(NULL), + m_FeedBufferSize(0), + m_FeedBytesPending(0), + m_FeedBytesParsed(0) +{ + AP4_ASSERT(source); + source->AddReference(); + m_FeedBuffer = new AP4_UI08[AP4_STREAM_FEEDER_DEFAULT_BUFFER_SIZE]; + if (m_FeedBuffer) { + m_FeedBufferSize = AP4_STREAM_FEEDER_DEFAULT_BUFFER_SIZE; + } +} + +/*---------------------------------------------------------------------- +| AP4_StreamFeeder::~AP4_StreamFeeder ++---------------------------------------------------------------------*/ +AP4_StreamFeeder::~AP4_StreamFeeder() +{ + m_Source->Release(); + delete[] m_FeedBuffer; +} + +/*---------------------------------------------------------------------- +| AP4_StreamFeeder::Feed ++---------------------------------------------------------------------*/ +AP4_Result +AP4_StreamFeeder::Feed() +{ + // read more data if the buffer is empty + if (m_FeedBytesPending == 0) { + m_FeedBytesParsed = 0; + if (!m_FeedBufferSize) return AP4_ERROR_INTERNAL; + AP4_Result result = m_Source->ReadPartial(m_FeedBuffer, m_FeedBufferSize, m_FeedBytesPending); + if (AP4_FAILED(result)) { + return result; + } + if (m_FeedBytesPending == 0) { + return AP4_ERROR_EOS; + } + } + + // feed the builder + AP4_Size bytes_consumed = 0; + AP4_Result result = m_Builder.Feed(&m_FeedBuffer[m_FeedBytesParsed], m_FeedBytesPending, bytes_consumed); + if (result < 0) return result; + + // update counters + m_FeedBytesParsed += bytes_consumed; + m_FeedBytesPending -= bytes_consumed; + + return AP4_SUCCESS; +}
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4SegmentBuilder.h -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4SegmentBuilder.h
Changed
@@ -34,11 +34,13 @@ +---------------------------------------------------------------------*/ #include "Ap4Types.h" #include "Ap4AvcParser.h" +#include "Ap4HevcParser.h" #include "Ap4AdtsParser.h" #include "Ap4List.h" #include "Ap4Sample.h" #include "Ap4String.h" #include "Ap4Track.h" +#include "Ap4SampleDescription.h" /*---------------------------------------------------------------------- | class references @@ -67,6 +69,7 @@ // methods virtual AP4_Result AddSample(AP4_Sample& sample); + //virtual AP4_Result CreateTrack(AP4_Track*& track); // create an AP4_Track object representing the media so far virtual AP4_Result WriteMediaSegment(AP4_ByteStream& stream, unsigned int sequence_number); virtual AP4_Result WriteInitSegment(AP4_ByteStream& stream) = 0; @@ -97,49 +100,97 @@ // methods virtual AP4_Result Feed(const void* data, AP4_Size data_size, - AP4_Size& bytes_consumed) = 0; + AP4_Size& bytes_consumed) = 0; }; /*---------------------------------------------------------------------- -| AP4_AvcSegmentBuilder +| AP4_VideoSegmentBuilder +---------------------------------------------------------------------*/ -class AP4_AvcSegmentBuilder : public AP4_FeedSegmentBuilder +class AP4_VideoSegmentBuilder : public AP4_FeedSegmentBuilder { public: // constructor - AP4_AvcSegmentBuilder(AP4_UI32 track_id, - double frames_per_second, - AP4_UI64 media_time_origin = 0); + AP4_VideoSegmentBuilder(AP4_UI32 track_id, + double frames_per_second, + AP4_UI64 media_time_origin = 0); // AP4_SegmentBuilder methods virtual AP4_Result WriteMediaSegment(AP4_ByteStream& stream, unsigned int sequence_number); - virtual AP4_Result WriteInitSegment(AP4_ByteStream& stream); - // methods - AP4_Result Feed(const void* data, - AP4_Size data_size, - AP4_Size& bytes_consumed); - protected: // types struct SampleOrder { SampleOrder(AP4_UI32 decode_order, AP4_UI32 display_order) : m_DecodeOrder(decode_order), m_DisplayOrder(display_order) {} - AP4_UI32 m_DecodeOrder; - AP4_UI32 m_DisplayOrder; + AP4_UI32 m_DecodeOrder; + AP4_UI32 m_DisplayOrder; }; // methods void SortSamples(SampleOrder* array, unsigned int n); + AP4_Result WriteVideoInitSegment(AP4_ByteStream& stream, + AP4_SampleDescription* sample_description, + unsigned int width, + unsigned int height, + AP4_UI32 brand); // members - AP4_AvcFrameParser m_FrameParser; double m_FramesPerSecond; AP4_Array<SampleOrder> m_SampleOrders; }; /*---------------------------------------------------------------------- +| AP4_AvcSegmentBuilder ++---------------------------------------------------------------------*/ +class AP4_AvcSegmentBuilder : public AP4_VideoSegmentBuilder +{ +public: + // constructor + AP4_AvcSegmentBuilder(AP4_UI32 track_id, + double frames_per_second, + AP4_UI64 media_time_origin = 0); + + // AP4_SegmentBuilder methods + virtual AP4_Result WriteInitSegment(AP4_ByteStream& stream); + + // methods + AP4_Result Feed(const void* data, + AP4_Size data_size, + AP4_Size& bytes_consumed); + +protected: + // members + AP4_AvcFrameParser m_FrameParser; +}; + +/*---------------------------------------------------------------------- +| AP4_HevcSegmentBuilder ++---------------------------------------------------------------------*/ +class AP4_HevcSegmentBuilder : public AP4_VideoSegmentBuilder +{ +public: + // constructor + AP4_HevcSegmentBuilder(AP4_UI32 track_id, + double frames_per_second, + AP4_UI32 video_format = AP4_SAMPLE_FORMAT_HEV1, + AP4_UI64 media_time_origin = 0); + + // AP4_SegmentBuilder methods + virtual AP4_Result WriteInitSegment(AP4_ByteStream& stream); + + // methods + AP4_Result Feed(const void* data, + AP4_Size data_size, + AP4_Size& bytes_consumed); + +protected: + // members + AP4_HevcFrameParser m_FrameParser; + AP4_UI32 m_VideoFormat; +}; + +/*---------------------------------------------------------------------- | AP4_AacSegmentBuilder +---------------------------------------------------------------------*/ class AP4_AacSegmentBuilder : public AP4_FeedSegmentBuilder @@ -163,4 +214,28 @@ AP4_MpegAudioSampleDescription* m_SampleDescription; }; +/*---------------------------------------------------------------------- +| AP4_StreamFeeder +| +| Class that can be used to feed an AP4_FeedSegmentBuilder from a stream ++---------------------------------------------------------------------*/ +class AP4_StreamFeeder +{ +public: + // constructor and destructor + AP4_StreamFeeder(AP4_ByteStream* source, AP4_FeedSegmentBuilder& builder); + ~AP4_StreamFeeder(); + + // methods + AP4_Result Feed(); // Read some data from the stream and feed it to the builder + +private: + AP4_ByteStream* m_Source; + AP4_FeedSegmentBuilder& m_Builder; + AP4_UI08* m_FeedBuffer; + AP4_Size m_FeedBufferSize; + AP4_Size m_FeedBytesPending; // number of bytes not yet parsed + AP4_Size m_FeedBytesParsed; // number of bytes already parsed +}; + #endif // _AP4_SEGMENT_BUILDER_H_
View file
bento4-1.5.1r628.tar.gz/Source/C++/Core/Ap4StcoAtom.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Core/Ap4StcoAtom.cpp
Changed
@@ -72,8 +72,13 @@ AP4_UI08 version, AP4_UI32 flags, AP4_ByteStream& stream) : - AP4_Atom(AP4_ATOM_TYPE_STCO, size, version, flags) + AP4_Atom(AP4_ATOM_TYPE_STCO, size, version, flags), + m_Entries(NULL), + m_EntryCount(0) { + if (size < AP4_FULL_ATOM_HEADER_SIZE + 4) { + return; + } stream.ReadUI32(m_EntryCount); if (m_EntryCount > (size-AP4_FULL_ATOM_HEADER_SIZE-4)/4) { m_EntryCount = (size-AP4_FULL_ATOM_HEADER_SIZE-4)/4;
View file
bento4-1.5.1r628.tar.gz/Source/C++/System/StdC/Ap4StdCFileByteStream.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/System/StdC/Ap4StdCFileByteStream.cpp
Changed
@@ -265,6 +265,9 @@ if (nbWritten > 0) { bytesWritten = (AP4_Size)nbWritten; m_Position += nbWritten; + if (m_Position > m_Size) { + m_Size = m_Position; + } return AP4_SUCCESS; } else { bytesWritten = 0;
View file
bento4-1.5.1r628.tar.gz/Source/C++/Test/FragmentCreator/FragmentCreatorTest.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Test/FragmentCreator/FragmentCreatorTest.cpp
Changed
@@ -44,7 +44,7 @@ main(int argc, char** argv) { if (argc != 8) { - printf("usage: fragmentcreatortest audio|video <media-input-filename> <track-id> <frames-per-segment>|<segment-duration> <frames-per-second>|0 <output-media-segment-filename-pattern> <output-init-segment-filename>\n"); + printf("usage: fragmentcreatortest h265|h264|aac <media-input-filename> <track-id> <frames-per-segment>|<segment-duration> <frames-per-second>|0 <output-media-segment-filename-pattern> <output-init-segment-filename>\n"); return 1; } @@ -67,78 +67,71 @@ } // instantiate a video segment builder or an audio sergment builder - AP4_AvcSegmentBuilder* video_builder = NULL; + AP4_VideoSegmentBuilder* video_builder = NULL; AP4_AacSegmentBuilder* audio_builder = NULL; AP4_FeedSegmentBuilder* feed_builder = NULL; - if (!strcmp(argv[1], "video")) { + if (!strcmp(argv[1], "h265")) { + video_builder = new AP4_HevcSegmentBuilder(track_id, frames_per_second); + feed_builder = video_builder; + } else if (!strcmp(argv[1], "h264")) { video_builder = new AP4_AvcSegmentBuilder(track_id, frames_per_second); feed_builder = video_builder; - } else { + } else if (!strcmp(argv[1], "aac")) { audio_builder = new AP4_AacSegmentBuilder(track_id); feed_builder = audio_builder; + } else { + fprintf(stderr, "ERROR: unsupported media type\n"); + return 1; } + // create a feeder to read from the input and feed the builder + AP4_StreamFeeder stream_feeder(input_stream, *feed_builder); + // parse the input until the end of the stream unsigned int segment_count = 0; - for (;;) { - bool eos; - unsigned char input_buffer[4096]; - AP4_Size bytes_in_buffer = 0; - result = input_stream->ReadPartial(input_buffer, sizeof(input_buffer), bytes_in_buffer); - if (AP4_SUCCEEDED(result)) { - eos = false; - } else if (result == AP4_ERROR_EOS) { + bool eos = false; + while (!eos) { + result = stream_feeder.Feed(); + if (AP4_FAILED(result)) { + if (result != AP4_ERROR_EOS) { + fprintf(stderr, "ERROR: failed to read from stream (%d)\n", result); + break; + } eos = true; - } else { - fprintf(stderr, "ERROR: failed to read from input file\n"); - break; } - AP4_Size offset = 0; - do { - AP4_Size bytes_consumed = 0; - result = feed_builder->Feed(eos?NULL:&input_buffer[offset], - bytes_in_buffer, - bytes_consumed); - if (result < 0) { - fprintf(stderr, "ERROR: Feed() failed (%d)\n", result); - break; + + bool flush = false; + if (video_builder) { + if (video_builder->GetSamples().ItemCount() >= (unsigned int)segment_duration || + (eos && video_builder->GetSamples().ItemCount() != 0)) { + flush = true; } - - offset += bytes_consumed; - bytes_in_buffer -= bytes_consumed; - - bool flush = false; - if (video_builder) { - if (video_builder->GetSamples().ItemCount() >= (unsigned int)segment_duration) { - flush = true; - } - } else { - double target_time = (segment_count+1)*segment_duration; - double elapsed_time = (double)(audio_builder->GetMediaDuration()+audio_builder->GetMediaStartTime())/(double)audio_builder->GetTimescale(); - if (elapsed_time >= target_time) { - flush = true; - } + } else { + double target_time = (segment_count+1)*segment_duration; + double elapsed_time = (double)(audio_builder->GetMediaDuration()+audio_builder->GetMediaStartTime())/(double)audio_builder->GetTimescale(); + if (elapsed_time >= target_time || + (eos && audio_builder->GetSamples().ItemCount() != 0)) { + flush = true; } - if (flush) { - unsigned int max_name_size = (unsigned int)strlen(output_media_segment_filename_pattern)+256; - char* media_segment_filename = new char[max_name_size+1]; - snprintf(media_segment_filename, max_name_size, output_media_segment_filename_pattern, segment_count); - AP4_ByteStream* media_segment_stream = NULL; - - result = AP4_FileByteStream::Create(media_segment_filename, AP4_FileByteStream::STREAM_MODE_WRITE, media_segment_stream); - if (AP4_FAILED(result)) { - fprintf(stderr, "ERROR: cannot create media segment file (%d)\n", result); - return 1; - } - - feed_builder->WriteMediaSegment(*media_segment_stream, segment_count); - - delete[] media_segment_filename; - media_segment_stream->Release(); - ++segment_count; + } + if (flush) { + unsigned int max_name_size = (unsigned int)strlen(output_media_segment_filename_pattern)+256; + char* media_segment_filename = new char[max_name_size+1]; + snprintf(media_segment_filename, max_name_size, output_media_segment_filename_pattern, segment_count); + AP4_ByteStream* media_segment_stream = NULL; + + result = AP4_FileByteStream::Create(media_segment_filename, AP4_FileByteStream::STREAM_MODE_WRITE, media_segment_stream); + if (AP4_FAILED(result)) { + fprintf(stderr, "ERROR: cannot create media segment file (%d)\n", result); + return 1; } - } while (bytes_in_buffer || result > 0); - if (eos) break; + + feed_builder->WriteMediaSegment(*media_segment_stream, segment_count); + + delete[] media_segment_filename; + media_segment_stream->Release(); + ++segment_count; + } } AP4_ByteStream* init_segment_stream = NULL;
View file
bento4-1.5.1r628.tar.gz/Source/C++/Test/LinearReader/LinearReaderTest.cpp -> bento4-1.5.1r629.tar.gz/Source/C++/Test/LinearReader/LinearReaderTest.cpp
Changed
@@ -116,25 +116,6 @@ CHECK(reader.GetBufferFullness() == 0); CHECK(audio_sample_count == audio_track->GetSampleCount()); CHECK(video_sample_count == video_track->GetSampleCount()); - - offset = 0; - audio_sample_count = 0; - //video_sample_count = 0; - reader.SetSampleIndex(audio_track->GetId(), 0); - reader.SetSampleIndex(video_track->GetId(), 0); - do { - result = reader.ReadNextSample(audio_track->GetId(), sample, sample_data); - if (AP4_SUCCEEDED(result)) { - CHECK(offset < sample.GetOffset()); - offset = sample.GetOffset(); - audio_sample_count++; - printf("size=%d, offset=%lld\n", (int)sample.GetSize(), sample.GetOffset()); - } else { - printf("result=%d\n", result); - } - } while (AP4_SUCCEEDED(result)); - CHECK(result == AP4_ERROR_NOT_ENOUGH_SPACE); - CHECK(reader.GetBufferFullness() != 0); // cleanup delete file;
View file
bento4-1.5.1r628.tar.gz/Source/Python/utils/mp4-dash.py -> bento4-1.5.1r629.tar.gz/Source/Python/utils/mp4-dash.py
Changed
@@ -11,6 +11,7 @@ # <platform> depends on the platform you're running on: # Mac OSX --> platform = macosx # Linux x86 --> platform = linux-x86 +# Linux x64 --> platform = linux-x86_64 # Windows --> platform = win32 from optparse import OptionParser @@ -27,7 +28,7 @@ # setup main options VERSION = "1.8.0" -SDK_REVISION = '628' +SDK_REVISION = '629' SCRIPT_PATH = path.abspath(path.dirname(__file__)) sys.path += [SCRIPT_PATH] @@ -42,9 +43,9 @@ NOSPLIT_INIT_FILE_PATTERN = 'init-%s.mp4' ONDEMAND_MEDIA_FILE_PATTERN = '%s-%s.mp4' -PADDED_SEGMENT_PATTERN = 'seg-%04llu.m4s' -PADDED_SEGMENT_URL_PATTERN = 'seg-%04d.m4s' -PADDED_SEGMENT_URL_TEMPLATE = '$RepresentationID$/seg-$Number%04d$.m4s' +PADDED_SEGMENT_PATTERN = 'seg-%05llu.m4s' +PADDED_SEGMENT_URL_PATTERN = 'seg-%05d.m4s' +PADDED_SEGMENT_URL_TEMPLATE = '$RepresentationID$/seg-$Number%05d$.m4s' NOPAD_SEGMENT_PATTERN = 'seg-%llu.m4s' NOPAD_SEGMENT_URL_PATTERN = 'seg-%d.m4s' NOPAD_SEGMENT_URL_TEMPLATE = '$RepresentationID$/seg-$Number$.m4s' @@ -656,6 +657,12 @@ index_playlist_file.write('#EXT-X-I-FRAMES-ONLY\r\n') + + iframe_total_segment_size = 0 + iframe_total_segment_duration = 0 + iframe_bitrate = 0 + iframe_max_bitrate = 0 + if not options.split: # get the I-frame index for a single file json_index = Mp4IframIndex(options, path.join(options.output_dir, media_file_name)) @@ -663,10 +670,18 @@ for i in range(len(track.segment_durations)): if i < len(index): index_entry = index[i] - index_playlist_file.write('#EXTINF:%f,\r\n' % (track.segment_durations[i])) + iframe_segment_duration = track.segment_durations[i] + index_playlist_file.write('#EXTINF:%f,\r\n' % (iframe_segment_duration)) fragment_start = int(index_entry['fragmentStart']) iframe_offset = int(index_entry['offset']) iframe_size = int(index_entry['size']) + + iframe_total_segment_size += iframe_size + iframe_total_segment_duration += iframe_segment_duration + iframe_bitrate = 8.0*(iframe_size/iframe_segment_duration) + if iframe_bitrate > iframe_max_bitrate: + iframe_max_bitrate = iframe_bitrate + iframe_range_size = iframe_size + (iframe_offset-fragment_start) index_playlist_file.write('#EXT-X-BYTERANGE:%d@%d\r\n' % (iframe_range_size, fragment_start)) index_playlist_file.write(media_file_name+'\r\n') @@ -685,12 +700,24 @@ iframe_size = int(index[0]['size']) iframe_offset = int(index[0]['offset']) iframe_range_size = iframe_size + iframe_offset - index_playlist_file.write('#EXTINF:%f,\r\n' % (track.segment_durations[i])) + iframe_segment_duration = track.segment_durations[i] + index_playlist_file.write('#EXTINF:%f,\r\n' % (iframe_segment_duration)) index_playlist_file.write('#EXT-X-BYTERANGE:%d@0\r\n' % (iframe_range_size)) index_playlist_file.write(fragment_basename+'\r\n') + iframe_total_segment_size += iframe_size + iframe_total_segment_duration += iframe_segment_duration + + iframe_bitrate = 8.0*(iframe_size/iframe_segment_duration) + if iframe_bitrate > iframe_max_bitrate: + iframe_max_bitrate = iframe_bitrate + index_playlist_file.write('#EXT-X-ENDLIST\r\n') + iframe_average_segment_bitrate = 8.0*(iframe_total_segment_size/iframe_total_segment_duration) + + return (iframe_average_segment_bitrate, iframe_max_bitrate) + ############################################# def OutputHls(options, set_attributes, audio_sets, video_sets, subtitles_sets, subtitles_files): # all_audio_tracks = sum(audio_sets.values(), []) @@ -760,46 +787,51 @@ media_playlist_name = video_track.representation_id+".m3u8" media_playlist_path = media_playlist_name iframes_playlist_name = video_track.representation_id+"_iframes.m3u8" + iframes_playlist_path = iframes_playlist_name else: media_subdir = video_track.representation_id media_file_name = '' media_playlist_name = options.hls_media_playlist_name media_playlist_path = media_subdir+'/'+media_playlist_name iframes_playlist_name = options.hls_iframes_playlist_name + iframes_playlist_path = media_subdir+'/'+iframes_playlist_name if len(audio_groups): # one entry per audio group for audio_group_name in audio_groups: audio_codec = audio_groups[audio_group_name]['codec'] - master_playlist_file.write('#EXT-X-STREAM-INF:AUDIO="%s",AVERAGE-BANDWIDTH=%d,BANDWIDTH=%d,CODECS="%s",RESOLUTION=%dx%d\r\n' % ( + master_playlist_file.write('#EXT-X-STREAM-INF:AUDIO="%s",AVERAGE-BANDWIDTH=%d,BANDWIDTH=%d,CODECS="%s",RESOLUTION=%dx%d,FRAME-RATE=%s\r\n' % ( audio_group_name, video_track.average_segment_bitrate + audio_groups[audio_group_name]['average_segment_bitrate'], video_track.max_segment_bitrate + audio_groups[audio_group_name]['max_segment_bitrate'], video_track.codec+','+audio_codec, video_track.width, - video_track.height)) + video_track.height, + video_track.frame_rate)) master_playlist_file.write(media_playlist_path+'\r\n') else: # no audio - master_playlist_file.write('#EXT-X-STREAM-INF:AVERAGE-BANDWIDTH=%d,BANDWIDTH=%d,CODECS="%s",RESOLUTION=%dx%d\r\n' % ( + master_playlist_file.write('#EXT-X-STREAM-INF:AVERAGE-BANDWIDTH=%d,BANDWIDTH=%d,CODECS="%s",RESOLUTION=%dx%d,FRAME-RATE=%s\r\n' % ( video_track.average_segment_bitrate, video_track.max_segment_bitrate, video_track.codec, video_track.width, - video_track.height)) + video_track.height, + video_track.frame_rate)) master_playlist_file.write(media_playlist_path+'\r\n') OutputHlsTrack(options, video_track, media_subdir, media_playlist_name, media_file_name) - OutputHlsIframeIndex(options, video_track, media_subdir, iframes_playlist_name, media_file_name) + iframe_average_segment_bitrate,iframe_max_bitrate = OutputHlsIframeIndex(options, video_track, media_subdir, iframes_playlist_name, media_file_name) + # this will be written later iframe_playlist_lines.append('#EXT-X-I-FRAME-STREAM-INF:AVERAGE-BANDWIDTH=%d,BANDWIDTH=%d,CODECS="%s",RESOLUTION=%dx%d,URI="%s"\r\n' % ( - video_track.average_segment_bitrate, - video_track.max_segment_bitrate, + iframe_average_segment_bitrate, + iframe_max_bitrate, video_track.codec, video_track.width, video_track.height, - media_playlist_path)) + iframes_playlist_path)) master_playlist_file.write('\r\n# I-Frame Playlists\r\n') master_playlist_file.write(''.join(iframe_playlist_lines)) @@ -1535,6 +1567,7 @@ track_file.name, track = str(track.id), index = True, + copy_udta = True, quiet = True) media_source = MediaSource(track_file.name)
View file
bento4-1.5.1r628.tar.gz/Source/Python/utils/mp4-hls.py -> bento4-1.5.1r629.tar.gz/Source/Python/utils/mp4-hls.py
Changed
@@ -22,7 +22,7 @@ # setup main options VERSION = "1.1.0" -SDK_REVISION = '628' +SDK_REVISION = '629' SCRIPT_PATH = path.abspath(path.dirname(__file__)) sys.path += [SCRIPT_PATH] @@ -444,7 +444,7 @@ int(media_info['stats']['max_segment_bitrate'])+group_info['max_segment_bitrate'], ','.join(codecs)) if 'video' in media_info: - ext_x_stream_inf += ',RESOLUTION='+str(int(media_info['video']['width']))+'x'+str(int(media_info['video']['height'])) + ext_x_stream_inf += ',FRAME-RATE='+str(media_info['stats']['frame_rate'])+',RESOLUTION='+str(int(media_info['video']['width']))+'x'+str(int(media_info['video']['height'])) # audio info if group_name:
View file
bento4-1.5.1r628.tar.gz/Source/Python/utils/skm.py -> bento4-1.5.1r629.tar.gz/Source/Python/utils/skm.py
Changed
@@ -2,6 +2,7 @@ import os import hashlib import json +import urllib KEKID_CONSTANT_1 = "KEKID_1" @@ -149,7 +150,7 @@ kid = spec_params['kid'] if '?' in base_url: (base_url_path, base_url_query) = tuple(base_url.split('?', 1)) - base_url_query = '?'+base_url_query + base_url_query = '?'+urllib.unquote(base_url_query).decode('utf8') else: base_url_path = base_url base_url_query = ''
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.