Bug 1300296: P3. Ensure that a new or flushed decoder first h264 frame is always a keyframe. r?gerald
MozReview-Commit-ID: s0NEB8hesj
--- a/dom/media/platforms/wrappers/H264Converter.cpp
+++ b/dom/media/platforms/wrappers/H264Converter.cpp
@@ -54,16 +54,24 @@ H264Converter::Input(MediaRawData* aSamp
{
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.
return NS_ERROR_FAILURE;
}
if (mInitPromiseRequest.Exists()) {
+ if (mNeedKeyframe) {
+ if (!aSample->mKeyframe) {
+ // Frames dropped, we need a new one.
+ mCallback->InputExhausted();
+ return NS_OK;
+ }
+ mNeedKeyframe = false;
+ }
mMediaRawSamples.AppendElement(aSample);
return NS_OK;
}
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
@@ -74,38 +82,47 @@ H264Converter::Input(MediaRawData* aSamp
// Ignore for the time being, the MediaRawData will be dropped.
return NS_OK;
}
} else {
rv = CheckForSPSChange(aSample);
}
NS_ENSURE_SUCCESS(rv, rv);
+ if (mNeedKeyframe && !aSample->mKeyframe) {
+ mCallback->InputExhausted();
+ return NS_OK;
+ }
+
if (!mNeedAVCC &&
!mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) {
return NS_ERROR_FAILURE;
}
+ mNeedKeyframe = false;
+
aSample->mExtraData = mCurrentConfig.mExtraData;
return mDecoder->Input(aSample);
}
nsresult
H264Converter::Flush()
{
+ mNeedKeyframe = true;
if (mDecoder) {
return mDecoder->Flush();
}
return mLastError;
}
nsresult
H264Converter::Drain()
{
+ mNeedKeyframe = true;
if (mDecoder) {
return mDecoder->Drain();
}
mCallback->DrainComplete();
return mLastError;
}
nsresult
@@ -152,16 +169,19 @@ H264Converter::CreateDecoder(DecoderDoct
mLayersBackend,
mGMPCrashHelper
});
if (!mDecoder) {
mLastError = NS_ERROR_FAILURE;
return NS_ERROR_FAILURE;
}
+
+ mNeedKeyframe = true;
+
return NS_OK;
}
nsresult
H264Converter::CreateDecoderAndInit(MediaRawData* aSample)
{
RefPtr<MediaByteBuffer> extra_data =
mp4_demuxer::AnnexB::ExtractExtraData(aSample);
@@ -185,21 +205,32 @@ H264Converter::CreateDecoderAndInit(Medi
}
return rv;
}
void
H264Converter::OnDecoderInitDone(const TrackType aTrackType)
{
mInitPromiseRequest.Complete();
+ bool gotInput = false;
for (uint32_t i = 0 ; i < mMediaRawSamples.Length(); i++) {
- if (NS_FAILED(mDecoder->Input(mMediaRawSamples[i]))) {
+ const RefPtr<MediaRawData>& sample = mMediaRawSamples[i];
+ if (mNeedKeyframe) {
+ if (!sample->mKeyframe) {
+ continue;
+ }
+ mNeedKeyframe = false;
+ }
+ if (NS_FAILED(mDecoder->Input(sample))) {
mCallback->Error(MediaDataDecoderError::FATAL_ERROR);
}
}
+ if (!gotInput) {
+ mCallback->InputExhausted();
+ }
mMediaRawSamples.Clear();
}
void
H264Converter::OnDecoderInitFailed(MediaDataDecoder::DecoderFailureReason aReason)
{
mInitPromiseRequest.Complete();
mCallback->Error(MediaDataDecoderError::FATAL_ERROR);
--- a/dom/media/platforms/wrappers/H264Converter.h
+++ b/dom/media/platforms/wrappers/H264Converter.h
@@ -61,13 +61,14 @@ private:
const RefPtr<TaskQueue> mTaskQueue;
nsTArray<RefPtr<MediaRawData>> mMediaRawSamples;
MediaDataDecoderCallback* mCallback;
RefPtr<MediaDataDecoder> mDecoder;
MozPromiseRequestHolder<InitPromise> mInitPromiseRequest;
RefPtr<GMPCrashHelper> mGMPCrashHelper;
bool mNeedAVCC;
nsresult mLastError;
+ bool mNeedKeyframe = true;
};
} // namespace mozilla
#endif // mozilla_H264Converter_h