# HG changeset patch # User Dan Minor # Date 1515594786 18000 # Wed Jan 10 09:33:06 2018 -0500 # Node ID 4b3b45da65d7cf502d30185374c45a2e8f565c8c # Parent 3fc5782dee241be35a58b26494ece4ec4e940302 Bug 1429390 - Make H.264 Encode dispatch asynchronous; r=jesup Historically we made a synchronous dispatch to the GMP thread on encode to avoid copying the frame buffer. The frame buffer is now held by a refptr so we can now make this call asynchronously. diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp --- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp +++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp @@ -311,25 +311,27 @@ WebrtcGmpVideoEncoder::InitEncoderForSiz int32_t WebrtcGmpVideoEncoder::Encode(const webrtc::VideoFrame& aInputImage, const webrtc::CodecSpecificInfo* aCodecSpecificInfo, const std::vector* aFrameTypes) { MOZ_ASSERT(aInputImage.width() >= 0 && aInputImage.height() >= 0); - // Would be really nice to avoid this sync dispatch, but it would require a - // copy of the frame, since it doesn't appear to actually have a refcount. - // Passing 'this' is safe since this is synchronous. - mozilla::SyncRunnable::DispatchToThread(mGMPThread, - WrapRunnable(this, - &WebrtcGmpVideoEncoder::Encode_g, - &aInputImage, - aCodecSpecificInfo, - aFrameTypes)); + if (!aFrameTypes) { + return WEBRTC_VIDEO_CODEC_ERROR; + } + + // It is safe to copy aInputImage here because the frame buffer is held by + // a refptr. + mGMPThread->Dispatch(WrapRunnableNM(&WebrtcGmpVideoEncoder::Encode_g, + RefPtr(this), + aInputImage, + *aFrameTypes), + NS_DISPATCH_NORMAL); return WEBRTC_VIDEO_CODEC_OK; } void WebrtcGmpVideoEncoder::RegetEncoderForResolutionChange( uint32_t aWidth, uint32_t aHeight, @@ -353,50 +355,51 @@ WebrtcGmpVideoEncoder::RegetEncoderForRe &tags, NS_LITERAL_CSTRING(""), Move(callback))))) { aInitDone->Dispatch(WEBRTC_VIDEO_CODEC_ERROR, "GMP Encode: GetGMPVideoEncoder failed"); } } -int32_t -WebrtcGmpVideoEncoder::Encode_g(const webrtc::VideoFrame* aInputImage, - const webrtc::CodecSpecificInfo* aCodecSpecificInfo, - const std::vector* aFrameTypes) +void +WebrtcGmpVideoEncoder::Encode_g(RefPtr& aEncoder, + webrtc::VideoFrame aInputImage, + std::vector aFrameTypes) { - if (!mGMP) { + if (!aEncoder->mGMP) { // destroyed via Terminate(), failed to init, or just not initted yet LOGD(("GMP Encode: not initted yet")); - return WEBRTC_VIDEO_CODEC_ERROR; + return; } - MOZ_ASSERT(mHost); + MOZ_ASSERT(aEncoder->mHost); - if (static_cast(aInputImage->width()) != mCodecParams.mWidth || - static_cast(aInputImage->height()) != mCodecParams.mHeight) { + if (static_cast(aInputImage.width()) != aEncoder->mCodecParams.mWidth || + static_cast(aInputImage.height()) != aEncoder->mCodecParams.mHeight) { LOGD(("GMP Encode: resolution change from %ux%u to %dx%d", - mCodecParams.mWidth, mCodecParams.mHeight, aInputImage->width(), aInputImage->height())); + aEncoder->mCodecParams.mWidth, aEncoder->mCodecParams.mHeight, aInputImage.width(), aInputImage.height())); - RefPtr initDone(new GmpInitDoneRunnable(mPCHandle)); - RegetEncoderForResolutionChange(aInputImage->width(), - aInputImage->height(), - initDone); - if (!mGMP) { + RefPtr initDone(new GmpInitDoneRunnable(aEncoder->mPCHandle)); + aEncoder->RegetEncoderForResolutionChange(aInputImage.width(), + aInputImage.height(), + initDone); + if (!aEncoder->mGMP) { // We needed to go async to re-get the encoder. Bail. - return WEBRTC_VIDEO_CODEC_ERROR; + return; } } GMPVideoFrame* ftmp = nullptr; - GMPErr err = mHost->CreateFrame(kGMPI420VideoFrame, &ftmp); + GMPErr err = aEncoder->mHost->CreateFrame(kGMPI420VideoFrame, &ftmp); if (err != GMPNoErr) { - return WEBRTC_VIDEO_CODEC_ERROR; + LOGD(("GMP Encode: failed to create frame on host")); + return; } GMPUniquePtr frame(static_cast(ftmp)); - rtc::scoped_refptr input_image = aInputImage->video_frame_buffer(); + rtc::scoped_refptr input_image = aInputImage.video_frame_buffer(); // check for overflow of stride * height CheckedInt32 ysize = CheckedInt32(input_image->StrideY()) * input_image->height(); MOZ_RELEASE_ASSERT(ysize.isValid()); // I will assume that if that doesn't overflow, the others case - YUV // 4:2:0 has U/V widths <= Y, even with alignment issues. err = frame->CreateFrame(ysize.value(), input_image->DataY(), input_image->StrideU() * ((input_image->height()+1)/2), @@ -404,47 +407,47 @@ WebrtcGmpVideoEncoder::Encode_g(const we input_image->StrideV() * ((input_image->height()+1)/2), input_image->DataV(), input_image->width(), input_image->height(), input_image->StrideY(), input_image->StrideU(), input_image->StrideV()); if (err != GMPNoErr) { - return err; + LOGD(("GMP Encode: failed to create frame")); + return; } - frame->SetTimestamp((aInputImage->timestamp() * 1000ll)/90); // note: rounds down! + frame->SetTimestamp((aInputImage.timestamp() * 1000ll)/90); // note: rounds down! //frame->SetDuration(1000000ll/30); // XXX base duration on measured current FPS - or don't bother // Bug XXXXXX: Set codecSpecific info GMPCodecSpecificInfo info; memset(&info, 0, sizeof(info)); info.mCodecType = kGMPVideoCodecH264; nsTArray codecSpecificInfo; codecSpecificInfo.AppendElements((uint8_t*)&info, sizeof(GMPCodecSpecificInfo)); nsTArray gmp_frame_types; - for (auto it = aFrameTypes->begin(); it != aFrameTypes->end(); ++it) { + for (auto it = aFrameTypes.begin(); it != aFrameTypes.end(); ++it) { GMPVideoFrameType ft; int32_t ret = WebrtcFrameTypeToGmpFrameType(*it, &ft); if (ret != WEBRTC_VIDEO_CODEC_OK) { - return ret; + LOGD(("GMP Encode: failed to map webrtc frame type to gmp frame type")); + return; } gmp_frame_types.AppendElement(ft); } - LOGD(("GMP Encode: %llu", (aInputImage->timestamp() * 1000ll)/90)); - err = mGMP->Encode(Move(frame), codecSpecificInfo, gmp_frame_types); + LOGD(("GMP Encode: %llu", (aInputImage.timestamp() * 1000ll)/90)); + err = aEncoder->mGMP->Encode(Move(frame), codecSpecificInfo, gmp_frame_types); if (err != GMPNoErr) { - return err; + LOGD(("GMP Encode: failed to encode frame")); } - - return WEBRTC_VIDEO_CODEC_OK; } int32_t WebrtcGmpVideoEncoder::RegisterEncodeCompleteCallback(webrtc::EncodedImageCallback* aCallback) { MutexAutoLock lock(mCallbackMutex); mCallback = aCallback; diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h --- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h +++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h @@ -247,19 +247,20 @@ private: private: RefPtr mEncoder; RefPtr mInitDone; GMPVideoCodec mCodecParams; uint32_t mMaxPayloadSize; }; - int32_t Encode_g(const webrtc::VideoFrame* aInputImage, - const webrtc::CodecSpecificInfo* aCodecSpecificInfo, - const std::vector* aFrameTypes); + static + void Encode_g(RefPtr& aEncoder, + webrtc::VideoFrame aInputImage, + std::vector aFrameTypes); void RegetEncoderForResolutionChange( uint32_t aWidth, uint32_t aHeight, const RefPtr& aInitDone); class InitDoneForResolutionChangeCallback : public GetGMPVideoEncoderCallback { public: