Closed
Bug 1150853
Opened 10 years ago
Closed 10 years ago
Replace MP4Sample with a MediaRawData refcounted object
Categories
(Core :: Audio/Video, defect)
Tracking
()
RESOLVED
FIXED
mozilla40
Tracking | Status | |
---|---|---|
firefox40 | --- | fixed |
People
(Reporter: jya, Assigned: jya)
References
Details
Attachments
(3 files, 3 obsolete files)
3.22 KB,
patch
|
eflores
:
review+
|
Details | Diff | Splinter Review |
26.30 KB,
patch
|
Details | Diff | Splinter Review | |
160.81 KB,
patch
|
Details | Diff | Splinter Review |
this bug track the work of replacing the MP4Sample object with a new refcounted MediaRawData.
Assignee | ||
Comment 1•10 years ago
|
||
Add MediaRawData object and generalise the use of CryptoTrack and CryptoSample
Attachment #8588920 -
Flags: review?(cpearce)
Assignee | ||
Updated•10 years ago
|
Assignee: nobody → jyavenard
Status: NEW → ASSIGNED
Assignee | ||
Comment 2•10 years ago
|
||
Use MediaRawData across the board, remove MP4Sample object
Attachment #8588921 -
Flags: review?(cpearce)
Assignee | ||
Comment 3•10 years ago
|
||
make a copy of extradata object as ffmpeg decoder modifies it
Attachment #8588922 -
Flags: review?(edwin)
Comment on attachment 8588922 [details] [diff] [review]
Part3. Do not modify provided extradata array
Review of attachment 8588922 [details] [diff] [review]:
-----------------------------------------------------------------
::: dom/media/fmp4/ffmpeg/FFmpegDataDecoder.cpp
@@ +95,5 @@
> mCodecContext->thread_safe_callbacks = false;
>
> if (mExtraData) {
> mCodecContext->extradata_size = mExtraData->Length();
> + // FFmepg may use SIMD instructions to access the data which reads the
nit: `mepg'
Attachment #8588922 -
Flags: review?(edwin) → review+
Assignee | ||
Comment 5•10 years ago
|
||
Comment on attachment 8588920 [details] [diff] [review]
Part1. Create MediaRawData object type
can't work on opt build
Attachment #8588920 -
Attachment is obsolete: true
Attachment #8588920 -
Flags: review?(cpearce)
Assignee | ||
Comment 6•10 years ago
|
||
Remove MOZ_ASSERTs, add documentation.
Attachment #8589938 -
Flags: review?(cpearce)
Comment 7•10 years ago
|
||
I think you should have a gtest that exercises MediaRawData, in particular, the cloning and expanding of the buffer.
Assignee | ||
Comment 8•10 years ago
|
||
Can do in a separate patch...
However, this is a version I had been using to test the behaviour:
https://treeherder.mozilla.org/#/jobs?repo=try&revision=2651571c14b3
Every creation, copy is surrounded by asserts that verify the size, the capacity and the content by running memcmp on all copied content.
here is a try with the last version (without the debugging):
https://treeherder.mozilla.org/#/jobs?repo=try&revision=b3b6faddfed4
Comment 9•10 years ago
|
||
Comment on attachment 8589938 [details] [diff] [review]
Part1. Create MediaRawData object type
Review of attachment 8589938 [details] [diff] [review]:
-----------------------------------------------------------------
::: dom/media/MediaData.cpp
@@ +113,3 @@
> {
> NS_ASSERTION(mDuration >= 0, "Frame must have non-negative duration.");
> + mTimecode = aTimecode;
Can you initialize this in the initialization list?
@@ +127,4 @@
> {
> NS_ASSERTION(mDuration >= 0, "Frame must have non-negative duration.");
> + mKeyframe = aKeyframe;
> + mTimecode = aTimecode;
Can you initialize these in the initialization list?
@@ +535,5 @@
> + }
> + if (!mBuffer->SetCapacity(aSize + RAW_DATA_ALIGNMENT * 2)) {
> + return false;
> + }
> + // Find alignment address.
You'll do an unnecessary copy here. The SetCapacity() call will copy any existing data in the existing buffer into the new buffer, and then you copy it again to ensure it's aligned. Maybe you should instead allocate the new buffer in a temporary, and copy the new data over into it, then set mBuffer to the temporary.
@@ +600,5 @@
> + if (!mTarget->EnsureCapacity(aSize)) {
> + return false;
> + }
> + mData = mBuffer->Elements() + mTarget->mPadding;
> + return true;
Everytime you call EnsureSize(aSize), you then call `mSize = mTarget->mSize = aSize;`. Why don't you call `mSize = mTarget->mSize = aSize;` here inside EnsureSize() instead?
::: dom/media/MediaData.h
@@ +75,5 @@
> int64_t GetEndTime() const { return mTime + mDuration; }
>
> protected:
> + explicit MediaData(Type aType)
> + : mType(aType)
Initializer list should be indented one more tab.
@@ +382,5 @@
> + CryptoSample mCrypto;
> + nsRefPtr<DataBuffer> mExtraData;
> +
> + // Return a deep copy or nullptr if out of memory.
> + virtual already_AddRefed<MediaRawData> Clone() const;
Comment here saying that the caller *must* delete the writer. Can you call this "CreateWriter()" instead, so it's clear that it allocates a new object?
Alternatively, can this return an nsAutoPtr<MediaRawDataWriter> instead, to force the caller to ensure it gets deleted? Does that work?
Attachment #8589938 -
Flags: review?(cpearce) → review+
Comment 10•10 years ago
|
||
Comment on attachment 8589938 [details] [diff] [review]
Part1. Create MediaRawData object type
Review of attachment 8589938 [details] [diff] [review]:
-----------------------------------------------------------------
::: dom/media/MediaData.h
@@ +312,5 @@
> +
> +class CryptoSample : public CryptoTrack
> +{
> +public:
> + nsTArray<uint16_t> plain_sizes;
It would be good to fix these members to use mStandardMozillaStyle instead of non_standard_underscored_style. In another patch maybe.
Comment 11•10 years ago
|
||
Comment on attachment 8589938 [details] [diff] [review]
Part1. Create MediaRawData object type
Review of attachment 8589938 [details] [diff] [review]:
-----------------------------------------------------------------
::: dom/media/MediaData.h
@@ +344,5 @@
> +class MediaRawDataWriter
> +{
> +public:
> + // Pointer to data or null if not-yet allocated
> + uint8_t* mData;
Since you're only supposed to write the data via the writer, why not only expose the raw data via a const accessor, i.e.:
const uint8_t* Data() const;
Ditto for size.
Comment 12•10 years ago
|
||
Comment on attachment 8588921 [details] [diff] [review]
Part2. Use new MediaRawObject across the board
Review of attachment 8588921 [details] [diff] [review]:
-----------------------------------------------------------------
Looks like you missed GMPEncryptedBufferDataImpl.h/cpp.
::: dom/media/fmp4/apple/AppleVDADecoder.h
@@ +34,5 @@
> int64_t byte_offset;
> bool is_sync_point;
>
> + explicit AppleFrameRef(const MediaRawData& aSample)
> + : decode_timestamp(aSample.mTimecode)
Initializer list should be indented 1 level. Yeah, yeah, the code was like that when you got here...
::: dom/media/fmp4/apple/AppleVTDecoder.cpp
@@ +218,5 @@
> // a custom block source which reuses the aSample buffer.
> // But note that there may be a problem keeping the samples
> // alive over multiple frames.
> + rv = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, // Struct allocator.
> + const_cast<uint8_t*>(aSample->mData),
Casting away const-ness... eww...
::: dom/media/fmp4/eme/EMEDecoderModule.cpp
@@ +56,1 @@
> &EMEDecryptor::Input,
Hanging args no longer line up.
@@ +67,1 @@
> &EMEDecryptor::Decrypted,
Hanging args no longer line up.
::: dom/media/fmp4/eme/SamplesWaitingForKey.cpp
@@ +56,1 @@
> &MediaDataDecoder::Input,
Hanging args no longer line up.
::: dom/media/fmp4/wmf/WMFAudioMFTManager.cpp
@@ +181,2 @@
> {
> + const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->mData);
Isn't MediaRawData::mData is already a uint8_t*, so you shouldn't need to cast it to const to use it?
::: dom/media/fmp4/wmf/WMFVideoMFTManager.cpp
@@ +241,5 @@
> // This can happen during shutdown.
> return E_FAIL;
> }
> // Forward sample data to the decoder.
> + const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->mData);
Isn't MediaRawData::mData is already a uint8_t*, so you shouldn't need to cast it to const to use it?
::: dom/media/gmp/GMPAudioHost.cpp
@@ -41,5 @@
> , mRate(aRate)
> {
> - mBuffer.AppendElements(aSample->data, aSample->size);
> - if (aSample->crypto.valid) {
> - mCrypto = new GMPEncryptedBufferDataImpl(aSample->crypto);
Don't you need to also change GMPEncryptedBufferDataImpl::GMPEncryptedBufferDataImpl(const mp4_demuxer::CryptoSample& aCrypto) too? You're using that here.
::: dom/media/webm/IntelWebMVideoDecoder.cpp
@@ +43,5 @@
> int64_t aByteOffset,
> uint8_t* aData,
> size_t aSize,
> bool aSyncPoint)
> + : MediaRawData(aData, aSize)
Initializer list should be indented.
@@ +364,4 @@
> if (mQueuedVideoSample) {
> return mQueuedVideoSample.forget();
> }
> + nsRefPtr<VP8Sample> sample = nullptr;
you shouldn't need the "= nulptr" here.
::: media/libstagefright/binding/H264.cpp
@@ +18,5 @@
> class BitReader
> {
> public:
> + explicit BitReader(const mozilla::DataBuffer* aBuffer)
> + : mBitReader(aBuffer->Elements(), aBuffer->Length())
Initializer list indented 1 level.
Attachment #8588921 -
Flags: review?(cpearce) → review+
Assignee | ||
Comment 13•10 years ago
|
||
(In reply to Chris Pearce (:cpearce) from comment #9)
> Comment on attachment 8589938 [details] [diff] [review]
> Part1. Create MediaRawData object type
>
> Review of attachment 8589938 [details] [diff] [review]:
> -----------------------------------------------------------------
>
> ::: dom/media/MediaData.cpp
> @@ +113,3 @@
> > {
> > NS_ASSERTION(mDuration >= 0, "Frame must have non-negative duration.");
> > + mTimecode = aTimecode;
>
> Can you initialize this in the initialization list?
those are member of the base class, they can't be initialized that way. Or do you mean having a new base constructor that set the time ?
>
> @@ +127,4 @@
> > {
> > NS_ASSERTION(mDuration >= 0, "Frame must have non-negative duration.");
> > + mKeyframe = aKeyframe;
> > + mTimecode = aTimecode;
>
> Can you initialize these in the initialization list?
same ...
> You'll do an unnecessary copy here. The SetCapacity() call will copy any
> existing data in the existing buffer into the new buffer, and then you copy
> it again to ensure it's aligned. Maybe you should instead allocate the new
> buffer in a temporary, and copy the new data over into it, then set mBuffer
> to the temporary.
Indeed, but I can't see a way around it if we are to use a nsTFallibleArray as backend.
The only way to avoid the unecessary copy then shift would be to manually manage the buffer. I have no problem doing that.
Having said that, in practice, you almost always get the same buffer. The only time we create a new copy is for Clone() or Prepend(). the way the memory allocation works in the nsTArray is by allocating a multiple of 2 greater than the required size. As we currently only use Prepend to add about 40 bytes, it means that the original capacity is actually enough and we end up only shifting once.
Now, nsTArray isn't the most efficient container, as it's designed to work on any size and as such, copies always occur byte by byte. A memmove/memcpy would be much better.
Luckily, the class is abstracted enough that we can change the backend very easily.
>
> @@ +600,5 @@
> > + if (!mTarget->EnsureCapacity(aSize)) {
> > + return false;
> > + }
> > + mData = mBuffer->Elements() + mTarget->mPadding;
> > + return true;
>
> Everytime you call EnsureSize(aSize), you then call `mSize = mTarget->mSize
> = aSize;`. Why don't you call `mSize = mTarget->mSize = aSize;` here inside
> EnsureSize() instead?
>
mSize was a later addition. will do.
Assignee | ||
Comment 14•10 years ago
|
||
(In reply to Chris Pearce (:cpearce) from comment #11)
> Comment on attachment 8589938 [details] [diff] [review]
> Part1. Create MediaRawData object type
>
> Review of attachment 8589938 [details] [diff] [review]:
> -----------------------------------------------------------------
>
> ::: dom/media/MediaData.h
> @@ +344,5 @@
> > +class MediaRawDataWriter
> > +{
> > +public:
> > + // Pointer to data or null if not-yet allocated
> > + uint8_t* mData;
>
> Since you're only supposed to write the data via the writer, why not only
> expose the raw data via a const accessor, i.e.:
>
> const uint8_t* Data() const;
>
> Ditto for size.
MediaRawData mData is a const uint8_t*
MediaRawDaraWriter gives you access in writing to the raw data.
I kept the use of mData and mSize so we could easily replaced MP4Sample. Having accessor rather than using member variables would be better across the board yes.
It would simplify the MediaRawData code too.
Would you prefer we move to accessor then?
What about the Crypto container classes. Should we use accessors too?
Assignee | ||
Comment 15•10 years ago
|
||
(In reply to Chris Pearce (:cpearce) from comment #12)
> > + explicit AppleFrameRef(const MediaRawData& aSample)
> > + : decode_timestamp(aSample.mTimecode)
>
> Initializer list should be indented 1 level. Yeah, yeah, the code was like
> that when you got here...
the code was like that when I got there !
>
> ::: dom/media/fmp4/apple/AppleVTDecoder.cpp
> @@ +218,5 @@
> > // a custom block source which reuses the aSample buffer.
> > // But note that there may be a problem keeping the samples
> > // alive over multiple frames.
> > + rv = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, // Struct allocator.
> > + const_cast<uint8_t*>(aSample->mData),
>
> Casting away const-ness... eww...
>
Tell that to Apple who never appears to have any of its API use const.
> ::: dom/media/fmp4/wmf/WMFAudioMFTManager.cpp
> @@ +181,2 @@
> > {
> > + const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->mData);
>
> Isn't MediaRawData::mData is already a uint8_t*, so you shouldn't need to
> cast it to const to use it?
it is a const uint8_t* yes... so that code is now unecessary. Looks like someone didn't know about const_cast<> :)
>
> Don't you need to also change
> GMPEncryptedBufferDataImpl::GMPEncryptedBufferDataImpl(const
> mp4_demuxer::CryptoSample& aCrypto) too? You're using that here.
hmm... wonder how that got through all the try test ... This isn't compiled by default ???
Assignee | ||
Comment 16•10 years ago
|
||
Carrying r+. Allocate the buffer to be a default 4kB. Any further allocation will be made big enough by the nsTArray that it will prevent further allocations unecessary under all current use.
Assignee | ||
Updated•10 years ago
|
Attachment #8589938 -
Attachment is obsolete: true
Assignee | ||
Comment 17•10 years ago
|
||
Carrying r+. Looks like I had uploaded an obsolete patch. Most comments had already been addressed.
Assignee | ||
Updated•10 years ago
|
Attachment #8588921 -
Attachment is obsolete: true
Assignee | ||
Comment 18•10 years ago
|
||
Comment 19•10 years ago
|
||
https://hg.mozilla.org/mozilla-central/rev/7f283bb1827c
https://hg.mozilla.org/mozilla-central/rev/5b615a235096
https://hg.mozilla.org/mozilla-central/rev/c2b367ccb601
Status: ASSIGNED → RESOLVED
Closed: 10 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla40
Comment 20•10 years ago
|
||
The Part 2 patch here causes a permanent crash on some systems. See bug 1153227.
Depends on: 1153227
Flags: needinfo?(jyavenard)
Updated•10 years ago
|
Assignee | ||
Comment 21•10 years ago
|
||
WebRTC uses MP4???
Comment 22•10 years ago
|
||
OK, we worked it out: the new DataBuffer class shadows the existing DataBuffer used in WebRTC.
Why this didn't cause a compilation error is simply another reason to despise C++.
Flags: needinfo?(jyavenard)
Assignee | ||
Comment 23•10 years ago
|
||
(In reply to Martin Thomson [:mt] from comment #22)
> OK, we worked it out: the new DataBuffer class shadows the existing
> DataBuffer used in WebRTC.
>
> Why this didn't cause a compilation error is simply another reason to
> despise C++.
This shouldn't have compiled. DataBuffer is held into a nsAutoPtr which would call the DataBuffer destructor which is private.
I don't think this is a C++ problem per-say... but that we have C and C++ headers mixed together.
You need to log in
before you can comment on or make changes to this bug.
Description
•