mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-25 09:57:32 +09:00
parent
5830ff1f2b
commit
74df182488
232 changed files with 256 additions and 36730 deletions
|
|
@ -1,84 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ISOControl.h"
|
||||
#include "ISOMediaBoxes.h"
|
||||
#include "AMRBox.h"
|
||||
#include "ISOTrackMetadata.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
nsresult
|
||||
AMRSampleEntry::Generate(uint32_t* aBoxSize)
|
||||
{
|
||||
uint32_t box_size;
|
||||
nsresult rv = amr_special_box->Generate(&box_size);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
size += box_size;
|
||||
|
||||
*aBoxSize = size;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AMRSampleEntry::Write()
|
||||
{
|
||||
BoxSizeChecker checker(mControl, size);
|
||||
nsresult rv;
|
||||
rv = AudioSampleEntry::Write();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = amr_special_box->Write();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AMRSampleEntry::AMRSampleEntry(ISOControl* aControl)
|
||||
: AudioSampleEntry(NS_LITERAL_CSTRING("samr"), aControl)
|
||||
{
|
||||
amr_special_box = new AMRSpecificBox(aControl);
|
||||
MOZ_COUNT_CTOR(AMRSampleEntry);
|
||||
}
|
||||
|
||||
AMRSampleEntry::~AMRSampleEntry()
|
||||
{
|
||||
MOZ_COUNT_DTOR(AMRSampleEntry);
|
||||
}
|
||||
|
||||
nsresult
|
||||
AMRSpecificBox::Generate(uint32_t* aBoxSize)
|
||||
{
|
||||
nsresult rv;
|
||||
FragmentBuffer* frag = mControl->GetFragment(Audio_Track);
|
||||
rv = frag->GetCSD(amrDecSpecInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
size += amrDecSpecInfo.Length();
|
||||
*aBoxSize = size;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AMRSpecificBox::Write()
|
||||
{
|
||||
BoxSizeChecker checker(mControl, size);
|
||||
Box::Write();
|
||||
mControl->Write(amrDecSpecInfo.Elements(), amrDecSpecInfo.Length());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AMRSpecificBox::AMRSpecificBox(ISOControl* aControl)
|
||||
: Box(NS_LITERAL_CSTRING("damr"), aControl)
|
||||
{
|
||||
MOZ_COUNT_CTOR(AMRSpecificBox);
|
||||
}
|
||||
|
||||
AMRSpecificBox::~AMRSpecificBox()
|
||||
{
|
||||
MOZ_COUNT_DTOR(AMRSpecificBox);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef AMRBOX_h_
|
||||
#define AMRBOX_h_
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "MuxerOperation.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ISOControl;
|
||||
|
||||
// 3GPP TS 26.244 6.7 'AMRSpecificBox field for AMRSampleEntry box'
|
||||
// Box type: 'damr'
|
||||
class AMRSpecificBox : public Box {
|
||||
public:
|
||||
// 3GPP members
|
||||
nsTArray<uint8_t> amrDecSpecInfo;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// AMRSpecificBox methods
|
||||
AMRSpecificBox(ISOControl* aControl);
|
||||
~AMRSpecificBox();
|
||||
};
|
||||
|
||||
// 3GPP TS 26.244 6.5 'AMRSampleEntry box'
|
||||
// Box type: 'sawb'
|
||||
class AMRSampleEntry : public AudioSampleEntry {
|
||||
public:
|
||||
// 3GPP members
|
||||
RefPtr<AMRSpecificBox> amr_special_box;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// AMRSampleEntry methods
|
||||
AMRSampleEntry(ISOControl* aControl);
|
||||
~AMRSampleEntry();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // AMRBOX_h_
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <climits>
|
||||
#include "ISOControl.h"
|
||||
#include "ISOMediaBoxes.h"
|
||||
#include "AVCBox.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
nsresult
|
||||
AVCSampleEntry::Generate(uint32_t* aBoxSize)
|
||||
{
|
||||
uint32_t avc_box_size = 0;
|
||||
nsresult rv;
|
||||
rv = avcConfigBox->Generate(&avc_box_size);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
size += avc_box_size;
|
||||
|
||||
*aBoxSize = size;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCSampleEntry::Write()
|
||||
{
|
||||
BoxSizeChecker checker(mControl, size);
|
||||
nsresult rv;
|
||||
rv = VisualSampleEntry::Write();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = avcConfigBox->Write();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AVCSampleEntry::AVCSampleEntry(ISOControl* aControl)
|
||||
: VisualSampleEntry(NS_LITERAL_CSTRING("avc1"), aControl)
|
||||
{
|
||||
avcConfigBox = new AVCConfigurationBox(aControl);
|
||||
MOZ_COUNT_CTOR(AVCSampleEntry);
|
||||
}
|
||||
|
||||
AVCSampleEntry::~AVCSampleEntry()
|
||||
{
|
||||
MOZ_COUNT_DTOR(AVCSampleEntry);
|
||||
}
|
||||
|
||||
AVCConfigurationBox::AVCConfigurationBox(ISOControl* aControl)
|
||||
: Box(NS_LITERAL_CSTRING("avcC"), aControl)
|
||||
{
|
||||
MOZ_COUNT_CTOR(AVCConfigurationBox);
|
||||
}
|
||||
|
||||
AVCConfigurationBox::~AVCConfigurationBox()
|
||||
{
|
||||
MOZ_COUNT_DTOR(AVCConfigurationBox);
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCConfigurationBox::Generate(uint32_t* aBoxSize)
|
||||
{
|
||||
nsresult rv;
|
||||
FragmentBuffer* frag = mControl->GetFragment(Video_Track);
|
||||
rv = frag->GetCSD(avcConfig);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
size += avcConfig.Length();
|
||||
*aBoxSize = size;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCConfigurationBox::Write()
|
||||
{
|
||||
BoxSizeChecker checker(mControl, size);
|
||||
Box::Write();
|
||||
|
||||
mControl->Write(avcConfig.Elements(), avcConfig.Length());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef AVCBox_h_
|
||||
#define AVCBox_h_
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "ISOMediaBoxes.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ISOControl;
|
||||
|
||||
// 14496-12 8.5.2.2
|
||||
#define resolution_72_dpi 0x00480000
|
||||
#define video_depth 0x0018
|
||||
|
||||
// 14496-15 5.3.4.1 'Sample description name and format'
|
||||
// Box type: 'avcC'
|
||||
class AVCConfigurationBox : public Box {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
|
||||
// avcConfig is CodecSpecificData from 14496-15 '5.3.4.1 Sample description
|
||||
// name and format.
|
||||
// These data are generated by encoder and we encapsulated the generated
|
||||
// bitstream into box directly.
|
||||
nsTArray<uint8_t> avcConfig;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// AVCConfigurationBox methods
|
||||
AVCConfigurationBox(ISOControl* aControl);
|
||||
~AVCConfigurationBox();
|
||||
};
|
||||
|
||||
// 14496-15 5.3.4.1 'Sample description name and format'
|
||||
// Box type: 'avc1'
|
||||
class AVCSampleEntry : public VisualSampleEntry {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
RefPtr<AVCConfigurationBox> avcConfigBox;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// VisualSampleEntry methods
|
||||
AVCSampleEntry(ISOControl* aControl);
|
||||
~AVCSampleEntry();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // AVCBox_h_
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ISOControl.h"
|
||||
#include "ISOMediaBoxes.h"
|
||||
#include "EVRCBox.h"
|
||||
#include "ISOTrackMetadata.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
nsresult
|
||||
EVRCSampleEntry::Generate(uint32_t* aBoxSize)
|
||||
{
|
||||
uint32_t box_size;
|
||||
nsresult rv = evrc_special_box->Generate(&box_size);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
size += box_size;
|
||||
|
||||
*aBoxSize = size;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
EVRCSampleEntry::Write()
|
||||
{
|
||||
BoxSizeChecker checker(mControl, size);
|
||||
nsresult rv;
|
||||
rv = AudioSampleEntry::Write();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = evrc_special_box->Write();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
EVRCSampleEntry::EVRCSampleEntry(ISOControl* aControl)
|
||||
: AudioSampleEntry(NS_LITERAL_CSTRING("sevc"), aControl)
|
||||
{
|
||||
evrc_special_box = new EVRCSpecificBox(aControl);
|
||||
MOZ_COUNT_CTOR(EVRCSampleEntry);
|
||||
}
|
||||
|
||||
EVRCSampleEntry::~EVRCSampleEntry()
|
||||
{
|
||||
MOZ_COUNT_DTOR(EVRCSampleEntry);
|
||||
}
|
||||
|
||||
nsresult
|
||||
EVRCSpecificBox::Generate(uint32_t* aBoxSize)
|
||||
{
|
||||
nsresult rv;
|
||||
FragmentBuffer* frag = mControl->GetFragment(Audio_Track);
|
||||
rv = frag->GetCSD(evrcDecSpecInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
size += evrcDecSpecInfo.Length();
|
||||
*aBoxSize = size;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
EVRCSpecificBox::Write()
|
||||
{
|
||||
BoxSizeChecker checker(mControl, size);
|
||||
Box::Write();
|
||||
mControl->Write(evrcDecSpecInfo.Elements(), evrcDecSpecInfo.Length());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
EVRCSpecificBox::EVRCSpecificBox(ISOControl* aControl)
|
||||
: Box(NS_LITERAL_CSTRING("devc"), aControl)
|
||||
{
|
||||
MOZ_COUNT_CTOR(EVRCSpecificBox);
|
||||
}
|
||||
|
||||
EVRCSpecificBox::~EVRCSpecificBox()
|
||||
{
|
||||
MOZ_COUNT_DTOR(EVRCSpecificBox);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef EVRCBOX_h_
|
||||
#define EVRCBOX_h_
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "MuxerOperation.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ISOControl;
|
||||
|
||||
// 3GPP TS 26.244 6.7 'EVRCSpecificBox field for EVRCSampleEntry box'
|
||||
// Box type: 'devc'
|
||||
class EVRCSpecificBox : public Box {
|
||||
public:
|
||||
// 3GPP members
|
||||
nsTArray<uint8_t> evrcDecSpecInfo;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// EVRCSpecificBox methods
|
||||
EVRCSpecificBox(ISOControl* aControl);
|
||||
~EVRCSpecificBox();
|
||||
};
|
||||
|
||||
// 3GPP TS 26.244 6.5 'EVRCSampleEntry box'
|
||||
// Box type: 'sevc'
|
||||
class EVRCSampleEntry : public AudioSampleEntry {
|
||||
public:
|
||||
// 3GPP members
|
||||
RefPtr<EVRCSpecificBox> evrc_special_box;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// EVRCSampleEntry methods
|
||||
EVRCSampleEntry(ISOControl* aControl);
|
||||
~EVRCSampleEntry();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // EVRCBOX_h_
|
||||
|
|
@ -1,415 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <time.h>
|
||||
#include "nsAutoPtr.h"
|
||||
#include "ISOControl.h"
|
||||
#include "ISOMediaBoxes.h"
|
||||
#include "EncodedFrameContainer.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// For MP4 creation_time and modification_time offset from January 1, 1904 to
|
||||
// January 1, 1970.
|
||||
#define iso_time_offset 2082844800
|
||||
|
||||
FragmentBuffer::FragmentBuffer(uint32_t aTrackType, uint32_t aFragDuration)
|
||||
: mTrackType(aTrackType)
|
||||
, mFragDuration(aFragDuration)
|
||||
, mMediaStartTime(0)
|
||||
, mFragmentNumber(0)
|
||||
, mLastFrameTimeOfLastFragment(0)
|
||||
, mEOS(false)
|
||||
{
|
||||
mFragArray.AppendElement();
|
||||
MOZ_COUNT_CTOR(FragmentBuffer);
|
||||
}
|
||||
|
||||
FragmentBuffer::~FragmentBuffer()
|
||||
{
|
||||
MOZ_COUNT_DTOR(FragmentBuffer);
|
||||
}
|
||||
|
||||
bool
|
||||
FragmentBuffer::HasEnoughData()
|
||||
{
|
||||
// Audio or video frame is enough to form a moof.
|
||||
return (mFragArray.Length() > 1);
|
||||
}
|
||||
|
||||
nsresult
|
||||
FragmentBuffer::GetCSD(nsTArray<uint8_t>& aCSD)
|
||||
{
|
||||
if (!mCSDFrame) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
aCSD.AppendElements(mCSDFrame->GetFrameData().Elements(),
|
||||
mCSDFrame->GetFrameData().Length());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FragmentBuffer::AddFrame(EncodedFrame* aFrame)
|
||||
{
|
||||
// already EOS, it rejects all new data.
|
||||
if (mEOS) {
|
||||
MOZ_ASSERT(0);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
EncodedFrame::FrameType type = aFrame->GetFrameType();
|
||||
if (type == EncodedFrame::AAC_CSD || type == EncodedFrame::AVC_CSD ||
|
||||
type == EncodedFrame::AMR_AUDIO_CSD || type == EncodedFrame::EVRC_AUDIO_CSD) {
|
||||
mCSDFrame = aFrame;
|
||||
// Use CSD's timestamp as the start time. Encoder should send CSD frame first
|
||||
// and then data frames.
|
||||
mMediaStartTime = aFrame->GetTimeStamp();
|
||||
mFragmentNumber = 1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// if the timestamp is incorrect, abort it.
|
||||
if (aFrame->GetTimeStamp() < mMediaStartTime) {
|
||||
MOZ_ASSERT(false);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mFragArray.LastElement().AppendElement(aFrame);
|
||||
|
||||
// check if current fragment is reach the fragment duration.
|
||||
if ((aFrame->GetTimeStamp() - mMediaStartTime) >= (mFragDuration * mFragmentNumber)) {
|
||||
mFragArray.AppendElement();
|
||||
mFragmentNumber++;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FragmentBuffer::GetFirstFragment(nsTArray<RefPtr<EncodedFrame>>& aFragment,
|
||||
bool aFlush)
|
||||
{
|
||||
// It should be called only if there is a complete fragment in mFragArray.
|
||||
if (mFragArray.Length() <= 1 && !mEOS) {
|
||||
MOZ_ASSERT(false);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (aFlush) {
|
||||
aFragment.SwapElements(mFragArray.ElementAt(0));
|
||||
mFragArray.RemoveElementAt(0);
|
||||
} else {
|
||||
aFragment.AppendElements(mFragArray.ElementAt(0));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
FragmentBuffer::GetFirstFragmentSampleNumber()
|
||||
{
|
||||
return mFragArray.ElementAt(0).Length();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
FragmentBuffer::GetFirstFragmentSampleSize()
|
||||
{
|
||||
uint32_t size = 0;
|
||||
uint32_t len = mFragArray.ElementAt(0).Length();
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
size += mFragArray.ElementAt(0).ElementAt(i)->GetFrameData().Length();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
ISOControl::ISOControl(uint32_t aMuxingType)
|
||||
: mMuxingType(aMuxingType)
|
||||
, mAudioFragmentBuffer(nullptr)
|
||||
, mVideoFragmentBuffer(nullptr)
|
||||
, mFragNum(0)
|
||||
, mOutputSize(0)
|
||||
, mBitCount(0)
|
||||
, mBit(0)
|
||||
{
|
||||
// Create a data array for first mp4 Box, ftyp.
|
||||
mOutBuffers.SetLength(1);
|
||||
MOZ_COUNT_CTOR(ISOControl);
|
||||
}
|
||||
|
||||
ISOControl::~ISOControl()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ISOControl);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ISOControl::GetNextTrackID()
|
||||
{
|
||||
return (mMetaArray.Length() + 1);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ISOControl::GetTrackID(TrackMetadataBase::MetadataKind aKind)
|
||||
{
|
||||
for (uint32_t i = 0; i < mMetaArray.Length(); i++) {
|
||||
if (mMetaArray[i]->GetKind() == aKind) {
|
||||
return (i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Track ID shouldn't be 0. It must be something wrong here.
|
||||
MOZ_ASSERT(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ISOControl::SetMetadata(TrackMetadataBase* aTrackMeta)
|
||||
{
|
||||
if (aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AAC ||
|
||||
aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AMR ||
|
||||
aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AVC ||
|
||||
aTrackMeta->GetKind() == TrackMetadataBase::METADATA_EVRC) {
|
||||
mMetaArray.AppendElement(aTrackMeta);
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ISOControl::GetAudioMetadata(RefPtr<AudioTrackMetadata>& aAudMeta)
|
||||
{
|
||||
for (uint32_t i = 0; i < mMetaArray.Length() ; i++) {
|
||||
if (mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AAC ||
|
||||
mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AMR ||
|
||||
mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_EVRC) {
|
||||
aAudMeta = static_cast<AudioTrackMetadata*>(mMetaArray[i].get());
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ISOControl::GetVideoMetadata(RefPtr<VideoTrackMetadata>& aVidMeta)
|
||||
{
|
||||
for (uint32_t i = 0; i < mMetaArray.Length() ; i++) {
|
||||
if (mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AVC) {
|
||||
aVidMeta = static_cast<VideoTrackMetadata*>(mMetaArray[i].get());
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool
|
||||
ISOControl::HasAudioTrack()
|
||||
{
|
||||
RefPtr<AudioTrackMetadata> audMeta;
|
||||
GetAudioMetadata(audMeta);
|
||||
return audMeta;
|
||||
}
|
||||
|
||||
bool
|
||||
ISOControl::HasVideoTrack()
|
||||
{
|
||||
RefPtr<VideoTrackMetadata> vidMeta;
|
||||
GetVideoMetadata(vidMeta);
|
||||
return vidMeta;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ISOControl::SetFragment(FragmentBuffer* aFragment)
|
||||
{
|
||||
if (aFragment->GetType() == Audio_Track) {
|
||||
mAudioFragmentBuffer = aFragment;
|
||||
} else {
|
||||
mVideoFragmentBuffer = aFragment;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
FragmentBuffer*
|
||||
ISOControl::GetFragment(uint32_t aType)
|
||||
{
|
||||
if (aType == Audio_Track) {
|
||||
return mAudioFragmentBuffer;
|
||||
} else if (aType == Video_Track){
|
||||
return mVideoFragmentBuffer;
|
||||
}
|
||||
MOZ_ASSERT(0);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ISOControl::GetBufs(nsTArray<nsTArray<uint8_t>>* aOutputBufs)
|
||||
{
|
||||
uint32_t len = mOutBuffers.Length();
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
mOutBuffers[i].SwapElements(*aOutputBufs->AppendElement());
|
||||
}
|
||||
return FlushBuf();
|
||||
}
|
||||
|
||||
nsresult
|
||||
ISOControl::FlushBuf()
|
||||
{
|
||||
mOutBuffers.SetLength(1);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ISOControl::WriteAVData(nsTArray<uint8_t>& aArray)
|
||||
{
|
||||
MOZ_ASSERT(!mBitCount);
|
||||
|
||||
uint32_t len = aArray.Length();
|
||||
if (!len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
mOutputSize += len;
|
||||
|
||||
// The last element already has data, allocated a new element for pointer
|
||||
// swapping.
|
||||
if (mOutBuffers.LastElement().Length()) {
|
||||
mOutBuffers.AppendElement();
|
||||
}
|
||||
// Swap the video/audio data pointer.
|
||||
mOutBuffers.LastElement().SwapElements(aArray);
|
||||
// Following data could be boxes, so appending a new uint8_t array here.
|
||||
mOutBuffers.AppendElement();
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ISOControl::WriteBits(uint64_t aBits, size_t aNumBits)
|
||||
{
|
||||
uint8_t output_byte = 0;
|
||||
|
||||
MOZ_ASSERT(aNumBits <= 64);
|
||||
// TODO: rewritten following with bitset?
|
||||
for (size_t i = aNumBits; i > 0; i--) {
|
||||
mBit |= (((aBits >> (i - 1)) & 1) << (8 - ++mBitCount));
|
||||
if (mBitCount == 8) {
|
||||
Write(&mBit, sizeof(uint8_t));
|
||||
mBit = 0;
|
||||
mBitCount = 0;
|
||||
output_byte++;
|
||||
}
|
||||
}
|
||||
return output_byte;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ISOControl::Write(uint8_t* aBuf, uint32_t aSize)
|
||||
{
|
||||
mOutBuffers.LastElement().AppendElements(aBuf, aSize);
|
||||
mOutputSize += aSize;
|
||||
return aSize;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ISOControl::Write(uint8_t aData)
|
||||
{
|
||||
MOZ_ASSERT(!mBitCount);
|
||||
Write((uint8_t*)&aData, sizeof(uint8_t));
|
||||
return sizeof(uint8_t);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ISOControl::GetBufPos()
|
||||
{
|
||||
uint32_t len = mOutBuffers.Length();
|
||||
uint32_t pos = 0;
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
pos += mOutBuffers.ElementAt(i).Length();
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ISOControl::WriteFourCC(const char* aType)
|
||||
{
|
||||
// Bit operation should be aligned to byte before writing any byte data.
|
||||
MOZ_ASSERT(!mBitCount);
|
||||
|
||||
uint32_t size = strlen(aType);
|
||||
if (size == 4) {
|
||||
return Write((uint8_t*)aType, size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ISOControl::GenerateFtyp()
|
||||
{
|
||||
nsresult rv;
|
||||
uint32_t size;
|
||||
nsAutoPtr<FileTypeBox> type_box(new FileTypeBox(this));
|
||||
rv = type_box->Generate(&size);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = type_box->Write();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ISOControl::GenerateMoov()
|
||||
{
|
||||
nsresult rv;
|
||||
uint32_t size;
|
||||
nsAutoPtr<MovieBox> moov_box(new MovieBox(this));
|
||||
rv = moov_box->Generate(&size);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = moov_box->Write();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ISOControl::GenerateMoof(uint32_t aTrackType)
|
||||
{
|
||||
mFragNum++;
|
||||
|
||||
nsresult rv;
|
||||
uint32_t size;
|
||||
uint64_t first_sample_offset = mOutputSize;
|
||||
nsAutoPtr<MovieFragmentBox> moof_box(new MovieFragmentBox(aTrackType, this));
|
||||
nsAutoPtr<MediaDataBox> mdat_box(new MediaDataBox(aTrackType, this));
|
||||
|
||||
rv = moof_box->Generate(&size);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
first_sample_offset += size;
|
||||
rv = mdat_box->Generate(&size);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
first_sample_offset += mdat_box->FirstSampleOffsetInMediaDataBox();
|
||||
|
||||
// correct offset info
|
||||
nsTArray<RefPtr<MuxerOperation>> tfhds;
|
||||
rv = moof_box->Find(NS_LITERAL_CSTRING("tfhd"), tfhds);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
uint32_t len = tfhds.Length();
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
TrackFragmentHeaderBox* tfhd = (TrackFragmentHeaderBox*) tfhds.ElementAt(i).get();
|
||||
rv = tfhd->UpdateBaseDataOffset(first_sample_offset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
rv = moof_box->Write();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mdat_box->Write();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ISOControl::GetTime()
|
||||
{
|
||||
return (uint64_t)time(nullptr) + iso_time_offset;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,250 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef ISOCOMPOSITOR_H_
|
||||
#define ISOCOMPOSITOR_H_
|
||||
|
||||
#include "mozilla/EndianUtils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "ISOTrackMetadata.h"
|
||||
#include "EncodedFrameContainer.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class Box;
|
||||
class ISOControl;
|
||||
|
||||
/**
|
||||
* This class collects elementary stream data to form a fragment.
|
||||
* ISOMediaWriter will check if the data is enough; if yes, the corresponding
|
||||
* moof will be created and write to ISOControl.
|
||||
* Each audio and video has its own fragment and only one during the whole
|
||||
* life cycle, when a fragment is formed in ISOControl, Flush() needs to
|
||||
* be called to reset it.
|
||||
*/
|
||||
class FragmentBuffer {
|
||||
public:
|
||||
// aTrackType: it could be Audio_Track or Video_Track.
|
||||
// aFragDuration: it is the fragment duration. (microsecond per unit)
|
||||
// Audio and video have the same fragment duration.
|
||||
FragmentBuffer(uint32_t aTrackType, uint32_t aFragDuration);
|
||||
~FragmentBuffer();
|
||||
|
||||
// Get samples of first fragment, that will swap all the elements in the
|
||||
// mFragArray[0] when aFlush = true, and caller is responsible for drop
|
||||
// EncodedFrame reference count.
|
||||
nsresult GetFirstFragment(nsTArray<RefPtr<EncodedFrame>>& aFragment,
|
||||
bool aFlush = false);
|
||||
|
||||
// Add sample frame to the last element fragment of mFragArray. If sample
|
||||
// number is enough, it will append a new fragment element. And the new
|
||||
// sample will be added to the new fragment element of mFragArray.
|
||||
nsresult AddFrame(EncodedFrame* aFrame);
|
||||
|
||||
// Get total sample size of first complete fragment size.
|
||||
uint32_t GetFirstFragmentSampleSize();
|
||||
|
||||
// Get sample number of first complete fragment.
|
||||
uint32_t GetFirstFragmentSampleNumber();
|
||||
|
||||
// Check if it accumulates enough frame data.
|
||||
// It returns true when data is enough to form a fragment.
|
||||
bool HasEnoughData();
|
||||
|
||||
// Called by ISOMediaWriter when TrackEncoder has sent the last frame. The
|
||||
// remains frame data will form the last moof and move the state machine to
|
||||
// in ISOMediaWriter to last phrase.
|
||||
nsresult SetEndOfStream() {
|
||||
mEOS = true;
|
||||
return NS_OK;
|
||||
}
|
||||
bool EOS() { return mEOS; }
|
||||
|
||||
// CSD (codec specific data), it is generated by encoder and the data depends
|
||||
// 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(),
|
||||
// when the difference between current frame time and mMediaStartTime is
|
||||
// exceeded current fragment ceiling timeframe, that means current fragment has
|
||||
// enough data and a new element in mFragArray will be added.
|
||||
uint64_t mMediaStartTime;
|
||||
|
||||
// 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 stamp of last fragment. It is for calculating the
|
||||
// play duration of first frame in current fragment. The frame duration is
|
||||
// defined as "current frame timestamp - last frame timestamp" here. So it
|
||||
// needs to keep the last timestamp of last fragment.
|
||||
uint32_t mLastFrameTimeOfLastFragment;
|
||||
|
||||
// Array of fragments, each element has enough samples to form a
|
||||
// complete fragment.
|
||||
nsTArray<nsTArray<RefPtr<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.
|
||||
RefPtr<EncodedFrame> mCSDFrame;
|
||||
|
||||
// END_OF_STREAM from ContainerWriter
|
||||
bool mEOS;
|
||||
};
|
||||
|
||||
/**
|
||||
* ISOControl will be carried to each box when box is created. It is the main
|
||||
* bridge for box to output stream to ContainerWriter and retrieve information.
|
||||
* ISOControl acts 3 different roles:
|
||||
* 1. Holds the pointer of audio metadata, video metadata, fragment and
|
||||
* pass them to boxes.
|
||||
* 2. Provide the functions to generate the base structure of MP4; they are
|
||||
* GenerateFtyp, GenerateMoov, GenerateMoof, and GenerateMfra.
|
||||
* 3. The actually writer used by MuxOperation::Write() in each box. It provides
|
||||
* writing methods for different kind of data; they are Write, WriteArray,
|
||||
* WriteBits...etc.
|
||||
*/
|
||||
class ISOControl {
|
||||
|
||||
friend class Box;
|
||||
|
||||
public:
|
||||
ISOControl(uint32_t aMuxingType);
|
||||
~ISOControl();
|
||||
|
||||
nsresult GenerateFtyp();
|
||||
nsresult GenerateMoov();
|
||||
nsresult GenerateMoof(uint32_t aTrackType);
|
||||
|
||||
// Swap elementary stream pointer to output buffers.
|
||||
uint32_t WriteAVData(nsTArray<uint8_t>& aArray);
|
||||
|
||||
uint32_t Write(uint8_t* aBuf, uint32_t aSize);
|
||||
|
||||
uint32_t Write(uint8_t aData);
|
||||
|
||||
template <typename T>
|
||||
uint32_t Write(T aData) {
|
||||
MOZ_ASSERT(!mBitCount);
|
||||
|
||||
aData = NativeEndian::swapToNetworkOrder(aData);
|
||||
Write((uint8_t*)&aData, sizeof(T));
|
||||
return sizeof(T);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
uint32_t WriteArray(const T &aArray, uint32_t aSize) {
|
||||
MOZ_ASSERT(!mBitCount);
|
||||
|
||||
uint32_t size = 0;
|
||||
for (uint32_t i = 0; i < aSize; i++) {
|
||||
size += Write(aArray[i]);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
uint32_t WriteFourCC(const char* aType);
|
||||
|
||||
// Bit writing. Note: it needs to be byte-boundary before using
|
||||
// others non-bit writing function.
|
||||
uint32_t WriteBits(uint64_t aBits, size_t aNumBits);
|
||||
|
||||
// This is called by GetContainerData and swap all the buffers to aOutputBuffers.
|
||||
nsresult GetBufs(nsTArray<nsTArray<uint8_t>>* aOutputBufs);
|
||||
|
||||
// Presentation time in seconds since midnight, Jan. 1, 1904, in UTC time.
|
||||
uint32_t GetTime();
|
||||
|
||||
// current fragment number
|
||||
uint32_t GetCurFragmentNumber() { return mFragNum; }
|
||||
|
||||
nsresult SetFragment(FragmentBuffer* aFragment);
|
||||
FragmentBuffer* GetFragment(uint32_t aType);
|
||||
|
||||
uint32_t GetMuxingType() { return mMuxingType; }
|
||||
|
||||
nsresult SetMetadata(TrackMetadataBase* aTrackMeta);
|
||||
nsresult GetAudioMetadata(RefPtr<AudioTrackMetadata>& aAudMeta);
|
||||
nsresult GetVideoMetadata(RefPtr<VideoTrackMetadata>& aVidMeta);
|
||||
|
||||
// Track ID is the Metadata index in mMetaArray. It allows only 1 audio
|
||||
// track and 1 video track in this muxer. In this muxer, it is prohibt to have
|
||||
// mutiple audio track or video track in the same file.
|
||||
uint32_t GetTrackID(TrackMetadataBase::MetadataKind aKind);
|
||||
uint32_t GetNextTrackID();
|
||||
|
||||
bool HasAudioTrack();
|
||||
bool HasVideoTrack();
|
||||
|
||||
private:
|
||||
uint32_t GetBufPos();
|
||||
nsresult FlushBuf();
|
||||
|
||||
// One of value in TYPE_XXX, defined in ISOMediaWriter.
|
||||
uint32_t mMuxingType;
|
||||
|
||||
// Audio and video fragments are owned by ISOMediaWriter.
|
||||
// They don't need to worry about pointer going stale because ISOMediaWriter's
|
||||
// lifetime is longer than ISOControl.
|
||||
FragmentBuffer* mAudioFragmentBuffer;
|
||||
FragmentBuffer* mVideoFragmentBuffer;
|
||||
|
||||
// Generated fragment number
|
||||
uint32_t mFragNum;
|
||||
|
||||
// The (index + 1) will be the track ID.
|
||||
nsTArray<RefPtr<TrackMetadataBase>> mMetaArray;
|
||||
|
||||
// Array of output buffers.
|
||||
// To save memory usage, audio/video sample will be swapped into a new element
|
||||
// of this array.
|
||||
//
|
||||
// For example,
|
||||
// mOutBuffers[0] --> boxes (allocated by muxer)
|
||||
// mOutBuffers[1] --> video raw data (allocated by encoder)
|
||||
// mOutBuffers[2] --> video raw data (allocated by encoder)
|
||||
// mOutBuffers[3] --> video raw data (allocated by encoder)
|
||||
// mOutBuffers[4] --> boxes (allocated by muxer)
|
||||
// mOutBuffers[5] --> audio raw data (allocated by encoder)
|
||||
// ...etc.
|
||||
//
|
||||
nsTArray<nsTArray<uint8_t>> mOutBuffers;
|
||||
|
||||
// Accumulate output size from Write().
|
||||
uint64_t mOutputSize;
|
||||
|
||||
// Bit writing operation. Note: the mBitCount should be 0 before any
|
||||
// byte-boundary writing method be called (Write(uint32_t), Write(uint16_t)...etc);
|
||||
// otherwise, there will be assertion on these functions.
|
||||
uint8_t mBitCount;
|
||||
uint8_t mBit;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,781 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef ISOMediaBoxes_h_
|
||||
#define ISOMediaBoxes_h_
|
||||
|
||||
#include <bitset>
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "MuxerOperation.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#define WRITE_FULLBOX(_compositor, _size) \
|
||||
BoxSizeChecker checker(_compositor, _size); \
|
||||
FullBox::Write();
|
||||
|
||||
#define FOURCC(a, b, c, d) ( ((a) << 24) | ((b) << 16) | ((c) << 8) | (d) )
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* track type from spec 8.4.3.3
|
||||
*/
|
||||
#define Audio_Track 0x01
|
||||
#define Video_Track 0x02
|
||||
|
||||
class AudioTrackMetadata;
|
||||
class VideoTrackMetadata;
|
||||
class ISOControl;
|
||||
|
||||
/**
|
||||
* This is the base class for all ISO media format boxes.
|
||||
* It provides the fields of box type(four CC) and size.
|
||||
* The data members in the beginning of a Box (or its descendants)
|
||||
* are the 14496-12 defined member. Other members prefix with 'm'
|
||||
* are private control data.
|
||||
*
|
||||
* This class is for inherited only, it shouldn't be instanced directly.
|
||||
*/
|
||||
class Box : public MuxerOperation {
|
||||
protected:
|
||||
// ISO BMFF members
|
||||
uint32_t size; // 14496-12 4-2 'Object Structure'. Size of this box.
|
||||
nsCString boxType; // four CC name, all table names are listed in
|
||||
// 14496-12 table 1.
|
||||
|
||||
public:
|
||||
// MuxerOperation methods
|
||||
nsresult Write() override;
|
||||
nsresult Find(const nsACString& aType,
|
||||
nsTArray<RefPtr<MuxerOperation>>& aOperations) override;
|
||||
|
||||
// This helper class will compare the written size in Write() and the size in
|
||||
// Generate(). If their are not equal, it will assert.
|
||||
class BoxSizeChecker {
|
||||
public:
|
||||
BoxSizeChecker(ISOControl* aControl, uint32_t aSize);
|
||||
~BoxSizeChecker();
|
||||
|
||||
uint32_t ori_size;
|
||||
uint32_t box_size;
|
||||
ISOControl* mControl;
|
||||
};
|
||||
|
||||
protected:
|
||||
Box() = delete;
|
||||
Box(const nsACString& aType, ISOControl* aControl);
|
||||
|
||||
ISOControl* mControl;
|
||||
RefPtr<AudioTrackMetadata> mAudioMeta;
|
||||
RefPtr<VideoTrackMetadata> mVideoMeta;
|
||||
};
|
||||
|
||||
/**
|
||||
* FullBox (and its descendants) is the box which contains the 'real' data
|
||||
* members. It is the edge in the ISO box structure and it doesn't contain
|
||||
* any box.
|
||||
*
|
||||
* This class is for inherited only, it shouldn't be instanced directly.
|
||||
*/
|
||||
class FullBox : public Box {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
uint8_t version; // 14496-12 4.2 'Object Structure'
|
||||
std::bitset<24> flags; //
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Write() override;
|
||||
|
||||
protected:
|
||||
// FullBox methods
|
||||
FullBox(const nsACString& aType, uint8_t aVersion, uint32_t aFlags,
|
||||
ISOControl* aControl);
|
||||
FullBox() = delete;
|
||||
};
|
||||
|
||||
/**
|
||||
* The default implementation of the container box.
|
||||
* Basically, the container box inherits this class and overrides the
|
||||
* constructor only.
|
||||
*
|
||||
* According to 14496-12 3.1.1 'container box', a container box is
|
||||
* 'box whose sole purpose is to contain and group a set of related boxes'
|
||||
*
|
||||
* This class is for inherited only, it shouldn't be instanced directly.
|
||||
*/
|
||||
class DefaultContainerImpl : public Box {
|
||||
public:
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
nsresult Find(const nsACString& aType,
|
||||
nsTArray<RefPtr<MuxerOperation>>& aOperations) override;
|
||||
|
||||
protected:
|
||||
// DefaultContainerImpl methods
|
||||
DefaultContainerImpl(const nsACString& aType, ISOControl* aControl);
|
||||
DefaultContainerImpl() = delete;
|
||||
|
||||
nsTArray<RefPtr<MuxerOperation>> boxes;
|
||||
};
|
||||
|
||||
// 14496-12 4.3 'File Type Box'
|
||||
// Box type: 'ftyp'
|
||||
class FileTypeBox : public Box {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
nsCString major_brand; // four chars
|
||||
uint32_t minor_version;
|
||||
nsTArray<nsCString> compatible_brands;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// FileTypeBox methods
|
||||
FileTypeBox(ISOControl* aControl);
|
||||
~FileTypeBox();
|
||||
};
|
||||
|
||||
// 14496-12 8.2.1 'Movie Box'
|
||||
// Box type: 'moov'
|
||||
// MovieBox contains MovieHeaderBox, TrackBox and MovieExtendsBox.
|
||||
class MovieBox : public DefaultContainerImpl {
|
||||
public:
|
||||
MovieBox(ISOControl* aControl);
|
||||
~MovieBox();
|
||||
};
|
||||
|
||||
// 14496-12 8.2.2 'Movie Header Box'
|
||||
// Box type: 'mvhd'
|
||||
class MovieHeaderBox : public FullBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
uint32_t creation_time;
|
||||
uint32_t modification_time;
|
||||
uint32_t timescale;
|
||||
uint32_t duration;
|
||||
uint32_t rate;
|
||||
uint16_t volume;
|
||||
uint16_t reserved16;
|
||||
uint32_t reserved32[2];
|
||||
uint32_t matrix[9];
|
||||
uint32_t pre_defined[6];
|
||||
uint32_t next_track_ID;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// MovieHeaderBox methods
|
||||
MovieHeaderBox(ISOControl* aControl);
|
||||
~MovieHeaderBox();
|
||||
uint32_t GetTimeScale();
|
||||
};
|
||||
|
||||
// 14496-12 8.4.2 'Media Header Box'
|
||||
// Box type: 'mdhd'
|
||||
class MediaHeaderBox : public FullBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
uint32_t creation_time;
|
||||
uint32_t modification_time;
|
||||
uint32_t timescale;
|
||||
uint32_t duration;
|
||||
std::bitset<1> pad;
|
||||
std::bitset<5> lang1;
|
||||
std::bitset<5> lang2;
|
||||
std::bitset<5> lang3;
|
||||
uint16_t pre_defined;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// MediaHeaderBox methods
|
||||
MediaHeaderBox(uint32_t aType, ISOControl* aControl);
|
||||
~MediaHeaderBox();
|
||||
uint32_t GetTimeScale();
|
||||
|
||||
protected:
|
||||
uint32_t mTrackType;
|
||||
};
|
||||
|
||||
// 14496-12 8.3.1 'Track Box'
|
||||
// Box type: 'trak'
|
||||
// TrackBox contains TrackHeaderBox and MediaBox.
|
||||
class TrackBox : public DefaultContainerImpl {
|
||||
public:
|
||||
TrackBox(uint32_t aTrackType, ISOControl* aControl);
|
||||
~TrackBox();
|
||||
};
|
||||
|
||||
// 14496-12 8.1.1 'Media Data Box'
|
||||
// Box type: 'mdat'
|
||||
class MediaDataBox : public Box {
|
||||
public:
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// MediaDataBox methods
|
||||
uint32_t GetAllSampleSize() { return mAllSampleSize; }
|
||||
uint32_t FirstSampleOffsetInMediaDataBox() { return mFirstSampleOffset; }
|
||||
MediaDataBox(uint32_t aTrackType, ISOControl* aControl);
|
||||
~MediaDataBox();
|
||||
|
||||
protected:
|
||||
uint32_t mAllSampleSize; // All audio and video sample size in this box.
|
||||
uint32_t mFirstSampleOffset; // The offset of first sample in this box from
|
||||
// the beginning of this mp4 file.
|
||||
uint32_t mTrackType;
|
||||
};
|
||||
|
||||
// flags for TrackRunBox::flags, 14496-12 8.8.8.1.
|
||||
#define flags_data_offset_present 0x000001
|
||||
#define flags_first_sample_flags_present 0x000002
|
||||
#define flags_sample_duration_present 0x000100
|
||||
#define flags_sample_size_present 0x000200
|
||||
#define flags_sample_flags_present 0x000400
|
||||
#define flags_sample_composition_time_offsets_present 0x000800
|
||||
|
||||
// flag for TrackRunBox::tbl::sample_flags and TrackExtendsBox::default_sample_flags
|
||||
// which is defined in 14496-12 8.8.3.1.
|
||||
uint32_t set_sample_flags(bool aSync);
|
||||
|
||||
// 14496-12 8.8.8 'Track Fragment Run Box'
|
||||
// Box type: 'trun'
|
||||
class TrackRunBox : public FullBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
typedef struct {
|
||||
uint32_t sample_duration;
|
||||
uint32_t sample_size;
|
||||
uint32_t sample_flags;
|
||||
uint32_t sample_composition_time_offset;
|
||||
} tbl;
|
||||
|
||||
uint32_t sample_count;
|
||||
// the following are optional fields
|
||||
uint32_t data_offset; // data offset exists when audio/video are present in file.
|
||||
uint32_t first_sample_flags;
|
||||
UniquePtr<tbl[]> sample_info_table;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// TrackRunBox methods
|
||||
uint32_t GetAllSampleSize() { return mAllSampleSize; }
|
||||
nsresult SetDataOffset(uint32_t aOffset);
|
||||
|
||||
TrackRunBox(uint32_t aType, uint32_t aFlags, ISOControl* aControl);
|
||||
~TrackRunBox();
|
||||
|
||||
protected:
|
||||
uint32_t fillSampleTable();
|
||||
|
||||
uint32_t mAllSampleSize;
|
||||
uint32_t mTrackType;
|
||||
};
|
||||
|
||||
// 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
|
||||
#define duration_is_empty 0x010000
|
||||
#define default_base_is_moof 0x020000
|
||||
|
||||
// 14496-12 8.8.7 'Track Fragment Header Box'
|
||||
// Box type: 'tfhd'
|
||||
class TrackFragmentHeaderBox : public FullBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
uint32_t track_ID;
|
||||
uint64_t base_data_offset;
|
||||
uint32_t default_sample_duration;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// TrackFragmentHeaderBox methods
|
||||
nsresult UpdateBaseDataOffset(uint64_t aOffset); // The offset of the first
|
||||
// sample in file.
|
||||
|
||||
TrackFragmentHeaderBox(uint32_t aType, uint32_t aFlags, ISOControl* aControl);
|
||||
~TrackFragmentHeaderBox();
|
||||
|
||||
protected:
|
||||
uint32_t mTrackType;
|
||||
};
|
||||
|
||||
// 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, ISOControl* aControl);
|
||||
~TrackFragmentBox();
|
||||
|
||||
protected:
|
||||
uint32_t mTrackType;
|
||||
};
|
||||
|
||||
// 14496-12 8.8.5 'Movie Fragment Header Box'
|
||||
// Box type: 'mfhd'
|
||||
class MovieFragmentHeaderBox : public FullBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
uint32_t sequence_number;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// MovieFragmentHeaderBox methods
|
||||
MovieFragmentHeaderBox(uint32_t aType, ISOControl* aControl);
|
||||
~MovieFragmentHeaderBox();
|
||||
|
||||
protected:
|
||||
uint32_t mTrackType;
|
||||
};
|
||||
|
||||
// 14496-12 8.8.4 'Movie Fragment Box'
|
||||
// Box type: 'moof'
|
||||
// MovieFragmentBox contains MovieFragmentHeaderBox and TrackFragmentBox.
|
||||
class MovieFragmentBox : public DefaultContainerImpl {
|
||||
public:
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
|
||||
// MovieFragmentBox methods
|
||||
MovieFragmentBox(uint32_t aType, ISOControl* aControl);
|
||||
~MovieFragmentBox();
|
||||
|
||||
protected:
|
||||
uint32_t mTrackType;
|
||||
};
|
||||
|
||||
// 14496-12 8.8.3 'Track Extends Box'
|
||||
// Box type: 'trex'
|
||||
class TrackExtendsBox : public FullBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
uint32_t track_ID;
|
||||
uint32_t default_sample_description_index;
|
||||
uint32_t default_sample_duration;
|
||||
uint32_t default_sample_size;
|
||||
uint32_t default_sample_flags;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// TrackExtendsBox methods
|
||||
TrackExtendsBox(uint32_t aType, ISOControl* aControl);
|
||||
~TrackExtendsBox();
|
||||
|
||||
protected:
|
||||
uint32_t mTrackType;
|
||||
};
|
||||
|
||||
// 14496-12 8.8.1 'Movie Extends Box'
|
||||
// Box type: 'mvex'
|
||||
// MovieExtendsBox contains TrackExtendsBox.
|
||||
class MovieExtendsBox : public DefaultContainerImpl {
|
||||
public:
|
||||
MovieExtendsBox(ISOControl* aControl);
|
||||
~MovieExtendsBox();
|
||||
};
|
||||
|
||||
// 14496-12 8.7.5 'Chunk Offset Box'
|
||||
// Box type: 'stco'
|
||||
class ChunkOffsetBox : public FullBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
typedef struct {
|
||||
uint32_t chunk_offset;
|
||||
} tbl;
|
||||
|
||||
uint32_t entry_count;
|
||||
UniquePtr<tbl[]> sample_tbl;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// ChunkOffsetBox methods
|
||||
ChunkOffsetBox(uint32_t aType, ISOControl* aControl);
|
||||
~ChunkOffsetBox();
|
||||
|
||||
protected:
|
||||
uint32_t mTrackType;
|
||||
};
|
||||
|
||||
// 14496-12 8.7.4 'Sample To Chunk Box'
|
||||
// Box type: 'stsc'
|
||||
class SampleToChunkBox : public FullBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
typedef struct {
|
||||
uint32_t first_chunk;
|
||||
uint32_t sample_per_chunk;
|
||||
uint32_t sample_description_index;
|
||||
} tbl;
|
||||
|
||||
uint32_t entry_count;
|
||||
UniquePtr<tbl[]> sample_tbl;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// SampleToChunkBox methods
|
||||
SampleToChunkBox(uint32_t aType, ISOControl* aControl);
|
||||
~SampleToChunkBox();
|
||||
|
||||
protected:
|
||||
uint32_t mTrackType;
|
||||
};
|
||||
|
||||
// 14496-12 8.6.1.2 'Decoding Time to Sample Box'
|
||||
// Box type: 'stts'
|
||||
class TimeToSampleBox : public FullBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
typedef struct {
|
||||
uint32_t sample_count;
|
||||
uint32_t sample_delta;
|
||||
} tbl;
|
||||
|
||||
uint32_t entry_count;
|
||||
UniquePtr<tbl[]> sample_tbl;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// TimeToSampleBox methods
|
||||
TimeToSampleBox(uint32_t aType, ISOControl* aControl);
|
||||
~TimeToSampleBox();
|
||||
|
||||
protected:
|
||||
uint32_t mTrackType;
|
||||
};
|
||||
|
||||
/**
|
||||
* 14496-12 8.5.2 'Sample Description Box'
|
||||
* This is the base class for VisualSampleEntry and AudioSampleEntry.
|
||||
*
|
||||
* This class is for inherited only, it shouldn't be instanced directly.
|
||||
*
|
||||
* The inhertied tree of a codec box should be:
|
||||
*
|
||||
* +--> AVCSampleEntry
|
||||
* +--> VisualSampleEntryBox +
|
||||
* | +--> ...
|
||||
* SampleEntryBox +
|
||||
* | +--> MP4AudioSampleEntry
|
||||
* +--> AudioSampleEntryBox +
|
||||
* +--> AMRSampleEntry
|
||||
* +
|
||||
* +--> ...
|
||||
*
|
||||
*/
|
||||
class SampleEntryBox : public Box {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
uint8_t reserved[6];
|
||||
uint16_t data_reference_index;
|
||||
|
||||
// sampleentrybox methods
|
||||
SampleEntryBox(const nsACString& aFormat, ISOControl* aControl);
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Write() override;
|
||||
|
||||
protected:
|
||||
SampleEntryBox() = delete;
|
||||
};
|
||||
|
||||
// 14496-12 8.5.2 'Sample Description Box'
|
||||
// Box type: 'stsd'
|
||||
class SampleDescriptionBox : public FullBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
uint32_t entry_count;
|
||||
RefPtr<SampleEntryBox> sample_entry_box;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// SampleDescriptionBox methods
|
||||
SampleDescriptionBox(uint32_t aType, ISOControl* aControl);
|
||||
~SampleDescriptionBox();
|
||||
|
||||
protected:
|
||||
nsresult CreateAudioSampleEntry(RefPtr<SampleEntryBox>& aSampleEntry);
|
||||
nsresult CreateVideoSampleEntry(RefPtr<SampleEntryBox>& aSampleEntry);
|
||||
|
||||
uint32_t mTrackType;
|
||||
};
|
||||
|
||||
// 14496-12 8.5.2.2
|
||||
// The base class for audio codec box.
|
||||
// This class is for inherited only, it shouldn't be instanced directly.
|
||||
class AudioSampleEntry : public SampleEntryBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
uint16_t sound_version;
|
||||
uint8_t reserved2[6];
|
||||
uint16_t channels;
|
||||
uint16_t sample_size;
|
||||
uint16_t compressionId;
|
||||
uint16_t packet_size;
|
||||
uint32_t timeScale; // (sample rate of media) <<16
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Write() override;
|
||||
|
||||
~AudioSampleEntry();
|
||||
|
||||
protected:
|
||||
AudioSampleEntry(const nsACString& aFormat, ISOControl* aControl);
|
||||
};
|
||||
|
||||
// 14496-12 8.5.2.2
|
||||
// The base class for video codec box.
|
||||
// This class is for inherited only, it shouldn't be instanced directly.
|
||||
class VisualSampleEntry : public SampleEntryBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
uint8_t reserved[16];
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
|
||||
uint32_t horizresolution; // 72 dpi
|
||||
uint32_t vertresolution; // 72 dpi
|
||||
uint32_t reserved2;
|
||||
uint16_t frame_count; // 1, defined in 14496-12 8.5.2.2
|
||||
|
||||
uint8_t compressorName[32];
|
||||
uint16_t depth; // 0x0018, defined in 14496-12 8.5.2.2;
|
||||
uint16_t pre_defined; // -1, defined in 14496-12 8.5.2.2;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Write() override;
|
||||
|
||||
// VisualSampleEntry methods
|
||||
~VisualSampleEntry();
|
||||
|
||||
protected:
|
||||
VisualSampleEntry(const nsACString& aFormat, ISOControl* aControl);
|
||||
};
|
||||
|
||||
// 14496-12 8.7.3.2 'Sample Size Box'
|
||||
// Box type: 'stsz'
|
||||
class SampleSizeBox : public FullBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
uint32_t sample_size;
|
||||
uint32_t sample_count;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// SampleSizeBox methods
|
||||
SampleSizeBox(ISOControl* aControl);
|
||||
~SampleSizeBox();
|
||||
};
|
||||
|
||||
// 14496-12 8.5.1 'Sample Table Box'
|
||||
// Box type: 'stbl'
|
||||
//
|
||||
// SampleTableBox contains SampleDescriptionBox,
|
||||
// TimeToSampleBox,
|
||||
// SampleToChunkBox,
|
||||
// SampleSizeBox and
|
||||
// ChunkOffsetBox.
|
||||
class SampleTableBox : public DefaultContainerImpl {
|
||||
public:
|
||||
SampleTableBox(uint32_t aType, ISOControl* aControl);
|
||||
~SampleTableBox();
|
||||
};
|
||||
|
||||
// 14496-12 8.7.2 'Data Reference Box'
|
||||
// Box type: 'url '
|
||||
class DataEntryUrlBox : public FullBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
// flags in DataEntryUrlBox::flags
|
||||
const static uint16_t flags_media_at_the_same_file = 0x0001;
|
||||
|
||||
nsCString location;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// DataEntryUrlBox methods
|
||||
DataEntryUrlBox();
|
||||
DataEntryUrlBox(ISOControl* aControl);
|
||||
DataEntryUrlBox(const DataEntryUrlBox& aBox);
|
||||
~DataEntryUrlBox();
|
||||
};
|
||||
|
||||
// 14496-12 8.7.2 'Data Reference Box'
|
||||
// Box type: 'dref'
|
||||
class DataReferenceBox : public FullBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
uint32_t entry_count;
|
||||
nsTArray<nsAutoPtr<DataEntryUrlBox>> urls;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// DataReferenceBox methods
|
||||
DataReferenceBox(ISOControl* aControl);
|
||||
~DataReferenceBox();
|
||||
};
|
||||
|
||||
// 14496-12 8.7.1 'Data Information Box'
|
||||
// Box type: 'dinf'
|
||||
// DataInformationBox contains DataReferenceBox.
|
||||
class DataInformationBox : public DefaultContainerImpl {
|
||||
public:
|
||||
DataInformationBox(ISOControl* aControl);
|
||||
~DataInformationBox();
|
||||
};
|
||||
|
||||
// 14496-12 8.4.5.2 'Video Media Header Box'
|
||||
// Box type: 'vmhd'
|
||||
class VideoMediaHeaderBox : public FullBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
uint16_t graphicsmode;
|
||||
uint16_t opcolor[3];
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// VideoMediaHeaderBox methods
|
||||
VideoMediaHeaderBox(ISOControl* aControl);
|
||||
~VideoMediaHeaderBox();
|
||||
};
|
||||
|
||||
// 14496-12 8.4.5.3 'Sound Media Header Box'
|
||||
// Box type: 'smhd'
|
||||
class SoundMediaHeaderBox : public FullBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
uint16_t balance;
|
||||
uint16_t reserved;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// SoundMediaHeaderBox methods
|
||||
SoundMediaHeaderBox(ISOControl* aControl);
|
||||
~SoundMediaHeaderBox();
|
||||
};
|
||||
|
||||
// 14496-12 8.4.4 'Media Information Box'
|
||||
// Box type: 'minf'
|
||||
// MediaInformationBox contains SoundMediaHeaderBox, DataInformationBox and
|
||||
// SampleTableBox.
|
||||
class MediaInformationBox : public DefaultContainerImpl {
|
||||
public:
|
||||
MediaInformationBox(uint32_t aType, ISOControl* aControl);
|
||||
~MediaInformationBox();
|
||||
|
||||
protected:
|
||||
uint32_t mTrackType;
|
||||
};
|
||||
|
||||
// flags for TrackHeaderBox::flags.
|
||||
#define flags_track_enabled 0x000001
|
||||
#define flags_track_in_movie 0x000002
|
||||
#define flags_track_in_preview 0x000004
|
||||
|
||||
// 14496-12 8.3.2 'Track Header Box'
|
||||
// Box type: 'tkhd'
|
||||
class TrackHeaderBox : public FullBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
// version = 0
|
||||
uint32_t creation_time;
|
||||
uint32_t modification_time;
|
||||
uint32_t track_ID;
|
||||
uint32_t reserved;
|
||||
uint32_t duration;
|
||||
|
||||
uint32_t reserved2[2];
|
||||
uint16_t layer;
|
||||
uint16_t alternate_group;
|
||||
uint16_t volume;
|
||||
uint16_t reserved3;
|
||||
uint32_t matrix[9];
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// TrackHeaderBox methods
|
||||
TrackHeaderBox(uint32_t aType, ISOControl* aControl);
|
||||
~TrackHeaderBox();
|
||||
|
||||
protected:
|
||||
uint32_t mTrackType;
|
||||
};
|
||||
|
||||
// 14496-12 8.4.3 'Handler Reference Box'
|
||||
// Box type: 'hdlr'
|
||||
class HandlerBox : public FullBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
uint32_t pre_defined;
|
||||
uint32_t handler_type;
|
||||
uint32_t reserved[3];
|
||||
nsCString name;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// HandlerBox methods
|
||||
HandlerBox(uint32_t aType, ISOControl* aControl);
|
||||
~HandlerBox();
|
||||
|
||||
protected:
|
||||
uint32_t mTrackType;
|
||||
};
|
||||
|
||||
// 14496-12 8.4.1 'Media Box'
|
||||
// Box type: 'mdia'
|
||||
// MediaBox contains MediaHeaderBox, HandlerBox, and MediaInformationBox.
|
||||
class MediaBox : public DefaultContainerImpl {
|
||||
public:
|
||||
MediaBox(uint32_t aType, ISOControl* aControl);
|
||||
~MediaBox();
|
||||
|
||||
protected:
|
||||
uint32_t mTrackType;
|
||||
};
|
||||
|
||||
}
|
||||
#endif // ISOMediaBoxes_h_
|
||||
|
|
@ -1,229 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ISOMediaWriter.h"
|
||||
#include "ISOControl.h"
|
||||
#include "ISOMediaBoxes.h"
|
||||
#include "ISOTrackMetadata.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "MediaEncoder.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "GeckoProfiler.h"
|
||||
|
||||
#undef LOG
|
||||
#define LOG(args, ...)
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
const static uint32_t FRAG_DURATION = 2 * USECS_PER_S; // microsecond per unit
|
||||
|
||||
ISOMediaWriter::ISOMediaWriter(uint32_t aType, uint32_t aHint)
|
||||
: ContainerWriter()
|
||||
, mState(MUXING_HEAD)
|
||||
, mBlobReady(false)
|
||||
, mType(0)
|
||||
{
|
||||
if (aType & CREATE_AUDIO_TRACK) {
|
||||
mType |= Audio_Track;
|
||||
}
|
||||
if (aType & CREATE_VIDEO_TRACK) {
|
||||
mType |= Video_Track;
|
||||
}
|
||||
mControl = new ISOControl(aHint);
|
||||
MOZ_COUNT_CTOR(ISOMediaWriter);
|
||||
}
|
||||
|
||||
ISOMediaWriter::~ISOMediaWriter()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ISOMediaWriter);
|
||||
}
|
||||
|
||||
nsresult
|
||||
ISOMediaWriter::RunState()
|
||||
{
|
||||
nsresult rv;
|
||||
switch (mState) {
|
||||
case MUXING_HEAD:
|
||||
{
|
||||
rv = mControl->GenerateFtyp();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mControl->GenerateMoov();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mState = MUXING_FRAG;
|
||||
break;
|
||||
}
|
||||
case MUXING_FRAG:
|
||||
{
|
||||
rv = mControl->GenerateMoof(mType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool EOS;
|
||||
if (ReadyToRunState(EOS) && EOS) {
|
||||
mState = MUXING_DONE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MUXING_DONE:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
mBlobReady = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ISOMediaWriter::WriteEncodedTrack(const EncodedFrameContainer& aData,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
PROFILER_LABEL("ISOMediaWriter", "WriteEncodedTrack",
|
||||
js::ProfileEntry::Category::OTHER);
|
||||
// Muxing complete, it doesn't allowed to reentry again.
|
||||
if (mState == MUXING_DONE) {
|
||||
MOZ_ASSERT(false);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
FragmentBuffer* frag = nullptr;
|
||||
uint32_t len = aData.GetEncodedFrames().Length();
|
||||
|
||||
if (!len) {
|
||||
// no frame? why bother to WriteEncodedTrack
|
||||
return NS_OK;
|
||||
}
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
RefPtr<EncodedFrame> frame(aData.GetEncodedFrames()[i]);
|
||||
EncodedFrame::FrameType type = frame->GetFrameType();
|
||||
if (type == EncodedFrame::AAC_AUDIO_FRAME ||
|
||||
type == EncodedFrame::AAC_CSD ||
|
||||
type == EncodedFrame::AMR_AUDIO_FRAME ||
|
||||
type == EncodedFrame::AMR_AUDIO_CSD ||
|
||||
type == EncodedFrame::EVRC_AUDIO_FRAME ||
|
||||
type == EncodedFrame::EVRC_AUDIO_CSD) {
|
||||
frag = mAudioFragmentBuffer;
|
||||
} else if (type == EncodedFrame::AVC_I_FRAME ||
|
||||
type == EncodedFrame::AVC_P_FRAME ||
|
||||
type == EncodedFrame::AVC_B_FRAME ||
|
||||
type == EncodedFrame::AVC_CSD) {
|
||||
frag = mVideoFragmentBuffer;
|
||||
} else {
|
||||
MOZ_ASSERT(0);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
frag->AddFrame(frame);
|
||||
}
|
||||
|
||||
// Encoder should send CSD (codec specific data) frame before sending the
|
||||
// audio/video frames. When CSD data is ready, it is sufficient to generate a
|
||||
// moov data. If encoder doesn't send CSD yet, muxer needs to wait before
|
||||
// generating anything.
|
||||
if (mType & Audio_Track && (!mAudioFragmentBuffer ||
|
||||
!mAudioFragmentBuffer->HasCSD())) {
|
||||
return NS_OK;
|
||||
}
|
||||
if (mType & Video_Track && (!mVideoFragmentBuffer ||
|
||||
!mVideoFragmentBuffer->HasCSD())) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Only one FrameType in EncodedFrameContainer so it doesn't need to be
|
||||
// inside the for-loop.
|
||||
if (frag && (aFlags & END_OF_STREAM)) {
|
||||
frag->SetEndOfStream();
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
bool EOS;
|
||||
if (ReadyToRunState(EOS)) {
|
||||
// Because track encoder won't generate new data after EOS, it needs to make
|
||||
// sure the state reaches MUXING_DONE when EOS is signaled.
|
||||
do {
|
||||
rv = RunState();
|
||||
} while (EOS && mState != MUXING_DONE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
ISOMediaWriter::ReadyToRunState(bool& aEOS)
|
||||
{
|
||||
aEOS = false;
|
||||
bool bReadyToMux = true;
|
||||
if ((mType & Audio_Track) && (mType & Video_Track)) {
|
||||
if (!mAudioFragmentBuffer->HasEnoughData()) {
|
||||
bReadyToMux = false;
|
||||
}
|
||||
if (!mVideoFragmentBuffer->HasEnoughData()) {
|
||||
bReadyToMux = false;
|
||||
}
|
||||
|
||||
if (mAudioFragmentBuffer->EOS() && mVideoFragmentBuffer->EOS()) {
|
||||
aEOS = true;
|
||||
bReadyToMux = true;
|
||||
}
|
||||
} else if (mType == Audio_Track) {
|
||||
if (!mAudioFragmentBuffer->HasEnoughData()) {
|
||||
bReadyToMux = false;
|
||||
}
|
||||
if (mAudioFragmentBuffer->EOS()) {
|
||||
aEOS = true;
|
||||
bReadyToMux = true;
|
||||
}
|
||||
} else if (mType == Video_Track) {
|
||||
if (!mVideoFragmentBuffer->HasEnoughData()) {
|
||||
bReadyToMux = false;
|
||||
}
|
||||
if (mVideoFragmentBuffer->EOS()) {
|
||||
aEOS = true;
|
||||
bReadyToMux = true;
|
||||
}
|
||||
}
|
||||
|
||||
return bReadyToMux;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ISOMediaWriter::GetContainerData(nsTArray<nsTArray<uint8_t>>* aOutputBufs,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
PROFILER_LABEL("ISOMediaWriter", "GetContainerData",
|
||||
js::ProfileEntry::Category::OTHER);
|
||||
if (mBlobReady) {
|
||||
if (mState == MUXING_DONE) {
|
||||
mIsWritingComplete = true;
|
||||
}
|
||||
mBlobReady = false;
|
||||
return mControl->GetBufs(aOutputBufs);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ISOMediaWriter::SetMetadata(TrackMetadataBase* aMetadata)
|
||||
{
|
||||
PROFILER_LABEL("ISOMediaWriter", "SetMetadata",
|
||||
js::ProfileEntry::Category::OTHER);
|
||||
if (aMetadata->GetKind() == TrackMetadataBase::METADATA_AAC ||
|
||||
aMetadata->GetKind() == TrackMetadataBase::METADATA_AMR ||
|
||||
aMetadata->GetKind() == TrackMetadataBase::METADATA_EVRC) {
|
||||
mControl->SetMetadata(aMetadata);
|
||||
mAudioFragmentBuffer = new FragmentBuffer(Audio_Track, FRAG_DURATION);
|
||||
mControl->SetFragment(mAudioFragmentBuffer);
|
||||
return NS_OK;
|
||||
}
|
||||
if (aMetadata->GetKind() == TrackMetadataBase::METADATA_AVC) {
|
||||
mControl->SetMetadata(aMetadata);
|
||||
mVideoFragmentBuffer = new FragmentBuffer(Video_Track, FRAG_DURATION);
|
||||
mControl->SetFragment(mVideoFragmentBuffer);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef ISOMediaWriter_h_
|
||||
#define ISOMediaWriter_h_
|
||||
|
||||
#include "ContainerWriter.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIRunnable.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ISOControl;
|
||||
class FragmentBuffer;
|
||||
|
||||
class ISOMediaWriter : public ContainerWriter
|
||||
{
|
||||
public:
|
||||
// Generate an fragmented MP4 stream, ISO/IEC 14496-12.
|
||||
// Brand names in 'ftyp' box are 'isom' and 'mp42'.
|
||||
const static uint32_t TYPE_FRAG_MP4 = 1 << 0;
|
||||
|
||||
// Generate an fragmented 3GP stream, 3GPP TS 26.244,
|
||||
// '5.4.3 Basic profile'.
|
||||
// Brand names in 'ftyp' box are '3gp9' and 'isom'.
|
||||
const static uint32_t TYPE_FRAG_3GP = 1 << 1;
|
||||
|
||||
// Generate an fragmented 3G2 stream, 3GPP2 C.S0050-B
|
||||
// Brand names in 'ftyp' box are '3g2c' and 'isom'
|
||||
const static uint32_t TYPE_FRAG_3G2 = 1 << 2;
|
||||
|
||||
// aType is the combination of CREATE_AUDIO_TRACK and CREATE_VIDEO_TRACK.
|
||||
// It is a hint to muxer that the output streaming contains audio, video
|
||||
// or both.
|
||||
//
|
||||
// aHint is one of the value in TYPE_XXXXXXXX. It is a hint to muxer what kind
|
||||
// of ISO format should be generated.
|
||||
ISOMediaWriter(uint32_t aType, uint32_t aHint = TYPE_FRAG_MP4);
|
||||
~ISOMediaWriter();
|
||||
|
||||
// ContainerWriter methods
|
||||
nsresult WriteEncodedTrack(const EncodedFrameContainer &aData,
|
||||
uint32_t aFlags = 0) override;
|
||||
|
||||
nsresult GetContainerData(nsTArray<nsTArray<uint8_t>>* aOutputBufs,
|
||||
uint32_t aFlags = 0) override;
|
||||
|
||||
nsresult SetMetadata(TrackMetadataBase* aMetadata) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* The state of each state will generate one or more blob.
|
||||
* Each blob will be a moov, moof, moof... until receiving EOS.
|
||||
* The generated sequence is:
|
||||
*
|
||||
* moov -> moof -> moof -> ... -> moof -> moof
|
||||
*
|
||||
* Following is the details of each state.
|
||||
* MUXING_HEAD:
|
||||
* It collects the metadata to generate a moov. The state transits to
|
||||
* MUXING_HEAD after output moov blob.
|
||||
*
|
||||
* MUXING_FRAG:
|
||||
* It collects enough audio/video data to generate a fragment blob. This
|
||||
* will be repeated until END_OF_STREAM and then transiting to MUXING_DONE.
|
||||
*
|
||||
* MUXING_DONE:
|
||||
* End of ISOMediaWriter life cycle.
|
||||
*/
|
||||
enum MuxState {
|
||||
MUXING_HEAD,
|
||||
MUXING_FRAG,
|
||||
MUXING_DONE,
|
||||
};
|
||||
|
||||
private:
|
||||
nsresult RunState();
|
||||
|
||||
// True if one of following conditions hold:
|
||||
// 1. Audio/Video accumulates enough data to generate a moof.
|
||||
// 2. Get EOS signal.
|
||||
// aEOS will be assigned to true if it gets EOS signal.
|
||||
bool ReadyToRunState(bool& aEOS);
|
||||
|
||||
// The main class to generate and iso box. Its life time is same as
|
||||
// ISOMediaWriter and deleted only if ISOMediaWriter is destroyed.
|
||||
nsAutoPtr<ISOControl> mControl;
|
||||
|
||||
// Buffers to keep audio/video data frames, they are created when metadata is
|
||||
// received. Only one instance for each media type is allowed and they will be
|
||||
// deleted only if ISOMediaWriter is destroyed.
|
||||
nsAutoPtr<FragmentBuffer> mAudioFragmentBuffer;
|
||||
nsAutoPtr<FragmentBuffer> mVideoFragmentBuffer;
|
||||
|
||||
MuxState mState;
|
||||
|
||||
// A flag to indicate the output buffer is ready to blob out.
|
||||
bool mBlobReady;
|
||||
|
||||
// Combination of Audio_Track or Video_Track.
|
||||
uint32_t mType;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // ISOMediaWriter_h_
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef ISOTrackMetadata_h_
|
||||
#define ISOTrackMetadata_h_
|
||||
|
||||
#include "TrackMetadataBase.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class AACTrackMetadata : public AudioTrackMetadata {
|
||||
public:
|
||||
// AudioTrackMetadata members
|
||||
uint32_t GetAudioFrameDuration() override { return mFrameDuration; }
|
||||
uint32_t GetAudioFrameSize() override { return mFrameSize; }
|
||||
uint32_t GetAudioSampleRate() override { return mSampleRate; }
|
||||
uint32_t GetAudioChannels() override { return mChannels; }
|
||||
|
||||
// TrackMetadataBase member
|
||||
MetadataKind GetKind() const override { return METADATA_AAC; }
|
||||
|
||||
// AACTrackMetadata members
|
||||
AACTrackMetadata()
|
||||
: mSampleRate(0)
|
||||
, mFrameDuration(0)
|
||||
, mFrameSize(0)
|
||||
, mChannels(0) {
|
||||
MOZ_COUNT_CTOR(AACTrackMetadata);
|
||||
}
|
||||
~AACTrackMetadata() { MOZ_COUNT_DTOR(AACTrackMetadata); }
|
||||
|
||||
uint32_t mSampleRate; // From 14496-3 table 1.16, it could be 7350 ~ 96000.
|
||||
uint32_t mFrameDuration; // Audio frame duration based on SampleRate.
|
||||
uint32_t mFrameSize; // Audio frame size, 0 is variant size.
|
||||
uint32_t mChannels; // Channel number, it should be 1 or 2.
|
||||
};
|
||||
|
||||
// AVC clock rate is 90k Hz.
|
||||
#define AVC_CLOCK_RATE 90000
|
||||
|
||||
class AVCTrackMetadata : public VideoTrackMetadata {
|
||||
public:
|
||||
// VideoTrackMetadata members
|
||||
uint32_t GetVideoHeight() override { return mHeight; }
|
||||
uint32_t GetVideoWidth() override {return mWidth; }
|
||||
uint32_t GetVideoDisplayHeight() override { return mDisplayHeight; }
|
||||
uint32_t GetVideoDisplayWidth() override { return mDisplayWidth; }
|
||||
uint32_t GetVideoClockRate() override { return AVC_CLOCK_RATE; }
|
||||
uint32_t GetVideoFrameRate() override { return mFrameRate; }
|
||||
|
||||
// TrackMetadataBase member
|
||||
MetadataKind GetKind() const override { return METADATA_AVC; }
|
||||
|
||||
// AVCTrackMetadata
|
||||
AVCTrackMetadata()
|
||||
: mHeight(0)
|
||||
, mWidth(0)
|
||||
, mDisplayHeight(0)
|
||||
, mDisplayWidth(0)
|
||||
, mFrameRate(0) {
|
||||
MOZ_COUNT_CTOR(AVCTrackMetadata);
|
||||
}
|
||||
~AVCTrackMetadata() { MOZ_COUNT_DTOR(AVCTrackMetadata); }
|
||||
|
||||
uint32_t mHeight;
|
||||
uint32_t mWidth;
|
||||
uint32_t mDisplayHeight;
|
||||
uint32_t mDisplayWidth;
|
||||
uint32_t mFrameRate; // frames per second
|
||||
};
|
||||
|
||||
|
||||
// AMR sample rate is 8000 samples/s.
|
||||
#define AMR_SAMPLE_RATE 8000
|
||||
|
||||
// Channel number is always 1.
|
||||
#define AMR_CHANNELS 1
|
||||
|
||||
// AMR speech codec, 3GPP TS 26.071. Encoder and continer support AMR-NB only
|
||||
// currently.
|
||||
class AMRTrackMetadata : public AudioTrackMetadata {
|
||||
public:
|
||||
// AudioTrackMetadata members
|
||||
//
|
||||
// The number of sample sets generates by encoder is variant. So the
|
||||
// frame duration and frame size are both 0.
|
||||
uint32_t GetAudioFrameDuration() override { return 0; }
|
||||
uint32_t GetAudioFrameSize() override { return 0; }
|
||||
uint32_t GetAudioSampleRate() override { return AMR_SAMPLE_RATE; }
|
||||
uint32_t GetAudioChannels() override { return AMR_CHANNELS; }
|
||||
|
||||
// TrackMetadataBase member
|
||||
MetadataKind GetKind() const override { return METADATA_AMR; }
|
||||
|
||||
// AMRTrackMetadata members
|
||||
AMRTrackMetadata() { MOZ_COUNT_CTOR(AMRTrackMetadata); }
|
||||
~AMRTrackMetadata() { MOZ_COUNT_DTOR(AMRTrackMetadata); }
|
||||
};
|
||||
|
||||
// EVRC sample rate is 8000 samples/s.
|
||||
#define EVRC_SAMPLE_RATE 8000
|
||||
|
||||
class EVRCTrackMetadata : public AudioTrackMetadata {
|
||||
public:
|
||||
// AudioTrackMetadata members
|
||||
//
|
||||
// The number of sample sets generates by encoder is variant. So the
|
||||
// frame duration and frame size are both 0.
|
||||
uint32_t GetAudioFrameDuration() override { return 0; }
|
||||
uint32_t GetAudioFrameSize() override { return 0; }
|
||||
uint32_t GetAudioSampleRate() override { return EVRC_SAMPLE_RATE; }
|
||||
uint32_t GetAudioChannels() override { return mChannels; }
|
||||
|
||||
// TrackMetadataBase member
|
||||
MetadataKind GetKind() const override { return METADATA_EVRC; }
|
||||
|
||||
// EVRCTrackMetadata members
|
||||
EVRCTrackMetadata()
|
||||
: mChannels(0) {
|
||||
MOZ_COUNT_CTOR(EVRCTrackMetadata);
|
||||
}
|
||||
~EVRCTrackMetadata() { MOZ_COUNT_DTOR(EVRCTrackMetadata); }
|
||||
|
||||
uint32_t mChannels; // Channel number, it should be 1 or 2.
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ISOTrackMetadata_h_
|
||||
|
|
@ -1,138 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <climits>
|
||||
#include "ISOControl.h"
|
||||
#include "ISOMediaBoxes.h"
|
||||
#include "MP4ESDS.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
nsresult
|
||||
MP4AudioSampleEntry::Generate(uint32_t* aBoxSize)
|
||||
{
|
||||
uint32_t box_size;
|
||||
nsresult rv = es->Generate(&box_size);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
size += box_size;
|
||||
|
||||
*aBoxSize = size;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MP4AudioSampleEntry::Write()
|
||||
{
|
||||
BoxSizeChecker checker(mControl, size);
|
||||
nsresult rv;
|
||||
rv = AudioSampleEntry::Write();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = es->Write();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MP4AudioSampleEntry::MP4AudioSampleEntry(ISOControl* aControl)
|
||||
: AudioSampleEntry(NS_LITERAL_CSTRING("mp4a"), aControl)
|
||||
{
|
||||
es = new ESDBox(aControl);
|
||||
MOZ_COUNT_CTOR(MP4AudioSampleEntry);
|
||||
}
|
||||
|
||||
MP4AudioSampleEntry::~MP4AudioSampleEntry()
|
||||
{
|
||||
MOZ_COUNT_DTOR(MP4AudioSampleEntry);
|
||||
}
|
||||
|
||||
nsresult
|
||||
ESDBox::Generate(uint32_t* aBoxSize)
|
||||
{
|
||||
uint32_t box_size;
|
||||
es_descriptor->Generate(&box_size);
|
||||
size += box_size;
|
||||
*aBoxSize = size;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ESDBox::Write()
|
||||
{
|
||||
WRITE_FULLBOX(mControl, size)
|
||||
es_descriptor->Write();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ESDBox::ESDBox(ISOControl* aControl)
|
||||
: FullBox(NS_LITERAL_CSTRING("esds"), 0, 0, aControl)
|
||||
{
|
||||
es_descriptor = new ES_Descriptor(aControl);
|
||||
MOZ_COUNT_CTOR(ESDBox);
|
||||
}
|
||||
|
||||
ESDBox::~ESDBox()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ESDBox);
|
||||
}
|
||||
|
||||
nsresult
|
||||
ES_Descriptor::Find(const nsACString& aType,
|
||||
nsTArray<RefPtr<MuxerOperation>>& aOperations)
|
||||
{
|
||||
// ES_Descriptor is not a real ISOMediaBox, so we return nothing here.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ES_Descriptor::Write()
|
||||
{
|
||||
mControl->Write(tag);
|
||||
mControl->Write(length);
|
||||
mControl->Write(ES_ID);
|
||||
mControl->WriteBits(streamDependenceFlag.to_ulong(), streamDependenceFlag.size());
|
||||
mControl->WriteBits(URL_Flag.to_ulong(), URL_Flag.size());
|
||||
mControl->WriteBits(reserved.to_ulong(), reserved.size());
|
||||
mControl->WriteBits(streamPriority.to_ulong(), streamPriority.size());
|
||||
mControl->Write(DecodeSpecificInfo.Elements(), DecodeSpecificInfo.Length());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ES_Descriptor::Generate(uint32_t* aBoxSize)
|
||||
{
|
||||
nsresult rv;
|
||||
// 14496-1 '8.3.4 DecoderConfigDescriptor'
|
||||
// 14496-1 '10.2.3 SL Packet Header Configuration'
|
||||
FragmentBuffer* frag = mControl->GetFragment(Audio_Track);
|
||||
rv = frag->GetCSD(DecodeSpecificInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
length = sizeof(ES_ID) + 1;
|
||||
length += DecodeSpecificInfo.Length();
|
||||
|
||||
*aBoxSize = sizeof(tag) + sizeof(length) + length;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ES_Descriptor::ES_Descriptor(ISOControl* aControl)
|
||||
: tag(ESDescrTag)
|
||||
, length(0)
|
||||
, ES_ID(0)
|
||||
, streamDependenceFlag(0)
|
||||
, URL_Flag(0)
|
||||
, reserved(0)
|
||||
, streamPriority(0)
|
||||
, mControl(aControl)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ES_Descriptor);
|
||||
}
|
||||
|
||||
ES_Descriptor::~ES_Descriptor()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ES_Descriptor);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MP4ESDS_h_
|
||||
#define MP4ESDS_h_
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "MuxerOperation.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ISOControl;
|
||||
|
||||
/**
|
||||
* ESDS tag
|
||||
*/
|
||||
#define ESDescrTag 0x03
|
||||
|
||||
/**
|
||||
* 14496-1 '8.3.3 ES_Descriptor'.
|
||||
* It will get DecoderConfigDescriptor and SLConfigDescriptor from
|
||||
* AAC CSD data.
|
||||
*/
|
||||
class ES_Descriptor : public MuxerOperation {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
uint8_t tag; // ESDescrTag
|
||||
uint8_t length;
|
||||
uint16_t ES_ID;
|
||||
std::bitset<1> streamDependenceFlag;
|
||||
std::bitset<1> URL_Flag;
|
||||
std::bitset<1> reserved;
|
||||
std::bitset<5> streamPriority;
|
||||
|
||||
nsTArray<uint8_t> DecodeSpecificInfo;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
nsresult Find(const nsACString& aType,
|
||||
nsTArray<RefPtr<MuxerOperation>>& aOperations) override;
|
||||
|
||||
// ES_Descriptor methods
|
||||
ES_Descriptor(ISOControl* aControl);
|
||||
~ES_Descriptor();
|
||||
|
||||
protected:
|
||||
ISOControl* mControl;
|
||||
};
|
||||
|
||||
// 14496-14 5.6 'Sample Description Boxes'
|
||||
// Box type: 'esds'
|
||||
class ESDBox : public FullBox {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
RefPtr<ES_Descriptor> es_descriptor;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// ESDBox methods
|
||||
ESDBox(ISOControl* aControl);
|
||||
~ESDBox();
|
||||
};
|
||||
|
||||
// 14496-14 5.6 'Sample Description Boxes'
|
||||
// Box type: 'mp4a'
|
||||
class MP4AudioSampleEntry : public AudioSampleEntry {
|
||||
public:
|
||||
// ISO BMFF members
|
||||
RefPtr<ESDBox> es;
|
||||
|
||||
// MuxerOperation methods
|
||||
nsresult Generate(uint32_t* aBoxSize) override;
|
||||
nsresult Write() override;
|
||||
|
||||
// MP4AudioSampleEntry methods
|
||||
MP4AudioSampleEntry(ISOControl* aControl);
|
||||
~MP4AudioSampleEntry();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MP4ESDS_h_
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#ifndef MuxerOperation_h_
|
||||
#define MuxerOperation_h_
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* The interface for ISO box. All Boxes inherit from this interface.
|
||||
* Generate() and Write() are needed to be called to produce a complete box.
|
||||
*
|
||||
* Generate() will generate all the data structures and their size.
|
||||
*
|
||||
* Write() will write all data into muxing output stream (ISOControl actually)
|
||||
* and update the data which can't be known at Generate() (for example, the
|
||||
* offset of the video data in mp4 file).
|
||||
*
|
||||
* ISO base media format is composed of several container boxes and the contained
|
||||
* boxes. The container boxes hold a list of MuxerOperation which is implemented
|
||||
* by contained boxes. The contained boxes will be called via the list.
|
||||
* For example:
|
||||
* MovieBox (container) ---> boxes (array of MuxerOperation)
|
||||
* |---> MovieHeaderBox (full box)
|
||||
* |---> TrakBox (container)
|
||||
* |---> MovieExtendsBox (container)
|
||||
*
|
||||
* The complete box structure can be found at 14496-12 E.2 "The‘isom’brand".
|
||||
*/
|
||||
class MuxerOperation {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MuxerOperation)
|
||||
|
||||
// Generate data of this box and its contained box, and calculate box size.
|
||||
virtual nsresult Generate(uint32_t* aBoxSize) = 0;
|
||||
|
||||
// Write data to stream.
|
||||
virtual nsresult Write() = 0;
|
||||
|
||||
// Find the box type via its name (name is the box type defined in 14496-12;
|
||||
// for example, 'moov' is the name of MovieBox).
|
||||
// It can only look child boxes including itself and the box in the boxes
|
||||
// list if exists. It can't look parent boxes.
|
||||
virtual nsresult Find(const nsACString& aType,
|
||||
nsTArray<RefPtr<MuxerOperation>>& aOperations) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~MuxerOperation() {}
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS += [
|
||||
'ISOMediaWriter.h',
|
||||
'ISOTrackMetadata.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'AMRBox.cpp',
|
||||
'AVCBox.cpp',
|
||||
'EVRCBox.cpp',
|
||||
'ISOControl.cpp',
|
||||
'ISOMediaBoxes.cpp',
|
||||
'ISOMediaWriter.cpp',
|
||||
'MP4ESDS.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
|
@ -7,9 +7,6 @@
|
|||
with Files('*'):
|
||||
BUG_COMPONENT = ('Core', 'Video/Audio: Recording')
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
DIRS += ['fmp4_muxer']
|
||||
|
||||
EXPORTS += [
|
||||
'ContainerWriter.h',
|
||||
'EncodedFrameContainer.h',
|
||||
|
|
@ -37,16 +34,6 @@ FINAL_LIBRARY = 'xul'
|
|||
# These includes are from Android JB, for use of MediaCodec.
|
||||
LOCAL_INCLUDES += ['/ipc/chromium/src']
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['ANDROID_VERSION'] > '15':
|
||||
LOCAL_INCLUDES += [
|
||||
'%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [
|
||||
'frameworks/av/include/media',
|
||||
'frameworks/native/include',
|
||||
'frameworks/native/opengl/include',
|
||||
]
|
||||
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
# Suppress some GCC warnings being treated as errors:
|
||||
|
|
|
|||
|
|
@ -1,667 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GonkOmxPlatformLayer.h"
|
||||
|
||||
#include <binder/MemoryDealer.h>
|
||||
#include <cutils/properties.h>
|
||||
#include <media/IOMX.h>
|
||||
#include <media/stagefright/MediaCodecList.h>
|
||||
#include <utils/List.h>
|
||||
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "mozilla/layers/GrallocTextureClient.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h"
|
||||
#include "mozilla/layers/TextureClientRecycleAllocator.h"
|
||||
|
||||
#include "ImageContainer.h"
|
||||
#include "MediaInfo.h"
|
||||
#include "OmxDataDecoder.h"
|
||||
|
||||
|
||||
#ifdef LOG
|
||||
#undef LOG
|
||||
#endif
|
||||
|
||||
#define LOG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("GonkOmxPlatformLayer(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||
|
||||
#define CHECK_ERR(err) \
|
||||
if (err != OK) { \
|
||||
LOG("error %d at %s", err, __func__); \
|
||||
return NS_ERROR_FAILURE; \
|
||||
} \
|
||||
|
||||
// Android proprietary value.
|
||||
#define ANDROID_OMX_VIDEO_CodingVP8 (static_cast<OMX_VIDEO_CODINGTYPE>(9))
|
||||
|
||||
using namespace android;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// In Gonk, the software component name has prefix "OMX.google". It needs to
|
||||
// have a way to use hardware codec first.
|
||||
bool IsSoftwareCodec(const char* aComponentName)
|
||||
{
|
||||
nsAutoCString str(aComponentName);
|
||||
return (str.Find(NS_LITERAL_CSTRING("OMX.google.")) == -1 ? false : true);
|
||||
}
|
||||
|
||||
bool IsInEmulator()
|
||||
{
|
||||
char propQemu[PROPERTY_VALUE_MAX];
|
||||
property_get("ro.kernel.qemu", propQemu, "");
|
||||
return !strncmp(propQemu, "1", 1);
|
||||
}
|
||||
|
||||
class GonkOmxObserver : public BnOMXObserver {
|
||||
public:
|
||||
void onMessage(const omx_message& aMsg)
|
||||
{
|
||||
switch (aMsg.type) {
|
||||
case omx_message::EVENT:
|
||||
{
|
||||
sp<GonkOmxObserver> self = this;
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self, aMsg] () {
|
||||
if (self->mClient && self->mClient->Event(aMsg.u.event_data.event,
|
||||
aMsg.u.event_data.data1,
|
||||
aMsg.u.event_data.data2))
|
||||
{
|
||||
return;
|
||||
}
|
||||
});
|
||||
mTaskQueue->Dispatch(r.forget());
|
||||
break;
|
||||
}
|
||||
case omx_message::EMPTY_BUFFER_DONE:
|
||||
{
|
||||
sp<GonkOmxObserver> self = this;
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self, aMsg] () {
|
||||
if (!self->mPromiseLayer) {
|
||||
return;
|
||||
}
|
||||
BufferData::BufferID id = (BufferData::BufferID)aMsg.u.buffer_data.buffer;
|
||||
self->mPromiseLayer->EmptyFillBufferDone(OMX_DirInput, id);
|
||||
});
|
||||
mTaskQueue->Dispatch(r.forget());
|
||||
break;
|
||||
}
|
||||
case omx_message::FILL_BUFFER_DONE:
|
||||
{
|
||||
sp<GonkOmxObserver> self = this;
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self, aMsg] () {
|
||||
if (!self->mPromiseLayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: these codes look a little ugly, it'd be better to improve them.
|
||||
RefPtr<BufferData> buf;
|
||||
BufferData::BufferID id = (BufferData::BufferID)aMsg.u.extended_buffer_data.buffer;
|
||||
buf = self->mPromiseLayer->FindAndRemoveBufferHolder(OMX_DirOutput, id);
|
||||
MOZ_RELEASE_ASSERT(buf);
|
||||
GonkBufferData* gonkBuffer = static_cast<GonkBufferData*>(buf.get());
|
||||
|
||||
// Copy the critical information to local buffer.
|
||||
if (gonkBuffer->IsLocalBuffer()) {
|
||||
gonkBuffer->mBuffer->nOffset = aMsg.u.extended_buffer_data.range_offset;
|
||||
gonkBuffer->mBuffer->nFilledLen = aMsg.u.extended_buffer_data.range_length;
|
||||
gonkBuffer->mBuffer->nFlags = aMsg.u.extended_buffer_data.flags;
|
||||
gonkBuffer->mBuffer->nTimeStamp = aMsg.u.extended_buffer_data.timestamp;
|
||||
}
|
||||
self->mPromiseLayer->EmptyFillBufferDone(OMX_DirOutput, buf);
|
||||
});
|
||||
mTaskQueue->Dispatch(r.forget());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
LOG("Unhandle event %d", aMsg.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
|
||||
mPromiseLayer = nullptr;
|
||||
mClient = nullptr;
|
||||
}
|
||||
|
||||
GonkOmxObserver(TaskQueue* aTaskQueue, OmxPromiseLayer* aPromiseLayer, OmxDataDecoder* aDataDecoder)
|
||||
: mTaskQueue(aTaskQueue)
|
||||
, mPromiseLayer(aPromiseLayer)
|
||||
, mClient(aDataDecoder)
|
||||
{}
|
||||
|
||||
protected:
|
||||
RefPtr<TaskQueue> mTaskQueue;
|
||||
// TODO:
|
||||
// we should combine both event handlers into one. And we should provide
|
||||
// an unified way for event handling in OmxPlatformLayer class.
|
||||
RefPtr<OmxPromiseLayer> mPromiseLayer;
|
||||
RefPtr<OmxDataDecoder> mClient;
|
||||
};
|
||||
|
||||
// This class allocates Gralloc buffer and manages TextureClient's recycle.
|
||||
class GonkTextureClientRecycleHandler : public layers::ITextureClientRecycleAllocator
|
||||
{
|
||||
typedef MozPromise<layers::TextureClient*, nsresult, /* IsExclusive = */ true> TextureClientRecyclePromise;
|
||||
|
||||
public:
|
||||
GonkTextureClientRecycleHandler(OMX_VIDEO_PORTDEFINITIONTYPE& aDef)
|
||||
: ITextureClientRecycleAllocator()
|
||||
, mMonitor("GonkTextureClientRecycleHandler")
|
||||
{
|
||||
RefPtr<layers::ImageBridgeChild> bridge = layers::ImageBridgeChild::GetSingleton();
|
||||
|
||||
// Allocate Gralloc texture memory.
|
||||
layers::GrallocTextureData* textureData =
|
||||
layers::GrallocTextureData::Create(gfx::IntSize(aDef.nFrameWidth, aDef.nFrameHeight),
|
||||
aDef.eColorFormat,
|
||||
gfx::BackendType::NONE,
|
||||
GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_READ_OFTEN,
|
||||
bridge);
|
||||
|
||||
mGraphBuffer = textureData->GetGraphicBuffer();
|
||||
MOZ_ASSERT(mGraphBuffer.get());
|
||||
|
||||
mTextureClient =
|
||||
layers::TextureClient::CreateWithData(textureData,
|
||||
layers::TextureFlags::DEALLOCATE_CLIENT | layers::TextureFlags::RECYCLE,
|
||||
bridge);
|
||||
MOZ_ASSERT(mTextureClient);
|
||||
|
||||
mPromise.SetMonitor(&mMonitor);
|
||||
}
|
||||
|
||||
RefPtr<TextureClientRecyclePromise> WaitforRecycle()
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
MOZ_ASSERT(!!mGraphBuffer.get());
|
||||
|
||||
mTextureClient->SetRecycleAllocator(this);
|
||||
return mPromise.Ensure(__func__);
|
||||
}
|
||||
|
||||
// DO NOT use smart pointer to receive TextureClient; otherwise it will
|
||||
// distrupt the reference count.
|
||||
layers::TextureClient* GetTextureClient()
|
||||
{
|
||||
return mTextureClient;
|
||||
}
|
||||
|
||||
GraphicBuffer* GetGraphicBuffer()
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
return mGraphBuffer.get();
|
||||
}
|
||||
|
||||
// This function is called from layers thread.
|
||||
void RecycleTextureClient(layers::TextureClient* aClient) override
|
||||
{
|
||||
MOZ_ASSERT(mTextureClient == aClient);
|
||||
|
||||
// Clearing the recycle allocator drops a reference, so make sure we stay alive
|
||||
// for the duration of this function.
|
||||
RefPtr<GonkTextureClientRecycleHandler> kungFuDeathGrip(this);
|
||||
aClient->SetRecycleAllocator(nullptr);
|
||||
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
mPromise.ResolveIfExists(mTextureClient, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
|
||||
mPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
|
||||
|
||||
// DO NOT clear TextureClient here.
|
||||
// The ref count could be 1 and RecycleCallback will be called if we clear
|
||||
// the ref count here. That breaks the whole mechanism. (RecycleCallback
|
||||
// should be called from layers)
|
||||
mGraphBuffer = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
// Because TextureClient calls RecycleCallbackl when ref count is 1, so we
|
||||
// should hold only one reference here and use raw pointer when out of this
|
||||
// class.
|
||||
RefPtr<layers::TextureClient> mTextureClient;
|
||||
|
||||
// It is protected by mMonitor.
|
||||
sp<android::GraphicBuffer> mGraphBuffer;
|
||||
|
||||
// It is protected by mMonitor.
|
||||
MozPromiseHolder<TextureClientRecyclePromise> mPromise;
|
||||
|
||||
Monitor mMonitor;
|
||||
};
|
||||
|
||||
GonkBufferData::GonkBufferData(bool aLiveInLocal,
|
||||
GonkOmxPlatformLayer* aGonkPlatformLayer)
|
||||
: BufferData(nullptr)
|
||||
, mId(0)
|
||||
, mGonkPlatformLayer(aGonkPlatformLayer)
|
||||
{
|
||||
if (!aLiveInLocal) {
|
||||
mMirrorBuffer = new OMX_BUFFERHEADERTYPE;
|
||||
PodZero(mMirrorBuffer.get());
|
||||
mBuffer = mMirrorBuffer.get();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GonkBufferData::ReleaseBuffer()
|
||||
{
|
||||
if (mTextureClientRecycleHandler) {
|
||||
mTextureClientRecycleHandler->Shutdown();
|
||||
mTextureClientRecycleHandler = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkBufferData::InitSharedMemory(android::IMemory* aMemory)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(mMirrorBuffer.get());
|
||||
|
||||
// aMemory is a IPC memory, it is safe to use it here.
|
||||
mBuffer->pBuffer = (OMX_U8*)aMemory->pointer();
|
||||
mBuffer->nAllocLen = aMemory->size();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkBufferData::InitLocalBuffer(IOMX::buffer_id aId)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!mMirrorBuffer.get());
|
||||
|
||||
mBuffer = (OMX_BUFFERHEADERTYPE*)aId;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkBufferData::InitGraphicBuffer(OMX_VIDEO_PORTDEFINITIONTYPE& aDef)
|
||||
{
|
||||
mTextureClientRecycleHandler = new GonkTextureClientRecycleHandler(aDef);
|
||||
|
||||
if (!mTextureClientRecycleHandler->GetGraphicBuffer()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<MediaData>
|
||||
GonkBufferData::GetPlatformMediaData()
|
||||
{
|
||||
if (mGonkPlatformLayer->GetTrackInfo()->GetAsAudioInfo()) {
|
||||
// This is audio decoding.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mTextureClientRecycleHandler) {
|
||||
// There is no GraphicBuffer, it should fallback to normal YUV420 VideoData.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VideoInfo info(*mGonkPlatformLayer->GetTrackInfo()->GetAsVideoInfo());
|
||||
RefPtr<VideoData> data =
|
||||
VideoData::CreateAndCopyIntoTextureClient(info,
|
||||
0,
|
||||
mBuffer->nTimeStamp,
|
||||
1,
|
||||
mTextureClientRecycleHandler->GetTextureClient(),
|
||||
false,
|
||||
0,
|
||||
info.ImageRect());
|
||||
LOG("%p, disp width %d, height %d, pic width %d, height %d, time %ld",
|
||||
this, info.mDisplay.width, info.mDisplay.height,
|
||||
info.mImage.width, info.mImage.height, mBuffer->nTimeStamp);
|
||||
|
||||
// Get TextureClient Promise here to wait for resolved.
|
||||
RefPtr<GonkBufferData> self(this);
|
||||
mTextureClientRecycleHandler->WaitforRecycle()
|
||||
->Then(mGonkPlatformLayer->GetTaskQueue(), __func__,
|
||||
[self] () {
|
||||
self->mPromise.ResolveIfExists(self, __func__);
|
||||
},
|
||||
[self] () {
|
||||
OmxBufferFailureHolder failure(OMX_ErrorUndefined, self);
|
||||
self->mPromise.RejectIfExists(failure, __func__);
|
||||
});
|
||||
|
||||
return data.forget();
|
||||
}
|
||||
|
||||
GonkOmxPlatformLayer::GonkOmxPlatformLayer(OmxDataDecoder* aDataDecoder,
|
||||
OmxPromiseLayer* aPromiseLayer,
|
||||
TaskQueue* aTaskQueue,
|
||||
layers::ImageContainer* aImageContainer)
|
||||
: mTaskQueue(aTaskQueue)
|
||||
, mImageContainer(aImageContainer)
|
||||
, mNode(0)
|
||||
{
|
||||
mOmxObserver = new GonkOmxObserver(mTaskQueue, aPromiseLayer, aDataDecoder);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkOmxPlatformLayer::AllocateOmxBuffer(OMX_DIRTYPE aType,
|
||||
BUFFERLIST* aBufferList)
|
||||
{
|
||||
MOZ_ASSERT(!mMemoryDealer[aType].get());
|
||||
|
||||
// Get port definition.
|
||||
OMX_PARAM_PORTDEFINITIONTYPE def;
|
||||
nsTArray<uint32_t> portindex;
|
||||
GetPortIndices(portindex);
|
||||
for (auto idx : portindex) {
|
||||
InitOmxParameter(&def);
|
||||
def.nPortIndex = idx;
|
||||
|
||||
OMX_ERRORTYPE err = GetParameter(OMX_IndexParamPortDefinition,
|
||||
&def,
|
||||
sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
|
||||
if (err != OMX_ErrorNone) {
|
||||
return NS_ERROR_FAILURE;
|
||||
} else if (def.eDir == aType) {
|
||||
LOG("Get OMX_IndexParamPortDefinition: port: %d, type: %d", def.nPortIndex, def.eDir);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t t = 0;
|
||||
|
||||
// Configure video output GraphicBuffer for video decoding acceleration.
|
||||
bool useGralloc = false;
|
||||
if (aType == OMX_DirOutput && mQuirks.test(kRequiresAllocateBufferOnOutputPorts) &&
|
||||
(def.eDomain == OMX_PortDomainVideo)) {
|
||||
if (NS_FAILED(EnableOmxGraphicBufferPort(def))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
LOG("Enable OMX GraphicBuffer port, number %d, width %d, height %d", def.nBufferCountActual,
|
||||
def.format.video.nFrameWidth, def.format.video.nFrameHeight);
|
||||
|
||||
useGralloc = true;
|
||||
|
||||
t = 1024; // MemoryDealer doesn't like 0, it's just for MemoryDealer happy.
|
||||
} else {
|
||||
t = def.nBufferCountActual * def.nBufferSize;
|
||||
LOG("Buffer count %d, buffer size %d", def.nBufferCountActual, def.nBufferSize);
|
||||
}
|
||||
|
||||
bool liveinlocal = mOmx->livesLocally(mNode, getpid());
|
||||
|
||||
// MemoryDealer is a IPC buffer allocator in Gonk because IOMX is actually
|
||||
// lives in mediaserver.
|
||||
mMemoryDealer[aType] = new MemoryDealer(t, "Gecko-OMX");
|
||||
for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
|
||||
RefPtr<GonkBufferData> buffer;
|
||||
IOMX::buffer_id bufferID;
|
||||
status_t st;
|
||||
nsresult rv;
|
||||
|
||||
buffer = new GonkBufferData(liveinlocal, this);
|
||||
if (useGralloc) {
|
||||
// Buffer is lived remotely. Use GraphicBuffer for decoded video frame display.
|
||||
rv = buffer->InitGraphicBuffer(def.format.video);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
st = mOmx->useGraphicBuffer(mNode,
|
||||
def.nPortIndex,
|
||||
buffer->mTextureClientRecycleHandler->GetGraphicBuffer(),
|
||||
&bufferID);
|
||||
CHECK_ERR(st);
|
||||
} else {
|
||||
sp<IMemory> mem = mMemoryDealer[aType]->allocate(def.nBufferSize);
|
||||
MOZ_ASSERT(mem.get());
|
||||
|
||||
if ((mQuirks.test(kRequiresAllocateBufferOnInputPorts) && aType == OMX_DirInput) ||
|
||||
(mQuirks.test(kRequiresAllocateBufferOnOutputPorts) && aType == OMX_DirOutput)) {
|
||||
// Buffer is lived remotely. We allocate a local OMX_BUFFERHEADERTYPE
|
||||
// as the mirror of the remote OMX_BUFFERHEADERTYPE.
|
||||
st = mOmx->allocateBufferWithBackup(mNode, aType, mem, &bufferID);
|
||||
CHECK_ERR(st);
|
||||
rv = buffer->InitSharedMemory(mem.get());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
// Buffer is lived locally, bufferID is the actually OMX_BUFFERHEADERTYPE
|
||||
// pointer.
|
||||
st = mOmx->useBuffer(mNode, aType, mem, &bufferID);
|
||||
CHECK_ERR(st);
|
||||
rv = buffer->InitLocalBuffer(bufferID);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
rv = buffer->SetBufferId(bufferID);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aBufferList->AppendElement(buffer);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkOmxPlatformLayer::ReleaseOmxBuffer(OMX_DIRTYPE aType,
|
||||
BUFFERLIST* aBufferList)
|
||||
{
|
||||
status_t st;
|
||||
uint32_t len = aBufferList->Length();
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
GonkBufferData* buffer = static_cast<GonkBufferData*>(aBufferList->ElementAt(i).get());
|
||||
IOMX::buffer_id id = (OMX_BUFFERHEADERTYPE*) buffer->ID();
|
||||
st = mOmx->freeBuffer(mNode, aType, id);
|
||||
if (st != OK) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
buffer->ReleaseBuffer();
|
||||
}
|
||||
aBufferList->Clear();
|
||||
mMemoryDealer[aType].clear();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkOmxPlatformLayer::EnableOmxGraphicBufferPort(OMX_PARAM_PORTDEFINITIONTYPE& aDef)
|
||||
{
|
||||
status_t st;
|
||||
|
||||
st = mOmx->enableGraphicBuffers(mNode, aDef.nPortIndex, OMX_TRUE);
|
||||
CHECK_ERR(st);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
OMX_ERRORTYPE
|
||||
GonkOmxPlatformLayer::GetState(OMX_STATETYPE* aType)
|
||||
{
|
||||
return (OMX_ERRORTYPE)mOmx->getState(mNode, aType);
|
||||
}
|
||||
|
||||
OMX_ERRORTYPE
|
||||
GonkOmxPlatformLayer::GetParameter(OMX_INDEXTYPE aParamIndex,
|
||||
OMX_PTR aComponentParameterStructure,
|
||||
OMX_U32 aComponentParameterSize)
|
||||
{
|
||||
return (OMX_ERRORTYPE)mOmx->getParameter(mNode,
|
||||
aParamIndex,
|
||||
aComponentParameterStructure,
|
||||
aComponentParameterSize);
|
||||
}
|
||||
|
||||
OMX_ERRORTYPE
|
||||
GonkOmxPlatformLayer::SetParameter(OMX_INDEXTYPE aParamIndex,
|
||||
OMX_PTR aComponentParameterStructure,
|
||||
OMX_U32 aComponentParameterSize)
|
||||
{
|
||||
return (OMX_ERRORTYPE)mOmx->setParameter(mNode,
|
||||
aParamIndex,
|
||||
aComponentParameterStructure,
|
||||
aComponentParameterSize);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkOmxPlatformLayer::Shutdown()
|
||||
{
|
||||
mOmx->freeNode(mNode);
|
||||
mOmxObserver->Shutdown();
|
||||
mOmxObserver = nullptr;
|
||||
mOmxClient.disconnect();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
OMX_ERRORTYPE
|
||||
GonkOmxPlatformLayer::InitOmxToStateLoaded(const TrackInfo* aInfo)
|
||||
{
|
||||
mInfo = aInfo;
|
||||
status_t err = mOmxClient.connect();
|
||||
if (err != OK) {
|
||||
return OMX_ErrorUndefined;
|
||||
}
|
||||
mOmx = mOmxClient.interface();
|
||||
if (!mOmx.get()) {
|
||||
return OMX_ErrorUndefined;
|
||||
}
|
||||
|
||||
LOG("find componenet for mime type %s", mInfo->mMimeType.Data());
|
||||
|
||||
nsTArray<ComponentInfo> components;
|
||||
if (FindComponents(mInfo->mMimeType, &components)) {
|
||||
for (auto comp : components) {
|
||||
if (LoadComponent(comp)) {
|
||||
return OMX_ErrorNone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG("no component is loaded");
|
||||
return OMX_ErrorUndefined;
|
||||
}
|
||||
|
||||
OMX_ERRORTYPE
|
||||
GonkOmxPlatformLayer::EmptyThisBuffer(BufferData* aData)
|
||||
{
|
||||
return (OMX_ERRORTYPE)mOmx->emptyBuffer(mNode,
|
||||
(IOMX::buffer_id)aData->ID(),
|
||||
aData->mBuffer->nOffset,
|
||||
aData->mBuffer->nFilledLen,
|
||||
aData->mBuffer->nFlags,
|
||||
aData->mBuffer->nTimeStamp);
|
||||
}
|
||||
|
||||
OMX_ERRORTYPE
|
||||
GonkOmxPlatformLayer::FillThisBuffer(BufferData* aData)
|
||||
{
|
||||
return (OMX_ERRORTYPE)mOmx->fillBuffer(mNode, (IOMX::buffer_id)aData->ID());
|
||||
}
|
||||
|
||||
OMX_ERRORTYPE
|
||||
GonkOmxPlatformLayer::SendCommand(OMX_COMMANDTYPE aCmd,
|
||||
OMX_U32 aParam1,
|
||||
OMX_PTR aCmdData)
|
||||
{
|
||||
return (OMX_ERRORTYPE)mOmx->sendCommand(mNode, aCmd, aParam1);
|
||||
}
|
||||
|
||||
bool
|
||||
GonkOmxPlatformLayer::LoadComponent(const ComponentInfo& aComponent)
|
||||
{
|
||||
status_t err = mOmx->allocateNode(aComponent.mName, mOmxObserver, &mNode);
|
||||
if (err == OK) {
|
||||
mQuirks = aComponent.mQuirks;
|
||||
LOG("Load OpenMax component %s, alloc input %d, alloc output %d, live locally %d",
|
||||
aComponent.mName, mQuirks.test(kRequiresAllocateBufferOnInputPorts),
|
||||
mQuirks.test(kRequiresAllocateBufferOnOutputPorts),
|
||||
mOmx->livesLocally(mNode, getpid()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
layers::ImageContainer*
|
||||
GonkOmxPlatformLayer::GetImageContainer()
|
||||
{
|
||||
return mImageContainer;
|
||||
}
|
||||
|
||||
const TrackInfo*
|
||||
GonkOmxPlatformLayer::GetTrackInfo()
|
||||
{
|
||||
return mInfo;
|
||||
}
|
||||
|
||||
bool
|
||||
GonkOmxPlatformLayer::FindComponents(const nsACString& aMimeType,
|
||||
nsTArray<ComponentInfo>* aComponents)
|
||||
{
|
||||
static const MediaCodecList* codecs = MediaCodecList::getInstance();
|
||||
|
||||
bool useHardwareCodecOnly = false;
|
||||
|
||||
// H264 and H263 has different profiles, software codec doesn't support high profile.
|
||||
// So we use hardware codec only.
|
||||
if (!IsInEmulator() &&
|
||||
(aMimeType.EqualsLiteral("video/avc") ||
|
||||
aMimeType.EqualsLiteral("video/mp4") ||
|
||||
aMimeType.EqualsLiteral("video/mp4v-es") ||
|
||||
aMimeType.EqualsLiteral("video/3gp"))) {
|
||||
useHardwareCodecOnly = true;
|
||||
}
|
||||
|
||||
const char* mime = aMimeType.Data();
|
||||
// Translate VP8 MIME type to Android format.
|
||||
if (aMimeType.EqualsLiteral("video/webm; codecs=vp8")) {
|
||||
mime = "video/x-vnd.on2.vp8";
|
||||
}
|
||||
|
||||
size_t start = 0;
|
||||
bool found = false;
|
||||
while (true) {
|
||||
ssize_t index = codecs->findCodecByType(mime, false /* encoder */, start);
|
||||
if (index < 0) {
|
||||
break;
|
||||
}
|
||||
start = index + 1;
|
||||
|
||||
const char* name = codecs->getCodecName(index);
|
||||
if (IsSoftwareCodec(name) && useHardwareCodecOnly) {
|
||||
continue;
|
||||
}
|
||||
|
||||
found = true;
|
||||
|
||||
if (!aComponents) {
|
||||
continue;
|
||||
}
|
||||
ComponentInfo* comp = aComponents->AppendElement();
|
||||
comp->mName = name;
|
||||
if (codecs->codecHasQuirk(index, "requires-allocate-on-input-ports")) {
|
||||
comp->mQuirks.set(kRequiresAllocateBufferOnInputPorts);
|
||||
}
|
||||
if (codecs->codecHasQuirk(index, "requires-allocate-on-output-ports")) {
|
||||
comp->mQuirks.set(kRequiresAllocateBufferOnOutputPorts);
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
OMX_VIDEO_CODINGTYPE
|
||||
GonkOmxPlatformLayer::CompressionFormat()
|
||||
{
|
||||
MOZ_ASSERT(mInfo);
|
||||
|
||||
return mInfo->mMimeType.EqualsLiteral("video/webm; codecs=vp8") ?
|
||||
ANDROID_OMX_VIDEO_CodingVP8 : OmxPlatformLayer::CompressionFormat();
|
||||
}
|
||||
|
||||
} // mozilla
|
||||
|
|
@ -1,205 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#if !defined(GonkOmxPlatformLayer_h_)
|
||||
#define GonkOmxPlatformLayer_h_
|
||||
|
||||
#pragma GCC visibility push(default)
|
||||
|
||||
#include <bitset>
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <media/stagefright/OMXClient.h>
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
#include "OMX_Component.h"
|
||||
|
||||
#include "OmxPlatformLayer.h"
|
||||
|
||||
class nsACString;
|
||||
|
||||
namespace android {
|
||||
class IMemory;
|
||||
class MemoryDealer;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class GonkOmxObserver;
|
||||
class GonkOmxPlatformLayer;
|
||||
class GonkTextureClientRecycleHandler;
|
||||
|
||||
/*
|
||||
* Due to Android's omx node could live in local process (client) or remote
|
||||
* process (mediaserver). And there are 3 kinds of buffer in Android OMX.
|
||||
*
|
||||
* 1.
|
||||
* When buffer is in local process, the IOMX::buffer_id is OMX_BUFFERHEADERTYPE
|
||||
* pointer actually, it is safe to use it directly.
|
||||
*
|
||||
* 2.
|
||||
* When buffer is in remote process, the OMX_BUFFERHEADERTYPE pointer is 'IN' the
|
||||
* remote process. It can't be used in local process, so here it allocates a
|
||||
* local OMX_BUFFERHEADERTYPE. The raw/decoded data is in the android shared
|
||||
* memory, IMemory.
|
||||
*
|
||||
* 3.
|
||||
* When buffer is in remote process for the display output port. It uses
|
||||
* GraphicBuffer to accelerate the decoding and display.
|
||||
*
|
||||
*/
|
||||
class GonkBufferData : public OmxPromiseLayer::BufferData {
|
||||
protected:
|
||||
virtual ~GonkBufferData() {}
|
||||
|
||||
public:
|
||||
GonkBufferData(bool aLiveInLocal,
|
||||
GonkOmxPlatformLayer* aLayer);
|
||||
|
||||
BufferID ID() override
|
||||
{
|
||||
return mId;
|
||||
}
|
||||
|
||||
already_AddRefed<MediaData> GetPlatformMediaData() override;
|
||||
|
||||
bool IsLocalBuffer()
|
||||
{
|
||||
return !!mMirrorBuffer.get();
|
||||
}
|
||||
|
||||
void ReleaseBuffer();
|
||||
|
||||
nsresult SetBufferId(android::IOMX::buffer_id aId)
|
||||
{
|
||||
mId = aId;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// The mBuffer is in local process. And aId is actually the OMX_BUFFERHEADERTYPE
|
||||
// pointer. It doesn't need a mirror buffer.
|
||||
nsresult InitLocalBuffer(android::IOMX::buffer_id aId);
|
||||
|
||||
// aMemory is an IPC based memory which will be used as the pBuffer in
|
||||
// mBuffer. And the mBuffer will be the mirror OMX_BUFFERHEADERTYPE
|
||||
// of the one in the remote process.
|
||||
nsresult InitSharedMemory(android::IMemory* aMemory);
|
||||
|
||||
// GraphicBuffer is for video decoding acceleration on output port.
|
||||
// Then mBuffer is the mirror OMX_BUFFERHEADERTYPE of the one in the remote
|
||||
// process.
|
||||
nsresult InitGraphicBuffer(OMX_VIDEO_PORTDEFINITIONTYPE& aDef);
|
||||
|
||||
// Android OMX uses this id to pass the buffer between OMX component and
|
||||
// client.
|
||||
android::IOMX::buffer_id mId;
|
||||
|
||||
// mMirrorBuffer are used only when the omx node is in mediaserver.
|
||||
// Due to IPC problem, the mId is the OMX_BUFFERHEADERTYPE address in mediaserver.
|
||||
// It can't mapping to client process, so we need a local OMX_BUFFERHEADERTYPE
|
||||
// here to mirror the remote OMX_BUFFERHEADERTYPE in mediaserver.
|
||||
nsAutoPtr<OMX_BUFFERHEADERTYPE> mMirrorBuffer;
|
||||
|
||||
// It creates GraphicBuffer and manages TextureClient.
|
||||
RefPtr<GonkTextureClientRecycleHandler> mTextureClientRecycleHandler;
|
||||
|
||||
GonkOmxPlatformLayer* mGonkPlatformLayer;
|
||||
};
|
||||
|
||||
class GonkOmxPlatformLayer : public OmxPlatformLayer {
|
||||
public:
|
||||
enum {
|
||||
kRequiresAllocateBufferOnInputPorts = 0,
|
||||
kRequiresAllocateBufferOnOutputPorts,
|
||||
QUIRKS,
|
||||
};
|
||||
typedef std::bitset<QUIRKS> Quirks;
|
||||
|
||||
struct ComponentInfo {
|
||||
const char* mName;
|
||||
Quirks mQuirks;
|
||||
};
|
||||
|
||||
GonkOmxPlatformLayer(OmxDataDecoder* aDataDecoder,
|
||||
OmxPromiseLayer* aPromiseLayer,
|
||||
TaskQueue* aTaskQueue,
|
||||
layers::ImageContainer* aImageContainer);
|
||||
|
||||
nsresult AllocateOmxBuffer(OMX_DIRTYPE aType, BUFFERLIST* aBufferList) override;
|
||||
|
||||
nsresult ReleaseOmxBuffer(OMX_DIRTYPE aType, BUFFERLIST* aBufferList) override;
|
||||
|
||||
OMX_ERRORTYPE GetState(OMX_STATETYPE* aType) override;
|
||||
|
||||
OMX_ERRORTYPE GetParameter(OMX_INDEXTYPE aParamIndex,
|
||||
OMX_PTR aComponentParameterStructure,
|
||||
OMX_U32 aComponentParameterSize) override;
|
||||
|
||||
OMX_ERRORTYPE SetParameter(OMX_INDEXTYPE nIndex,
|
||||
OMX_PTR aComponentParameterStructure,
|
||||
OMX_U32 aComponentParameterSize) override;
|
||||
|
||||
OMX_ERRORTYPE InitOmxToStateLoaded(const TrackInfo* aInfo) override;
|
||||
|
||||
OMX_ERRORTYPE EmptyThisBuffer(BufferData* aData) override;
|
||||
|
||||
OMX_ERRORTYPE FillThisBuffer(BufferData* aData) override;
|
||||
|
||||
OMX_ERRORTYPE SendCommand(OMX_COMMANDTYPE aCmd,
|
||||
OMX_U32 aParam1,
|
||||
OMX_PTR aCmdData) override;
|
||||
|
||||
nsresult Shutdown() override;
|
||||
|
||||
static bool FindComponents(const nsACString& aMimeType,
|
||||
nsTArray<ComponentInfo>* aComponents = nullptr);
|
||||
|
||||
// Android/QCOM decoder uses its own OMX_VIDEO_CodingVP8 definition in
|
||||
// frameworks/native/media/include/openmax/OMX_Video.h, not the one defined
|
||||
// in OpenMAX v1.1.2 OMX_VideoExt.h
|
||||
OMX_VIDEO_CODINGTYPE CompressionFormat() override;
|
||||
|
||||
protected:
|
||||
friend GonkBufferData;
|
||||
|
||||
layers::ImageContainer* GetImageContainer();
|
||||
|
||||
const TrackInfo* GetTrackInfo();
|
||||
|
||||
TaskQueue* GetTaskQueue()
|
||||
{
|
||||
return mTaskQueue;
|
||||
}
|
||||
|
||||
nsresult EnableOmxGraphicBufferPort(OMX_PARAM_PORTDEFINITIONTYPE& aDef);
|
||||
|
||||
bool LoadComponent(const ComponentInfo& aComponent);
|
||||
|
||||
friend class GonkOmxObserver;
|
||||
|
||||
RefPtr<TaskQueue> mTaskQueue;
|
||||
|
||||
RefPtr<layers::ImageContainer> mImageContainer;
|
||||
|
||||
// OMX_DirInput is 0, OMX_DirOutput is 1.
|
||||
android::sp<android::MemoryDealer> mMemoryDealer[2];
|
||||
|
||||
android::sp<GonkOmxObserver> mOmxObserver;
|
||||
|
||||
android::sp<android::IOMX> mOmx;
|
||||
|
||||
android::IOMX::node_id mNode;
|
||||
|
||||
android::OMXClient mOmxClient;
|
||||
|
||||
Quirks mQuirks;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#pragma GCC visibility pop
|
||||
|
||||
#endif // GonkOmxPlatformLayer_h_
|
||||
|
|
@ -21,29 +21,6 @@ LOCAL_INCLUDES += [
|
|||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and (CONFIG['ANDROID_VERSION'] == '19' or CONFIG['ANDROID_VERSION'] == '20'):
|
||||
# Suppress some GCC/clang warnings being treated as errors:
|
||||
# - about attributes on forward declarations for types that are already
|
||||
# defined, which complains about an important MOZ_EXPORT for android::AString
|
||||
# - about multi-character constants which are used in codec-related code
|
||||
if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
|
||||
CXXFLAGS += [
|
||||
'-Wno-error=attributes',
|
||||
'-Wno-error=multichar'
|
||||
]
|
||||
CXXFLAGS += [
|
||||
'-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [
|
||||
'frameworks/base/include/binder',
|
||||
'frameworks/base/include/utils',
|
||||
]
|
||||
]
|
||||
UNIFIED_SOURCES += [
|
||||
'GonkOmxPlatformLayer.cpp',
|
||||
]
|
||||
EXTRA_DSO_LDOPTS += [
|
||||
'-libbinder',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
if CONFIG['OS_TARGET'] != 'WINNT' and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
|
||||
if CONFIG['OS_TARGET'] != 'WINNT':
|
||||
Library('media_standalone')
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
|
|
|
|||
|
|
@ -42,16 +42,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
|||
UNIFIED_SOURCES += ['OSXRunLoopSingleton.cpp']
|
||||
EXPORTS += ['OSXRunLoopSingleton.h']
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
if CONFIG['ANDROID_VERSION'] >= '17':
|
||||
LOCAL_INCLUDES += [
|
||||
'%' + '%s/frameworks/wilhelm/include' % CONFIG['ANDROID_SOURCE'],
|
||||
]
|
||||
else:
|
||||
LOCAL_INCLUDES += [
|
||||
'%' + '%s/system/media/wilhelm/include' % CONFIG['ANDROID_SOURCE'],
|
||||
]
|
||||
|
||||
if CONFIG['_MSC_VER']:
|
||||
DEFINES['__PRETTY_FUNCTION__'] = '__FUNCSIG__'
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue