Bug 1319987: P4. Refactor H264 Converter. r?cpearce
We can make some assumptions now that the Input method is only called once and never again while a decode is pending.
MozReview-Commit-ID: EmzKEcwNY2J
--- a/dom/media/platforms/wrappers/H264Converter.cpp
+++ b/dom/media/platforms/wrappers/H264Converter.cpp
@@ -47,57 +47,48 @@ H264Converter::Init()
// We haven't been able to initialize a decoder due to a missing SPS/PPS.
return MediaDataDecoder::InitPromise::CreateAndResolve(
TrackType::kVideoTrack, __func__);
}
void
H264Converter::Input(MediaRawData* aSample)
{
+ MOZ_RELEASE_ASSERT(!mInitPromiseRequest.Exists(),
+ "Still processing previous sample");
+
if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample)) {
// We need AVCC content to be able to later parse the SPS.
// This is a no-op if the data is already AVCC.
mCallback->Error(MediaResult(NS_ERROR_OUT_OF_MEMORY,
RESULT_DETAIL("ConvertSampleToAVCC")));
return;
}
- if (mInitPromiseRequest.Exists()) {
- if (mNeedKeyframe) {
- if (!aSample->mKeyframe) {
- // Frames dropped, we need a new one.
- mCallback->InputExhausted();
- return;
- }
- mNeedKeyframe = false;
- }
- mMediaRawSamples.AppendElement(aSample);
- return;
- }
-
nsresult rv;
if (!mDecoder) {
// It is not possible to create an AVCC H264 decoder without SPS.
// As such, creation will fail if the extra_data just extracted doesn't
// contain a SPS.
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 MediaRawData will be dropped.
mCallback->InputExhausted();
return;
}
} else {
rv = CheckForSPSChange(aSample);
- if (rv == NS_ERROR_NOT_INITIALIZED) {
- // The decoder is pending initialization.
- mCallback->InputExhausted();
- return;
- }
}
+
+ if (rv == NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER) {
+ // The decoder is pending initialization.
+ return;
+ }
+
if (NS_FAILED(rv)) {
mCallback->Error(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
RESULT_DETAIL("Unable to create H264 decoder")));
return;
}
if (mNeedKeyframe && !aSample->mKeyframe) {
@@ -224,58 +215,49 @@ H264Converter::CreateDecoderAndInit(Medi
return NS_ERROR_NOT_INITIALIZED;
}
UpdateConfigFromExtraData(extra_data);
nsresult rv = CreateDecoder(/* DecoderDoctorDiagnostics* */ nullptr);
if (NS_SUCCEEDED(rv)) {
// Queue the incoming sample.
- mMediaRawSamples.AppendElement(aSample);
+ mPendingSample = aSample;
mDecoder->Init()
->Then(AbstractThread::GetCurrent()->AsTaskQueue(), __func__, this,
&H264Converter::OnDecoderInitDone,
&H264Converter::OnDecoderInitFailed)
->Track(mInitPromiseRequest);
- return NS_ERROR_NOT_INITIALIZED;
+ return NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER;
}
return rv;
}
void
H264Converter::OnDecoderInitDone(const TrackType aTrackType)
{
mInitPromiseRequest.Complete();
- bool gotInput = false;
- for (uint32_t i = 0 ; i < mMediaRawSamples.Length(); i++) {
- const RefPtr<MediaRawData>& sample = mMediaRawSamples[i];
- if (mNeedKeyframe) {
- if (!sample->mKeyframe) {
- continue;
- }
- mNeedKeyframe = false;
- }
- if (!mNeedAVCC &&
- !mp4_demuxer::AnnexB::ConvertSampleToAnnexB(sample, mNeedKeyframe)) {
- mCallback->Error(MediaResult(NS_ERROR_OUT_OF_MEMORY,
- RESULT_DETAIL("ConvertSampleToAnnexB")));
- mMediaRawSamples.Clear();
- return;
- }
- mDecoder->Input(sample);
+ RefPtr<MediaRawData> sample = mPendingSample.forget();
+ if (mNeedKeyframe && !sample->mKeyframe) {
+ mCallback->InputExhausted();
+ return;
}
- if (!gotInput) {
- mCallback->InputExhausted();
+ mNeedKeyframe = false;
+ if (!mNeedAVCC &&
+ !mp4_demuxer::AnnexB::ConvertSampleToAnnexB(sample, mNeedKeyframe)) {
+ mCallback->Error(MediaResult(NS_ERROR_OUT_OF_MEMORY,
+ RESULT_DETAIL("ConvertSampleToAnnexB")));
+ return;
}
- mMediaRawSamples.Clear();
+ mDecoder->Input(sample);
}
void
-H264Converter::OnDecoderInitFailed(MediaResult aError)
+H264Converter::OnDecoderInitFailed(const MediaResult& aError)
{
mInitPromiseRequest.Complete();
mCallback->Error(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
RESULT_DETAIL("Unable to initialize H264 decoder")));
}
nsresult
--- a/dom/media/platforms/wrappers/H264Converter.h
+++ b/dom/media/platforms/wrappers/H264Converter.h
@@ -54,24 +54,24 @@ private:
// Returns NS_ERROR_FAILURE if error is permanent and can't be recovered and
// will set mError accordingly.
nsresult CreateDecoder(DecoderDoctorDiagnostics* aDiagnostics);
nsresult CreateDecoderAndInit(MediaRawData* aSample);
nsresult CheckForSPSChange(MediaRawData* aSample);
void UpdateConfigFromExtraData(MediaByteBuffer* aExtraData);
void OnDecoderInitDone(const TrackType aTrackType);
- void OnDecoderInitFailed(MediaResult aError);
+ void OnDecoderInitFailed(const MediaResult& aError);
RefPtr<PlatformDecoderModule> mPDM;
VideoInfo mCurrentConfig;
RefPtr<layers::KnowsCompositor> mKnowsCompositor;
RefPtr<layers::ImageContainer> mImageContainer;
const RefPtr<TaskQueue> mTaskQueue;
- nsTArray<RefPtr<MediaRawData>> mMediaRawSamples;
+ RefPtr<MediaRawData> mPendingSample;
MediaDataDecoderCallback* mCallback;
RefPtr<MediaDataDecoder> mDecoder;
MozPromiseRequestHolder<InitPromise> mInitPromiseRequest;
RefPtr<GMPCrashHelper> mGMPCrashHelper;
bool mNeedAVCC;
nsresult mLastError;
bool mNeedKeyframe = true;
};
--- a/xpcom/base/ErrorList.h
+++ b/xpcom/base/ErrorList.h
@@ -982,16 +982,17 @@
ERROR(NS_ERROR_DOM_MEDIA_OVERFLOW_ERR, FAILURE(7)),
ERROR(NS_ERROR_DOM_MEDIA_END_OF_STREAM, FAILURE(8)),
ERROR(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, FAILURE(9)),
ERROR(NS_ERROR_DOM_MEDIA_CANCELED, FAILURE(10)),
ERROR(NS_ERROR_DOM_MEDIA_MEDIASINK_ERR, FAILURE(11)),
ERROR(NS_ERROR_DOM_MEDIA_DEMUXER_ERR, FAILURE(12)),
ERROR(NS_ERROR_DOM_MEDIA_CDM_ERR, FAILURE(13)),
ERROR(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER, FAILURE(14)),
+ ERROR(NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER, FAILURE(15)),
/* Internal platform-related errors */
ERROR(NS_ERROR_DOM_MEDIA_CUBEB_INITIALIZATION_ERR, FAILURE(101)),
#undef MODULE
/* ======================================================================= */
/* 42: NS_ERROR_MODULE_URL_CLASSIFIER */
/* ======================================================================= */