зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1150853: Part2. Use new MediaRawObject across the board. r=cpearce.
This commit is contained in:
Родитель
a441d92aa3
Коммит
e6858f0af5
|
@ -17,6 +17,7 @@
|
|||
#include "prenv.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/CDMCallbackProxy.h"
|
||||
#include "MediaData.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -613,7 +614,7 @@ CDMProxy::Capabilites() {
|
|||
}
|
||||
|
||||
void
|
||||
CDMProxy::Decrypt(mp4_demuxer::MP4Sample* aSample,
|
||||
CDMProxy::Decrypt(MediaRawData* aSample,
|
||||
DecryptionClient* aClient)
|
||||
{
|
||||
nsAutoPtr<DecryptJob> job(new DecryptJob(aSample, aClient));
|
||||
|
@ -636,8 +637,8 @@ CDMProxy::gmp_Decrypt(nsAutoPtr<DecryptJob> aJob)
|
|||
|
||||
aJob->mId = ++mDecryptionJobCount;
|
||||
nsTArray<uint8_t> data;
|
||||
data.AppendElements(aJob->mSample->data, aJob->mSample->size);
|
||||
mCDM->Decrypt(aJob->mId, aJob->mSample->crypto, data);
|
||||
data.AppendElements(aJob->mSample->mData, aJob->mSample->mSize);
|
||||
mCDM->Decrypt(aJob->mId, aJob->mSample->mCrypto, data);
|
||||
mDecryptionJobs.AppendElement(aJob.forget());
|
||||
}
|
||||
|
||||
|
@ -650,19 +651,20 @@ CDMProxy::gmp_Decrypted(uint32_t aId,
|
|||
for (size_t i = 0; i < mDecryptionJobs.Length(); i++) {
|
||||
DecryptJob* job = mDecryptionJobs[i];
|
||||
if (job->mId == aId) {
|
||||
if (aDecryptedData.Length() != job->mSample->size) {
|
||||
if (aDecryptedData.Length() != job->mSample->mSize) {
|
||||
NS_WARNING("CDM returned incorrect number of decrypted bytes");
|
||||
}
|
||||
if (GMP_SUCCEEDED(aResult)) {
|
||||
PodCopy(job->mSample->data,
|
||||
nsAutoPtr<MediaRawDataWriter> writer(job->mSample->CreateWriter());
|
||||
PodCopy(writer->mData,
|
||||
aDecryptedData.Elements(),
|
||||
std::min<size_t>(aDecryptedData.Length(), job->mSample->size));
|
||||
job->mClient->Decrypted(GMPNoErr, job->mSample.forget());
|
||||
std::min<size_t>(aDecryptedData.Length(), job->mSample->mSize));
|
||||
job->mClient->Decrypted(GMPNoErr, job->mSample);
|
||||
} else if (aResult == GMPNoKeyErr) {
|
||||
NS_WARNING("CDM returned GMPNoKeyErr");
|
||||
// We still have the encrypted sample, so we can re-enqueue it to be
|
||||
// decrypted again once the key is usable again.
|
||||
job->mClient->Decrypted(GMPNoKeyErr, job->mSample.forget());
|
||||
job->mClient->Decrypted(GMPNoKeyErr, job->mSample);
|
||||
} else {
|
||||
nsAutoCString str("CDM returned decode failure GMPErr=");
|
||||
str.AppendInt(aResult);
|
||||
|
|
|
@ -14,10 +14,9 @@
|
|||
#include "nsIThread.h"
|
||||
#include "GMPDecryptorProxy.h"
|
||||
#include "mozilla/CDMCaps.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class MediaRawData;
|
||||
class CDMCallbackProxy;
|
||||
|
||||
namespace dom {
|
||||
|
@ -28,7 +27,7 @@ class DecryptionClient {
|
|||
public:
|
||||
virtual ~DecryptionClient() {}
|
||||
virtual void Decrypted(GMPErr aResult,
|
||||
mp4_demuxer::MP4Sample* aSample) = 0;
|
||||
MediaRawData* aSample) = 0;
|
||||
};
|
||||
|
||||
// Proxies calls GMP/CDM, and proxies calls back.
|
||||
|
@ -142,8 +141,7 @@ public:
|
|||
const nsAString& aMsg);
|
||||
|
||||
// Threadsafe.
|
||||
void Decrypt(mp4_demuxer::MP4Sample* aSample,
|
||||
DecryptionClient* aSink);
|
||||
void Decrypt(MediaRawData* aSample, DecryptionClient* aSink);
|
||||
|
||||
// Reject promise with DOMException corresponding to aExceptionCode.
|
||||
// Can be called from any thread.
|
||||
|
@ -236,14 +234,13 @@ private:
|
|||
void gmp_RemoveSession(nsAutoPtr<SessionOpData> aData);
|
||||
|
||||
struct DecryptJob {
|
||||
DecryptJob(mp4_demuxer::MP4Sample* aSample,
|
||||
DecryptionClient* aClient)
|
||||
DecryptJob(MediaRawData* aSample, DecryptionClient* aClient)
|
||||
: mId(0)
|
||||
, mSample(aSample)
|
||||
, mClient(aClient)
|
||||
{}
|
||||
uint32_t mId;
|
||||
nsAutoPtr<mp4_demuxer::MP4Sample> mSample;
|
||||
nsRefPtr<MediaRawData> mSample;
|
||||
nsAutoPtr<DecryptionClient> mClient;
|
||||
};
|
||||
// GMP thread only.
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
|
||||
class OutputEvent : public nsRunnable {
|
||||
public:
|
||||
OutputEvent(mp4_demuxer::MP4Sample* aSample,
|
||||
OutputEvent(MediaRawData* aSample,
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
BlankMediaDataCreator* aCreator)
|
||||
: mSample(aSample)
|
||||
|
@ -51,19 +51,19 @@ public:
|
|||
}
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
nsRefPtr<MediaData> data = mCreator->Create(mSample->composition_timestamp,
|
||||
mSample->duration,
|
||||
mSample->byte_offset);
|
||||
nsRefPtr<MediaData> data = mCreator->Create(mSample->mTime,
|
||||
mSample->mDuration,
|
||||
mSample->mOffset);
|
||||
mCallback->Output(data);
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
nsAutoPtr<mp4_demuxer::MP4Sample> mSample;
|
||||
nsRefPtr<MediaRawData> mSample;
|
||||
BlankMediaDataCreator* mCreator;
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
};
|
||||
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override
|
||||
virtual nsresult Input(MediaRawData* aSample) override
|
||||
{
|
||||
// The MediaDataDecoder must delete the sample when we're finished
|
||||
// with it, so the OutputEvent stores it in an nsAutoPtr and deletes
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "MP4Reader.h"
|
||||
#include "MP4Stream.h"
|
||||
#include "MediaData.h"
|
||||
#include "MediaResource.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsSize.h"
|
||||
|
@ -70,7 +71,7 @@ TrackTypeToStr(TrackType aTrack)
|
|||
#endif
|
||||
|
||||
bool
|
||||
AccumulateSPSTelemetry(const ByteBuffer* aExtradata)
|
||||
AccumulateSPSTelemetry(const DataBuffer* aExtradata)
|
||||
{
|
||||
SPSData spsdata;
|
||||
if (H264::DecodeSPSFromExtraData(aExtradata, spsdata)) {
|
||||
|
@ -778,16 +779,16 @@ MP4Reader::Update(TrackType aTrack)
|
|||
decoder.mIsFlushing);
|
||||
|
||||
if (needInput) {
|
||||
nsAutoPtr<MediaSample> sample(PopSample(aTrack));
|
||||
nsRefPtr<MediaRawData> sample(PopSample(aTrack));
|
||||
|
||||
// Collect telemetry from h264 Annex B SPS.
|
||||
if (!mFoundSPSForTelemetry && sample && AnnexB::HasSPS(sample->mMp4Sample)) {
|
||||
nsRefPtr<ByteBuffer> extradata = AnnexB::ExtractExtraData(sample->mMp4Sample);
|
||||
if (!mFoundSPSForTelemetry && sample && AnnexB::HasSPS(sample)) {
|
||||
nsRefPtr<DataBuffer> extradata = AnnexB::ExtractExtraData(sample);
|
||||
mFoundSPSForTelemetry = AccumulateSPSTelemetry(extradata);
|
||||
}
|
||||
|
||||
if (sample) {
|
||||
decoder.mDecoder->Input(sample->mMp4Sample.forget());
|
||||
decoder.mDecoder->Input(sample);
|
||||
if (aTrack == kVideo) {
|
||||
a.mParsed++;
|
||||
}
|
||||
|
@ -831,31 +832,49 @@ MP4Reader::ReturnOutput(MediaData* aData, TrackType aTrack)
|
|||
}
|
||||
}
|
||||
|
||||
MediaSample*
|
||||
already_AddRefed<MediaRawData>
|
||||
MP4Reader::PopSample(TrackType aTrack)
|
||||
{
|
||||
MonitorAutoLock mon(mDemuxerMonitor);
|
||||
return PopSampleLocked(aTrack);
|
||||
}
|
||||
|
||||
MediaSample*
|
||||
already_AddRefed<MediaRawData>
|
||||
MP4Reader::PopSampleLocked(TrackType aTrack)
|
||||
{
|
||||
mDemuxerMonitor.AssertCurrentThreadOwns();
|
||||
nsRefPtr<MediaRawData> sample;
|
||||
switch (aTrack) {
|
||||
case kAudio:
|
||||
return InvokeAndRetry(mAudio.mTrackDemuxer.get(), &TrackDemuxer::DemuxSample, mStream, &mDemuxerMonitor);
|
||||
sample =
|
||||
InvokeAndRetry(this, &MP4Reader::DemuxAudioSample, mStream, &mDemuxerMonitor);
|
||||
return sample.forget();
|
||||
case kVideo:
|
||||
if (mQueuedVideoSample) {
|
||||
return mQueuedVideoSample.forget();
|
||||
}
|
||||
return InvokeAndRetry(mVideo.mTrackDemuxer.get(), &TrackDemuxer::DemuxSample, mStream, &mDemuxerMonitor);
|
||||
|
||||
sample =
|
||||
InvokeAndRetry(this, &MP4Reader::DemuxVideoSample, mStream, &mDemuxerMonitor);
|
||||
return sample.forget();
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<MediaRawData>
|
||||
MP4Reader::DemuxAudioSample()
|
||||
{
|
||||
nsRefPtr<MediaRawData> sample = mAudio.mTrackDemuxer->DemuxSample();
|
||||
return sample;
|
||||
}
|
||||
|
||||
nsRefPtr<MediaRawData>
|
||||
MP4Reader::DemuxVideoSample()
|
||||
{
|
||||
nsRefPtr<MediaRawData> sample = mVideo.mTrackDemuxer->DemuxSample();
|
||||
return sample;
|
||||
}
|
||||
|
||||
size_t
|
||||
MP4Reader::SizeOfVideoQueueInFrames()
|
||||
{
|
||||
|
@ -1007,7 +1026,7 @@ MP4Reader::SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed
|
|||
|
||||
// Loop until we reach the next keyframe after the threshold.
|
||||
while (true) {
|
||||
nsAutoPtr<MediaSample> compressed(PopSample(kVideo));
|
||||
nsRefPtr<MediaRawData> compressed(PopSample(kVideo));
|
||||
if (!compressed) {
|
||||
// EOS, or error. This code assumes EOS, which may or may not be right.
|
||||
MonitorAutoLock mon(mVideo.mMonitor);
|
||||
|
@ -1015,8 +1034,8 @@ MP4Reader::SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed
|
|||
return false;
|
||||
}
|
||||
parsed++;
|
||||
if (!compressed->mMp4Sample->is_sync_point ||
|
||||
compressed->mMp4Sample->composition_timestamp < aTimeThreshold) {
|
||||
if (!compressed->mKeyframe ||
|
||||
compressed->mTime < aTimeThreshold) {
|
||||
continue;
|
||||
}
|
||||
mQueuedVideoSample = compressed;
|
||||
|
@ -1043,7 +1062,7 @@ MP4Reader::Seek(int64_t aTime, int64_t aEndTime)
|
|||
mVideo.mTrackDemuxer->Seek(seekTime);
|
||||
mQueuedVideoSample = PopSampleLocked(kVideo);
|
||||
if (mQueuedVideoSample) {
|
||||
seekTime = mQueuedVideoSample->mMp4Sample->composition_timestamp;
|
||||
seekTime = mQueuedVideoSample->mTime;
|
||||
}
|
||||
}
|
||||
if (mDemuxer->HasValidAudio()) {
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace dom {
|
|||
class TimeRanges;
|
||||
}
|
||||
|
||||
typedef std::deque<MediaSample*> MediaSampleQueue;
|
||||
typedef std::deque<nsRefPtr<MediaRawData>> MediaSampleQueue;
|
||||
|
||||
class MP4Stream;
|
||||
|
||||
|
@ -121,8 +121,8 @@ private:
|
|||
|
||||
// Blocks until the demuxer produces an sample of specified type.
|
||||
// Returns nullptr on error on EOS. Caller must delete sample.
|
||||
MediaSample* PopSample(mp4_demuxer::TrackType aTrack);
|
||||
MediaSample* PopSampleLocked(mp4_demuxer::TrackType aTrack);
|
||||
already_AddRefed<MediaRawData> PopSample(mp4_demuxer::TrackType aTrack);
|
||||
already_AddRefed<MediaRawData> PopSampleLocked(mp4_demuxer::TrackType aTrack);
|
||||
|
||||
bool SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed);
|
||||
|
||||
|
@ -260,7 +260,7 @@ private:
|
|||
|
||||
// Queued samples extracted by the demuxer, but not yet sent to the platform
|
||||
// decoder.
|
||||
nsAutoPtr<MediaSample> mQueuedVideoSample;
|
||||
nsRefPtr<MediaRawData> mQueuedVideoSample;
|
||||
|
||||
// Returns true when the decoder for this track needs input.
|
||||
// aDecoder.mMonitor must be locked.
|
||||
|
@ -276,6 +276,10 @@ private:
|
|||
|
||||
layers::LayersBackend mLayersBackendType;
|
||||
|
||||
// For use with InvokeAndRetry as an already_refed can't be converted to bool
|
||||
nsRefPtr<MediaRawData> DemuxVideoSample();
|
||||
nsRefPtr<MediaRawData> DemuxAudioSample();
|
||||
|
||||
// True if we've read the streams' metadata.
|
||||
bool mDemuxerInitialized;
|
||||
|
||||
|
|
|
@ -17,12 +17,13 @@ namespace mp4_demuxer {
|
|||
class TrackConfig;
|
||||
class VideoDecoderConfig;
|
||||
class AudioDecoderConfig;
|
||||
class MP4Sample;
|
||||
}
|
||||
|
||||
class nsIThreadPool;
|
||||
|
||||
namespace mozilla {
|
||||
class MediaRawData;
|
||||
class DataBuffer;
|
||||
|
||||
namespace layers {
|
||||
class ImageContainer;
|
||||
|
@ -219,10 +220,8 @@ public:
|
|||
// be done here so that it can be canceled by calling Shutdown()!
|
||||
virtual nsresult Init() = 0;
|
||||
|
||||
// Inserts a sample into the decoder's decode pipeline. The decoder must
|
||||
// delete the sample once its been decoded. If Input() returns an error,
|
||||
// aSample will be deleted by the caller.
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) = 0;
|
||||
// Inserts a sample into the decoder's decode pipeline.
|
||||
virtual nsresult Input(MediaRawData* aSample) = 0;
|
||||
|
||||
// Causes all samples in the decoding pipeline to be discarded. When
|
||||
// this function returns, the decoder must be ready to accept new input
|
||||
|
|
|
@ -218,7 +218,7 @@ SharedDecoderProxy::Init()
|
|||
}
|
||||
|
||||
nsresult
|
||||
SharedDecoderProxy::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
SharedDecoderProxy::Input(MediaRawData* aSample)
|
||||
{
|
||||
if (mManager->mActiveProxy != this) {
|
||||
mManager->Select(this);
|
||||
|
|
|
@ -69,7 +69,7 @@ public:
|
|||
virtual ~SharedDecoderProxy();
|
||||
|
||||
virtual nsresult Init() override;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual nsresult Input(MediaRawData* aSample) override;
|
||||
virtual nsresult Flush() override;
|
||||
virtual nsresult Drain() override;
|
||||
virtual nsresult Shutdown() override;
|
||||
|
|
|
@ -62,7 +62,7 @@ public:
|
|||
mGLContext = nullptr;
|
||||
}
|
||||
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override {
|
||||
virtual nsresult Input(MediaRawData* aSample) override {
|
||||
return MediaCodecDataDecoder::Input(aSample);
|
||||
}
|
||||
|
||||
|
@ -397,7 +397,7 @@ void MediaCodecDataDecoder::DecoderLoop()
|
|||
bool waitingEOF = false;
|
||||
|
||||
AutoLocalJNIFrame frame(GetJNIForThread(), 1);
|
||||
mp4_demuxer::MP4Sample* sample = nullptr;
|
||||
nsRefPtr<MediaRawData> sample;
|
||||
|
||||
MediaFormat::LocalRef outputFormat(frame.GetEnv());
|
||||
nsresult res;
|
||||
|
@ -464,7 +464,7 @@ void MediaCodecDataDecoder::DecoderLoop()
|
|||
|
||||
void* directBuffer = frame.GetEnv()->GetDirectBufferAddress(buffer.Get());
|
||||
|
||||
MOZ_ASSERT(frame.GetEnv()->GetDirectBufferCapacity(buffer.Get()) >= sample->size,
|
||||
MOZ_ASSERT(frame.GetEnv()->GetDirectBufferCapacity(buffer.Get()) >= sample->mSize,
|
||||
"Decoder buffer is not large enough for sample");
|
||||
|
||||
{
|
||||
|
@ -473,14 +473,13 @@ void MediaCodecDataDecoder::DecoderLoop()
|
|||
mQueue.pop();
|
||||
}
|
||||
|
||||
PodCopy((uint8_t*)directBuffer, sample->data, sample->size);
|
||||
PodCopy((uint8_t*)directBuffer, sample->mData, sample->mSize);
|
||||
|
||||
res = mDecoder->QueueInputBuffer(inputIndex, 0, sample->size,
|
||||
sample->composition_timestamp, 0);
|
||||
res = mDecoder->QueueInputBuffer(inputIndex, 0, sample->mSize,
|
||||
sample->mTime, 0);
|
||||
HANDLE_DECODER_ERROR();
|
||||
|
||||
mDurations.push(sample->duration);
|
||||
delete sample;
|
||||
mDurations.push(sample->mDuration);
|
||||
sample = nullptr;
|
||||
outputDone = false;
|
||||
}
|
||||
|
@ -572,7 +571,6 @@ void MediaCodecDataDecoder::ClearQueue()
|
|||
{
|
||||
mMonitor.AssertCurrentThreadOwns();
|
||||
while (!mQueue.empty()) {
|
||||
delete mQueue.front();
|
||||
mQueue.pop();
|
||||
}
|
||||
while (!mDurations.empty()) {
|
||||
|
@ -580,7 +578,7 @@ void MediaCodecDataDecoder::ClearQueue()
|
|||
}
|
||||
}
|
||||
|
||||
nsresult MediaCodecDataDecoder::Input(mp4_demuxer::MP4Sample* aSample) {
|
||||
nsresult MediaCodecDataDecoder::Input(MediaRawData* aSample) {
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
mQueue.push(aSample);
|
||||
lock.NotifyAll();
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
typedef std::queue<mp4_demuxer::MP4Sample*> SampleQueue;
|
||||
typedef std::queue<nsRefPtr<MediaRawData>> SampleQueue;
|
||||
|
||||
class AndroidDecoderModule : public PlatformDecoderModule {
|
||||
public:
|
||||
|
@ -55,7 +55,7 @@ public:
|
|||
virtual nsresult Flush() override;
|
||||
virtual nsresult Drain() override;
|
||||
virtual nsresult Shutdown() override;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample);
|
||||
virtual nsresult Input(MediaRawData* aSample);
|
||||
|
||||
protected:
|
||||
friend class AndroidDecoderModule;
|
||||
|
|
|
@ -66,21 +66,21 @@ AppleATDecoder::Init()
|
|||
}
|
||||
|
||||
nsresult
|
||||
AppleATDecoder::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
AppleATDecoder::Input(MediaRawData* aSample)
|
||||
{
|
||||
LOG("mp4 input sample %p %lld us %lld pts%s %llu bytes audio",
|
||||
aSample,
|
||||
aSample->duration,
|
||||
aSample->composition_timestamp,
|
||||
aSample->is_sync_point ? " keyframe" : "",
|
||||
(unsigned long long)aSample->size);
|
||||
aSample->mDuration,
|
||||
aSample->mTime,
|
||||
aSample->mKeyframe ? " keyframe" : "",
|
||||
(unsigned long long)aSample->mSize);
|
||||
|
||||
// Queue a task to perform the actual decoding on a separate thread.
|
||||
mTaskQueue->Dispatch(
|
||||
NS_NewRunnableMethodWithArg<nsAutoPtr<mp4_demuxer::MP4Sample>>(
|
||||
NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData>>(
|
||||
this,
|
||||
&AppleATDecoder::SubmitSample,
|
||||
nsAutoPtr<mp4_demuxer::MP4Sample>(aSample)));
|
||||
nsRefPtr<MediaRawData>(aSample)));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ _PassthroughInputDataCallback(AudioConverterRef aAudioConverter,
|
|||
}
|
||||
|
||||
void
|
||||
AppleATDecoder::SubmitSample(nsAutoPtr<mp4_demuxer::MP4Sample> aSample)
|
||||
AppleATDecoder::SubmitSample(MediaRawData* aSample)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
if (!mConverter) {
|
||||
|
@ -203,7 +203,7 @@ AppleATDecoder::SubmitSample(nsAutoPtr<mp4_demuxer::MP4Sample> aSample)
|
|||
}
|
||||
|
||||
nsresult
|
||||
AppleATDecoder::DecodeSample(mp4_demuxer::MP4Sample* aSample)
|
||||
AppleATDecoder::DecodeSample(MediaRawData* aSample)
|
||||
{
|
||||
// Array containing the queued decoded audio frames, about to be output.
|
||||
nsTArray<AudioDataValue> outputData;
|
||||
|
@ -220,7 +220,7 @@ AppleATDecoder::DecodeSample(mp4_demuxer::MP4Sample* aSample)
|
|||
// This API insists on having packets spoon-fed to it from a callback.
|
||||
// This structure exists only to pass our state.
|
||||
PassthroughUserData userData =
|
||||
{ channels, (UInt32)aSample->size, aSample->data };
|
||||
{ channels, (UInt32)aSample->mSize, aSample->mData };
|
||||
|
||||
// Decompressed audio buffer
|
||||
nsAutoArrayPtr<AudioDataValue> decoded(new AudioDataValue[maxDecodedSamples]);
|
||||
|
@ -272,14 +272,14 @@ AppleATDecoder::DecodeSample(mp4_demuxer::MP4Sample* aSample)
|
|||
|
||||
#ifdef LOG_SAMPLE_DECODE
|
||||
LOG("pushed audio at time %lfs; duration %lfs\n",
|
||||
(double)aSample->composition_timestamp / USECS_PER_S,
|
||||
(double)aSample->mTime / USECS_PER_S,
|
||||
(double)duration.value() / USECS_PER_S);
|
||||
#endif
|
||||
|
||||
nsAutoArrayPtr<AudioDataValue> data(new AudioDataValue[outputData.Length()]);
|
||||
PodCopy(data.get(), &outputData[0], outputData.Length());
|
||||
nsRefPtr<AudioData> audio = new AudioData(aSample->byte_offset,
|
||||
aSample->composition_timestamp,
|
||||
nsRefPtr<AudioData> audio = new AudioData(aSample->mOffset,
|
||||
aSample->mTime,
|
||||
duration.value(),
|
||||
numFrames,
|
||||
data.forget(),
|
||||
|
@ -364,7 +364,7 @@ AppleATDecoder::GetInputAudioDescription(AudioStreamBasicDescription& aDesc,
|
|||
}
|
||||
|
||||
nsresult
|
||||
AppleATDecoder::SetupDecoder(mp4_demuxer::MP4Sample* aSample)
|
||||
AppleATDecoder::SetupDecoder(MediaRawData* aSample)
|
||||
{
|
||||
if (mFormatID == kAudioFormatMPEG4AAC &&
|
||||
mConfig.extended_profile == 2) {
|
||||
|
@ -461,10 +461,10 @@ _SampleCallback(void* aSBR,
|
|||
}
|
||||
|
||||
nsresult
|
||||
AppleATDecoder::GetImplicitAACMagicCookie(const mp4_demuxer::MP4Sample* aSample)
|
||||
AppleATDecoder::GetImplicitAACMagicCookie(const MediaRawData* aSample)
|
||||
{
|
||||
// Prepend ADTS header to AAC audio.
|
||||
nsAutoPtr<mp4_demuxer::MP4Sample> adtssample(aSample->Clone());
|
||||
nsRefPtr<MediaRawData> adtssample(aSample->Clone());
|
||||
if (!adtssample) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
@ -490,8 +490,8 @@ AppleATDecoder::GetImplicitAACMagicCookie(const mp4_demuxer::MP4Sample* aSample)
|
|||
}
|
||||
|
||||
OSStatus status = AudioFileStreamParseBytes(mStream,
|
||||
adtssample->size,
|
||||
adtssample->data,
|
||||
adtssample->mSize,
|
||||
adtssample->mData,
|
||||
0 /* discontinuity */);
|
||||
if (status) {
|
||||
NS_WARNING("Couldn't parse sample");
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
virtual ~AppleATDecoder();
|
||||
|
||||
virtual nsresult Init() override;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual nsresult Input(MediaRawData* aSample) override;
|
||||
virtual nsresult Flush() override;
|
||||
virtual nsresult Drain() override;
|
||||
virtual nsresult Shutdown() override;
|
||||
|
@ -47,16 +47,16 @@ private:
|
|||
AudioStreamBasicDescription mOutputFormat;
|
||||
UInt32 mFormatID;
|
||||
AudioFileStreamID mStream;
|
||||
nsTArray<nsAutoPtr<mp4_demuxer::MP4Sample>> mQueuedSamples;
|
||||
nsTArray<nsRefPtr<MediaRawData>> mQueuedSamples;
|
||||
|
||||
void SubmitSample(nsAutoPtr<mp4_demuxer::MP4Sample> aSample);
|
||||
nsresult DecodeSample(mp4_demuxer::MP4Sample* aSample);
|
||||
void SubmitSample(MediaRawData* aSample);
|
||||
nsresult DecodeSample(MediaRawData* aSample);
|
||||
nsresult GetInputAudioDescription(AudioStreamBasicDescription& aDesc,
|
||||
const nsTArray<uint8_t>& aExtraData);
|
||||
// Setup AudioConverter once all information required has been gathered.
|
||||
// Will return NS_ERROR_NOT_INITIALIZED if more data is required.
|
||||
nsresult SetupDecoder(mp4_demuxer::MP4Sample* aSample);
|
||||
nsresult GetImplicitAACMagicCookie(const mp4_demuxer::MP4Sample* aSample);
|
||||
nsresult SetupDecoder(MediaRawData* aSample);
|
||||
nsresult GetImplicitAACMagicCookie(const MediaRawData* aSample);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -104,20 +104,20 @@ AppleVDADecoder::Shutdown()
|
|||
}
|
||||
|
||||
nsresult
|
||||
AppleVDADecoder::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
AppleVDADecoder::Input(MediaRawData* aSample)
|
||||
{
|
||||
LOG("mp4 input sample %p pts %lld duration %lld us%s %d bytes",
|
||||
aSample,
|
||||
aSample->composition_timestamp,
|
||||
aSample->duration,
|
||||
aSample->is_sync_point ? " keyframe" : "",
|
||||
aSample->size);
|
||||
aSample->mTime,
|
||||
aSample->mDuration,
|
||||
aSample->mKeyframe ? " keyframe" : "",
|
||||
aSample->mSize);
|
||||
|
||||
mTaskQueue->Dispatch(
|
||||
NS_NewRunnableMethodWithArg<nsAutoPtr<mp4_demuxer::MP4Sample>>(
|
||||
NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData>>(
|
||||
this,
|
||||
&AppleVDADecoder::SubmitFrame,
|
||||
nsAutoPtr<mp4_demuxer::MP4Sample>(aSample)));
|
||||
nsRefPtr<MediaRawData>(aSample)));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -224,7 +224,7 @@ PlatformCallback(void* decompressionOutputRefCon,
|
|||
}
|
||||
|
||||
AppleVDADecoder::AppleFrameRef*
|
||||
AppleVDADecoder::CreateAppleFrameRef(const mp4_demuxer::MP4Sample* aSample)
|
||||
AppleVDADecoder::CreateAppleFrameRef(const MediaRawData* aSample)
|
||||
{
|
||||
MOZ_ASSERT(aSample);
|
||||
return new AppleFrameRef(*aSample);
|
||||
|
@ -307,10 +307,10 @@ AppleVDADecoder::OutputFrame(CVPixelBufferRef aImage,
|
|||
}
|
||||
|
||||
nsresult
|
||||
AppleVDADecoder::SubmitFrame(mp4_demuxer::MP4Sample* aSample)
|
||||
AppleVDADecoder::SubmitFrame(MediaRawData* aSample)
|
||||
{
|
||||
AutoCFRelease<CFDataRef> block =
|
||||
CFDataCreate(kCFAllocatorDefault, aSample->data, aSample->size);
|
||||
CFDataCreate(kCFAllocatorDefault, aSample->mData, aSample->mSize);
|
||||
if (!block) {
|
||||
NS_ERROR("Couldn't create CFData");
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -319,20 +319,20 @@ AppleVDADecoder::SubmitFrame(mp4_demuxer::MP4Sample* aSample)
|
|||
AutoCFRelease<CFNumberRef> pts =
|
||||
CFNumberCreate(kCFAllocatorDefault,
|
||||
kCFNumberSInt64Type,
|
||||
&aSample->composition_timestamp);
|
||||
&aSample->mTime);
|
||||
AutoCFRelease<CFNumberRef> dts =
|
||||
CFNumberCreate(kCFAllocatorDefault,
|
||||
kCFNumberSInt64Type,
|
||||
&aSample->decode_timestamp);
|
||||
&aSample->mTimecode);
|
||||
AutoCFRelease<CFNumberRef> duration =
|
||||
CFNumberCreate(kCFAllocatorDefault,
|
||||
kCFNumberSInt64Type,
|
||||
&aSample->duration);
|
||||
&aSample->mDuration);
|
||||
AutoCFRelease<CFNumberRef> byte_offset =
|
||||
CFNumberCreate(kCFAllocatorDefault,
|
||||
kCFNumberSInt64Type,
|
||||
&aSample->byte_offset);
|
||||
char keyframe = aSample->is_sync_point ? 1 : 0;
|
||||
&aSample->mOffset);
|
||||
char keyframe = aSample->mKeyframe ? 1 : 0;
|
||||
AutoCFRelease<CFNumberRef> cfkeyframe =
|
||||
CFNumberCreate(kCFAllocatorDefault,
|
||||
kCFNumberSInt8Type,
|
||||
|
|
|
@ -34,12 +34,12 @@ public:
|
|||
int64_t byte_offset;
|
||||
bool is_sync_point;
|
||||
|
||||
explicit AppleFrameRef(const mp4_demuxer::MP4Sample& aSample)
|
||||
: decode_timestamp(aSample.decode_timestamp)
|
||||
, composition_timestamp(aSample.composition_timestamp)
|
||||
, duration(aSample.duration)
|
||||
, byte_offset(aSample.byte_offset)
|
||||
, is_sync_point(aSample.is_sync_point)
|
||||
explicit AppleFrameRef(const MediaRawData& aSample)
|
||||
: decode_timestamp(aSample.mTimecode)
|
||||
, composition_timestamp(aSample.mTime)
|
||||
, duration(aSample.mDuration)
|
||||
, byte_offset(aSample.mOffset)
|
||||
, is_sync_point(aSample.mKeyframe)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -48,11 +48,11 @@ public:
|
|||
Microseconds aDuration,
|
||||
int64_t aByte_offset,
|
||||
bool aIs_sync_point)
|
||||
: decode_timestamp(aDts)
|
||||
, composition_timestamp(aPts)
|
||||
, duration(aDuration)
|
||||
, byte_offset(aByte_offset)
|
||||
, is_sync_point(aIs_sync_point)
|
||||
: decode_timestamp(aDts)
|
||||
, composition_timestamp(aPts)
|
||||
, duration(aDuration)
|
||||
, byte_offset(aByte_offset)
|
||||
, is_sync_point(aIs_sync_point)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
@ -71,7 +71,7 @@ public:
|
|||
layers::ImageContainer* aImageContainer);
|
||||
virtual ~AppleVDADecoder();
|
||||
virtual nsresult Init() override;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual nsresult Input(MediaRawData* aSample) override;
|
||||
virtual nsresult Flush() override;
|
||||
virtual nsresult Drain() override;
|
||||
virtual nsresult Shutdown() override;
|
||||
|
@ -84,12 +84,12 @@ public:
|
|||
nsAutoPtr<AppleFrameRef> aFrameRef);
|
||||
|
||||
protected:
|
||||
AppleFrameRef* CreateAppleFrameRef(const mp4_demuxer::MP4Sample* aSample);
|
||||
AppleFrameRef* CreateAppleFrameRef(const MediaRawData* aSample);
|
||||
void DrainReorderedFrames();
|
||||
void ClearReorderedFrames();
|
||||
CFDictionaryRef CreateOutputConfiguration();
|
||||
|
||||
nsRefPtr<mp4_demuxer::ByteBuffer> mExtraData;
|
||||
nsRefPtr<DataBuffer> mExtraData;
|
||||
nsRefPtr<FlushableMediaTaskQueue> mTaskQueue;
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
nsRefPtr<layers::ImageContainer> mImageContainer;
|
||||
|
@ -105,7 +105,7 @@ private:
|
|||
bool mIs106;
|
||||
|
||||
// Method to pass a frame to VideoToolbox for decoding.
|
||||
nsresult SubmitFrame(mp4_demuxer::MP4Sample* aSample);
|
||||
nsresult SubmitFrame(MediaRawData* aSample);
|
||||
// Method to set up the decompression session.
|
||||
nsresult InitializeSession();
|
||||
CFDictionaryRef CreateDecoderSpecification();
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "AppleUtils.h"
|
||||
#include "AppleVTDecoder.h"
|
||||
#include "AppleVTLinker.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "mp4_demuxer/H264.h"
|
||||
#include "MediaData.h"
|
||||
#include "MacIOSurfaceImage.h"
|
||||
|
@ -82,14 +81,14 @@ AppleVTDecoder::Shutdown()
|
|||
}
|
||||
|
||||
nsresult
|
||||
AppleVTDecoder::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
AppleVTDecoder::Input(MediaRawData* aSample)
|
||||
{
|
||||
LOG("mp4 input sample %p pts %lld duration %lld us%s %d bytes",
|
||||
aSample,
|
||||
aSample->composition_timestamp,
|
||||
aSample->duration,
|
||||
aSample->is_sync_point ? " keyframe" : "",
|
||||
aSample->size);
|
||||
aSample->mTime,
|
||||
aSample->mDuration,
|
||||
aSample->mKeyframe ? " keyframe" : "",
|
||||
aSample->mSize);
|
||||
|
||||
#ifdef LOG_MEDIA_SHA1
|
||||
SHA1Sum hash;
|
||||
|
@ -104,10 +103,10 @@ AppleVTDecoder::Input(mp4_demuxer::MP4Sample* aSample)
|
|||
#endif // LOG_MEDIA_SHA1
|
||||
|
||||
mTaskQueue->Dispatch(
|
||||
NS_NewRunnableMethodWithArg<nsAutoPtr<mp4_demuxer::MP4Sample>>(
|
||||
NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData>>(
|
||||
this,
|
||||
&AppleVTDecoder::SubmitFrame,
|
||||
nsAutoPtr<mp4_demuxer::MP4Sample>(aSample)));
|
||||
nsRefPtr<MediaRawData>(aSample)));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -193,21 +192,21 @@ AppleVTDecoder::WaitForAsynchronousFrames()
|
|||
|
||||
// Helper to fill in a timestamp structure.
|
||||
static CMSampleTimingInfo
|
||||
TimingInfoFromSample(mp4_demuxer::MP4Sample* aSample)
|
||||
TimingInfoFromSample(MediaRawData* aSample)
|
||||
{
|
||||
CMSampleTimingInfo timestamp;
|
||||
|
||||
timestamp.duration = CMTimeMake(aSample->duration, USECS_PER_S);
|
||||
timestamp.duration = CMTimeMake(aSample->mDuration, USECS_PER_S);
|
||||
timestamp.presentationTimeStamp =
|
||||
CMTimeMake(aSample->composition_timestamp, USECS_PER_S);
|
||||
CMTimeMake(aSample->mTime, USECS_PER_S);
|
||||
timestamp.decodeTimeStamp =
|
||||
CMTimeMake(aSample->decode_timestamp, USECS_PER_S);
|
||||
CMTimeMake(aSample->mTimecode, USECS_PER_S);
|
||||
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AppleVTDecoder::SubmitFrame(mp4_demuxer::MP4Sample* aSample)
|
||||
AppleVTDecoder::SubmitFrame(MediaRawData* aSample)
|
||||
{
|
||||
// For some reason this gives me a double-free error with stagefright.
|
||||
AutoCFRelease<CMBlockBufferRef> block = nullptr;
|
||||
|
@ -219,15 +218,15 @@ AppleVTDecoder::SubmitFrame(mp4_demuxer::MP4Sample* aSample)
|
|||
// a custom block source which reuses the aSample buffer.
|
||||
// But note that there may be a problem keeping the samples
|
||||
// alive over multiple frames.
|
||||
rv = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault // Struct allocator.
|
||||
,aSample->data
|
||||
,aSample->size
|
||||
,kCFAllocatorNull // Block allocator.
|
||||
,NULL // Block source.
|
||||
,0 // Data offset.
|
||||
,aSample->size
|
||||
,false
|
||||
,block.receive());
|
||||
rv = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, // Struct allocator.
|
||||
const_cast<uint8_t*>(aSample->mData),
|
||||
aSample->mSize,
|
||||
kCFAllocatorNull, // Block allocator.
|
||||
NULL, // Block source.
|
||||
0, // Data offset.
|
||||
aSample->mSize,
|
||||
false,
|
||||
block.receive());
|
||||
if (rv != noErr) {
|
||||
NS_ERROR("Couldn't create CMBlockBuffer");
|
||||
return NS_ERROR_FAILURE;
|
||||
|
|
|
@ -21,7 +21,7 @@ public:
|
|||
layers::ImageContainer* aImageContainer);
|
||||
virtual ~AppleVTDecoder();
|
||||
virtual nsresult Init() override;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual nsresult Input(MediaRawData* aSample) override;
|
||||
virtual nsresult Flush() override;
|
||||
virtual nsresult Drain() override;
|
||||
virtual nsresult Shutdown() override;
|
||||
|
@ -35,7 +35,7 @@ private:
|
|||
VTDecompressionSessionRef mSession;
|
||||
|
||||
// Method to pass a frame to VideoToolbox for decoding.
|
||||
nsresult SubmitFrame(mp4_demuxer::MP4Sample* aSample);
|
||||
nsresult SubmitFrame(MediaRawData* aSample);
|
||||
// Method to set up the decompression session.
|
||||
nsresult InitializeSession();
|
||||
nsresult WaitForAsynchronousFrames();
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
#include "mozilla/CDMProxy.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class EMEDecryptor : public MediaDataDecoder {
|
||||
typedef mp4_demuxer::MP4Sample MP4Sample;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -49,12 +49,13 @@ public:
|
|||
, mTaskQueue(aTaskQueue)
|
||||
{}
|
||||
virtual void Decrypted(GMPErr aResult,
|
||||
mp4_demuxer::MP4Sample* aSample) override {
|
||||
MediaRawData* aSample) override {
|
||||
if (aResult == GMPNoKeyErr) {
|
||||
RefPtr<nsIRunnable> task;
|
||||
task = NS_NewRunnableMethodWithArg<MP4Sample*>(mDecryptor,
|
||||
&EMEDecryptor::Input,
|
||||
aSample);
|
||||
task = NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData>>(
|
||||
mDecryptor,
|
||||
&EMEDecryptor::Input,
|
||||
nsRefPtr<MediaRawData>(aSample));
|
||||
mTaskQueue->Dispatch(task.forget());
|
||||
} else if (GMP_FAILED(aResult)) {
|
||||
if (mDecryptor->mCallback) {
|
||||
|
@ -63,9 +64,10 @@ public:
|
|||
MOZ_ASSERT(!aSample);
|
||||
} else {
|
||||
RefPtr<nsIRunnable> task;
|
||||
task = NS_NewRunnableMethodWithArg<MP4Sample*>(mDecryptor,
|
||||
&EMEDecryptor::Decrypted,
|
||||
aSample);
|
||||
task = NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData>>(
|
||||
mDecryptor,
|
||||
&EMEDecryptor::Decrypted,
|
||||
nsRefPtr<MediaRawData>(aSample));
|
||||
mTaskQueue->Dispatch(task.forget());
|
||||
}
|
||||
mTaskQueue = nullptr;
|
||||
|
@ -76,7 +78,7 @@ public:
|
|||
nsRefPtr<FlushableMediaTaskQueue> mTaskQueue;
|
||||
};
|
||||
|
||||
virtual nsresult Input(MP4Sample* aSample) override {
|
||||
virtual nsresult Input(MediaRawData* aSample) override {
|
||||
MOZ_ASSERT(!mIsShutdown);
|
||||
// We run the PDM on its own task queue. We can't run it on the decode
|
||||
// task queue, because that calls into Input() in a loop and waits until
|
||||
|
@ -89,20 +91,20 @@ public:
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
mProxy->GetSessionIdsForKeyId(aSample->crypto.key,
|
||||
aSample->crypto.session_ids);
|
||||
mProxy->GetSessionIdsForKeyId(aSample->mCrypto.key,
|
||||
aSample->mCrypto.session_ids);
|
||||
|
||||
mProxy->Decrypt(aSample, new DeliverDecrypted(this, mTaskQueue));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Decrypted(mp4_demuxer::MP4Sample* aSample) {
|
||||
void Decrypted(MediaRawData* aSample) {
|
||||
MOZ_ASSERT(!mIsShutdown);
|
||||
nsresult rv = mTaskQueue->Dispatch(
|
||||
NS_NewRunnableMethodWithArg<mp4_demuxer::MP4Sample*>(
|
||||
NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData>>(
|
||||
mDecoder,
|
||||
&MediaDataDecoder::Input,
|
||||
aSample));
|
||||
nsRefPtr<MediaRawData>(aSample)));
|
||||
unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
|
||||
|
@ -169,7 +171,7 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual nsresult Input(MediaRawData* aSample) override;
|
||||
virtual nsresult Shutdown() override;
|
||||
|
||||
private:
|
||||
|
@ -178,14 +180,14 @@ private:
|
|||
};
|
||||
|
||||
nsresult
|
||||
EMEMediaDataDecoderProxy::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
EMEMediaDataDecoderProxy::Input(MediaRawData* aSample)
|
||||
{
|
||||
if (mSamplesWaitingForKey->WaitIfKeyNotUsable(aSample)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mProxy->GetSessionIdsForKeyId(aSample->crypto.key,
|
||||
aSample->crypto.session_ids);
|
||||
mProxy->GetSessionIdsForKeyId(aSample->mCrypto.key,
|
||||
aSample->mCrypto.session_ids);
|
||||
|
||||
return MediaDataDecoderProxy::Input(aSample);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "EMEVideoDecoder.h"
|
||||
#include "GMPVideoEncodedFrameImpl.h"
|
||||
#include "mozilla/CDMProxy.h"
|
||||
#include "MediaData.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -36,11 +37,11 @@ EMEVideoDecoder::GetNodeId()
|
|||
}
|
||||
|
||||
GMPUnique<GMPVideoEncodedFrame>::Ptr
|
||||
EMEVideoDecoder::CreateFrame(mp4_demuxer::MP4Sample* aSample)
|
||||
EMEVideoDecoder::CreateFrame(MediaRawData* aSample)
|
||||
{
|
||||
GMPUnique<GMPVideoEncodedFrame>::Ptr frame = GMPVideoDecoder::CreateFrame(aSample);
|
||||
if (frame && aSample->crypto.valid) {
|
||||
static_cast<gmp::GMPVideoEncodedFrameImpl*>(frame.get())->InitCrypto(aSample->crypto);
|
||||
if (frame && aSample->mCrypto.valid) {
|
||||
static_cast<gmp::GMPVideoEncodedFrameImpl*>(frame.get())->InitCrypto(aSample->mCrypto);
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public:
|
|||
private:
|
||||
virtual void InitTags(nsTArray<nsCString>& aTags) override;
|
||||
virtual nsCString GetNodeId() override;
|
||||
virtual GMPUnique<GMPVideoEncodedFrame>::Ptr CreateFrame(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual GMPUnique<GMPVideoEncodedFrame>::Ptr CreateFrame(MediaRawData* aSample) override;
|
||||
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "SamplesWaitingForKey.h"
|
||||
#include "mozilla/CDMProxy.h"
|
||||
#include "mozilla/CDMCaps.h"
|
||||
#include "MediaData.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -25,19 +26,19 @@ SamplesWaitingForKey::~SamplesWaitingForKey()
|
|||
}
|
||||
|
||||
bool
|
||||
SamplesWaitingForKey::WaitIfKeyNotUsable(MP4Sample* aSample)
|
||||
SamplesWaitingForKey::WaitIfKeyNotUsable(MediaRawData* aSample)
|
||||
{
|
||||
if (!aSample || !aSample->crypto.valid || !mProxy) {
|
||||
if (!aSample || !aSample->mCrypto.valid || !mProxy) {
|
||||
return false;
|
||||
}
|
||||
CDMCaps::AutoLock caps(mProxy->Capabilites());
|
||||
const auto& keyid = aSample->crypto.key;
|
||||
const auto& keyid = aSample->mCrypto.key;
|
||||
if (!caps.IsKeyUsable(keyid)) {
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mSamples.AppendElement(aSample);
|
||||
}
|
||||
caps.NotifyWhenKeyIdUsable(aSample->crypto.key, this);
|
||||
caps.NotifyWhenKeyIdUsable(aSample->mCrypto.key, this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -49,11 +50,11 @@ SamplesWaitingForKey::NotifyUsable(const CencKeyId& aKeyId)
|
|||
MutexAutoLock lock(mMutex);
|
||||
size_t i = 0;
|
||||
while (i < mSamples.Length()) {
|
||||
if (aKeyId == mSamples[i]->crypto.key) {
|
||||
if (aKeyId == mSamples[i]->mCrypto.key) {
|
||||
RefPtr<nsIRunnable> task;
|
||||
task = NS_NewRunnableMethodWithArg<MP4Sample*>(mDecoder,
|
||||
task = NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData>>(mDecoder,
|
||||
&MediaDataDecoder::Input,
|
||||
mSamples[i].forget());
|
||||
nsRefPtr<MediaRawData>(mSamples[i]));
|
||||
mSamples.RemoveElementAt(i);
|
||||
mTaskQueue->Dispatch(task.forget());
|
||||
} else {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#ifndef SamplesWaitingForKey_h_
|
||||
#define SamplesWaitingForKey_h_
|
||||
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "MediaTaskQueue.h"
|
||||
#include "PlatformDecoderModule.h"
|
||||
|
||||
|
@ -20,7 +19,6 @@ class CDMProxy;
|
|||
// Encapsulates the task of waiting for the CDMProxy to have the necessary
|
||||
// keys to decypt a given sample.
|
||||
class SamplesWaitingForKey {
|
||||
typedef mp4_demuxer::MP4Sample MP4Sample;
|
||||
public:
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SamplesWaitingForKey)
|
||||
|
@ -33,7 +31,7 @@ public:
|
|||
// Will callback MediaDataDecoder::Input(aSample) on mDecoder once the
|
||||
// sample is ready to be decrypted. The order of input samples is
|
||||
// preserved.
|
||||
bool WaitIfKeyNotUsable(MP4Sample* aSample);
|
||||
bool WaitIfKeyNotUsable(MediaRawData* aSample);
|
||||
|
||||
void NotifyUsable(const CencKeyId& aKeyId);
|
||||
|
||||
|
@ -49,7 +47,7 @@ private:
|
|||
nsRefPtr<MediaDataDecoder> mDecoder;
|
||||
nsRefPtr<MediaTaskQueue> mTaskQueue;
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
nsTArray<nsAutoPtr<MP4Sample>> mSamples;
|
||||
nsTArray<nsRefPtr<MediaRawData>> mSamples;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
|
||||
#define MAX_CHANNELS 16
|
||||
|
||||
typedef mp4_demuxer::MP4Sample MP4Sample;
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
|
||||
|
@ -83,19 +81,13 @@ CopyAndPackAudio(AVFrame* aFrame, uint32_t aNumChannels, uint32_t aNumAFrames)
|
|||
}
|
||||
|
||||
void
|
||||
FFmpegAudioDecoder<LIBAV_VER>::DecodePacket(MP4Sample* aSample)
|
||||
FFmpegAudioDecoder<LIBAV_VER>::DecodePacket(MediaRawData* aSample)
|
||||
{
|
||||
AVPacket packet;
|
||||
av_init_packet(&packet);
|
||||
|
||||
if (!aSample->Pad(FF_INPUT_BUFFER_PADDING_SIZE)) {
|
||||
NS_WARNING("FFmpeg audio decoder failed to allocate sample.");
|
||||
mCallback->Error();
|
||||
return;
|
||||
}
|
||||
|
||||
packet.data = aSample->data;
|
||||
packet.size = aSample->size;
|
||||
packet.data = const_cast<uint8_t*>(aSample->mData);
|
||||
packet.size = aSample->mSize;
|
||||
|
||||
if (!PrepareFrame()) {
|
||||
NS_WARNING("FFmpeg audio decoder failed to allocate frame.");
|
||||
|
@ -103,8 +95,8 @@ FFmpegAudioDecoder<LIBAV_VER>::DecodePacket(MP4Sample* aSample)
|
|||
return;
|
||||
}
|
||||
|
||||
int64_t samplePosition = aSample->byte_offset;
|
||||
Microseconds pts = aSample->composition_timestamp;
|
||||
int64_t samplePosition = aSample->mOffset;
|
||||
Microseconds pts = aSample->mTime;
|
||||
|
||||
while (packet.size > 0) {
|
||||
int decoded;
|
||||
|
@ -153,10 +145,10 @@ FFmpegAudioDecoder<LIBAV_VER>::DecodePacket(MP4Sample* aSample)
|
|||
}
|
||||
|
||||
nsresult
|
||||
FFmpegAudioDecoder<LIBAV_VER>::Input(MP4Sample* aSample)
|
||||
FFmpegAudioDecoder<LIBAV_VER>::Input(MediaRawData* aSample)
|
||||
{
|
||||
mTaskQueue->Dispatch(NS_NewRunnableMethodWithArg<nsAutoPtr<MP4Sample> >(
|
||||
this, &FFmpegAudioDecoder::DecodePacket, nsAutoPtr<MP4Sample>(aSample)));
|
||||
mTaskQueue->Dispatch(NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData> >(
|
||||
this, &FFmpegAudioDecoder::DecodePacket, nsRefPtr<MediaRawData>(aSample)));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -26,12 +26,12 @@ public:
|
|||
virtual ~FFmpegAudioDecoder();
|
||||
|
||||
virtual nsresult Init() override;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual nsresult Input(MediaRawData* aSample) override;
|
||||
virtual nsresult Drain() override;
|
||||
static AVCodecID GetCodecId(const nsACString& aMimeType);
|
||||
|
||||
private:
|
||||
void DecodePacket(mp4_demuxer::MP4Sample* aSample);
|
||||
void DecodePacket(MediaRawData* aSample);
|
||||
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
};
|
||||
|
|
|
@ -30,7 +30,7 @@ public:
|
|||
static bool Link();
|
||||
|
||||
virtual nsresult Init() override;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override = 0;
|
||||
virtual nsresult Input(MediaRawData* aSample) override = 0;
|
||||
virtual nsresult Flush() override;
|
||||
virtual nsresult Drain() override = 0;
|
||||
virtual nsresult Shutdown() override;
|
||||
|
@ -41,7 +41,7 @@ protected:
|
|||
FlushableMediaTaskQueue* mTaskQueue;
|
||||
AVCodecContext* mCodecContext;
|
||||
AVFrame* mFrame;
|
||||
nsRefPtr<mp4_demuxer::ByteBuffer> mExtraData;
|
||||
nsRefPtr<DataBuffer> mExtraData;
|
||||
|
||||
private:
|
||||
static bool sFFmpegInitDone;
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
typedef mozilla::layers::Image Image;
|
||||
typedef mozilla::layers::PlanarYCbCrImage PlanarYCbCrImage;
|
||||
|
||||
typedef mp4_demuxer::MP4Sample MP4Sample;
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
|
||||
|
@ -50,23 +48,17 @@ FFmpegH264Decoder<LIBAV_VER>::Init()
|
|||
}
|
||||
|
||||
FFmpegH264Decoder<LIBAV_VER>::DecodeResult
|
||||
FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(mp4_demuxer::MP4Sample* aSample)
|
||||
FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample)
|
||||
{
|
||||
AVPacket packet;
|
||||
av_init_packet(&packet);
|
||||
|
||||
if (!aSample->Pad(FF_INPUT_BUFFER_PADDING_SIZE)) {
|
||||
NS_WARNING("FFmpeg h264 decoder failed to allocate sample.");
|
||||
mCallback->Error();
|
||||
return DecodeResult::DECODE_ERROR;
|
||||
}
|
||||
|
||||
packet.data = aSample->data;
|
||||
packet.size = aSample->size;
|
||||
packet.dts = aSample->decode_timestamp;
|
||||
packet.pts = aSample->composition_timestamp;
|
||||
packet.flags = aSample->is_sync_point ? AV_PKT_FLAG_KEY : 0;
|
||||
packet.pos = aSample->byte_offset;
|
||||
packet.data = const_cast<uint8_t*>(aSample->mData);
|
||||
packet.size = aSample->mSize;
|
||||
packet.dts = aSample->mTimecode;
|
||||
packet.pts = aSample->mTime;
|
||||
packet.flags = aSample->mKeyframe ? AV_PKT_FLAG_KEY : 0;
|
||||
packet.pos = aSample->mOffset;
|
||||
|
||||
if (!PrepareFrame()) {
|
||||
NS_WARNING("FFmpeg h264 decoder failed to allocate frame.");
|
||||
|
@ -112,11 +104,11 @@ FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(mp4_demuxer::MP4Sample* aSample)
|
|||
|
||||
nsRefPtr<VideoData> v = VideoData::Create(info,
|
||||
mImageContainer,
|
||||
aSample->byte_offset,
|
||||
aSample->mOffset,
|
||||
mFrame->pkt_pts,
|
||||
aSample->duration,
|
||||
aSample->mDuration,
|
||||
b,
|
||||
aSample->is_sync_point,
|
||||
aSample->mKeyframe,
|
||||
-1,
|
||||
gfx::IntRect(0, 0, mCodecContext->width, mCodecContext->height));
|
||||
if (!v) {
|
||||
|
@ -131,7 +123,7 @@ FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(mp4_demuxer::MP4Sample* aSample)
|
|||
}
|
||||
|
||||
void
|
||||
FFmpegH264Decoder<LIBAV_VER>::DecodeFrame(mp4_demuxer::MP4Sample* aSample)
|
||||
FFmpegH264Decoder<LIBAV_VER>::DecodeFrame(MediaRawData* aSample)
|
||||
{
|
||||
if (DoDecodeFrame(aSample) != DecodeResult::DECODE_ERROR &&
|
||||
mTaskQueue->IsEmpty()) {
|
||||
|
@ -245,12 +237,12 @@ FFmpegH264Decoder<LIBAV_VER>::AllocateYUV420PVideoBuffer(
|
|||
}
|
||||
|
||||
nsresult
|
||||
FFmpegH264Decoder<LIBAV_VER>::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
FFmpegH264Decoder<LIBAV_VER>::Input(MediaRawData* aSample)
|
||||
{
|
||||
mTaskQueue->Dispatch(
|
||||
NS_NewRunnableMethodWithArg<nsAutoPtr<mp4_demuxer::MP4Sample>>(
|
||||
NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData>>(
|
||||
this, &FFmpegH264Decoder<LIBAV_VER>::DecodeFrame,
|
||||
nsAutoPtr<mp4_demuxer::MP4Sample>(aSample)));
|
||||
nsRefPtr<MediaRawData>(aSample)));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -258,7 +250,7 @@ FFmpegH264Decoder<LIBAV_VER>::Input(mp4_demuxer::MP4Sample* aSample)
|
|||
void
|
||||
FFmpegH264Decoder<LIBAV_VER>::DoDrain()
|
||||
{
|
||||
nsAutoPtr<MP4Sample> empty(new MP4Sample());
|
||||
nsRefPtr<MediaRawData> empty(new MediaRawData());
|
||||
while (DoDecodeFrame(empty) == DecodeResult::DECODE_FRAME) {
|
||||
}
|
||||
mCallback->DrainComplete();
|
||||
|
|
|
@ -37,14 +37,14 @@ public:
|
|||
virtual ~FFmpegH264Decoder();
|
||||
|
||||
virtual nsresult Init() override;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual nsresult Input(MediaRawData* aSample) override;
|
||||
virtual nsresult Drain() override;
|
||||
virtual nsresult Flush() override;
|
||||
static AVCodecID GetCodecId(const nsACString& aMimeType);
|
||||
|
||||
private:
|
||||
void DecodeFrame(mp4_demuxer::MP4Sample* aSample);
|
||||
DecodeResult DoDecodeFrame(mp4_demuxer::MP4Sample* aSample);
|
||||
void DecodeFrame(MediaRawData* aSample);
|
||||
DecodeResult DoDecodeFrame(MediaRawData* aSample);
|
||||
void DoDrain();
|
||||
void OutputDelayedFrames();
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "GMPAudioDecoder.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -191,17 +192,17 @@ GMPAudioDecoder::Init()
|
|||
}
|
||||
|
||||
nsresult
|
||||
GMPAudioDecoder::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
GMPAudioDecoder::Input(MediaRawData* aSample)
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
|
||||
nsAutoPtr<mp4_demuxer::MP4Sample> sample(aSample);
|
||||
nsRefPtr<MediaRawData> sample(aSample);
|
||||
if (!mGMP) {
|
||||
mCallback->Error();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mAdapter->SetLastStreamOffset(sample->byte_offset);
|
||||
mAdapter->SetLastStreamOffset(sample->mOffset);
|
||||
|
||||
gmp::GMPAudioSamplesImpl samples(sample, mConfig.channel_count, mConfig.samples_per_second);
|
||||
nsresult rv = mGMP->Decode(samples);
|
||||
|
|
|
@ -70,7 +70,7 @@ public:
|
|||
}
|
||||
|
||||
virtual nsresult Init() override;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual nsresult Input(MediaRawData* aSample) override;
|
||||
virtual nsresult Flush() override;
|
||||
virtual nsresult Drain() override;
|
||||
virtual nsresult Shutdown() override;
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "GMPVideoHost.h"
|
||||
#include "mozilla/Endian.h"
|
||||
#include "prsystem.h"
|
||||
#include "MediaData.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -115,7 +117,7 @@ GMPVideoDecoder::GetNodeId()
|
|||
}
|
||||
|
||||
GMPUnique<GMPVideoEncodedFrame>::Ptr
|
||||
GMPVideoDecoder::CreateFrame(mp4_demuxer::MP4Sample* aSample)
|
||||
GMPVideoDecoder::CreateFrame(MediaRawData* aSample)
|
||||
{
|
||||
GMPVideoFrame* ftmp = nullptr;
|
||||
GMPErr err = mHost->CreateFrame(kGMPEncodedVideoFrame, &ftmp);
|
||||
|
@ -125,13 +127,13 @@ GMPVideoDecoder::CreateFrame(mp4_demuxer::MP4Sample* aSample)
|
|||
}
|
||||
|
||||
GMPUnique<GMPVideoEncodedFrame>::Ptr frame(static_cast<GMPVideoEncodedFrame*>(ftmp));
|
||||
err = frame->CreateEmptyFrame(aSample->size);
|
||||
err = frame->CreateEmptyFrame(aSample->mSize);
|
||||
if (GMP_FAILED(err)) {
|
||||
mCallback->Error();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
memcpy(frame->Buffer(), aSample->data, frame->Size());
|
||||
memcpy(frame->Buffer(), aSample->mData, frame->Size());
|
||||
|
||||
// Convert 4-byte NAL unit lengths to host-endian 4-byte buffer lengths to
|
||||
// suit the GMP API.
|
||||
|
@ -149,10 +151,10 @@ GMPVideoDecoder::CreateFrame(mp4_demuxer::MP4Sample* aSample)
|
|||
|
||||
frame->SetEncodedWidth(mConfig.display_width);
|
||||
frame->SetEncodedHeight(mConfig.display_height);
|
||||
frame->SetTimeStamp(aSample->composition_timestamp);
|
||||
frame->SetTimeStamp(aSample->mTime);
|
||||
frame->SetCompleteFrame(true);
|
||||
frame->SetDuration(aSample->duration);
|
||||
frame->SetFrameType(aSample->is_sync_point ? kGMPKeyFrame : kGMPDeltaFrame);
|
||||
frame->SetDuration(aSample->mDuration);
|
||||
frame->SetFrameType(aSample->mKeyframe ? kGMPKeyFrame : kGMPDeltaFrame);
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
@ -235,17 +237,17 @@ GMPVideoDecoder::Init()
|
|||
}
|
||||
|
||||
nsresult
|
||||
GMPVideoDecoder::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
GMPVideoDecoder::Input(MediaRawData* aSample)
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
|
||||
nsAutoPtr<mp4_demuxer::MP4Sample> sample(aSample);
|
||||
nsRefPtr<MediaRawData> sample(aSample);
|
||||
if (!mGMP) {
|
||||
mCallback->Error();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mAdapter->SetLastStreamOffset(sample->byte_offset);
|
||||
mAdapter->SetLastStreamOffset(sample->mOffset);
|
||||
|
||||
GMPUnique<GMPVideoEncodedFrame>::Ptr frame = CreateFrame(sample);
|
||||
nsTArray<uint8_t> info; // No codec specific per-frame info to pass.
|
||||
|
|
|
@ -85,7 +85,7 @@ public:
|
|||
}
|
||||
|
||||
virtual nsresult Init() override;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual nsresult Input(MediaRawData* aSample) override;
|
||||
virtual nsresult Flush() override;
|
||||
virtual nsresult Drain() override;
|
||||
virtual nsresult Shutdown() override;
|
||||
|
@ -93,7 +93,7 @@ public:
|
|||
protected:
|
||||
virtual void InitTags(nsTArray<nsCString>& aTags);
|
||||
virtual nsCString GetNodeId();
|
||||
virtual GMPUnique<GMPVideoEncodedFrame>::Ptr CreateFrame(mp4_demuxer::MP4Sample* aSample);
|
||||
virtual GMPUnique<GMPVideoEncodedFrame>::Ptr CreateFrame(MediaRawData* aSample);
|
||||
|
||||
private:
|
||||
class GMPInitDoneRunnable : public nsRunnable
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MediaDataDecoderProxy.h"
|
||||
#include "MediaData.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -33,7 +34,7 @@ MediaDataDecoderProxy::Init()
|
|||
}
|
||||
|
||||
nsresult
|
||||
MediaDataDecoderProxy::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
MediaDataDecoderProxy::Input(MediaRawData* aSample)
|
||||
{
|
||||
MOZ_ASSERT(!IsOnProxyThread());
|
||||
MOZ_ASSERT(!mIsShutdown);
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
#define MediaDataDecoderProxy_h_
|
||||
|
||||
#include "PlatformDecoderModule.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsRefPtr.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nscore.h"
|
||||
|
@ -19,19 +17,19 @@ namespace mozilla {
|
|||
class InputTask : public nsRunnable {
|
||||
public:
|
||||
InputTask(MediaDataDecoder* aDecoder,
|
||||
mp4_demuxer::MP4Sample* aSample)
|
||||
MediaRawData* aSample)
|
||||
: mDecoder(aDecoder)
|
||||
, mSample(aSample)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
mDecoder->Input(mSample.forget());
|
||||
mDecoder->Input(mSample);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<MediaDataDecoder> mDecoder;
|
||||
nsAutoPtr<mp4_demuxer::MP4Sample> mSample;
|
||||
nsRefPtr<MediaRawData> mSample;
|
||||
};
|
||||
|
||||
class InitTask : public nsRunnable {
|
||||
|
@ -88,7 +86,7 @@ class MediaDataDecoderProxy;
|
|||
|
||||
class MediaDataDecoderCallbackProxy : public MediaDataDecoderCallback {
|
||||
public:
|
||||
explicit MediaDataDecoderCallbackProxy(MediaDataDecoderProxy* aProxyDecoder, MediaDataDecoderCallback* aCallback)
|
||||
MediaDataDecoderCallbackProxy(MediaDataDecoderProxy* aProxyDecoder, MediaDataDecoderCallback* aCallback)
|
||||
: mProxyDecoder(aProxyDecoder)
|
||||
, mProxyCallback(aCallback)
|
||||
{
|
||||
|
@ -157,7 +155,7 @@ public:
|
|||
// asynchronously and responded to via the MediaDataDecoderCallback.
|
||||
// Note: the nsresults returned by the proxied decoder are lost.
|
||||
virtual nsresult Init() override;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual nsresult Input(MediaRawData* aSample) override;
|
||||
virtual nsresult Flush() override;
|
||||
virtual nsresult Drain() override;
|
||||
virtual nsresult Shutdown() override;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <stagefright/foundation/AMessage.h>
|
||||
#include <stagefright/foundation/ALooper.h>
|
||||
#include "media/openmax/OMX_Audio.h"
|
||||
#include "MediaData.h"
|
||||
|
||||
#include <android/log.h>
|
||||
#define GADM_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkAudioDecoderManager", __VA_ARGS__)
|
||||
|
@ -100,16 +101,16 @@ GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback)
|
|||
}
|
||||
|
||||
status_t
|
||||
GonkAudioDecoderManager::SendSampleToOMX(mp4_demuxer::MP4Sample* aSample)
|
||||
GonkAudioDecoderManager::SendSampleToOMX(MediaRawData* aSample)
|
||||
{
|
||||
return mDecoder->Input(reinterpret_cast<const uint8_t*>(aSample->data),
|
||||
aSample->size,
|
||||
aSample->composition_timestamp,
|
||||
return mDecoder->Input(reinterpret_cast<const uint8_t*>(aSample->mData),
|
||||
aSample->mSize,
|
||||
aSample->mTime,
|
||||
0);
|
||||
}
|
||||
|
||||
bool
|
||||
GonkAudioDecoderManager::PerformFormatSpecificProcess(mp4_demuxer::MP4Sample* aSample)
|
||||
GonkAudioDecoderManager::PerformFormatSpecificProcess(MediaRawData* aSample)
|
||||
{
|
||||
if (aSample && mUseAdts) {
|
||||
int8_t frequency_index =
|
||||
|
|
|
@ -35,9 +35,9 @@ public:
|
|||
virtual nsresult Flush() override;
|
||||
|
||||
protected:
|
||||
virtual bool PerformFormatSpecificProcess(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual bool PerformFormatSpecificProcess(MediaRawData* aSample) override;
|
||||
|
||||
virtual status_t SendSampleToOMX(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual status_t SendSampleToOMX(MediaRawData* aSample) override;
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "VideoUtils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "MediaCodecProxy.h"
|
||||
#include "MediaData.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#include <android/log.h>
|
||||
|
@ -30,7 +31,7 @@ GonkDecoderManager::GonkDecoderManager(MediaTaskQueue* aTaskQueue)
|
|||
}
|
||||
|
||||
nsresult
|
||||
GonkDecoderManager::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
GonkDecoderManager::Input(MediaRawData* aSample)
|
||||
{
|
||||
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
|
||||
|
||||
|
@ -49,18 +50,18 @@ GonkDecoderManager::Input(mp4_demuxer::MP4Sample* aSample)
|
|||
mQueueSample.RemoveElementAt(0);
|
||||
}
|
||||
|
||||
// When EOS, aSample will be null and sends this empty MP4Sample to nofity
|
||||
// When EOS, aSample will be null and sends this empty MediaRawData to nofity
|
||||
// OMX it reachs EOS.
|
||||
nsAutoPtr<mp4_demuxer::MP4Sample> sample;
|
||||
nsRefPtr<MediaRawData> sample;
|
||||
if (!aSample) {
|
||||
sample = new mp4_demuxer::MP4Sample();
|
||||
sample = new MediaRawData();
|
||||
}
|
||||
|
||||
// If rv is OK, that means mQueueSample is empty, now try to queue current input
|
||||
// aSample.
|
||||
if (rv == OK) {
|
||||
MOZ_ASSERT(!mQueueSample.Length());
|
||||
mp4_demuxer::MP4Sample* tmp;
|
||||
MediaRawData* tmp;
|
||||
if (aSample) {
|
||||
tmp = aSample;
|
||||
if (!PerformFormatSpecificProcess(aSample)) {
|
||||
|
@ -151,18 +152,18 @@ GonkMediaDataDecoder::Shutdown()
|
|||
|
||||
// Inserts data into the decoder's pipeline.
|
||||
nsresult
|
||||
GonkMediaDataDecoder::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
GonkMediaDataDecoder::Input(MediaRawData* aSample)
|
||||
{
|
||||
mTaskQueue->Dispatch(
|
||||
NS_NewRunnableMethodWithArg<nsAutoPtr<mp4_demuxer::MP4Sample>>(
|
||||
NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData>>(
|
||||
this,
|
||||
&GonkMediaDataDecoder::ProcessDecode,
|
||||
nsAutoPtr<mp4_demuxer::MP4Sample>(aSample)));
|
||||
nsRefPtr<MediaRawData>(aSample)));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
GonkMediaDataDecoder::ProcessDecode(mp4_demuxer::MP4Sample* aSample)
|
||||
GonkMediaDataDecoder::ProcessDecode(MediaRawData* aSample)
|
||||
{
|
||||
nsresult rv = mManager->Input(aSample);
|
||||
if (rv != NS_OK) {
|
||||
|
@ -172,7 +173,7 @@ GonkMediaDataDecoder::ProcessDecode(mp4_demuxer::MP4Sample* aSample)
|
|||
return;
|
||||
}
|
||||
if (aSample) {
|
||||
mLastStreamOffset = aSample->byte_offset;
|
||||
mLastStreamOffset = aSample->mOffset;
|
||||
}
|
||||
ProcessOutput();
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
#if !defined(GonkMediaDataDecoder_h_)
|
||||
#define GonkMediaDataDecoder_h_
|
||||
#include "mp4_demuxer/mp4_demuxer.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "MP4Reader.h"
|
||||
|
||||
|
@ -15,6 +14,7 @@ class MediaCodecProxy;
|
|||
} // namespace android
|
||||
|
||||
namespace mozilla {
|
||||
class MediaRawData;
|
||||
|
||||
// Manage the data flow from inputting encoded data and outputting decode data.
|
||||
class GonkDecoderManager {
|
||||
|
@ -28,7 +28,7 @@ public:
|
|||
virtual android::sp<android::MediaCodecProxy> Init(MediaDataDecoderCallback* aCallback) = 0;
|
||||
|
||||
// Add samples into OMX decoder or queue them if decoder is out of input buffer.
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample);
|
||||
virtual nsresult Input(MediaRawData* aSample);
|
||||
|
||||
// Produces decoded output, it blocks until output can be produced or a timeout
|
||||
// is expired or until EOS. Returns NS_OK on success, or NS_ERROR_NOT_AVAILABLE
|
||||
|
@ -62,15 +62,15 @@ public:
|
|||
protected:
|
||||
// It performs special operation to MP4 sample, the real action is depended on
|
||||
// the codec type.
|
||||
virtual bool PerformFormatSpecificProcess(mp4_demuxer::MP4Sample* aSample) { return true; }
|
||||
virtual bool PerformFormatSpecificProcess(MediaRawData* aSample) { return true; }
|
||||
|
||||
// It sends MP4Sample to OMX layer. It must be overrided by subclass.
|
||||
virtual android::status_t SendSampleToOMX(mp4_demuxer::MP4Sample* aSample) = 0;
|
||||
virtual android::status_t SendSampleToOMX(MediaRawData* aSample) = 0;
|
||||
|
||||
// An queue with the MP4 samples which are waiting to be sent into OMX.
|
||||
// If an element is an empty MP4Sample, that menas EOS. There should not
|
||||
// any sample be queued after EOS.
|
||||
nsTArray<nsAutoPtr<mp4_demuxer::MP4Sample>> mQueueSample;
|
||||
nsTArray<nsRefPtr<MediaRawData>> mQueueSample;
|
||||
|
||||
RefPtr<MediaTaskQueue> mTaskQueue;
|
||||
};
|
||||
|
@ -90,7 +90,7 @@ public:
|
|||
|
||||
virtual nsresult Init() override;
|
||||
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample);
|
||||
virtual nsresult Input(MediaRawData* aSample);
|
||||
|
||||
virtual nsresult Flush() override;
|
||||
|
||||
|
@ -112,7 +112,7 @@ private:
|
|||
// extracts output if available, if aSample is null, it means there is
|
||||
// no data from source, it will notify the decoder EOS and flush all the
|
||||
// decoded frames.
|
||||
void ProcessDecode(mp4_demuxer::MP4Sample* aSample);
|
||||
void ProcessDecode(MediaRawData* aSample);
|
||||
|
||||
// Called on the task queue. Extracts output if available, and delivers
|
||||
// it to the reader. Called after ProcessDecode() and ProcessDrain().
|
||||
|
|
|
@ -438,17 +438,17 @@ void GonkVideoDecoderManager::ReleaseVideoBuffer() {
|
|||
}
|
||||
|
||||
status_t
|
||||
GonkVideoDecoderManager::SendSampleToOMX(mp4_demuxer::MP4Sample* aSample)
|
||||
GonkVideoDecoderManager::SendSampleToOMX(MediaRawData* aSample)
|
||||
{
|
||||
// An empty MP4Sample is going to notify EOS to decoder. It doesn't need
|
||||
// An empty MediaRawData is going to notify EOS to decoder. It doesn't need
|
||||
// to keep PTS and duration.
|
||||
if (aSample->data && aSample->duration && aSample->composition_timestamp) {
|
||||
QueueFrameTimeIn(aSample->composition_timestamp, aSample->duration);
|
||||
if (aSample->mData && aSample->mDuration && aSample->mTime) {
|
||||
QueueFrameTimeIn(aSample->mTime, aSample->mDuration);
|
||||
}
|
||||
|
||||
return mDecoder->Input(reinterpret_cast<const uint8_t*>(aSample->data),
|
||||
aSample->size,
|
||||
aSample->composition_timestamp,
|
||||
return mDecoder->Input(reinterpret_cast<const uint8_t*>(aSample->mData),
|
||||
aSample->mSize,
|
||||
aSample->mTime,
|
||||
0);
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ public:
|
|||
static void RecycleCallback(TextureClient* aClient, void* aClosure);
|
||||
|
||||
protected:
|
||||
virtual android::status_t SendSampleToOMX(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual android::status_t SendSampleToOMX(MediaRawData* aSample) override;
|
||||
|
||||
private:
|
||||
struct FrameInfo
|
||||
|
|
|
@ -177,11 +177,11 @@ WMFAudioMFTManager::Init()
|
|||
}
|
||||
|
||||
HRESULT
|
||||
WMFAudioMFTManager::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
WMFAudioMFTManager::Input(MediaRawData* aSample)
|
||||
{
|
||||
const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
|
||||
uint32_t length = aSample->size;
|
||||
return mDecoder->Input(data, length, aSample->composition_timestamp);
|
||||
return mDecoder->Input(aSample->mData,
|
||||
uint32_t(aSample->mSize),
|
||||
aSample->mTime);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
|
|
|
@ -22,7 +22,7 @@ public:
|
|||
|
||||
virtual TemporaryRef<MFTDecoder> Init() override;
|
||||
|
||||
virtual HRESULT Input(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual HRESULT Input(MediaRawData* aSample) override;
|
||||
|
||||
// Note WMF's AAC decoder sometimes output negatively timestamped samples,
|
||||
// presumably they're the preroll samples, and we strip them. We may return
|
||||
|
|
|
@ -75,18 +75,18 @@ WMFMediaDataDecoder::ProcessReleaseDecoder()
|
|||
|
||||
// Inserts data into the decoder's pipeline.
|
||||
nsresult
|
||||
WMFMediaDataDecoder::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
WMFMediaDataDecoder::Input(MediaRawData* aSample)
|
||||
{
|
||||
mTaskQueue->Dispatch(
|
||||
NS_NewRunnableMethodWithArg<nsAutoPtr<mp4_demuxer::MP4Sample>>(
|
||||
NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData>>(
|
||||
this,
|
||||
&WMFMediaDataDecoder::ProcessDecode,
|
||||
nsAutoPtr<mp4_demuxer::MP4Sample>(aSample)));
|
||||
nsRefPtr<MediaRawData>(aSample)));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
WMFMediaDataDecoder::ProcessDecode(mp4_demuxer::MP4Sample* aSample)
|
||||
WMFMediaDataDecoder::ProcessDecode(MediaRawData* aSample)
|
||||
{
|
||||
HRESULT hr = mMFTManager->Input(aSample);
|
||||
if (FAILED(hr)) {
|
||||
|
@ -95,7 +95,7 @@ WMFMediaDataDecoder::ProcessDecode(mp4_demuxer::MP4Sample* aSample)
|
|||
return;
|
||||
}
|
||||
|
||||
mLastStreamOffset = aSample->byte_offset;
|
||||
mLastStreamOffset = aSample->mOffset;
|
||||
|
||||
ProcessOutput();
|
||||
}
|
||||
|
|
|
@ -13,10 +13,6 @@
|
|||
#include "MFTDecoder.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
namespace mp4_demuxer {
|
||||
class MP4Sample;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Encapsulates the initialization of the MFTDecoder appropriate for decoding
|
||||
|
@ -33,7 +29,7 @@ public:
|
|||
// Submit a compressed sample for decoding.
|
||||
// This should forward to the MFTDecoder after performing
|
||||
// any required sample formatting.
|
||||
virtual HRESULT Input(mp4_demuxer::MP4Sample* aSample) = 0;
|
||||
virtual HRESULT Input(MediaRawData* aSample) = 0;
|
||||
|
||||
// Produces decoded output, if possible. Blocks until output can be produced,
|
||||
// or until no more is able to be produced.
|
||||
|
@ -65,7 +61,7 @@ public:
|
|||
|
||||
virtual nsresult Init() override;
|
||||
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample);
|
||||
virtual nsresult Input(MediaRawData* aSample);
|
||||
|
||||
virtual nsresult Flush() override;
|
||||
|
||||
|
@ -83,7 +79,7 @@ private:
|
|||
|
||||
// Called on the task queue. Inserts the sample into the decoder, and
|
||||
// extracts output if available.
|
||||
void ProcessDecode(mp4_demuxer::MP4Sample* aSample);
|
||||
void ProcessDecode(MediaRawData* aSample);
|
||||
|
||||
// Called on the task queue. Extracts output if available, and delivers
|
||||
// it to the reader. Called after ProcessDecode() and ProcessDrain().
|
||||
|
|
|
@ -235,16 +235,16 @@ WMFVideoMFTManager::Init()
|
|||
}
|
||||
|
||||
HRESULT
|
||||
WMFVideoMFTManager::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
WMFVideoMFTManager::Input(MediaRawData* aSample)
|
||||
{
|
||||
if (!mDecoder) {
|
||||
// This can happen during shutdown.
|
||||
return E_FAIL;
|
||||
}
|
||||
// Forward sample data to the decoder.
|
||||
const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
|
||||
uint32_t length = aSample->size;
|
||||
return mDecoder->Input(data, length, aSample->composition_timestamp);
|
||||
return mDecoder->Input(aSample->mData,
|
||||
uint32_t(aSample->mSize),
|
||||
aSample->mTime);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
|
||||
virtual TemporaryRef<MFTDecoder> Init() override;
|
||||
|
||||
virtual HRESULT Input(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual HRESULT Input(MediaRawData* aSample) override;
|
||||
|
||||
virtual HRESULT Output(int64_t aStreamOffset,
|
||||
nsRefPtr<MediaData>& aOutput) override;
|
||||
|
|
|
@ -52,7 +52,7 @@ H264Converter::Init()
|
|||
}
|
||||
|
||||
nsresult
|
||||
H264Converter::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
H264Converter::Input(MediaRawData* aSample)
|
||||
{
|
||||
if (!mNeedAVCC) {
|
||||
if (!mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) {
|
||||
|
@ -71,7 +71,7 @@ H264Converter::Input(mp4_demuxer::MP4Sample* aSample)
|
|||
rv = CreateDecoderAndInit(aSample);
|
||||
if (rv == NS_ERROR_NOT_INITIALIZED) {
|
||||
// We are missing the required SPS to create the decoder.
|
||||
// Ignore for the time being, the MP4Sample will be dropped.
|
||||
// Ignore for the time being, the MediaRawData will be dropped.
|
||||
return NS_OK;
|
||||
}
|
||||
} else {
|
||||
|
@ -79,7 +79,7 @@ H264Converter::Input(mp4_demuxer::MP4Sample* aSample)
|
|||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aSample->extra_data = mCurrentConfig.extra_data;
|
||||
aSample->mExtraData = mCurrentConfig.extra_data;
|
||||
|
||||
return mDecoder->Input(aSample);
|
||||
}
|
||||
|
@ -187,9 +187,9 @@ H264Converter::CreateDecoder()
|
|||
}
|
||||
|
||||
nsresult
|
||||
H264Converter::CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample)
|
||||
H264Converter::CreateDecoderAndInit(MediaRawData* aSample)
|
||||
{
|
||||
nsRefPtr<mp4_demuxer::ByteBuffer> extra_data =
|
||||
nsRefPtr<DataBuffer> extra_data =
|
||||
mp4_demuxer::AnnexB::ExtractExtraData(aSample);
|
||||
if (!mp4_demuxer::AnnexB::HasSPS(extra_data)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
@ -202,9 +202,9 @@ H264Converter::CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample)
|
|||
}
|
||||
|
||||
nsresult
|
||||
H264Converter::CheckForSPSChange(mp4_demuxer::MP4Sample* aSample)
|
||||
H264Converter::CheckForSPSChange(MediaRawData* aSample)
|
||||
{
|
||||
nsRefPtr<mp4_demuxer::ByteBuffer> extra_data =
|
||||
nsRefPtr<DataBuffer> extra_data =
|
||||
mp4_demuxer::AnnexB::ExtractExtraData(aSample);
|
||||
if (!mp4_demuxer::AnnexB::HasSPS(extra_data) ||
|
||||
mp4_demuxer::AnnexB::CompareExtraData(extra_data,
|
||||
|
@ -224,7 +224,7 @@ H264Converter::CheckForSPSChange(mp4_demuxer::MP4Sample* aSample)
|
|||
}
|
||||
|
||||
void
|
||||
H264Converter::UpdateConfigFromExtraData(mp4_demuxer::ByteBuffer* aExtraData)
|
||||
H264Converter::UpdateConfigFromExtraData(DataBuffer* aExtraData)
|
||||
{
|
||||
mp4_demuxer::SPSData spsdata;
|
||||
if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata) &&
|
||||
|
|
|
@ -30,7 +30,7 @@ public:
|
|||
virtual ~H264Converter();
|
||||
|
||||
virtual nsresult Init() override;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual nsresult Input(MediaRawData* aSample) override;
|
||||
virtual nsresult Flush() override;
|
||||
virtual nsresult Drain() override;
|
||||
virtual nsresult Shutdown() override;
|
||||
|
@ -48,9 +48,9 @@ private:
|
|||
// Returns NS_ERROR_FAILURE if error is permanent and can't be recovered and
|
||||
// will set mError accordingly.
|
||||
nsresult CreateDecoder();
|
||||
nsresult CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample);
|
||||
nsresult CheckForSPSChange(mp4_demuxer::MP4Sample* aSample);
|
||||
void UpdateConfigFromExtraData(mp4_demuxer::ByteBuffer* aExtraData);
|
||||
nsresult CreateDecoderAndInit(MediaRawData* aSample);
|
||||
nsresult CheckForSPSChange(MediaRawData* aSample);
|
||||
void UpdateConfigFromExtraData(DataBuffer* aExtraData);
|
||||
|
||||
nsRefPtr<PlatformDecoderModule> mPDM;
|
||||
mp4_demuxer::VideoDecoderConfig mCurrentConfig;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "gmp-audio-samples.h"
|
||||
#include "gmp-errors.h"
|
||||
#include "GMPEncryptedBufferDataImpl.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "MediaData.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
@ -32,17 +32,17 @@ GMPAudioSamplesImpl::GMPAudioSamplesImpl(const GMPAudioEncodedSampleData& aData)
|
|||
}
|
||||
}
|
||||
|
||||
GMPAudioSamplesImpl::GMPAudioSamplesImpl(mp4_demuxer::MP4Sample* aSample,
|
||||
GMPAudioSamplesImpl::GMPAudioSamplesImpl(MediaRawData* aSample,
|
||||
uint32_t aChannels,
|
||||
uint32_t aRate)
|
||||
: mFormat(kGMPAudioEncodedSamples)
|
||||
, mTimeStamp(aSample->composition_timestamp)
|
||||
, mTimeStamp(aSample->mTime)
|
||||
, mChannels(aChannels)
|
||||
, mRate(aRate)
|
||||
{
|
||||
mBuffer.AppendElements(aSample->data, aSample->size);
|
||||
if (aSample->crypto.valid) {
|
||||
mCrypto = new GMPEncryptedBufferDataImpl(aSample->crypto);
|
||||
mBuffer.AppendElements(aSample->mData, aSample->mSize);
|
||||
if (aSample->mCrypto.valid) {
|
||||
mCrypto = new GMPEncryptedBufferDataImpl(aSample->mCrypto);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,12 +14,9 @@
|
|||
#include "GMPEncryptedBufferDataImpl.h"
|
||||
#include "mozilla/gmp/GMPTypes.h"
|
||||
|
||||
namespace mp4_demuxer {
|
||||
class MP4Sample;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
class CryptoSample;
|
||||
class MediaRawData;
|
||||
|
||||
namespace gmp {
|
||||
|
||||
|
@ -27,7 +24,7 @@ class GMPAudioSamplesImpl : public GMPAudioSamples {
|
|||
public:
|
||||
explicit GMPAudioSamplesImpl(GMPAudioFormat aFormat);
|
||||
explicit GMPAudioSamplesImpl(const GMPAudioEncodedSampleData& aData);
|
||||
GMPAudioSamplesImpl(mp4_demuxer::MP4Sample* aSample,
|
||||
GMPAudioSamplesImpl(MediaRawData* aSample,
|
||||
uint32_t aChannels,
|
||||
uint32_t aRate);
|
||||
virtual ~GMPAudioSamplesImpl();
|
||||
|
|
|
@ -43,23 +43,23 @@ TEST(MP4Demuxer, Seek)
|
|||
|
||||
EXPECT_TRUE(d->Init());
|
||||
|
||||
nsTArray<nsAutoPtr<MP4Sample>> samples;
|
||||
MP4Sample* sample;
|
||||
nsTArray<nsRefPtr<MediaRawData>> samples;
|
||||
nsRefPtr<MediaRawData> sample;
|
||||
while (!!(sample = d->DemuxVideoSample())) {
|
||||
samples.AppendElement(sample);
|
||||
if (samples.Length() >= 2) {
|
||||
EXPECT_LT(samples[samples.Length() - 2]->decode_timestamp,
|
||||
samples[samples.Length() - 1]->decode_timestamp);
|
||||
EXPECT_LT(samples[samples.Length() - 2]->mTimecode,
|
||||
samples[samples.Length() - 1]->mTimecode);
|
||||
}
|
||||
}
|
||||
Microseconds keyFrame = 0;
|
||||
for (size_t i = 0; i < samples.Length(); i++) {
|
||||
if (samples[i]->is_sync_point) {
|
||||
keyFrame = samples[i]->decode_timestamp;
|
||||
if (samples[i]->mKeyframe) {
|
||||
keyFrame = samples[i]->mTimecode;
|
||||
}
|
||||
d->SeekVideo(samples[i]->composition_timestamp);
|
||||
d->SeekVideo(samples[i]->mTime);
|
||||
sample = d->DemuxVideoSample();
|
||||
EXPECT_EQ(keyFrame, sample->decode_timestamp);
|
||||
EXPECT_EQ(keyFrame, sample->mTimecode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,10 +158,10 @@ TEST(MP4Demuxer, CENCFrag)
|
|||
"1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000019cd 5,2392",
|
||||
};
|
||||
|
||||
MP4Sample* sample;
|
||||
nsRefPtr<MediaRawData> sample;
|
||||
size_t i = 0;
|
||||
while (!!(sample = d->DemuxVideoSample())) {
|
||||
nsCString text = ToCryptoString(sample->crypto);
|
||||
nsCString text = ToCryptoString(sample->mCrypto);
|
||||
EXPECT_STREQ(video[i++], text.get());
|
||||
}
|
||||
EXPECT_EQ(ArrayLength(video), i);
|
||||
|
@ -265,7 +265,7 @@ TEST(MP4Demuxer, CENCFrag)
|
|||
|
||||
i = 0;
|
||||
while (!!(sample = d->DemuxAudioSample())) {
|
||||
nsCString text = ToCryptoString(sample->crypto);
|
||||
nsCString text = ToCryptoString(sample->mCrypto);
|
||||
EXPECT_STREQ(audio[i++], text.get());
|
||||
}
|
||||
EXPECT_EQ(ArrayLength(audio), i);
|
||||
|
@ -292,11 +292,11 @@ TEST(MP4Demuxer, GetNextKeyframe)
|
|||
// gizmp-frag has two keyframes; one at dts=cts=0, and another at
|
||||
// dts=cts=1000000. Verify we get expected results.
|
||||
|
||||
MP4Sample* sample;
|
||||
nsRefPtr<MediaRawData> sample;
|
||||
size_t i = 0;
|
||||
const int64_t keyframe = 1000000;
|
||||
while (!!(sample = d->DemuxVideoSample())) {
|
||||
int64_t expected = (sample->decode_timestamp < keyframe) ? keyframe : -1;
|
||||
int64_t expected = (sample->mTimecode < keyframe) ? keyframe : -1;
|
||||
EXPECT_EQ(d->GetNextKeyframeTime(), expected);
|
||||
i++;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ using layers::Image;
|
|||
using layers::LayerManager;
|
||||
using layers::LayersBackend;
|
||||
|
||||
class VP8Sample : public MP4Sample
|
||||
class VP8Sample : public MediaRawData
|
||||
{
|
||||
public:
|
||||
VP8Sample(int64_t aTimestamp,
|
||||
|
@ -44,21 +44,13 @@ public:
|
|||
uint8_t* aData,
|
||||
size_t aSize,
|
||||
bool aSyncPoint)
|
||||
: MediaRawData(aData, aSize)
|
||||
{
|
||||
decode_timestamp = -1;
|
||||
composition_timestamp = aTimestamp;
|
||||
duration = aDuration;
|
||||
byte_offset = aByteOffset;
|
||||
is_sync_point = aSyncPoint;
|
||||
|
||||
data = new uint8_t[aSize];
|
||||
size = aSize;
|
||||
memmove(data, aData, size);
|
||||
}
|
||||
|
||||
virtual ~VP8Sample()
|
||||
{
|
||||
delete data;
|
||||
mTimecode = -1;
|
||||
mTime = aTimestamp;
|
||||
mDuration = aDuration;
|
||||
mOffset = aByteOffset;
|
||||
mKeyframe = aSyncPoint;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -162,7 +154,7 @@ IntelWebMVideoDecoder::Init(unsigned int aWidth, unsigned int aHeight)
|
|||
}
|
||||
|
||||
bool
|
||||
IntelWebMVideoDecoder::Demux(nsAutoPtr<VP8Sample>& aSample, bool* aEOS)
|
||||
IntelWebMVideoDecoder::Demux(nsRefPtr<VP8Sample>& aSample, bool* aEOS)
|
||||
{
|
||||
nsAutoRef<NesteggPacketHolder> holder(mReader->NextPacket(WebMReader::VIDEO));
|
||||
if (!holder) {
|
||||
|
@ -232,6 +224,9 @@ IntelWebMVideoDecoder::Demux(nsAutoPtr<VP8Sample>& aSample, bool* aEOS)
|
|||
data,
|
||||
length,
|
||||
si.is_kf);
|
||||
if (!aSample->mData) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -257,7 +252,7 @@ IntelWebMVideoDecoder::Decode()
|
|||
!mEOS) {
|
||||
mMonitor.AssertCurrentThreadOwns();
|
||||
mMonitor.Unlock();
|
||||
nsAutoPtr<VP8Sample> compressed(PopSample());
|
||||
nsRefPtr<VP8Sample> compressed(PopSample());
|
||||
if (!compressed) {
|
||||
// EOS, or error. Let the state machine know there are no more
|
||||
// frames coming.
|
||||
|
@ -272,7 +267,7 @@ IntelWebMVideoDecoder::Decode()
|
|||
} else {
|
||||
#ifdef LOG_SAMPLE_DECODE
|
||||
LOG("PopSample %s time=%lld dur=%lld", TrackTypeToStr(aTrack),
|
||||
compressed->composition_timestamp, compressed->duration);
|
||||
compressed->mTime, compressed->mDuration);
|
||||
#endif
|
||||
mMonitor.Lock();
|
||||
mDrainComplete = false;
|
||||
|
@ -282,10 +277,6 @@ IntelWebMVideoDecoder::Decode()
|
|||
if (NS_FAILED(mMediaDataDecoder->Input(compressed))) {
|
||||
return false;
|
||||
}
|
||||
// If Input() failed, we let the auto pointer delete |compressed|.
|
||||
// Otherwise, we assume the decoder will delete it when it's finished
|
||||
// with it.
|
||||
compressed.forget();
|
||||
}
|
||||
mMonitor.Lock();
|
||||
}
|
||||
|
@ -317,14 +308,14 @@ IntelWebMVideoDecoder::SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint
|
|||
|
||||
// Loop until we reach the next keyframe after the threshold.
|
||||
while (true) {
|
||||
nsAutoPtr<VP8Sample> compressed(PopSample());
|
||||
nsRefPtr<VP8Sample> compressed(PopSample());
|
||||
if (!compressed) {
|
||||
// EOS, or error. Let the state machine know.
|
||||
return false;
|
||||
}
|
||||
aParsed++;
|
||||
if (!compressed->is_sync_point ||
|
||||
compressed->composition_timestamp < aTimeThreshold) {
|
||||
if (!compressed->mKeyframe ||
|
||||
compressed->mTime < aTimeThreshold) {
|
||||
continue;
|
||||
}
|
||||
mQueuedVideoSample = compressed;
|
||||
|
@ -367,15 +358,14 @@ IntelWebMVideoDecoder::DecodeVideoFrame(bool& aKeyframeSkip,
|
|||
return rv;
|
||||
}
|
||||
|
||||
VP8Sample*
|
||||
already_AddRefed<VP8Sample>
|
||||
IntelWebMVideoDecoder::PopSample()
|
||||
{
|
||||
VP8Sample* sample = nullptr;
|
||||
if (mQueuedVideoSample) {
|
||||
return mQueuedVideoSample.forget();
|
||||
}
|
||||
nsRefPtr<VP8Sample> sample;
|
||||
while (mSampleQueue.empty()) {
|
||||
nsAutoPtr<VP8Sample> sample;
|
||||
bool eos = false;
|
||||
bool ok = Demux(sample, &eos);
|
||||
if (!ok || eos) {
|
||||
|
@ -389,7 +379,7 @@ IntelWebMVideoDecoder::PopSample()
|
|||
MOZ_ASSERT(!mSampleQueue.empty());
|
||||
sample = mSampleQueue.front();
|
||||
mSampleQueue.pop_front();
|
||||
return sample;
|
||||
return sample.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "mp4_demuxer/mp4_demuxer.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "MediaData.h"
|
||||
|
||||
class MediaTaskQueue;
|
||||
|
||||
|
@ -22,7 +23,7 @@ namespace mozilla {
|
|||
|
||||
class VP8Sample;
|
||||
|
||||
typedef std::deque<VP8Sample*> VP8SampleQueue;
|
||||
typedef std::deque<nsRefPtr<VP8Sample>> VP8SampleQueue;
|
||||
|
||||
class IntelWebMVideoDecoder : public WebMVideoDecoder, public MediaDataDecoderCallback
|
||||
{
|
||||
|
@ -50,13 +51,13 @@ private:
|
|||
|
||||
bool Decode();
|
||||
|
||||
bool Demux(nsAutoPtr<VP8Sample>& aSample, bool* aEOS);
|
||||
bool Demux(nsRefPtr<VP8Sample>& aSample, bool* aEOS);
|
||||
|
||||
bool SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed);
|
||||
|
||||
bool IsSupportedVideoMimeType(const nsACString& aMimeType);
|
||||
|
||||
VP8Sample* PopSample();
|
||||
already_AddRefed<VP8Sample> PopSample();
|
||||
|
||||
nsRefPtr<WebMReader> mReader;
|
||||
nsRefPtr<PlatformDecoderModule> mPlatform;
|
||||
|
@ -72,7 +73,7 @@ private:
|
|||
nsAutoPtr<mp4_demuxer::VideoDecoderConfig> mDecoderConfig;
|
||||
|
||||
VP8SampleQueue mSampleQueue;
|
||||
nsAutoPtr<VP8Sample> mQueuedVideoSample;
|
||||
nsRefPtr<VP8Sample> mQueuedVideoSample;
|
||||
uint64_t mNumSamplesInput;
|
||||
uint64_t mNumSamplesOutput;
|
||||
uint64_t mLastReportedNumDecodedFrames;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mp4_demuxer/Adts.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "MediaData.h"
|
||||
#include "media/stagefright/MediaBuffer.h"
|
||||
#include "mozilla/Array.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
@ -34,11 +34,11 @@ Adts::GetFrequencyIndex(uint16_t aSamplesPerSecond)
|
|||
|
||||
bool
|
||||
Adts::ConvertSample(uint16_t aChannelCount, int8_t aFrequencyIndex,
|
||||
int8_t aProfile, MP4Sample* aSample)
|
||||
int8_t aProfile, MediaRawData* aSample)
|
||||
{
|
||||
static const int kADTSHeaderSize = 7;
|
||||
|
||||
size_t newSize = aSample->size + kADTSHeaderSize;
|
||||
size_t newSize = aSample->mSize + kADTSHeaderSize;
|
||||
|
||||
// ADTS header uses 13 bits for packet size.
|
||||
if (newSize >= (1 << 13) || aChannelCount > 15 ||
|
||||
|
@ -56,16 +56,17 @@ Adts::ConvertSample(uint16_t aChannelCount, int8_t aFrequencyIndex,
|
|||
header[5] = ((newSize & 7) << 5) + 0x1f;
|
||||
header[6] = 0xfc;
|
||||
|
||||
if (!aSample->Prepend(&header[0], ArrayLength(header))) {
|
||||
nsAutoPtr<MediaRawDataWriter> writer(aSample->CreateWriter());
|
||||
if (!writer->Prepend(&header[0], ArrayLength(header))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aSample->crypto.valid) {
|
||||
if (aSample->crypto.plain_sizes.Length() == 0) {
|
||||
aSample->crypto.plain_sizes.AppendElement(kADTSHeaderSize);
|
||||
aSample->crypto.encrypted_sizes.AppendElement(aSample->size - kADTSHeaderSize);
|
||||
if (aSample->mCrypto.valid) {
|
||||
if (aSample->mCrypto.plain_sizes.Length() == 0) {
|
||||
aSample->mCrypto.plain_sizes.AppendElement(kADTSHeaderSize);
|
||||
aSample->mCrypto.encrypted_sizes.AppendElement(aSample->mSize - kADTSHeaderSize);
|
||||
} else {
|
||||
aSample->crypto.plain_sizes[0] += kADTSHeaderSize;
|
||||
aSample->mCrypto.plain_sizes[0] += kADTSHeaderSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "mp4_demuxer/AnnexB.h"
|
||||
#include "mp4_demuxer/ByteReader.h"
|
||||
#include "mp4_demuxer/ByteWriter.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "MediaData.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
|
@ -17,25 +17,25 @@ namespace mp4_demuxer
|
|||
static const uint8_t kAnnexBDelimiter[] = { 0, 0, 0, 1 };
|
||||
|
||||
bool
|
||||
AnnexB::ConvertSampleToAnnexB(MP4Sample* aSample)
|
||||
AnnexB::ConvertSampleToAnnexB(mozilla::MediaRawData* aSample)
|
||||
{
|
||||
MOZ_ASSERT(aSample);
|
||||
|
||||
if (!IsAVCC(aSample)) {
|
||||
return true;
|
||||
}
|
||||
MOZ_ASSERT(aSample->data);
|
||||
MOZ_ASSERT(aSample->mData);
|
||||
|
||||
if (!ConvertSampleTo4BytesAVCC(aSample)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aSample->size < 4) {
|
||||
if (aSample->mSize < 4) {
|
||||
// Nothing to do, it's corrupted anyway.
|
||||
return true;
|
||||
}
|
||||
|
||||
ByteReader reader(aSample->data, aSample->size);
|
||||
ByteReader reader(aSample->mData, aSample->mSize);
|
||||
|
||||
mozilla::Vector<uint8_t> tmp;
|
||||
ByteWriter writer(tmp);
|
||||
|
@ -51,15 +51,17 @@ AnnexB::ConvertSampleToAnnexB(MP4Sample* aSample)
|
|||
writer.Write(p, nalLen);
|
||||
}
|
||||
|
||||
if (!aSample->Replace(tmp.begin(), tmp.length())) {
|
||||
nsAutoPtr<MediaRawDataWriter> samplewriter(aSample->CreateWriter());
|
||||
|
||||
if (!samplewriter->Replace(tmp.begin(), tmp.length())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prepend the Annex B NAL with SPS and PPS tables to keyframes.
|
||||
if (aSample->is_sync_point) {
|
||||
nsRefPtr<ByteBuffer> annexB =
|
||||
ConvertExtraDataToAnnexB(aSample->extra_data);
|
||||
if (!aSample->Prepend(annexB->Elements(), annexB->Length())) {
|
||||
if (aSample->mKeyframe) {
|
||||
nsRefPtr<DataBuffer> annexB =
|
||||
ConvertExtraDataToAnnexB(aSample->mExtraData);
|
||||
if (!samplewriter->Prepend(annexB->Elements(), annexB->Length())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -67,8 +69,8 @@ AnnexB::ConvertSampleToAnnexB(MP4Sample* aSample)
|
|||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<ByteBuffer>
|
||||
AnnexB::ConvertExtraDataToAnnexB(const ByteBuffer* aExtraData)
|
||||
already_AddRefed<mozilla::DataBuffer>
|
||||
AnnexB::ConvertExtraDataToAnnexB(const mozilla::DataBuffer* aExtraData)
|
||||
{
|
||||
// AVCC 6 byte header looks like:
|
||||
// +------+------+------+------+------+------+------+------+
|
||||
|
@ -85,7 +87,7 @@ AnnexB::ConvertExtraDataToAnnexB(const ByteBuffer* aExtraData)
|
|||
// [5] | unused | numSps |
|
||||
// +------+------+------+------+------+------+------+------+
|
||||
|
||||
nsRefPtr<ByteBuffer> annexB = new ByteBuffer;
|
||||
nsRefPtr<mozilla::DataBuffer> annexB = new mozilla::DataBuffer;
|
||||
|
||||
ByteReader reader(*aExtraData);
|
||||
const uint8_t* ptr = reader.Read(5);
|
||||
|
@ -103,7 +105,7 @@ AnnexB::ConvertExtraDataToAnnexB(const ByteBuffer* aExtraData)
|
|||
|
||||
void
|
||||
AnnexB::ConvertSPSOrPPS(ByteReader& aReader, uint8_t aCount,
|
||||
ByteBuffer* aAnnexB)
|
||||
mozilla::DataBuffer* aAnnexB)
|
||||
{
|
||||
for (int i = 0; i < aCount; i++) {
|
||||
uint16_t length = aReader.ReadU16();
|
||||
|
@ -212,7 +214,7 @@ ParseNALUnits(ByteWriter& aBw, ByteReader& aBr)
|
|||
}
|
||||
|
||||
bool
|
||||
AnnexB::ConvertSampleToAVCC(MP4Sample* aSample)
|
||||
AnnexB::ConvertSampleToAVCC(mozilla::MediaRawData* aSample)
|
||||
{
|
||||
if (IsAVCC(aSample)) {
|
||||
return ConvertSampleTo4BytesAVCC(aSample);
|
||||
|
@ -224,19 +226,20 @@ AnnexB::ConvertSampleToAVCC(MP4Sample* aSample)
|
|||
|
||||
mozilla::Vector<uint8_t> nalu;
|
||||
ByteWriter writer(nalu);
|
||||
ByteReader reader(aSample->data, aSample->size);
|
||||
ByteReader reader(aSample->mData, aSample->mSize);
|
||||
|
||||
ParseNALUnits(writer, reader);
|
||||
return aSample->Replace(nalu.begin(), nalu.length());
|
||||
nsAutoPtr<MediaRawDataWriter> samplewriter(aSample->CreateWriter());
|
||||
return samplewriter->Replace(nalu.begin(), nalu.length());
|
||||
}
|
||||
|
||||
already_AddRefed<ByteBuffer>
|
||||
AnnexB::ExtractExtraData(const MP4Sample* aSample)
|
||||
already_AddRefed<mozilla::DataBuffer>
|
||||
AnnexB::ExtractExtraData(const mozilla::MediaRawData* aSample)
|
||||
{
|
||||
nsRefPtr<ByteBuffer> extradata = new ByteBuffer;
|
||||
if (IsAVCC(aSample) && HasSPS(aSample->extra_data)) {
|
||||
nsRefPtr<mozilla::DataBuffer> extradata = new mozilla::DataBuffer;
|
||||
if (IsAVCC(aSample) && HasSPS(aSample->mExtraData)) {
|
||||
// We already have an explicit extradata, re-use it.
|
||||
extradata = aSample->extra_data;
|
||||
extradata = aSample->mExtraData;
|
||||
return extradata.forget();
|
||||
}
|
||||
|
||||
|
@ -254,16 +257,15 @@ AnnexB::ExtractExtraData(const MP4Sample* aSample)
|
|||
|
||||
int nalLenSize;
|
||||
if (IsAVCC(aSample)) {
|
||||
nalLenSize = ((*aSample->extra_data)[4] & 3) + 1;
|
||||
nalLenSize = ((*aSample->mExtraData)[4] & 3) + 1;
|
||||
} else {
|
||||
// We do not have an extradata, assume it's AnnexB converted to AVCC via
|
||||
// ConvertSampleToAVCC.
|
||||
nalLenSize = 4;
|
||||
}
|
||||
ByteReader reader(aSample->data, aSample->size);
|
||||
ByteReader reader(aSample->mData, aSample->mSize);
|
||||
|
||||
// Find SPS and PPS NALUs in AVCC data
|
||||
uint8_t* d = aSample->data;
|
||||
while (reader.Remaining() > nalLenSize) {
|
||||
uint32_t nalLen;
|
||||
switch (nalLenSize) {
|
||||
|
@ -307,19 +309,19 @@ AnnexB::ExtractExtraData(const MP4Sample* aSample)
|
|||
}
|
||||
|
||||
bool
|
||||
AnnexB::HasSPS(const MP4Sample* aSample)
|
||||
AnnexB::HasSPS(const mozilla::MediaRawData* aSample)
|
||||
{
|
||||
return HasSPS(aSample->extra_data);
|
||||
return HasSPS(aSample->mExtraData);
|
||||
}
|
||||
|
||||
bool
|
||||
AnnexB::HasSPS(const ByteBuffer* aExtraData)
|
||||
AnnexB::HasSPS(const mozilla::DataBuffer* aExtraData)
|
||||
{
|
||||
if (!aExtraData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ByteReader reader(*aExtraData);
|
||||
ByteReader reader(aExtraData);
|
||||
const uint8_t* ptr = reader.Read(5);
|
||||
if (!ptr || !reader.CanRead8()) {
|
||||
return false;
|
||||
|
@ -331,18 +333,18 @@ AnnexB::HasSPS(const ByteBuffer* aExtraData)
|
|||
}
|
||||
|
||||
bool
|
||||
AnnexB::ConvertSampleTo4BytesAVCC(MP4Sample* aSample)
|
||||
AnnexB::ConvertSampleTo4BytesAVCC(mozilla::MediaRawData* aSample)
|
||||
{
|
||||
MOZ_ASSERT(IsAVCC(aSample));
|
||||
|
||||
int nalLenSize = ((*aSample->extra_data)[4] & 3) + 1;
|
||||
int nalLenSize = ((*aSample->mExtraData)[4] & 3) + 1;
|
||||
|
||||
if (nalLenSize == 4) {
|
||||
return true;
|
||||
}
|
||||
mozilla::Vector<uint8_t> dest;
|
||||
ByteWriter writer(dest);
|
||||
ByteReader reader(aSample->data, aSample->size);
|
||||
ByteReader reader(aSample->mData, aSample->mSize);
|
||||
while (reader.Remaining() > nalLenSize) {
|
||||
uint32_t nalLen;
|
||||
switch (nalLenSize) {
|
||||
|
@ -358,29 +360,30 @@ AnnexB::ConvertSampleTo4BytesAVCC(MP4Sample* aSample)
|
|||
writer.WriteU32(nalLen);
|
||||
writer.Write(p, nalLen);
|
||||
}
|
||||
return aSample->Replace(dest.begin(), dest.length());
|
||||
nsAutoPtr<MediaRawDataWriter> samplewriter(aSample->CreateWriter());
|
||||
return samplewriter->Replace(dest.begin(), dest.length());
|
||||
}
|
||||
|
||||
bool
|
||||
AnnexB::IsAVCC(const MP4Sample* aSample)
|
||||
AnnexB::IsAVCC(const mozilla::MediaRawData* aSample)
|
||||
{
|
||||
return aSample->size >= 3 && aSample->extra_data &&
|
||||
aSample->extra_data->Length() >= 7 && (*aSample->extra_data)[0] == 1;
|
||||
return aSample->mSize >= 3 && aSample->mExtraData &&
|
||||
aSample->mExtraData->Length() >= 7 && (*aSample->mExtraData)[0] == 1;
|
||||
}
|
||||
|
||||
bool
|
||||
AnnexB::IsAnnexB(const MP4Sample* aSample)
|
||||
AnnexB::IsAnnexB(const mozilla::MediaRawData* aSample)
|
||||
{
|
||||
if (aSample->size < 4) {
|
||||
if (aSample->mSize < 4) {
|
||||
return false;
|
||||
}
|
||||
uint32_t header = mozilla::BigEndian::readUint32(aSample->data);
|
||||
uint32_t header = mozilla::BigEndian::readUint32(aSample->mData);
|
||||
return header == 0x00000001 || (header >> 8) == 0x000001;
|
||||
}
|
||||
|
||||
bool
|
||||
AnnexB::CompareExtraData(const ByteBuffer* aExtraData1,
|
||||
const ByteBuffer* aExtraData2)
|
||||
AnnexB::CompareExtraData(const mozilla::DataBuffer* aExtraData1,
|
||||
const mozilla::DataBuffer* aExtraData2)
|
||||
{
|
||||
// Very crude comparison.
|
||||
return aExtraData1 == aExtraData2 || *aExtraData1 == *aExtraData2;
|
||||
|
|
|
@ -75,7 +75,7 @@ FindData(const MetaData* aMetaData, uint32_t aKey, nsTArray<T>* aDest)
|
|||
}
|
||||
|
||||
static bool
|
||||
FindData(const MetaData* aMetaData, uint32_t aKey, ByteBuffer* aDest)
|
||||
FindData(const MetaData* aMetaData, uint32_t aKey, mozilla::DataBuffer* aDest)
|
||||
{
|
||||
return FindData(aMetaData, aKey, static_cast<nsTArray<uint8_t>*>(aDest));
|
||||
}
|
||||
|
@ -170,90 +170,4 @@ VideoDecoderConfig::IsValid()
|
|||
{
|
||||
return display_width > 0 && display_height > 0;
|
||||
}
|
||||
|
||||
MP4Sample::MP4Sample()
|
||||
: decode_timestamp(0)
|
||||
, composition_timestamp(0)
|
||||
, duration(0)
|
||||
, byte_offset(0)
|
||||
, is_sync_point(0)
|
||||
, data(nullptr)
|
||||
, size(0)
|
||||
, extra_data(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
MP4Sample*
|
||||
MP4Sample::Clone() const
|
||||
{
|
||||
nsAutoPtr<MP4Sample> s(new MP4Sample());
|
||||
s->decode_timestamp = decode_timestamp;
|
||||
s->composition_timestamp = composition_timestamp;
|
||||
s->duration = duration;
|
||||
s->byte_offset = byte_offset;
|
||||
s->is_sync_point = is_sync_point;
|
||||
s->size = size;
|
||||
s->crypto = crypto;
|
||||
s->extra_data = extra_data;
|
||||
s->extra_buffer = s->data = new (fallible) uint8_t[size];
|
||||
if (!s->extra_buffer) {
|
||||
return nullptr;
|
||||
}
|
||||
memcpy(s->data, data, size);
|
||||
return s.forget();
|
||||
}
|
||||
|
||||
MP4Sample::~MP4Sample()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Sample::Pad(size_t aPaddingBytes)
|
||||
{
|
||||
size_t newSize = size + aPaddingBytes;
|
||||
|
||||
uint8_t* newData = new (fallible) uint8_t[newSize];
|
||||
if (!newData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(newData + size, 0, aPaddingBytes);
|
||||
memcpy(newData, data, size);
|
||||
extra_buffer = data = newData;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Sample::Prepend(const uint8_t* aData, size_t aSize)
|
||||
{
|
||||
size_t newSize = size + aSize;
|
||||
|
||||
uint8_t* newData = new (fallible) uint8_t[newSize];
|
||||
if (!newData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memmove(newData + aSize, data, size);
|
||||
memmove(newData, aData, aSize);
|
||||
size = newSize;
|
||||
extra_buffer = data = newData;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Sample::Replace(const uint8_t* aData, size_t aSize)
|
||||
{
|
||||
uint8_t* newData = new (fallible) uint8_t[aSize];
|
||||
if (!newData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(newData, aData, aSize);
|
||||
size = aSize;
|
||||
extra_buffer = data = newData;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ namespace mp4_demuxer
|
|||
class BitReader
|
||||
{
|
||||
public:
|
||||
explicit BitReader(const ByteBuffer& aBuffer)
|
||||
: mBitReader(aBuffer.Elements(), aBuffer.Length())
|
||||
explicit BitReader(const mozilla::DataBuffer* aBuffer)
|
||||
: mBitReader(aBuffer->Elements(), aBuffer->Length())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -82,8 +82,8 @@ SPSData::SPSData()
|
|||
sample_ratio = 1.0;
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<ByteBuffer>
|
||||
H264::DecodeNALUnit(const ByteBuffer* aNAL)
|
||||
/* static */ already_AddRefed<mozilla::DataBuffer>
|
||||
H264::DecodeNALUnit(const mozilla::DataBuffer* aNAL)
|
||||
{
|
||||
MOZ_ASSERT(aNAL);
|
||||
|
||||
|
@ -91,8 +91,8 @@ H264::DecodeNALUnit(const ByteBuffer* aNAL)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<ByteBuffer> rbsp = new ByteBuffer;
|
||||
ByteReader reader(*aNAL);
|
||||
nsRefPtr<mozilla::DataBuffer> rbsp = new mozilla::DataBuffer;
|
||||
ByteReader reader(aNAL);
|
||||
uint8_t nal_unit_type = reader.ReadU8() & 0x1f;
|
||||
uint32_t nalUnitHeaderBytes = 1;
|
||||
if (nal_unit_type == 14 || nal_unit_type == 20 || nal_unit_type == 21) {
|
||||
|
@ -138,10 +138,10 @@ ConditionDimension(float aValue)
|
|||
}
|
||||
|
||||
/* static */ bool
|
||||
H264::DecodeSPS(const ByteBuffer* aSPS, SPSData& aDest)
|
||||
H264::DecodeSPS(const mozilla::DataBuffer* aSPS, SPSData& aDest)
|
||||
{
|
||||
MOZ_ASSERT(aSPS);
|
||||
BitReader br(*aSPS);
|
||||
BitReader br(aSPS);
|
||||
|
||||
int32_t lastScale;
|
||||
int32_t nextScale;
|
||||
|
@ -461,12 +461,12 @@ H264::vui_parameters(BitReader& aBr, SPSData& aDest)
|
|||
}
|
||||
|
||||
/* static */ bool
|
||||
H264::DecodeSPSFromExtraData(const ByteBuffer* aExtraData, SPSData& aDest)
|
||||
H264::DecodeSPSFromExtraData(const mozilla::DataBuffer* aExtraData, SPSData& aDest)
|
||||
{
|
||||
if (!AnnexB::HasSPS(aExtraData)) {
|
||||
return false;
|
||||
}
|
||||
ByteReader reader(*aExtraData);
|
||||
ByteReader reader(aExtraData);
|
||||
|
||||
if (!reader.Read(5)) {
|
||||
return false;
|
||||
|
@ -490,10 +490,10 @@ H264::DecodeSPSFromExtraData(const ByteBuffer* aExtraData, SPSData& aDest)
|
|||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<ByteBuffer> rawNAL = new ByteBuffer;
|
||||
nsRefPtr<mozilla::DataBuffer> rawNAL = new mozilla::DataBuffer;
|
||||
rawNAL->AppendElements(ptr, length);
|
||||
|
||||
nsRefPtr<ByteBuffer> sps = DecodeNALUnit(rawNAL);
|
||||
nsRefPtr<mozilla::DataBuffer> sps = DecodeNALUnit(rawNAL);
|
||||
|
||||
reader.DiscardRemaining();
|
||||
|
||||
|
|
|
@ -84,30 +84,29 @@ SampleIterator::SampleIterator(Index* aIndex)
|
|||
{
|
||||
}
|
||||
|
||||
MP4Sample* SampleIterator::GetNext()
|
||||
already_AddRefed<MediaRawData> SampleIterator::GetNext()
|
||||
{
|
||||
Sample* s(Get());
|
||||
if (!s) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsAutoPtr<MP4Sample> sample(new MP4Sample());
|
||||
sample->decode_timestamp = s->mDecodeTime;
|
||||
sample->composition_timestamp = s->mCompositionRange.start;
|
||||
sample->duration = s->mCompositionRange.Length();
|
||||
sample->byte_offset = s->mByteRange.mStart;
|
||||
sample->is_sync_point = s->mSync;
|
||||
sample->size = s->mByteRange.Length();
|
||||
nsRefPtr<MediaRawData> sample = new MediaRawData();
|
||||
sample->mTimecode= s->mDecodeTime;
|
||||
sample->mTime = s->mCompositionRange.start;
|
||||
sample->mDuration = s->mCompositionRange.Length();
|
||||
sample->mOffset = s->mByteRange.mStart;
|
||||
sample->mKeyframe = s->mSync;
|
||||
|
||||
nsAutoPtr<MediaRawDataWriter> writer(sample->CreateWriter());
|
||||
// Do the blocking read
|
||||
sample->data = sample->extra_buffer = new (fallible) uint8_t[sample->size];
|
||||
if (!sample->data) {
|
||||
if (!writer->SetSize(s->mByteRange.Length())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t bytesRead;
|
||||
if (!mIndex->mSource->ReadAt(sample->byte_offset, sample->data, sample->size,
|
||||
&bytesRead) || bytesRead != sample->size) {
|
||||
if (!mIndex->mSource->ReadAt(sample->mOffset, writer->mData, sample->mSize,
|
||||
&bytesRead) || bytesRead != sample->mSize) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -128,10 +127,10 @@ MP4Sample* SampleIterator::GetNext()
|
|||
return nullptr;
|
||||
}
|
||||
ByteReader reader(cenc);
|
||||
sample->crypto.valid = true;
|
||||
sample->crypto.iv_size = ivSize;
|
||||
sample->mCrypto.valid = true;
|
||||
sample->mCrypto.iv_size = ivSize;
|
||||
|
||||
if (!reader.ReadArray(sample->crypto.iv, ivSize)) {
|
||||
if (!reader.ReadArray(sample->mCrypto.iv, ivSize)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -143,13 +142,13 @@ MP4Sample* SampleIterator::GetNext()
|
|||
}
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
sample->crypto.plain_sizes.AppendElement(reader.ReadU16());
|
||||
sample->crypto.encrypted_sizes.AppendElement(reader.ReadU32());
|
||||
sample->mCrypto.plain_sizes.AppendElement(reader.ReadU16());
|
||||
sample->mCrypto.encrypted_sizes.AppendElement(reader.ReadU32());
|
||||
}
|
||||
} else {
|
||||
// No subsample information means the entire sample is encrypted.
|
||||
sample->crypto.plain_sizes.AppendElement(0);
|
||||
sample->crypto.encrypted_sizes.AppendElement(sample->size);
|
||||
sample->mCrypto.plain_sizes.AppendElement(0);
|
||||
sample->mCrypto.encrypted_sizes.AppendElement(sample->mSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,14 +16,11 @@ MP4AudioDemuxer::Seek(Microseconds aTime)
|
|||
mDemuxer->SeekAudio(aTime);
|
||||
}
|
||||
|
||||
MediaSample*
|
||||
already_AddRefed<MediaRawData>
|
||||
MP4AudioDemuxer::DemuxSample()
|
||||
{
|
||||
nsAutoPtr<MP4Sample> sample(mDemuxer->DemuxAudioSample());
|
||||
if (!sample) {
|
||||
return nullptr;
|
||||
}
|
||||
return new MediaSample(sample.forget());
|
||||
nsRefPtr<MediaRawData> sample(mDemuxer->DemuxAudioSample());
|
||||
return sample.forget();
|
||||
}
|
||||
|
||||
Microseconds
|
||||
|
@ -38,14 +35,11 @@ MP4VideoDemuxer::Seek(Microseconds aTime)
|
|||
mDemuxer->SeekVideo(aTime);
|
||||
}
|
||||
|
||||
MediaSample*
|
||||
already_AddRefed<MediaRawData>
|
||||
MP4VideoDemuxer::DemuxSample()
|
||||
{
|
||||
nsAutoPtr<MP4Sample> sample(mDemuxer->DemuxVideoSample());
|
||||
if (!sample) {
|
||||
return nullptr;
|
||||
}
|
||||
return new MediaSample(sample.forget());
|
||||
nsRefPtr<MediaRawData> sample(mDemuxer->DemuxVideoSample());
|
||||
return sample.forget();
|
||||
}
|
||||
|
||||
Microseconds
|
||||
|
|
|
@ -5,23 +5,15 @@
|
|||
#ifndef TRACK_DEMUXER_H_
|
||||
#define TRACK_DEMUXER_H_
|
||||
|
||||
namespace mp4_demuxer { class MP4Sample; }
|
||||
template <class T> struct already_AddRefed;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class MediaRawData;
|
||||
class MediaByteRange;
|
||||
|
||||
typedef int64_t Microseconds;
|
||||
|
||||
class MediaSample {
|
||||
public:
|
||||
explicit MediaSample(mp4_demuxer::MP4Sample* aMp4Sample) : mMp4Sample(aMp4Sample)
|
||||
{
|
||||
}
|
||||
|
||||
nsAutoPtr<mp4_demuxer::MP4Sample> mMp4Sample;
|
||||
};
|
||||
|
||||
class TrackDemuxer {
|
||||
public:
|
||||
TrackDemuxer() {}
|
||||
|
@ -30,7 +22,7 @@ public:
|
|||
virtual void Seek(Microseconds aTime) = 0;
|
||||
|
||||
// DemuxSample returns nullptr on end of stream or error.
|
||||
virtual MediaSample* DemuxSample() = 0;
|
||||
virtual already_AddRefed<MediaRawData> DemuxSample() = 0;
|
||||
|
||||
// Returns timestamp of next keyframe, or -1 if demuxer can't
|
||||
// report this.
|
||||
|
|
|
@ -7,17 +7,19 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mozilla {
|
||||
class MediaRawData;
|
||||
}
|
||||
|
||||
namespace mp4_demuxer
|
||||
{
|
||||
|
||||
class MP4Sample;
|
||||
|
||||
class Adts
|
||||
{
|
||||
public:
|
||||
static int8_t GetFrequencyIndex(uint16_t aSamplesPerSecond);
|
||||
static bool ConvertSample(uint16_t aChannelCount, int8_t aFrequencyIndex,
|
||||
int8_t aProfile, MP4Sample* aSample);
|
||||
int8_t aProfile, mozilla::MediaRawData* aSample);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -5,48 +5,49 @@
|
|||
#ifndef MP4_DEMUXER_ANNEX_B_H_
|
||||
#define MP4_DEMUXER_ANNEX_B_H_
|
||||
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
|
||||
template <class T> struct already_AddRefed;
|
||||
|
||||
namespace mozilla {
|
||||
class MediaRawData;
|
||||
class DataBuffer;
|
||||
}
|
||||
namespace mp4_demuxer
|
||||
{
|
||||
class ByteReader;
|
||||
class MP4Sample;
|
||||
|
||||
class AnnexB
|
||||
{
|
||||
public:
|
||||
// All conversions assume size of NAL length field is 4 bytes.
|
||||
// Convert a sample from AVCC format to Annex B.
|
||||
static bool ConvertSampleToAnnexB(MP4Sample* aSample);
|
||||
static bool ConvertSampleToAnnexB(mozilla::MediaRawData* aSample);
|
||||
// Convert a sample from Annex B to AVCC.
|
||||
// an AVCC extradata must not be set.
|
||||
static bool ConvertSampleToAVCC(MP4Sample* aSample);
|
||||
static bool ConvertSampleTo4BytesAVCC(MP4Sample* aSample);
|
||||
static bool ConvertSampleToAVCC(mozilla::MediaRawData* aSample);
|
||||
static bool ConvertSampleTo4BytesAVCC(mozilla::MediaRawData* aSample);
|
||||
|
||||
// Parse an AVCC extradata and construct the Annex B sample header.
|
||||
static already_AddRefed<ByteBuffer> ConvertExtraDataToAnnexB(
|
||||
const ByteBuffer* aExtraData);
|
||||
static already_AddRefed<mozilla::DataBuffer> ConvertExtraDataToAnnexB(
|
||||
const mozilla::DataBuffer* aExtraData);
|
||||
// Extract SPS and PPS NALs from aSample, aSample must be in AVCC format.
|
||||
// If aSample already contains an extradata with an SPS, it will be returned
|
||||
// otherwise the SPS/PPS NALs are searched in-band.
|
||||
static already_AddRefed<ByteBuffer> ExtractExtraData(
|
||||
const MP4Sample* aSample);
|
||||
static bool HasSPS(const MP4Sample* aSample);
|
||||
static bool HasSPS(const ByteBuffer* aExtraData);
|
||||
static already_AddRefed<mozilla::DataBuffer> ExtractExtraData(
|
||||
const mozilla::MediaRawData* aSample);
|
||||
static bool HasSPS(const mozilla::MediaRawData* aSample);
|
||||
static bool HasSPS(const mozilla::DataBuffer* aExtraData);
|
||||
// Returns true if format is AVCC and sample has valid extradata.
|
||||
static bool IsAVCC(const MP4Sample* aSample);
|
||||
static bool IsAVCC(const mozilla::MediaRawData* aSample);
|
||||
// Returns true if format is AnnexB.
|
||||
static bool IsAnnexB(const MP4Sample* aSample);
|
||||
static bool IsAnnexB(const mozilla::MediaRawData* aSample);
|
||||
// Return true if both extradata are equal.
|
||||
static bool CompareExtraData(const ByteBuffer* aExtraData1,
|
||||
const ByteBuffer* aExtraData2);
|
||||
static bool CompareExtraData(const mozilla::DataBuffer* aExtraData1,
|
||||
const mozilla::DataBuffer* aExtraData2);
|
||||
|
||||
private:
|
||||
// AVCC box parser helper.
|
||||
static void ConvertSPSOrPPS(ByteReader& aReader, uint8_t aCount,
|
||||
ByteBuffer* aAnnexB);
|
||||
mozilla::DataBuffer* aAnnexB);
|
||||
};
|
||||
|
||||
} // namespace mp4_demuxer
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "mozilla/Endian.h"
|
||||
#include "mozilla/Vector.h"
|
||||
#include "nsTArray.h"
|
||||
#include "MediaData.h"
|
||||
|
||||
namespace mp4_demuxer {
|
||||
|
||||
|
@ -32,6 +33,10 @@ public:
|
|||
: mPtr(aData.Elements()), mRemaining(aData.Length()), mLength(aData.Length())
|
||||
{
|
||||
}
|
||||
explicit ByteReader(const DataBuffer* aData)
|
||||
: mPtr(aData->Elements()), mRemaining(aData->Length()), mLength(aData->Length())
|
||||
{
|
||||
}
|
||||
|
||||
void SetData(const nsTArray<uint8_t>& aData)
|
||||
{
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include "MediaData.h"
|
||||
#include "mozilla/Types.h"
|
||||
#include "mozilla/Vector.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsRefPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
@ -24,16 +23,6 @@ namespace mp4_demuxer
|
|||
|
||||
class MP4Demuxer;
|
||||
|
||||
template <typename T>
|
||||
class nsRcTArray : public nsTArray<T> {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsRcTArray);
|
||||
|
||||
private:
|
||||
~nsRcTArray() {}
|
||||
};
|
||||
|
||||
typedef nsRcTArray<uint8_t> ByteBuffer;
|
||||
|
||||
struct PsshInfo
|
||||
{
|
||||
PsshInfo() {}
|
||||
|
@ -109,8 +98,8 @@ public:
|
|||
, frequency_index(0)
|
||||
, aac_profile(0)
|
||||
, extended_profile(0)
|
||||
, extra_data(new ByteBuffer)
|
||||
, audio_specific_config(new ByteBuffer)
|
||||
, extra_data(new mozilla::DataBuffer)
|
||||
, audio_specific_config(new mozilla::DataBuffer)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -120,8 +109,8 @@ public:
|
|||
int8_t frequency_index;
|
||||
int8_t aac_profile;
|
||||
int8_t extended_profile;
|
||||
nsRefPtr<ByteBuffer> extra_data;
|
||||
nsRefPtr<ByteBuffer> audio_specific_config;
|
||||
nsRefPtr<mozilla::DataBuffer> extra_data;
|
||||
nsRefPtr<mozilla::DataBuffer> audio_specific_config;
|
||||
|
||||
void Update(const stagefright::MetaData* aMetaData,
|
||||
const char* aMimeType);
|
||||
|
@ -140,7 +129,7 @@ public:
|
|||
, display_height(0)
|
||||
, image_width(0)
|
||||
, image_height(0)
|
||||
, extra_data(new ByteBuffer)
|
||||
, extra_data(new mozilla::DataBuffer)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -150,7 +139,7 @@ public:
|
|||
int32_t image_width;
|
||||
int32_t image_height;
|
||||
|
||||
nsRefPtr<ByteBuffer> extra_data; // Unparsed AVCDecoderConfig payload.
|
||||
nsRefPtr<mozilla::DataBuffer> extra_data; // Unparsed AVCDecoderConfig payload.
|
||||
|
||||
void Update(const stagefright::MetaData* aMetaData,
|
||||
const char* aMimeType);
|
||||
|
@ -158,34 +147,6 @@ public:
|
|||
};
|
||||
|
||||
typedef int64_t Microseconds;
|
||||
|
||||
class MP4Sample
|
||||
{
|
||||
public:
|
||||
MP4Sample();
|
||||
virtual ~MP4Sample();
|
||||
MP4Sample* Clone() const;
|
||||
bool Pad(size_t aPaddingBytes);
|
||||
|
||||
Microseconds decode_timestamp;
|
||||
Microseconds composition_timestamp;
|
||||
Microseconds duration;
|
||||
int64_t byte_offset;
|
||||
bool is_sync_point;
|
||||
|
||||
uint8_t* data;
|
||||
size_t size;
|
||||
|
||||
mozilla::CryptoSample crypto;
|
||||
nsRefPtr<ByteBuffer> extra_data;
|
||||
|
||||
bool Prepend(const uint8_t* aData, size_t aSize);
|
||||
bool Replace(const uint8_t* aData, size_t aSize);
|
||||
|
||||
nsAutoArrayPtr<uint8_t> extra_buffer;
|
||||
private:
|
||||
MP4Sample(const MP4Sample&); // Not implemented
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -331,14 +331,14 @@ struct SPSData
|
|||
class H264
|
||||
{
|
||||
public:
|
||||
static bool DecodeSPSFromExtraData(const ByteBuffer* aExtraData, SPSData& aDest);
|
||||
static bool DecodeSPSFromExtraData(const mozilla::DataBuffer* aExtraData, SPSData& aDest);
|
||||
/* Extract RAW BYTE SEQUENCE PAYLOAD from NAL content.
|
||||
Returns nullptr if invalid content.
|
||||
This is compliant to ITU H.264 7.3.1 Syntax in tabular form NAL unit syntax
|
||||
*/
|
||||
static already_AddRefed<ByteBuffer> DecodeNALUnit(const ByteBuffer* aNAL);
|
||||
static already_AddRefed<mozilla::DataBuffer> DecodeNALUnit(const mozilla::DataBuffer* aNAL);
|
||||
/* Decode SPS NAL RBSP and fill SPSData structure */
|
||||
static bool DecodeSPS(const ByteBuffer* aSPS, SPSData& aDest);
|
||||
static bool DecodeSPS(const mozilla::DataBuffer* aSPS, SPSData& aDest);
|
||||
// Ensure that SPS data makes sense, Return true if SPS data was, and false
|
||||
// otherwise. If false, then content will be adjusted accordingly.
|
||||
static bool EnsureSPSIsSane(SPSData& aSPS);
|
||||
|
|
|
@ -20,7 +20,7 @@ class SampleIterator
|
|||
{
|
||||
public:
|
||||
explicit SampleIterator(Index* aIndex);
|
||||
MP4Sample* GetNext();
|
||||
already_AddRefed<mozilla::MediaRawData> GetNext();
|
||||
void Seek(Microseconds aTime);
|
||||
Microseconds GetNextKeyframeTime();
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ class MP4AudioDemuxer : public mozilla::TrackDemuxer {
|
|||
public:
|
||||
explicit MP4AudioDemuxer(MP4Demuxer* aDemuxer) : mDemuxer(aDemuxer) {}
|
||||
virtual void Seek(Microseconds aTime) override;
|
||||
virtual mozilla::MediaSample* DemuxSample() override;
|
||||
virtual already_AddRefed<mozilla::MediaRawData> DemuxSample() override;
|
||||
virtual Microseconds GetNextKeyframeTime() override;
|
||||
|
||||
private:
|
||||
|
@ -26,7 +26,7 @@ class MP4VideoDemuxer : public mozilla::TrackDemuxer {
|
|||
public:
|
||||
explicit MP4VideoDemuxer(MP4Demuxer* aDemuxer) : mDemuxer(aDemuxer) {}
|
||||
virtual void Seek(Microseconds aTime) override;
|
||||
virtual mozilla::MediaSample* DemuxSample() override;
|
||||
virtual already_AddRefed<mozilla::MediaRawData> DemuxSample() override;
|
||||
virtual Microseconds GetNextKeyframeTime() override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -59,8 +59,8 @@ public:
|
|||
|
||||
// DemuxAudioSample and DemuxVideoSample functions
|
||||
// return nullptr on end of stream or error.
|
||||
MP4Sample* DemuxAudioSample();
|
||||
MP4Sample* DemuxVideoSample();
|
||||
already_AddRefed<mozilla::MediaRawData> DemuxAudioSample();
|
||||
already_AddRefed<mozilla::MediaRawData> DemuxVideoSample();
|
||||
|
||||
const CryptoFile& Crypto() { return mCrypto; }
|
||||
const AudioDecoderConfig& AudioConfig() { return mAudioConfig; }
|
||||
|
|
|
@ -212,39 +212,39 @@ MP4Demuxer::SeekVideo(Microseconds aTime)
|
|||
}
|
||||
}
|
||||
|
||||
MP4Sample*
|
||||
already_AddRefed<mozilla::MediaRawData>
|
||||
MP4Demuxer::DemuxAudioSample()
|
||||
{
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
if (!mPrivate->mAudioIterator) {
|
||||
return nullptr;
|
||||
}
|
||||
nsAutoPtr<MP4Sample> sample(mPrivate->mAudioIterator->GetNext());
|
||||
nsRefPtr<mozilla::MediaRawData> sample(mPrivate->mAudioIterator->GetNext());
|
||||
if (sample) {
|
||||
if (sample->crypto.valid) {
|
||||
sample->crypto.mode = mAudioConfig.crypto.mode;
|
||||
sample->crypto.iv_size = mAudioConfig.crypto.iv_size;
|
||||
sample->crypto.key.AppendElements(mAudioConfig.crypto.key);
|
||||
if (sample->mCrypto.valid) {
|
||||
sample->mCrypto.mode = mAudioConfig.crypto.mode;
|
||||
sample->mCrypto.iv_size = mAudioConfig.crypto.iv_size;
|
||||
sample->mCrypto.key.AppendElements(mAudioConfig.crypto.key);
|
||||
}
|
||||
}
|
||||
return sample.forget();
|
||||
}
|
||||
|
||||
MP4Sample*
|
||||
already_AddRefed<MediaRawData>
|
||||
MP4Demuxer::DemuxVideoSample()
|
||||
{
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
if (!mPrivate->mVideoIterator) {
|
||||
return nullptr;
|
||||
}
|
||||
nsAutoPtr<MP4Sample> sample(mPrivate->mVideoIterator->GetNext());
|
||||
nsRefPtr<mozilla::MediaRawData> sample(mPrivate->mVideoIterator->GetNext());
|
||||
if (sample) {
|
||||
sample->extra_data = mVideoConfig.extra_data;
|
||||
if (sample->crypto.valid) {
|
||||
sample->crypto.mode = mVideoConfig.crypto.mode;
|
||||
sample->crypto.key.AppendElements(mVideoConfig.crypto.key);
|
||||
sample->mExtraData = mVideoConfig.extra_data;
|
||||
if (sample->mCrypto.valid) {
|
||||
sample->mCrypto.mode = mVideoConfig.crypto.mode;
|
||||
sample->mCrypto.key.AppendElements(mVideoConfig.crypto.key);
|
||||
}
|
||||
if (sample->composition_timestamp >= mNextKeyframeTime) {
|
||||
if (sample->mTime >= mNextKeyframeTime) {
|
||||
mNextKeyframeTime = mPrivate->mVideoIterator->GetNextKeyframeTime();
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче