From af7d046d0707b4c8b59996d79a43100c7865b10a Mon Sep 17 00:00:00 2001 From: Jakub Bogusz Date: Mon, 27 Oct 2014 21:59:25 +0100 Subject: [PATCH] - added firefox33 patch, build GMP plugin --- openh264-firefox33.patch | 387 +++++++++++++++++++++++++++++++++++++++ openh264.spec | 56 +++++- 2 files changed, 441 insertions(+), 2 deletions(-) create mode 100644 openh264-firefox33.patch diff --git a/openh264-firefox33.patch b/openh264-firefox33.patch new file mode 100644 index 0000000..06cd7ed --- /dev/null +++ b/openh264-firefox33.patch @@ -0,0 +1,387 @@ +From 1acb0fb89fed6178057eccb28730bc4156746826 Mon Sep 17 00:00:00 2001 +From: Ethan Hugg +Date: Fri, 11 Jul 2014 08:29:02 -0700 +Subject: [PATCH] Updated to match gmp-api changes for Firefox33 + +--- + module/gmp-openh264.cpp | 159 +++++++++++++++++++++++++++++------------------- + module/task_utils.h | 3 + + 2 files changed, 101 insertions(+), 61 deletions(-) + +diff --git a/module/gmp-openh264.cpp b/module/gmp-openh264.cpp +index a70e883..5996ac8 100644 +--- a/module/gmp-openh264.cpp ++++ b/module/gmp-openh264.cpp +@@ -190,19 +190,21 @@ class OpenH264VideoEncoder : public GMPVideoEncoder { + worker_thread_->Join(); + } + +- virtual GMPVideoErr InitEncode (const GMPVideoCodec& codecSettings, +- GMPEncoderCallback* callback, +- int32_t numberOfCores, +- uint32_t maxPayloadSize) { ++ virtual GMPErr InitEncode (const GMPVideoCodec& codecSettings, ++ const uint8_t* aCodecSpecific, ++ uint32_t aCodecSpecificSize, ++ GMPVideoEncoderCallback* callback, ++ int32_t numberOfCores, ++ uint32_t maxPayloadSize) { + GMPErr err = g_platform_api->createthread (&worker_thread_); + if (err != GMPNoErr) { + GMPLOG (GL_ERROR, "Couldn't create new thread"); +- return GMPVideoGenericErr; ++ return GMPGenericErr; + } + + int rv = WelsCreateSVCEncoder (&encoder_); + if (rv) { +- return GMPVideoGenericErr; ++ return GMPGenericErr; + } + + SEncParamBase param; +@@ -236,7 +238,7 @@ class OpenH264VideoEncoder : public GMPVideoEncoder { + rv = encoder_->Initialize (¶m); + if (rv) { + GMPLOG (GL_ERROR, "Couldn't initialize encoder"); +- return GMPVideoGenericErr; ++ return GMPGenericErr; + } + + max_payload_size_ = maxPayloadSize; +@@ -244,12 +246,14 @@ class OpenH264VideoEncoder : public GMPVideoEncoder { + + GMPLOG (GL_INFO, "Initialized encoder"); + +- return GMPVideoNoErr; ++ return GMPNoErr; + } + +- virtual GMPVideoErr Encode (GMPVideoi420Frame* inputImage, +- const GMPCodecSpecificInfo& codecSpecificInfo, +- const std::vector& frameTypes) { ++ virtual GMPErr Encode (GMPVideoi420Frame* inputImage, ++ const uint8_t* aCodecSpecificInfo, ++ uint32_t aCodecSpecificInfoLength, ++ const GMPVideoFrameType* aFrameTypes, ++ uint32_t aFrameTypesLength) { + GMPLOG (GL_DEBUG, + __FUNCTION__ + << " size=" +@@ -257,19 +261,14 @@ class OpenH264VideoEncoder : public GMPVideoEncoder { + + stats_.FrameIn(); + +- assert (!frameTypes.empty()); +- if (frameTypes.empty()) { +- GMPLOG (GL_ERROR, "No frame types provided"); +- inputImage->Destroy(); +- return GMPVideoGenericErr; +- } ++ assert (aFrameTypesLength != 0); + + worker_thread_->Post (WrapTask ( + this, &OpenH264VideoEncoder::Encode_w, + inputImage, +- (frameTypes)[0])); ++ (aFrameTypes)[0])); + +- return GMPVideoGenericErr; ++ return GMPGenericErr; + } + + void Encode_w (GMPVideoi420Frame* inputImage, +@@ -363,8 +362,8 @@ class OpenH264VideoEncoder : public GMPVideoEncoder { + GMPVideoFrameType frame_type) { + // Now return the encoded data back to the parent. + GMPVideoFrame* ftmp; +- GMPVideoErr err = host_->CreateFrame (kGMPEncodedVideoFrame, &ftmp); +- if (err != GMPVideoNoErr) { ++ GMPErr err = host_->CreateFrame (kGMPEncodedVideoFrame, &ftmp); ++ if (err != GMPNoErr) { + GMPLOG (GL_ERROR, "Error creating encoded frame"); + frame->Destroy(); + return; +@@ -377,17 +376,20 @@ class OpenH264VideoEncoder : public GMPVideoEncoder { + + for (int i = 0; i < encoded->iLayerNum; ++i) { + lengths.push_back (0); ++ uint8_t *tmp = encoded->sLayerInfo[i].pBsBuf; + for (int j = 0; j < encoded->sLayerInfo[i].iNalCount; ++j) { + lengths[i] += encoded->sLayerInfo[i].pNalLengthInByte[j]; ++ // Convert from 4-byte start codes to GMP_BufferLength32 (NAL lengths) ++ assert(*(reinterpret_cast(tmp)) == 0x01000000); ++ // BufferType32 doesn't include the length of the length itself! ++ *(reinterpret_cast(tmp)) = encoded->sLayerInfo[i].pNalLengthInByte[j] - sizeof(uint32_t); + length += encoded->sLayerInfo[i].pNalLengthInByte[j]; ++ tmp += encoded->sLayerInfo[i].pNalLengthInByte[j]; + } + } + +- // TODO start-code to length conversion here when gmp +- // stops doing it for us before this call. +- + err = f->CreateEmptyFrame (length); +- if (err != GMPVideoNoErr) { ++ if (err != GMPNoErr) { + GMPLOG (GL_ERROR, "Error allocating frame data"); + f->Destroy(); + frame->Destroy(); +@@ -407,6 +409,7 @@ class OpenH264VideoEncoder : public GMPVideoEncoder { + f->SetTimeStamp (frame->Timestamp()); + f->SetFrameType (frame_type); + f->SetCompleteFrame (true); ++ f->SetBufferType (GMP_BufferLength32); + + GMPLOG (GL_DEBUG, "Encoding complete. type= " + << f->FrameType() +@@ -420,9 +423,12 @@ class OpenH264VideoEncoder : public GMPVideoEncoder { + + // Return the encoded frame. + GMPCodecSpecificInfo info; +- memset (&info, 0, sizeof (info)); +- // TODO need to set what goes in this info structure. +- callback_->Encoded (f, info); ++ memset (&info, 0, sizeof (info)); // shouldn't be needed, we init everything ++ info.mCodecType = kGMPVideoCodecH264; ++ info.mBufferType = GMP_BufferLength32; ++ info.mCodecSpecific.mH264.mSimulcastIdx = 0; ++ ++ callback_->Encoded (f, reinterpret_cast(&info), sizeof(info)); + + stats_.FrameOut(); + } +@@ -432,11 +438,11 @@ class OpenH264VideoEncoder : public GMPVideoEncoder { + frame->Destroy(); + } + +- virtual GMPVideoErr SetChannelParameters (uint32_t aPacketLoss, uint32_t aRTT) { +- return GMPVideoNoErr; ++ virtual GMPErr SetChannelParameters (uint32_t aPacketLoss, uint32_t aRTT) { ++ return GMPNoErr; + } + +- virtual GMPVideoErr SetRates (uint32_t aNewBitRate, uint32_t aFrameRate) { ++ virtual GMPErr SetRates (uint32_t aNewBitRate, uint32_t aFrameRate) { + GMPLOG (GL_INFO, "[SetRates] Begin with: " + << aNewBitRate << " , " << aFrameRate); + //update bitrate if needed +@@ -451,7 +457,7 @@ class OpenH264VideoEncoder : public GMPVideoEncoder { + << existEncoderBitRate.iLayer + << " ; BR = " + << existEncoderBitRate.iBitrate); +- return GMPVideoGenericErr; ++ return GMPGenericErr; + } + if (rv == cmResultSuccess && existEncoderBitRate.iBitrate != newBitRate) { + SBitrateInfo newEncoderBitRate; +@@ -470,7 +476,7 @@ class OpenH264VideoEncoder : public GMPVideoEncoder { + << newEncoderBitRate.iLayer + << " ; BR = " + << newEncoderBitRate.iBitrate); +- return GMPVideoGenericErr; ++ return GMPGenericErr; + } + } + //update framerate if needed +@@ -479,7 +485,7 @@ class OpenH264VideoEncoder : public GMPVideoEncoder { + if (rv != cmResultSuccess) { + GMPLOG (GL_ERROR, "[SetRates] Error in Getting Frame Rate:" + << rv << " FrameRate: " << existFrameRate); +- return GMPVideoGenericErr; ++ return GMPGenericErr; + } + if (rv == cmResultSuccess && + (aFrameRate - existFrameRate > 0.001f || +@@ -492,14 +498,14 @@ class OpenH264VideoEncoder : public GMPVideoEncoder { + } else { + GMPLOG (GL_ERROR, "[SetRates] Error in Setting Frame Rate: ReturnValue: " + << rv << " FrameRate: " << aFrameRate); +- return GMPVideoGenericErr; ++ return GMPGenericErr; + } + } +- return GMPVideoNoErr; ++ return GMPNoErr; + } + +- virtual GMPVideoErr SetPeriodicKeyFrames (bool aEnable) { +- return GMPVideoNoErr; ++ virtual GMPErr SetPeriodicKeyFrames (bool aEnable) { ++ return GMPNoErr; + } + + virtual void EncodingComplete() { +@@ -511,7 +517,7 @@ class OpenH264VideoEncoder : public GMPVideoEncoder { + GMPThread* worker_thread_; + ISVCEncoder* encoder_; + uint32_t max_payload_size_; +- GMPEncoderCallback* callback_; ++ GMPVideoEncoderCallback* callback_; + FrameStats stats_; + }; + +@@ -527,25 +533,27 @@ class OpenH264VideoDecoder : public GMPVideoDecoder { + virtual ~OpenH264VideoDecoder() { + } + +- virtual GMPVideoErr InitDecode (const GMPVideoCodec& codecSettings, +- GMPDecoderCallback* callback, +- int32_t coreCount) { ++ virtual GMPErr InitDecode (const GMPVideoCodec& codecSettings, ++ const uint8_t* aCodecSpecific, ++ uint32_t aCodecSpecificSize, ++ GMPVideoDecoderCallback* callback, ++ int32_t coreCount) { + GMPLOG (GL_INFO, "InitDecode"); + + GMPErr err = g_platform_api->createthread (&worker_thread_); + if (err != GMPNoErr) { + GMPLOG (GL_ERROR, "Couldn't create new thread"); +- return GMPVideoGenericErr; ++ return GMPGenericErr; + } + + if (WelsCreateDecoder (&decoder_)) { + GMPLOG (GL_ERROR, "Couldn't create decoder"); +- return GMPVideoGenericErr; ++ return GMPGenericErr; + } + + if (!decoder_) { + GMPLOG (GL_ERROR, "Couldn't create decoder"); +- return GMPVideoGenericErr; ++ return GMPGenericErr; + } + + SDecodingParam param; +@@ -557,21 +565,50 @@ class OpenH264VideoDecoder : public GMPVideoDecoder { + + if (decoder_->Initialize (¶m)) { + GMPLOG (GL_ERROR, "Couldn't initialize decoder"); +- return GMPVideoGenericErr; ++ return GMPGenericErr; + } + + callback_ = callback; +- return GMPVideoNoErr; ++ return GMPNoErr; + } + +- virtual GMPVideoErr Decode (GMPVideoEncodedFrame* inputFrame, +- bool missingFrames, +- const GMPCodecSpecificInfo& codecSpecificInfo, +- int64_t renderTimeMs = -1) { ++ virtual GMPErr Decode (GMPVideoEncodedFrame* inputFrame, ++ bool missingFrames, ++ const uint8_t* aCodecSpecificInfo, ++ uint32_t aCodecSpecificInfoLength, ++ int64_t renderTimeMs = -1) { + GMPLOG (GL_DEBUG, __FUNCTION__ + << "Decoding frame size=" << inputFrame->Size() + << " timestamp=" << inputFrame->TimeStamp()); + stats_.FrameIn(); ++ //const GMPCodecSpecificInfo *codecSpecificInfo = (GMPCodecSpecificInfo) aCodecSpecificInfo; ++ ++ // Convert to H.264 start codes ++ switch (inputFrame->BufferType()) { ++ case GMP_BufferSingle: ++ case GMP_BufferLength8: ++ case GMP_BufferLength16: ++ case GMP_BufferLength24: ++ // We should look to support these, especially GMP_BufferSingle ++ assert(false); ++ break; ++ ++ case GMP_BufferLength32: ++ { ++ uint8_t *start_code = inputFrame->Buffer(); ++ while (start_code < inputFrame->Buffer() + inputFrame->Size()) { ++ static const uint8_t code[] = { 0x00, 0x00, 0x00, 0x01 }; ++ uint8_t *lenp = start_code; ++ start_code += *(reinterpret_cast(lenp)); ++ memcpy(lenp, code, 4); ++ } ++ } ++ break; ++ ++ default: ++ assert(false); ++ break; ++ } + + worker_thread_->Post (WrapTask ( + this, &OpenH264VideoDecoder::Decode_w, +@@ -579,15 +616,15 @@ class OpenH264VideoDecoder : public GMPVideoDecoder { + missingFrames, + renderTimeMs)); + +- return GMPVideoNoErr; ++ return GMPNoErr; + } + +- virtual GMPVideoErr Reset() { +- return GMPVideoNoErr; ++ virtual GMPErr Reset() { ++ return GMPNoErr; + } + +- virtual GMPVideoErr Drain() { +- return GMPVideoNoErr; ++ virtual GMPErr Drain() { ++ return GMPNoErr; + } + + virtual void DecodingComplete() { +@@ -660,8 +697,8 @@ class OpenH264VideoDecoder : public GMPVideoDecoder { + GMPVideoFrame* ftmp = nullptr; + + // Translate the image. +- GMPVideoErr err = host_->CreateFrame (kGMPI420VideoFrame, &ftmp); +- if (err != GMPVideoNoErr) { ++ GMPErr err = host_->CreateFrame (kGMPI420VideoFrame, &ftmp); ++ if (err != GMPNoErr) { + GMPLOG (GL_ERROR, "Couldn't allocate empty I420 frame"); + return; + } +@@ -674,7 +711,7 @@ class OpenH264VideoDecoder : public GMPVideoDecoder { + uvstride * height / 2, static_cast (data[2]), + width, height, + ystride, uvstride, uvstride); +- if (err != GMPVideoNoErr) { ++ if (err != GMPNoErr) { + GMPLOG (GL_ERROR, "Couldn't make decoded frame"); + return; + } +@@ -682,7 +719,7 @@ class OpenH264VideoDecoder : public GMPVideoDecoder { + GMPLOG (GL_DEBUG, "Allocated size = " + << frame->AllocatedSize (kGMPYPlane)); + frame->SetTimestamp (inputFrame->TimeStamp()); +- frame->SetRenderTime_ms (renderTimeMs); ++ frame->SetDuration (inputFrame->Duration()); + callback_->Decoded (frame); + + stats_.FrameOut(); +@@ -690,7 +727,7 @@ class OpenH264VideoDecoder : public GMPVideoDecoder { + + GMPVideoHost* host_; + GMPThread* worker_thread_; +- GMPDecoderCallback* callback_; ++ GMPVideoDecoderCallback* callback_; + ISVCDecoder* decoder_; + FrameStats stats_; + }; +diff --git a/module/task_utils.h b/module/task_utils.h +index 2bd8937..c53e8d4 100644 +--- a/module/task_utils.h ++++ b/module/task_utils.h +@@ -13,6 +13,9 @@ + class gmp_args_base : public GMPTask { + public: + void Run() = 0; ++ void Destroy() { ++ delete this; ++ } + }; + + // The generated file contains four major function templates diff --git a/openh264.spec b/openh264.spec index 5325a78..2d71278 100644 --- a/openh264.spec +++ b/openh264.spec @@ -1,4 +1,8 @@ -# TODO: GMP plugin +# TODO: handle GMP plugins better in browser-plugins architecture (only firefox33+ based browsers supported) +# +# Conditional build: +%bcond_without xulrunner # GMP plugin +# Summary: H.264 codec library Summary(pl.UTF-8): Biblioteka kodeka H.264 Name: openh264 @@ -8,10 +12,15 @@ License: BSD Group: Libraries Source0: https://github.com/cisco/openh264/archive/v%{version}/%{name}-%{version}.tar.gz # Source0-md5: 2dccd64e0359acbaec54f442792bba67 +Patch0: %{name}-firefox33.patch URL: http://www.openh264.org/ BuildRequires: libstdc++-devel +BuildRequires: rpmbuild(macros) >= 1.357 +%{?with_xulrunner:BuildRequires: xulrunner-devel >= 2:33} BuildRoot: %{tmpdir}/%{name}-%{version}-root-%(id -u -n) +%define gmp_plugindir %{_browserpluginsdir} + %description OpenH264 is a codec library which supports H.264 encoding and decoding. It is suitable for use in real time applications such as @@ -47,11 +56,31 @@ Static OpenH264 library. %description static -l pl.UTF-8 Statyczna biblioteka OpenH264. +%package -n browser-gmp-openh264 +Summary: OpenH264 plugin for Gecko based browsers +Summary(pl.UTF-8): Wtyczka OpenH264 dla przeglądarek opartych na Gecko +License: BSD and MPL v2.0 +Group: Libraries +Requires: browser-plugins >= 2.0 + +%description -n browser-gmp-openh264 +OpenH264 Gecko Media Plugin for modern Gecko based browsers (like +Firefox/Iceweasel 33+). + +%description -n browser-gmp-openh264 -l pl.UTF-8 +Wtyczka GMP (Gecko Media Plugin) OpenH264 dla nowych przeglądarek +opartych na Gecko (takich jak Firefox/Iceweasel 33+). + %prep %setup -q +%patch0 -p1 + +%if %{with xulrunner} +ln -s /usr/include/xulrunner gmp-api +%endif %build -%{__make} \ +%{__make} libraries binaries %{?with_xulrunner:plugin} \ CXX="%{__cxx}" \ CFLAGS_OPT="%{rpmcxxflags}" @@ -65,12 +94,27 @@ install -d $RPM_BUILD_ROOT{%{_bindir},%{_libdir}} install libopenh264.so libopenh264.a $RPM_BUILD_ROOT%{_libdir} install h264dec h264enc $RPM_BUILD_ROOT%{_bindir} +%if %{with xulrunner} +# see https://wiki.mozilla.org/GeckoMediaPlugins +install -d $RPM_BUILD_ROOT%{gmp_plugindir}/gmp-openh264 +install libgmpopenh264.so $RPM_BUILD_ROOT%{gmp_plugindir}/gmp-openh264 +cp -p gmpopenh264.info $RPM_BUILD_ROOT%{gmp_plugindir}/gmp-openh264 +%endif + %clean rm -rf $RPM_BUILD_ROOT %post -p /sbin/ldconfig %postun -p /sbin/ldconfig +%post -n browser-gmp-openh264 +%update_browser_plugins + +%postun -n browser-gmp-openh264 +if [ "$1" = 0 ]; then + %update_browser_plugins +fi + %files %defattr(644,root,root,755) %doc CONTRIBUTORS LICENSE README.md RELEASES @@ -85,3 +129,11 @@ rm -rf $RPM_BUILD_ROOT %files static %defattr(644,root,root,755) %{_libdir}/libopenh264.a + +%if %{with xulrunner} +%files -n browser-gmp-openh264 +%defattr(644,root,root,755) +%dir %{gmp_plugindir}/gmp-openh264 +%attr(755,root,root) %{gmp_plugindir}/gmp-openh264/libgmpopenh264.so +%{gmp_plugindir}/gmp-openh264/gmpopenh264.info +%endif -- 2.43.0