Mozilla Home
Privacy
Cookies
Legal
Bugzilla
Browse
Advanced Search
New Bug
Reports
Documentation
Log In
Log In with GitHub
or
Remember me
Browse
Advanced Search
New Bug
Reports
Documentation
Attachment 8365844 Details for
Bug 964197
[patch]
keep_each_frame_duration
keep_each_frame_duration (text/plain), 14.75 KB, created by
Alfredo Yang (:alfredo)
(
hide
)
Description:
keep_each_frame_duration
Filename:
MIME Type:
Creator:
Alfredo Yang (:alfredo)
Size:
14.75 KB
patch
obsolete
># HG changeset patch ># Parent 77026e0c13ee1ed0ee82ee6cc199647f02d93378 ># User Alfredo Yang <ayang@mozilla.com> > >diff --git a/content/media/encoder/fmp4_muxer/ISOControl.cpp b/content/media/encoder/fmp4_muxer/ISOControl.cpp >--- a/content/media/encoder/fmp4_muxer/ISOControl.cpp >+++ b/content/media/encoder/fmp4_muxer/ISOControl.cpp >@@ -18,16 +18,17 @@ namespace mozilla { > const static uint32_t MUXING_BUFFER_SIZE = 512*1024; > > FragmentBuffer::FragmentBuffer(uint32_t aTrackType, uint32_t aFragDuration, > TrackMetadataBase* aMetadata) > : mTrackType(aTrackType) > , mFragDuration(aFragDuration) > , mMediaStartTime(0) > , mFragmentNumber(0) >+ , mLastFrameTimeOfLastFragment(0) > , mEOS(false) > { > mFragArray.AppendElement(); > if (mTrackType == Audio_Track) { > nsRefPtr<AACTrackMetadata> audMeta = static_cast<AACTrackMetadata*>(aMetadata); > MOZ_ASSERT(audMeta); > } else { > nsRefPtr<AVCTrackMetadata> vidMeta = static_cast<AVCTrackMetadata*>(aMetadata); >diff --git a/content/media/encoder/fmp4_muxer/ISOControl.h b/content/media/encoder/fmp4_muxer/ISOControl.h >--- a/content/media/encoder/fmp4_muxer/ISOControl.h >+++ b/content/media/encoder/fmp4_muxer/ISOControl.h >@@ -68,16 +68,24 @@ public: > // on codec type. This data will be sent as a special frame from encoder to > // ISOMediaWriter and pass to this class via AddFrame(). > nsresult GetCSD(nsTArray<uint8_t>& aCSD); > > bool HasCSD() { return mCSDFrame; } > > uint32_t GetType() { return mTrackType; } > >+ void SetLastFragmentLastFrameTime(uint32_t aTime) { >+ mLastFrameTimeOfLastFragment = aTime; >+ } >+ >+ uint32_t GetLastFragmentLastFrameTime() { >+ return mLastFrameTimeOfLastFragment; >+ } >+ > private: > uint32_t mTrackType; > > // Fragment duration, microsecond per unit. > uint32_t mFragDuration; > > // Media start time, microsecond per unit. > // Together with mFragDuration, mFragmentNumber and EncodedFrame->GetTimeStamp(), >@@ -88,16 +96,22 @@ private: > > // Current fragment number. It will be increase when a new element of > // mFragArray is created. > // Note: > // It only means the fragment number of current accumulated frames, not > // the current 'creating' fragment mFragNum in ISOControl. > uint32_t mFragmentNumber; > >+ // The last frame time tamp of last fragment. It is for cauculating the >+ // play duration of first frame in current fragmenet. The frame duration is >+ // defined as "current frame timestamp - last frame timestamp" here. So it >+ // needs to keep the last timestamp of last fragmenet. >+ uint32_t mLastFrameTimeOfLastFragment; >+ > // Array of fragments, each element has enough samples to form a > // complete fragment. > nsTArray<nsTArray<nsRefPtr<EncodedFrame>>> mFragArray; > > // Codec specific data frame, it will be generated by encoder and send to > // ISOMediaWriter through WriteEncodedTrack(). The data will be vary depends > // on codec type. > nsRefPtr<EncodedFrame> mCSDFrame; >diff --git a/content/media/encoder/fmp4_muxer/ISOMediaBoxes.cpp b/content/media/encoder/fmp4_muxer/ISOMediaBoxes.cpp >--- a/content/media/encoder/fmp4_muxer/ISOMediaBoxes.cpp >+++ b/content/media/encoder/fmp4_muxer/ISOMediaBoxes.cpp >@@ -117,29 +117,58 @@ TrackRunBox::fillSampleTable() > FragmentBuffer* frag = mControl->GetFragment(mTrackType); > > rv = frag->GetFirstFragment(frames); > if (NS_FAILED(rv)) { > return 0; > } > uint32_t len = frames.Length(); > sample_info_table = new tbl[len]; >+ // Create sample table according to 14496-12 8.8.8.2. > for (uint32_t i = 0; i < len; i++) { >- sample_info_table[i].sample_duration = 0; >- sample_info_table[i].sample_size = frames.ElementAt(i)->GetFrameData().Length(); >- mAllSampleSize += sample_info_table[i].sample_size; >- table_size += sizeof(uint32_t); >+ // Sample size. >+ sample_info_table[i].sample_size = 0; >+ if (flags.to_ulong() & flags_sample_size_present) { >+ sample_info_table[i].sample_size = frames.ElementAt(i)->GetFrameData().Length(); >+ mAllSampleSize += sample_info_table[i].sample_size; >+ table_size += sizeof(uint32_t); >+ } >+ >+ // Sample flags. >+ sample_info_table[i].sample_flags = 0; > if (flags.to_ulong() & flags_sample_flags_present) { > sample_info_table[i].sample_flags = > set_sample_flags( > (frames.ElementAt(i)->GetFrameType() == EncodedFrame::I_FRAME)); > table_size += sizeof(uint32_t); >- } else { >- sample_info_table[i].sample_flags = 0; > } >+ >+ // Sample duration. >+ sample_info_table[i].sample_duration = 0; >+ if (flags.to_ulong() & flags_sample_duration_present) { >+ // Calculate each frame's duration, it is decided by "current frame >+ // timestamp - last frame timestamp". >+ uint64_t frame_time = 0; >+ if (i == 0) { >+ frame_time = frames.ElementAt(i)->GetTimeStamp() - >+ frag->GetLastFragmentLastFrameTime(); >+ } else { >+ frame_time = frames.ElementAt(i)->GetTimeStamp() - >+ frames.ElementAt(i - 1)->GetTimeStamp(); >+ // Keep the last frame time of current fagment, it will be used to calculate >+ // the first frame duration of next fragment. >+ if ((len - 1) == i) { >+ frag->SetLastFragmentLastFrameTime(frames.ElementAt(i)->GetTimeStamp()); >+ } >+ } >+ sample_info_table[i].sample_duration = >+ frame_time * mMeta.mVidMeta->VideoFrequency / 1000000; >+ table_size += sizeof(uint32_t); >+ } >+ > sample_info_table[i].sample_composition_time_offset = 0; > } > return table_size; > } > > nsresult > TrackRunBox::Generate(uint32_t* aBoxSize) > { >@@ -171,33 +200,39 @@ nsresult > TrackRunBox::Write() > { > WRITE_FULLBOX(mControl, size) > mControl->Write(sample_count); > if (flags.to_ulong() & flags_data_offset_present) { > mControl->Write(data_offset); > } > for (uint32_t i = 0; i < sample_count; i++) { >- mControl->Write(sample_info_table[i].sample_size); >+ if (flags.to_ulong() & flags_sample_duration_present) { >+ mControl->Write(sample_info_table[i].sample_duration); >+ } >+ if (flags.to_ulong() & flags_sample_size_present) { >+ mControl->Write(sample_info_table[i].sample_size); >+ } > if (flags.to_ulong() & flags_sample_flags_present) { > mControl->Write(sample_info_table[i].sample_flags); > } > } > > return NS_OK; > } > > TrackRunBox::TrackRunBox(uint32_t aType, uint32_t aFlags, ISOControl* aControl) > : FullBox(NS_LITERAL_CSTRING("trun"), 0, aFlags, aControl) > , sample_count(0) > , data_offset(0) > , first_sample_flags(0) > , mAllSampleSize(0) > , mTrackType(aType) > { >+ mMeta.Init(aControl); > MOZ_COUNT_CTOR(TrackRunBox); > } > > TrackRunBox::~TrackRunBox() > { > MOZ_COUNT_DTOR(TrackRunBox); > } > >@@ -209,25 +244,32 @@ TrackFragmentHeaderBox::UpdateBaseDataOf > } > > nsresult > TrackFragmentHeaderBox::Generate(uint32_t* aBoxSize) > { > track_ID = mControl->GetTrackID(mTrackType); > size += sizeof(track_ID); > >- if (flags.to_ulong() | base_data_offset_present) { >+ if (flags.to_ulong() & base_data_offset_present) { > // base_data_offset needs to add size of 'trun', 'tfhd' and >- // header of 'mdat 'later. >+ // header of 'mdat' later. > base_data_offset = 0; > size += sizeof(base_data_offset); > } >- if (flags.to_ulong() | default_sample_duration_present) { >+ if (flags.to_ulong() & default_sample_duration_present) { > if (mTrackType == Video_Track) { >- default_sample_duration = mMeta.mVidMeta->VideoFrequency / mMeta.mVidMeta->FrameRate; >+ if (!mMeta.mVidMeta->FrameRate) { >+ // 0 means frame rate is variant, so it is wrong to write >+ // default_sample_duration. >+ MOZ_ASSERT(0); >+ default_sample_duration = 0; >+ } else { >+ default_sample_duration = mMeta.mVidMeta->VideoFrequency / mMeta.mVidMeta->FrameRate; >+ } > } else if (mTrackType == Audio_Track) { > default_sample_duration = mMeta.mAudMeta->FrameDuration; > } else { > MOZ_ASSERT(0); > return NS_ERROR_FAILURE; > } > size += sizeof(default_sample_duration); > } >@@ -235,56 +277,70 @@ TrackFragmentHeaderBox::Generate(uint32_ > return NS_OK; > } > > nsresult > TrackFragmentHeaderBox::Write() > { > WRITE_FULLBOX(mControl, size) > mControl->Write(track_ID); >- if (flags.to_ulong() | base_data_offset_present) { >+ if (flags.to_ulong() & base_data_offset_present) { > mControl->Write(base_data_offset); > } >- if (flags.to_ulong() | default_sample_duration_present) { >+ if (flags.to_ulong() & default_sample_duration_present) { > mControl->Write(default_sample_duration); > } > return NS_OK; > } > > TrackFragmentHeaderBox::TrackFragmentHeaderBox(uint32_t aType, >+ uint32_t aFlags, > ISOControl* aControl) >- // TODO: tf_flags, we may need to customize it from caller >- : FullBox(NS_LITERAL_CSTRING("tfhd"), >- 0, >- base_data_offset_present | default_sample_duration_present, >- aControl) >+ : FullBox(NS_LITERAL_CSTRING("tfhd"), 0, aFlags, aControl) > , track_ID(0) > , base_data_offset(0) > , default_sample_duration(0) > { > mTrackType = aType; > mMeta.Init(mControl); > MOZ_COUNT_CTOR(TrackFragmentHeaderBox); > } > > TrackFragmentHeaderBox::~TrackFragmentHeaderBox() > { > MOZ_COUNT_DTOR(TrackFragmentHeaderBox); > } > >-TrackFragmentBox::TrackFragmentBox(uint32_t aType, uint32_t aFlags, >- ISOControl* aControl) >+TrackFragmentBox::TrackFragmentBox(uint32_t aType, ISOControl* aControl) > : DefaultContainerImpl(NS_LITERAL_CSTRING("traf"), aControl) > , mTrackType(aType) > { >- boxes.AppendElement(new TrackFragmentHeaderBox(aType, aControl)); >+ // Flags in TrackFragmentHeaderBox. >+ uint32_t tf_flags = base_data_offset_present; >+ >+ // Audio frame rate should be fixed; otherwise it will cause noise when playback. >+ // So it doesn't need to keep duration of each audio frame in TrackRunBox. It >+ // keeps the default sample duration in TrackFragmentHeaderBox. >+ tf_flags |= (mTrackType & Audio_Track ? default_sample_duration_present : 0); >+ >+ boxes.AppendElement(new TrackFragmentHeaderBox(aType, tf_flags, aControl)); >+ >+ // Always adds flags_data_offset_present in each TrackRunBox, Android >+ // parser requires this flag to calculate the correct bitstream offset. >+ uint32_t tr_flags = flags_sample_size_present | flags_data_offset_present; >+ >+ // Flags in TrackRunBox. >+ // If there is no default sample duration exists, each frame duration needs to >+ // be recored in the TrackRunBox. >+ tr_flags |= (tf_flags & default_sample_duration_present ? 0 : flags_sample_duration_present); > > // For video, add sample_flags to record I frame. >- aFlags |= (mTrackType & Video_Track ? flags_sample_flags_present : 0); >- boxes.AppendElement(new TrackRunBox(mTrackType, aFlags, aControl)); >+ tr_flags |= (mTrackType & Video_Track ? flags_sample_flags_present : 0); >+ >+ boxes.AppendElement(new TrackRunBox(mTrackType, tr_flags, aControl)); > MOZ_COUNT_CTOR(TrackFragmentBox); > } > > TrackFragmentBox::~TrackFragmentBox() > { > MOZ_COUNT_DTOR(TrackFragmentBox); > } > >@@ -320,29 +376,23 @@ MovieFragmentHeaderBox::~MovieFragmentHe > } > > MovieFragmentBox::MovieFragmentBox(uint32_t aType, ISOControl* aControl) > : DefaultContainerImpl(NS_LITERAL_CSTRING("moof"), aControl) > , mTrackType(aType) > { > boxes.AppendElement(new MovieFragmentHeaderBox(mTrackType, aControl)); > >- // Always adds flags_data_offset_present in each TrackFragmentBox, Android >- // parser requires this flag to calculate the correct bitstream offset. > if (mTrackType & Audio_Track) { > boxes.AppendElement( >- new TrackFragmentBox(Audio_Track, >- flags_sample_size_present | flags_data_offset_present, >- aControl)); >+ new TrackFragmentBox(Audio_Track, aControl)); > } > if (mTrackType & Video_Track) { > boxes.AppendElement( >- new TrackFragmentBox(Video_Track, >- flags_sample_size_present | flags_data_offset_present, >- aControl)); >+ new TrackFragmentBox(Video_Track, aControl)); > } > MOZ_COUNT_CTOR(MovieFragmentBox); > } > > MovieFragmentBox::~MovieFragmentBox() > { > MOZ_COUNT_DTOR(MovieFragmentBox); > } >@@ -379,18 +429,22 @@ TrackExtendsBox::Generate(uint32_t* aBox > > if (mTrackType == Audio_Track) { > default_sample_description_index = 1; > default_sample_duration = mMeta.mAudMeta->FrameDuration; > default_sample_size = mMeta.mAudMeta->FrameSize; > default_sample_flags = set_sample_flags(1); > } else if (mTrackType == Video_Track) { > default_sample_description_index = 1; >- default_sample_duration = >- mMeta.mVidMeta->VideoFrequency / mMeta.mVidMeta->FrameRate; >+ // Video meta data has assigned framerate, it implies that this video's >+ // frame rate should be fixed. >+ if (mMeta.mVidMeta->FrameRate) { >+ default_sample_duration = >+ mMeta.mVidMeta->VideoFrequency / mMeta.mVidMeta->FrameRate; >+ } > default_sample_size = 0; > default_sample_flags = set_sample_flags(0); > } else { > MOZ_ASSERT(0); > return NS_ERROR_FAILURE; > } > > size += sizeof(track_ID) + >diff --git a/content/media/encoder/fmp4_muxer/ISOMediaBoxes.h b/content/media/encoder/fmp4_muxer/ISOMediaBoxes.h >--- a/content/media/encoder/fmp4_muxer/ISOMediaBoxes.h >+++ b/content/media/encoder/fmp4_muxer/ISOMediaBoxes.h >@@ -294,16 +294,17 @@ public: > TrackRunBox(uint32_t aType, uint32_t aFlags, ISOControl* aControl); > ~TrackRunBox(); > > protected: > uint32_t fillSampleTable(); > > uint32_t mAllSampleSize; > uint32_t mTrackType; >+ MetaHelper mMeta; > }; > > // tf_flags in TrackFragmentHeaderBox, 14496-12 8.8.7.1. > #define base_data_offset_present 0x000001 > #define sample_description_index_present 0x000002 > #define default_sample_duration_present 0x000008 > #define default_sample_size_present 0x000010 > #define default_sample_flags_present 0x000020 >@@ -322,30 +323,30 @@ public: > // MuxerOperation methods > nsresult Generate(uint32_t* aBoxSize) MOZ_OVERRIDE; > nsresult Write() MOZ_OVERRIDE; > > // TrackFragmentHeaderBox methods > nsresult UpdateBaseDataOffset(uint64_t aOffset); // The offset of the first > // sample in file. > >- TrackFragmentHeaderBox(uint32_t aType, ISOControl* aControl); >+ TrackFragmentHeaderBox(uint32_t aType, uint32_t aFlags, ISOControl* aControl); > ~TrackFragmentHeaderBox(); > > protected: > uint32_t mTrackType; > MetaHelper mMeta; > }; > > // 14496-12 8.8.6 'Track Fragment Box' > // Box type: 'traf' > // TrackFragmentBox cotains TrackFragmentHeaderBox and TrackRunBox. > class TrackFragmentBox : public DefaultContainerImpl { > public: >- TrackFragmentBox(uint32_t aType, uint32_t aFlags, ISOControl* aControl); >+ TrackFragmentBox(uint32_t aType, ISOControl* aControl); > ~TrackFragmentBox(); > > protected: > uint32_t mTrackType; > }; > > // 14496-12 8.8.5 'Movie Fragment Header Box' > // Box type: 'mfhd'
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
Flags:
cpearce
: review+
Actions:
View
|
Diff
|
Review
Attachments on
bug 964197
:
8365844
|
8369138