diff --git a/.travis.yml b/.travis.yml index 8a9bbc62..ee5cf361 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,5 +5,19 @@ compiler: before_install: - sudo apt-get update -qq - sudo apt-get install -qq nasm g++-4.6-multilib gcc-multilib libc6-dev-i386 -install: make gtest-bootstrap -script: make -B ENABLE64BIT=Yes && make test && make -B ENABLE64BIT=Yes BUILDTYPE=Debug && make test && make -B ENABLE64BIT=No && make test && make -B ENABLE64BIT=No BUILDTYPE=Debug && make test +install: + - make gmp-bootstrap + - make gtest-bootstrap +script: + - make -B ENABLE64BIT=Yes + - make -B ENABLE64BIT=Yes plugin + - make -B ENABLE64BIT=Yes test + - make -B ENABLE64BIT=Yes BUILDTYPE=Debug + - make -B ENABLE64BIT=Yes BUILDTYPE=Debug plugin + - make -B ENABLE64BIT=Yes test + - make -B ENABLE64BIT=No + - make -B ENABLE64BIT=No plugin + - make -B ENABLE64BIT=No test + - make -B ENABLE64BIT=No BUILDTYPE=Debug + - make -B ENABLE64BIT=No BUILDTYPE=Debug plugin + - make -B ENABLE64BIT=No test diff --git a/Makefile b/Makefile index 28816b78..35349a90 100644 --- a/Makefile +++ b/Makefile @@ -15,8 +15,15 @@ PREFIX=/usr/local SHARED=-shared OBJ=o PROJECT_NAME=openh264 +MODULE_NAME=gmpopenh264 CCASFLAGS=$(CFLAGS) +ifeq (,$(wildcard ./gmp-api)) +HAVE_GMP_API=No +else +HAVE_GMP_API=Yes +endif + ifeq (,$(wildcard ./gtest)) HAVE_GTEST=No else @@ -98,6 +105,8 @@ ENCODER_UNITTEST_INCLUDES = $(CODEC_UNITTEST_INCLUDES) $(ENCODER_INCLUDES) -Ites PROCESSING_UNITTEST_INCLUDES = $(CODEC_UNITTEST_INCLUDES) $(PROCESSING_INCLUDES) -Itest -Itest/processing API_TEST_INCLUDES = $(CODEC_UNITTEST_INCLUDES) -Itest -Itest/api COMMON_UNITTEST_INCLUDES = $(CODEC_UNITTEST_INCLUDES) $(DECODER_INCLUDES) -Itest -Itest/common +MODULE_INCLUDES = -Igmp-api + .PHONY: test gtest-bootstrap clean all: libraries binaries @@ -108,6 +117,9 @@ clean: clean_Android endif $(QUIET)rm -f $(OBJS) $(OBJS:.$(OBJ)=.d) $(LIBRARIES) $(BINARIES) +gmp-bootstrap: + git clone https://github.com/mozilla/gmp-api gmp-api + gtest-bootstrap: svn co https://googletest.googlecode.com/svn/trunk/ gtest @@ -131,6 +143,10 @@ include codec/decoder/targets.mk include codec/encoder/targets.mk include codec/processing/targets.mk +ifeq ($(HAVE_GMP_API),Yes) +include module/targets.mk +endif + ifneq (android, $(OS)) ifneq (ios, $(OS)) include codec/console/dec/targets.mk @@ -154,6 +170,19 @@ $(LIBPREFIX)$(PROJECT_NAME).$(SHAREDLIBSUFFIX): $(ENCODER_OBJS) $(DECODER_OBJS) $(QUIET)rm -f $@ $(QUIET_CXX)$(CXX) $(SHARED) $(LDFLAGS) $(CXX_LINK_O) $+ $(SHLDFLAGS) +ifeq ($(HAVE_GMP_API),Yes) +plugin: $(LIBPREFIX)$(MODULE_NAME).$(SHAREDLIBSUFFIX) +PLUGINS += $(LIBPREFIX)$(MODULE_NAME).$(SHAREDLIBSUFFIX) +else +plugin: + @echo "./gmp-api : No such file or directory." + @echo "You do not have gmp-api. Run make gmp-bootstrap to get the gmp-api headers." +endif + +$(LIBPREFIX)$(MODULE_NAME).$(SHAREDLIBSUFFIX): $(MODULE_OBJS) $(ENCODER_OBJS) $(DECODER_OBJS) $(PROCESSING_OBJS) $(COMMON_OBJS) + $(QUIET)rm -f $@ + $(QUIET_CXX)$(CXX) $(SHARED) $(LDFLAGS) $(CXX_LINK_O) $+ $(SHLDFLAGS) + install-headers: mkdir -p $(PREFIX)/include/wels install -m 644 codec/api/svc/codec*.h $(PREFIX)/include/wels diff --git a/build/mktargets.sh b/build/mktargets.sh index 28cdfec7..e2e16d38 100755 --- a/build/mktargets.sh +++ b/build/mktargets.sh @@ -11,4 +11,5 @@ python build/mktargets.py --directory test/encoder --prefix encoder_unittest python build/mktargets.py --directory test/decoder --prefix decoder_unittest python build/mktargets.py --directory test/processing --prefix processing_unittest python build/mktargets.py --directory test/api --prefix api_test +python build/mktargets.py --directory module --library module python build/mktargets.py --directory gtest --library gtest --out build/gtest-targets.mk --cpp-suffix .cc --include gtest-all.cc diff --git a/gmpopenh264.info b/gmpopenh264.info new file mode 100644 index 00000000..8e33aa81 --- /dev/null +++ b/gmpopenh264.info @@ -0,0 +1,4 @@ +Name: gmpopenh264 +Description: GMP Plugin for OpenH264. +Version: 1.0 +APIs: encode-video[h264:vp8], decode-video[h264:vp8] diff --git a/module/gmp-openh264.cpp b/module/gmp-openh264.cpp new file mode 100644 index 00000000..7243945b --- /dev/null +++ b/module/gmp-openh264.cpp @@ -0,0 +1,703 @@ +/*! + * \copy + * Copyright (c) 2009-2014, Cisco Systems + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * + ************************************************************************************* + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gmp-platform.h" +#include "gmp-video-host.h" +#include "gmp-video-encode.h" +#include "gmp-video-decode.h" +#include "gmp-video-frame-i420.h" +#include "gmp-video-frame-encoded.h" + +#include "codec_def.h" +#include "codec_app_def.h" +#include "codec_api.h" + +#include "task_utils.h" + +#if defined(_MSC_VER) +#define PUBLIC_FUNC __declspec(dllexport) +#else +#define PUBLIC_FUNC +#endif + +// This is for supporting older versions which do not have support for nullptr. +#if defined(__clang__) +# ifndef __has_extension +# define __has_extension __has_feature +# endif + +# if __has_extension(cxx_nullptr) +# define GMP_HAVE_NULLPTR +# endif + +#elif defined(__GNUC__) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L +# if (__GNU_C__ >=4) +# if (__GNU_C_MINOR__ >= 6) +# define GMP_HAVE_NULLPTR +# endif +# endif +# endif + +#elif defined(_MSC_VER) +# define GMP_HAVE_NULLPTR +#endif + +#if !defined (GMP_HAVE_NULLPTR) +# define nullptr __null +#endif + +static int g_log_level = 0; + +#define GMPLOG(l, x) do { \ + if (l <= g_log_level) { \ + const char *log_string = "unknown"; \ + if ((l >= 0) && (l <= 3)) { \ + log_string = kLogStrings[l]; \ + } \ + std::cerr << log_string << ": " << x << std::endl; \ + } \ + } while(0) + +#define GL_CRIT 0 +#define GL_ERROR 1 +#define GL_INFO 2 +#define GL_DEBUG 3 + +const char *kLogStrings[] = { + "Critical", + "Error", + "Info", + "Debug" +}; + + +static GMPPlatformAPI* g_platform_api = nullptr; + +class OpenH264VideoEncoder; + +template class SelfDestruct { + public: + SelfDestruct(T* t) : t_(t) {} + ~SelfDestruct() { + if (t_) { + t_->Destroy(); + } + } + + T* forget() { + T* t = t_; + t_ = nullptr; + + return t; + } + + private: + T* t_; +}; + +class FrameStats { + public: + FrameStats(const char *type) : + frames_in_(0), + frames_out_(0), + start_time_(time(0)), + last_time_(start_time_), + type_(type) {} + + void FrameIn() { + ++frames_in_; + time_t now = time(0); + + if (now == last_time_) { + return; + } + + if (!(frames_in_ % 10)) { + GMPLOG(GL_INFO, type_ << ": " << now << " Frame count " + << frames_in_ + << "(" << (frames_in_ / (now - start_time_)) << "/" + << (30 / (now - last_time_)) << ")" + << " -- " << frames_out_); + last_time_ = now; + } + } + + void FrameOut() { + ++frames_out_; + } + + private: + uint64_t frames_in_; + uint64_t frames_out_; + time_t start_time_; + time_t last_time_; + const std::string type_; +}; + +class OpenH264VideoEncoder : public GMPVideoEncoder +{ + public: + OpenH264VideoEncoder(GMPVideoHost *hostAPI) : + host_(hostAPI), + worker_thread_(nullptr), + encoder_(nullptr), + max_payload_size_(0), + callback_(nullptr), + stats_("Encoder") {} + + virtual ~OpenH264VideoEncoder() { + worker_thread_->Join(); + } + + virtual GMPVideoErr InitEncode(const GMPVideoCodec& codecSettings, + GMPEncoderCallback* 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; + } + + int rv = WelsCreateSVCEncoder(&encoder_); + if (rv) { + return GMPVideoGenericErr; + } + + SEncParamBase param; + memset(¶m, 0, sizeof(param)); + + GMPLOG(GL_INFO, "Initializing encoder at " + << codecSettings.mWidth + << "x" + << codecSettings.mHeight + << "@" + << static_cast(codecSettings.mMaxFramerate) + << "max payload size=" + << maxPayloadSize); + + // Translate parameters. + param.iUsageType = CAMERA_VIDEO_REAL_TIME; + param.iPicWidth = codecSettings.mWidth; + param.iPicHeight = codecSettings.mHeight; + param.iTargetBitrate = codecSettings.mStartBitrate * 1000; + GMPLOG(GL_INFO, "Initializing Bit Rate at: Start: " + << codecSettings.mStartBitrate + << "; Min: " + << codecSettings.mMinBitrate + << "; Max: " + << codecSettings.mMaxBitrate); + param.iRCMode = RC_BITRATE_MODE; + + // TODO(ekr@rtfm.com). Scary conversion from unsigned char to float below. + param.fMaxFrameRate = static_cast(codecSettings.mMaxFramerate); + param.iInputCsp = videoFormatI420; + + rv = encoder_->Initialize(¶m); + if (rv) { + GMPLOG(GL_ERROR, "Couldn't initialize encoder"); + return GMPVideoGenericErr; + } + + max_payload_size_ = maxPayloadSize; + callback_ = callback; + + GMPLOG(GL_INFO, "Initialized encoder"); + + return GMPVideoNoErr; + } + + virtual GMPVideoErr Encode(GMPVideoi420Frame* inputImage, + const GMPCodecSpecificInfo& codecSpecificInfo, + const std::vector& frameTypes) + { + GMPLOG(GL_DEBUG, + __FUNCTION__ + << " size=" + << inputImage->Width() << "x" << inputImage->Height()); + + stats_.FrameIn(); + + assert(!frameTypes.empty()); + if (frameTypes.empty()) { + GMPLOG(GL_ERROR, "No frame types provided"); + return GMPVideoGenericErr; + } + + worker_thread_->Post(WrapTask( + this, &OpenH264VideoEncoder::Encode_w, + inputImage, + (frameTypes)[0])); + + return GMPVideoGenericErr; + } + + void Encode_w(GMPVideoi420Frame* inputImage, + GMPVideoFrameType frame_type) { + SFrameBSInfo encoded; + + SSourcePicture src; + + src.iColorFormat = videoFormatI420; + src.iStride[0] = inputImage->Stride(kGMPYPlane); + src.pData[0] = reinterpret_cast( + const_cast(inputImage->Buffer(kGMPYPlane))); + src.iStride[1] = inputImage->Stride(kGMPUPlane); + src.pData[1] = reinterpret_cast( + const_cast(inputImage->Buffer(kGMPUPlane))); + src.iStride[2] = inputImage->Stride(kGMPVPlane); + src.pData[2] = reinterpret_cast( + const_cast(inputImage->Buffer(kGMPVPlane))); + src.iStride[3] = 0; + src.pData[3] = nullptr; + src.iPicWidth = inputImage->Width(); + src.iPicHeight = inputImage->Height(); + + const SSourcePicture* pics = &src; + + int result = encoder_->EncodeFrame(pics, &encoded); + if (result != cmResultSuccess) { + GMPLOG(GL_ERROR, "Couldn't encode frame. Error = " << result); + } + + + // Translate int to enum + GMPVideoFrameType encoded_type; + bool has_frame = false; + + switch (encoded.eOutputFrameType) { + case videoFrameTypeIDR: + encoded_type = kGMPKeyFrame; + has_frame = true; + break; + case videoFrameTypeI: + encoded_type = kGMPKeyFrame; + has_frame = true; + break; + case videoFrameTypeP: + encoded_type = kGMPDeltaFrame; + has_frame = true; + break; + case videoFrameTypeSkip: + // Can skip the call back since no actual bitstream will be generated + break; + case videoFrameTypeIPMixed://this type is currently not suppported + case videoFrameTypeInvalid: + GMPLOG(GL_ERROR, "Couldn't encode frame. Type = " + << encoded.eOutputFrameType); + break; + default: + // The API is defined as returning a type. + assert(false); + break; + } + + if (!has_frame) { + return; + } + + // Synchronously send this back to the main thread for delivery. + g_platform_api->syncrunonmainthread(WrapTask( + this, + &OpenH264VideoEncoder::Encode_m, + inputImage, + &encoded, + encoded_type)); + } + + void Encode_m(GMPVideoi420Frame* frame, SFrameBSInfo* encoded, + GMPVideoFrameType frame_type) { + // Now return the encoded data back to the parent. + GMPVideoFrame* ftmp; + GMPVideoErr err = host_->CreateFrame(kGMPEncodedVideoFrame, &ftmp); + if (err != GMPVideoNoErr) { + GMPLOG(GL_ERROR, "Error creating encoded frame"); + return; + } + + GMPVideoEncodedFrame* f = static_cast(ftmp); + // Buffer up the data. + uint32_t length = 0; + std::vector lengths; + + for (int i=0; iiLayerNum; ++i) { + lengths.push_back(0); + for (int j=0; jsLayerInfo[i].iNalCount; ++j) { + lengths[i] += encoded->sLayerInfo[i].pNalLengthInByte[j]; + length += 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) { + GMPLOG(GL_ERROR, "Error allocating frame data"); + f->Destroy(); + return; + } + + // Copy the data. + // Here we concatenate into one big buffer + uint8_t* tmp = f->Buffer(); + for (int i=0; iiLayerNum; ++i) { + memcpy(tmp, encoded->sLayerInfo[i].pBsBuf, lengths[i]); + tmp += lengths[i]; + } + + f->SetEncodedWidth(frame->Width()); + f->SetEncodedHeight(frame->Height()); + f->SetTimeStamp(frame->Timestamp()); + f->SetFrameType(frame_type); + f->SetCompleteFrame(true); + + GMPLOG(GL_DEBUG, "Encoding complete. type= " + << f->FrameType() + << " length=" + << f->Size() + << " timestamp=" + << f->TimeStamp()); + + // Destroy the frame. + frame->Destroy(); + + // 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); + + stats_.FrameOut(); + } + + virtual GMPVideoErr SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT) { + return GMPVideoNoErr; + } + + virtual GMPVideoErr SetRates(uint32_t aNewBitRate, uint32_t aFrameRate) { + GMPLOG(GL_INFO, "[SetRates] Begin with: " + << aNewBitRate << " , "<< aFrameRate); + //update bitrate if needed + const int32_t newBitRate = aNewBitRate*1000; //kbps->bps + SBitrateInfo existEncoderBitRate; + existEncoderBitRate.iLayer = SPATIAL_LAYER_ALL; + int rv = encoder_->GetOption(ENCODER_OPTION_BITRATE, &existEncoderBitRate); + if (rv!=cmResultSuccess) { + GMPLOG(GL_ERROR, "[SetRates] Error in Getting Bit Rate at Layer:" + << rv + << " ; Layer = " + << existEncoderBitRate.iLayer + << " ; BR = " + << existEncoderBitRate.iBitrate); + return GMPVideoGenericErr; + } + if ( rv==cmResultSuccess && existEncoderBitRate.iBitrate!=newBitRate ) { + SBitrateInfo newEncoderBitRate; + newEncoderBitRate.iLayer = SPATIAL_LAYER_ALL; + newEncoderBitRate.iBitrate = newBitRate; + rv = encoder_->SetOption(ENCODER_OPTION_BITRATE, &newEncoderBitRate); + if (rv==cmResultSuccess) { + GMPLOG(GL_INFO, "[SetRates] Update Encoder Bandwidth (AllLayers): ReturnValue: " + << rv + << "BitRate(kbps): " + << aNewBitRate); + } else { + GMPLOG(GL_ERROR, "[SetRates] Error in Setting Bit Rate at Layer:" + << rv + << " ; Layer = " + << newEncoderBitRate.iLayer + << " ; BR = " + << newEncoderBitRate.iBitrate); + return GMPVideoGenericErr; + } + } + //update framerate if needed + float existFrameRate = 0; + rv = encoder_->GetOption(ENCODER_OPTION_FRAME_RATE, &existFrameRate); + if (rv!=cmResultSuccess) { + GMPLOG(GL_ERROR, "[SetRates] Error in Getting Frame Rate:" + << rv << " FrameRate: " << existFrameRate); + return GMPVideoGenericErr; + } + if ( rv==cmResultSuccess && + ( aFrameRate-existFrameRate > 0.001f || + existFrameRate-aFrameRate > 0.001f ) ) { + float newFrameRate = static_cast(aFrameRate); + rv = encoder_->SetOption(ENCODER_OPTION_FRAME_RATE, &newFrameRate); + if (rv==cmResultSuccess) { + GMPLOG(GL_INFO, "[SetRates] Update Encoder Frame Rate: ReturnValue: " + << rv << " FrameRate: " << aFrameRate); + } else { + GMPLOG(GL_ERROR, "[SetRates] Error in Setting Frame Rate: ReturnValue: " + << rv << " FrameRate: " << aFrameRate); + return GMPVideoGenericErr; + } + } + return GMPVideoNoErr; + } + + virtual GMPVideoErr SetPeriodicKeyFrames(bool aEnable) { + return GMPVideoNoErr; + } + + virtual void EncodingComplete() { + delete this; + } + +private: + GMPVideoHost* host_; + GMPThread* worker_thread_; + ISVCEncoder* encoder_; + uint32_t max_payload_size_; + GMPEncoderCallback* callback_; + FrameStats stats_; +}; + +class OpenH264VideoDecoder : public GMPVideoDecoder { +public: + OpenH264VideoDecoder(GMPVideoHost *hostAPI) : + host_(hostAPI), + worker_thread_(nullptr), + callback_(nullptr), + decoder_(nullptr), + stats_("Decoder") {} + + virtual ~OpenH264VideoDecoder() { + } + + virtual GMPVideoErr InitDecode(const GMPVideoCodec& codecSettings, + GMPDecoderCallback* 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; + } + + if (WelsCreateDecoder(&decoder_)) { + GMPLOG(GL_ERROR, "Couldn't create decoder"); + return GMPVideoGenericErr; + } + + if (!decoder_) { + GMPLOG(GL_ERROR, "Couldn't create decoder"); + return GMPVideoGenericErr; + } + + SDecodingParam param; + memset(¶m, 0, sizeof(param)); + param.iOutputColorFormat = videoFormatI420; + param.uiTargetDqLayer = UCHAR_MAX; // Default value + param.uiEcActiveFlag = 1; // Error concealment on. + param.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT; + + if (decoder_->Initialize(¶m)) { + GMPLOG(GL_ERROR, "Couldn't initialize decoder"); + return GMPVideoGenericErr; + } + + callback_ = callback; + return GMPVideoNoErr; + } + + virtual GMPVideoErr Decode(GMPVideoEncodedFrame* inputFrame, + bool missingFrames, + const GMPCodecSpecificInfo& codecSpecificInfo, + int64_t renderTimeMs = -1) { + GMPLOG(GL_DEBUG, __FUNCTION__ + << "Decoding frame size=" << inputFrame->Size() + << " timestamp=" << inputFrame->TimeStamp()); + stats_.FrameIn(); + + worker_thread_->Post(WrapTask( + this, &OpenH264VideoDecoder::Decode_w, + inputFrame, + missingFrames, + renderTimeMs)); + + return GMPVideoNoErr; + } + + virtual GMPVideoErr Reset() { + return GMPVideoNoErr; + } + + virtual GMPVideoErr Drain() { + return GMPVideoNoErr; + } + + virtual void DecodingComplete() { + delete this; + } + +private: + void Decode_w(GMPVideoEncodedFrame* inputFrame, + bool missingFrames, + int64_t renderTimeMs = -1) { + GMPLOG(GL_DEBUG, "Frame decode on worker thread length = " + << inputFrame->Size()); + + SBufferInfo decoded; + bool valid = false; + memset(&decoded, 0, sizeof(decoded)); + unsigned char *data[3] = {nullptr, nullptr, nullptr}; + + int rv = decoder_->DecodeFrame2(inputFrame->Buffer(), + inputFrame->Size(), + data, + &decoded); + + if (rv) { + GMPLOG(GL_ERROR, "Decoding error rv=" << rv); + } else { + valid = true; + } + + g_platform_api->syncrunonmainthread(WrapTask( + this, + &OpenH264VideoDecoder::Decode_m, + inputFrame, + &decoded, + data, + renderTimeMs, + valid)); + } + + // Return the decoded data back to the parent. + void Decode_m(GMPVideoEncodedFrame* inputFrame, + SBufferInfo* decoded, + unsigned char* data[3], + int64_t renderTimeMs, + bool valid) { + // Attach a self-destructor so that this dies on return. + SelfDestruct ifd(inputFrame); + + // If we don't actually have data, just abort. + if (!valid) { + return; + } + + if (decoded->iBufferStatus != 1) { + return; + } + + int width = decoded->UsrData.sSystemBuffer.iWidth; + int height = decoded->UsrData.sSystemBuffer.iHeight; + int ystride = decoded->UsrData.sSystemBuffer.iStride[0]; + int uvstride = decoded->UsrData.sSystemBuffer.iStride[1]; + + GMPLOG(GL_DEBUG, "Video frame ready for display " + << width + << "x" + << height + << " timestamp=" + << inputFrame->TimeStamp()); + + GMPVideoFrame* ftmp = nullptr; + + // Translate the image. + GMPVideoErr err = host_->CreateFrame(kGMPI420VideoFrame, &ftmp); + if (err != GMPVideoNoErr) { + GMPLOG(GL_ERROR, "Couldn't allocate empty I420 frame"); + return; + } + + + GMPVideoi420Frame* frame = static_cast(ftmp); + err = frame->CreateFrame( + ystride * height, static_cast(data[0]), + uvstride * height/2, static_cast(data[1]), + uvstride * height/2, static_cast(data[2]), + width, height, + ystride, uvstride, uvstride); + if (err != GMPVideoNoErr) { + GMPLOG(GL_ERROR, "Couldn't make decoded frame"); + return; + } + + GMPLOG(GL_DEBUG, "Allocated size = " + << frame->AllocatedSize(kGMPYPlane)); + frame->SetTimestamp(inputFrame->TimeStamp()); + frame->SetRenderTime_ms(renderTimeMs); + callback_->Decoded(frame); + + stats_.FrameOut(); + } + + GMPVideoHost* host_; + GMPThread* worker_thread_; + GMPDecoderCallback* callback_; + ISVCDecoder* decoder_; + FrameStats stats_; +}; + +extern "C" { + +PUBLIC_FUNC GMPErr +GMPInit(GMPPlatformAPI* aPlatformAPI) { + g_platform_api = aPlatformAPI; + return GMPNoErr; +} + +PUBLIC_FUNC GMPErr +GMPGetAPI(const char* aApiName, void* aHostAPI, void** aPluginApi) { + if (!strcmp(aApiName, "decode-video")) { + *aPluginApi = new OpenH264VideoDecoder(static_cast(aHostAPI)); + return GMPNoErr; + } else if (!strcmp(aApiName, "encode-video")) { + *aPluginApi = new OpenH264VideoEncoder(static_cast(aHostAPI)); + return GMPNoErr; + } + return GMPGenericErr; +} + +PUBLIC_FUNC void +GMPShutdown(void) { + g_platform_api = nullptr; +} + +} // extern "C" diff --git a/module/targets.mk b/module/targets.mk new file mode 100644 index 00000000..42cdb789 --- /dev/null +++ b/module/targets.mk @@ -0,0 +1,16 @@ +MODULE_SRCDIR=module +MODULE_CPP_SRCS=\ + $(MODULE_SRCDIR)/gmp-openh264.cpp\ + +MODULE_OBJS += $(MODULE_CPP_SRCS:.cpp=.$(OBJ)) + +OBJS += $(MODULE_OBJS) +$(MODULE_SRCDIR)/%.$(OBJ): $(MODULE_SRCDIR)/%.cpp + $(QUIET_CXX)$(CXX) $(CFLAGS) $(CXXFLAGS) $(INCLUDES) $(MODULE_CFLAGS) $(MODULE_INCLUDES) -c $(CXX_O) $< + +$(LIBPREFIX)module.$(LIBSUFFIX): $(MODULE_OBJS) + $(QUIET)rm -f $@ + $(QUIET_AR)$(AR) $(AR_OPTS) $+ + +plugin: $(LIBPREFIX)module.$(LIBSUFFIX) +LIBRARIES += $(LIBPREFIX)module.$(LIBSUFFIX) diff --git a/module/task_utils.h b/module/task_utils.h new file mode 100644 index 00000000..2bd8937c --- /dev/null +++ b/module/task_utils.h @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Original author: ekr@rtfm.com + +#ifndef task_utils_h__ +#define task_utils_h__ + + +class gmp_args_base : public GMPTask { + public: + void Run() = 0; +}; + +// The generated file contains four major function templates +// (in variants for arbitrary numbers of arguments up to 10, +// which is why it is machine generated). The four templates +// are: +// +// WrapTask(o, m, ...) -- wraps a member function m of an object ptr o +// WrapTaskRet(o, m, ..., r) -- wraps a member function m of an object ptr o +// the function returns something that can +// be assigned to *r +// WrapTaskNM(f, ...) -- wraps a function f +// WrapTaskNMRet(f, ..., r) -- wraps a function f that returns something +// that can be assigned to *r +// +// All of these template functions return a Task* which can be passed +// to Post(). +#include "task_utils_generated.h" + +#endif diff --git a/module/task_utils.py b/module/task_utils.py new file mode 100644 index 00000000..6eed6d4b --- /dev/null +++ b/module/task_utils.py @@ -0,0 +1,171 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +MAX_ARGS = 15 + +boilerplate = "/* This Source Code Form is subject to the terms of the Mozilla Public\n\ + * License, v. 2.0. If a copy of the MPL was not distributed with this\n\ + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */\n" + +def gen_args_type(args, member): + if member: + ret = ["C o"] + else: + ret = [] + ret.append("M m") + for arg in range(0, args): + ret.append("A%d a%d"%(arg, arg)) + return ", ".join(ret) + +def gen_args(args, member): + if member: + ret = ["o"] + else: + ret = [] + ret.append("m") + for arg in range(0, args): + ret.append("a%d"%(arg)) + return ", ".join(ret) + +def gen_args_(args): + ret = [] + for arg in range(0, args): + ret.append("a%d_"%(arg)) + return ", ".join(ret) + +def gen_init(args, r = False, member = False): + if member: + ret = ["o_(o)"] + else: + ret = [] + ret.append("m_(m)") + + if r: + ret.append("r_(r)") + + for arg in range(0, args): + ret.append("a%d_(a%d)"%(arg, arg)) + return ", ".join(ret) + +def gen_typenames(args, member): + if member: + ret = ["typename C"] + else: + ret = [] + ret.append("typename M") + + for arg in range(0, args): + ret.append("typename A%d"%(arg)) + return ", ".join(ret) + +def gen_types(args, member): + if member: + ret = ["C"] + else: + ret = [] + ret.append("M") + for arg in range(0, args): + ret.append("A%d"%(arg)) + return ", ".join(ret) + + +def generate_class_template(args, ret = False, member = True): + print "// %d arguments --"%args + if member: + nm = "m" + else: + nm = "nm" + + if not ret: + print "template<"+ gen_typenames(args, member) + "> class gmp_args_%s_%d : public gmp_args_base {"%(nm, args) + else: + print "template<"+ gen_typenames(args, member) + ", typename R> class gmp_args_%s_%d_ret : public gmp_args_base {"%(nm, args) + + print " public:" + + if not ret: + print " gmp_args_%s_%d("%(nm, args) + gen_args_type(args, member) + ") :" + print " " + gen_init(args, False, member) + " {}" + else: + print " gmp_args_%s_%d_ret("%(nm, args) + gen_args_type(args, member) + ", R *r) :" + print " " + gen_init(args, True, member) + " {}" + print " virtual bool returns_value() const { return true; }" + print + print " void Run() {" + if ret: + print " *r_ =", + else: + print " ", + if member: + print "((*o_).*m_)(" + gen_args_(args) + ");" + else: + print "m_(" + gen_args_(args) + ");" + print " }" + print + print " private:" + if member: + print " C o_;" + print " M m_;" + if ret: + print " R* r_;" + for arg in range(0, args): + print " A%d a%d_;"%(arg, arg) + print "};" + print + print + print + +def generate_function_template(args, member): + if member: + nm = "m" + NM = ""; + else: + nm = "nm" + NM = "NM"; + + print "// %d arguments --"%args + print "template<" + gen_typenames(args, member) + ">" + print "gmp_args_%s_%d<"%(nm, args) + gen_types(args, member) + ">* WrapTask%s("%NM + gen_args_type(args, member) + ") {" + print " return new gmp_args_%s_%d<"%(nm, args) + gen_types(args, member) + ">" + print " (" + gen_args(args, member) + ");" + print "}" + print + +def generate_function_template_ret(args, member): + if member: + nm = "m" + NM = ""; + else: + nm = "nm" + NM = "NM"; + print "// %d arguments --"%args + print "template<" + gen_typenames(args, member) + ", typename R>" + print "gmp_args_%s_%d_ret<"%(nm, args) + gen_types(args, member) + ", R>* WrapTask%sRet("%NM + gen_args_type(args, member) + ", R* r) {" + print " return new gmp_args_%s_%d_ret<"%(nm, args) + gen_types(args, member) + ", R>" + print " (" + gen_args(args, member) + ", r);" + print "}" + print + + +print boilerplate +print + +for num_args in range (0, MAX_ARGS): + generate_class_template(num_args, False, False) + generate_class_template(num_args, True, False) + generate_class_template(num_args, False, True) + generate_class_template(num_args, True, True) + + +print +print +print + +for num_args in range(0, MAX_ARGS): + generate_function_template(num_args, False) + generate_function_template_ret(num_args, False) + generate_function_template(num_args, True) + generate_function_template_ret(num_args, True) + + + diff --git a/module/task_utils_generated.h b/module/task_utils_generated.h new file mode 100644 index 00000000..60f84144 --- /dev/null +++ b/module/task_utils_generated.h @@ -0,0 +1,1898 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + +// 0 arguments -- +template class gmp_args_nm_0 : public gmp_args_base { + public: + gmp_args_nm_0(M m) : + m_(m) {} + + void Run() { + m_(); + } + + private: + M m_; +}; + + + +// 0 arguments -- +template class gmp_args_nm_0_ret : public gmp_args_base { + public: + gmp_args_nm_0_ret(M m, R *r) : + m_(m), r_(r) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(); + } + + private: + M m_; + R* r_; +}; + + + +// 0 arguments -- +template class gmp_args_m_0 : public gmp_args_base { + public: + gmp_args_m_0(C o, M m) : + o_(o), m_(m) {} + + void Run() { + ((*o_).*m_)(); + } + + private: + C o_; + M m_; +}; + + + +// 0 arguments -- +template class gmp_args_m_0_ret : public gmp_args_base { + public: + gmp_args_m_0_ret(C o, M m, R *r) : + o_(o), m_(m), r_(r) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(); + } + + private: + C o_; + M m_; + R* r_; +}; + + + +// 1 arguments -- +template class gmp_args_nm_1 : public gmp_args_base { + public: + gmp_args_nm_1(M m, A0 a0) : + m_(m), a0_(a0) {} + + void Run() { + m_(a0_); + } + + private: + M m_; + A0 a0_; +}; + + + +// 1 arguments -- +template class gmp_args_nm_1_ret : public gmp_args_base { + public: + gmp_args_nm_1_ret(M m, A0 a0, R *r) : + m_(m), r_(r), a0_(a0) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_); + } + + private: + M m_; + R* r_; + A0 a0_; +}; + + + +// 1 arguments -- +template class gmp_args_m_1 : public gmp_args_base { + public: + gmp_args_m_1(C o, M m, A0 a0) : + o_(o), m_(m), a0_(a0) {} + + void Run() { + ((*o_).*m_)(a0_); + } + + private: + C o_; + M m_; + A0 a0_; +}; + + + +// 1 arguments -- +template class gmp_args_m_1_ret : public gmp_args_base { + public: + gmp_args_m_1_ret(C o, M m, A0 a0, R *r) : + o_(o), m_(m), r_(r), a0_(a0) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; +}; + + + +// 2 arguments -- +template class gmp_args_nm_2 : public gmp_args_base { + public: + gmp_args_nm_2(M m, A0 a0, A1 a1) : + m_(m), a0_(a0), a1_(a1) {} + + void Run() { + m_(a0_, a1_); + } + + private: + M m_; + A0 a0_; + A1 a1_; +}; + + + +// 2 arguments -- +template class gmp_args_nm_2_ret : public gmp_args_base { + public: + gmp_args_nm_2_ret(M m, A0 a0, A1 a1, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; +}; + + + +// 2 arguments -- +template class gmp_args_m_2 : public gmp_args_base { + public: + gmp_args_m_2(C o, M m, A0 a0, A1 a1) : + o_(o), m_(m), a0_(a0), a1_(a1) {} + + void Run() { + ((*o_).*m_)(a0_, a1_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; +}; + + + +// 2 arguments -- +template class gmp_args_m_2_ret : public gmp_args_base { + public: + gmp_args_m_2_ret(C o, M m, A0 a0, A1 a1, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; +}; + + + +// 3 arguments -- +template class gmp_args_nm_3 : public gmp_args_base { + public: + gmp_args_nm_3(M m, A0 a0, A1 a1, A2 a2) : + m_(m), a0_(a0), a1_(a1), a2_(a2) {} + + void Run() { + m_(a0_, a1_, a2_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; +}; + + + +// 3 arguments -- +template class gmp_args_nm_3_ret : public gmp_args_base { + public: + gmp_args_nm_3_ret(M m, A0 a0, A1 a1, A2 a2, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; +}; + + + +// 3 arguments -- +template class gmp_args_m_3 : public gmp_args_base { + public: + gmp_args_m_3(C o, M m, A0 a0, A1 a1, A2 a2) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; +}; + + + +// 3 arguments -- +template class gmp_args_m_3_ret : public gmp_args_base { + public: + gmp_args_m_3_ret(C o, M m, A0 a0, A1 a1, A2 a2, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; +}; + + + +// 4 arguments -- +template class gmp_args_nm_4 : public gmp_args_base { + public: + gmp_args_nm_4(M m, A0 a0, A1 a1, A2 a2, A3 a3) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3) {} + + void Run() { + m_(a0_, a1_, a2_, a3_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; +}; + + + +// 4 arguments -- +template class gmp_args_nm_4_ret : public gmp_args_base { + public: + gmp_args_nm_4_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; +}; + + + +// 4 arguments -- +template class gmp_args_m_4 : public gmp_args_base { + public: + gmp_args_m_4(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; +}; + + + +// 4 arguments -- +template class gmp_args_m_4_ret : public gmp_args_base { + public: + gmp_args_m_4_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; +}; + + + +// 5 arguments -- +template class gmp_args_nm_5 : public gmp_args_base { + public: + gmp_args_nm_5(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; +}; + + + +// 5 arguments -- +template class gmp_args_nm_5_ret : public gmp_args_base { + public: + gmp_args_nm_5_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; +}; + + + +// 5 arguments -- +template class gmp_args_m_5 : public gmp_args_base { + public: + gmp_args_m_5(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; +}; + + + +// 5 arguments -- +template class gmp_args_m_5_ret : public gmp_args_base { + public: + gmp_args_m_5_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; +}; + + + +// 6 arguments -- +template class gmp_args_nm_6 : public gmp_args_base { + public: + gmp_args_nm_6(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_, a5_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; +}; + + + +// 6 arguments -- +template class gmp_args_nm_6_ret : public gmp_args_base { + public: + gmp_args_nm_6_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; +}; + + + +// 6 arguments -- +template class gmp_args_m_6 : public gmp_args_base { + public: + gmp_args_m_6(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; +}; + + + +// 6 arguments -- +template class gmp_args_m_6_ret : public gmp_args_base { + public: + gmp_args_m_6_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; +}; + + + +// 7 arguments -- +template class gmp_args_nm_7 : public gmp_args_base { + public: + gmp_args_nm_7(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; +}; + + + +// 7 arguments -- +template class gmp_args_nm_7_ret : public gmp_args_base { + public: + gmp_args_nm_7_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; +}; + + + +// 7 arguments -- +template class gmp_args_m_7 : public gmp_args_base { + public: + gmp_args_m_7(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; +}; + + + +// 7 arguments -- +template class gmp_args_m_7_ret : public gmp_args_base { + public: + gmp_args_m_7_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; +}; + + + +// 8 arguments -- +template class gmp_args_nm_8 : public gmp_args_base { + public: + gmp_args_nm_8(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; +}; + + + +// 8 arguments -- +template class gmp_args_nm_8_ret : public gmp_args_base { + public: + gmp_args_nm_8_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; +}; + + + +// 8 arguments -- +template class gmp_args_m_8 : public gmp_args_base { + public: + gmp_args_m_8(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; +}; + + + +// 8 arguments -- +template class gmp_args_m_8_ret : public gmp_args_base { + public: + gmp_args_m_8_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; +}; + + + +// 9 arguments -- +template class gmp_args_nm_9 : public gmp_args_base { + public: + gmp_args_nm_9(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; +}; + + + +// 9 arguments -- +template class gmp_args_nm_9_ret : public gmp_args_base { + public: + gmp_args_nm_9_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; +}; + + + +// 9 arguments -- +template class gmp_args_m_9 : public gmp_args_base { + public: + gmp_args_m_9(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; +}; + + + +// 9 arguments -- +template class gmp_args_m_9_ret : public gmp_args_base { + public: + gmp_args_m_9_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; +}; + + + +// 10 arguments -- +template class gmp_args_nm_10 : public gmp_args_base { + public: + gmp_args_nm_10(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; +}; + + + +// 10 arguments -- +template class gmp_args_nm_10_ret : public gmp_args_base { + public: + gmp_args_nm_10_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; +}; + + + +// 10 arguments -- +template class gmp_args_m_10 : public gmp_args_base { + public: + gmp_args_m_10(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; +}; + + + +// 10 arguments -- +template class gmp_args_m_10_ret : public gmp_args_base { + public: + gmp_args_m_10_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; +}; + + + +// 11 arguments -- +template class gmp_args_nm_11 : public gmp_args_base { + public: + gmp_args_nm_11(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; +}; + + + +// 11 arguments -- +template class gmp_args_nm_11_ret : public gmp_args_base { + public: + gmp_args_nm_11_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; +}; + + + +// 11 arguments -- +template class gmp_args_m_11 : public gmp_args_base { + public: + gmp_args_m_11(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; +}; + + + +// 11 arguments -- +template class gmp_args_m_11_ret : public gmp_args_base { + public: + gmp_args_m_11_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; +}; + + + +// 12 arguments -- +template class gmp_args_nm_12 : public gmp_args_base { + public: + gmp_args_nm_12(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; +}; + + + +// 12 arguments -- +template class gmp_args_nm_12_ret : public gmp_args_base { + public: + gmp_args_nm_12_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; +}; + + + +// 12 arguments -- +template class gmp_args_m_12 : public gmp_args_base { + public: + gmp_args_m_12(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; +}; + + + +// 12 arguments -- +template class gmp_args_m_12_ret : public gmp_args_base { + public: + gmp_args_m_12_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; +}; + + + +// 13 arguments -- +template class gmp_args_nm_13 : public gmp_args_base { + public: + gmp_args_nm_13(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; + A12 a12_; +}; + + + +// 13 arguments -- +template class gmp_args_nm_13_ret : public gmp_args_base { + public: + gmp_args_nm_13_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; + A12 a12_; +}; + + + +// 13 arguments -- +template class gmp_args_m_13 : public gmp_args_base { + public: + gmp_args_m_13(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; + A12 a12_; +}; + + + +// 13 arguments -- +template class gmp_args_m_13_ret : public gmp_args_base { + public: + gmp_args_m_13_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; + A12 a12_; +}; + + + +// 14 arguments -- +template class gmp_args_nm_14 : public gmp_args_base { + public: + gmp_args_nm_14(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; + A12 a12_; + A13 a13_; +}; + + + +// 14 arguments -- +template class gmp_args_nm_14_ret : public gmp_args_base { + public: + gmp_args_nm_14_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; + A12 a12_; + A13 a13_; +}; + + + +// 14 arguments -- +template class gmp_args_m_14 : public gmp_args_base { + public: + gmp_args_m_14(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; + A12 a12_; + A13 a13_; +}; + + + +// 14 arguments -- +template class gmp_args_m_14_ret : public gmp_args_base { + public: + gmp_args_m_14_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; + A12 a12_; + A13 a13_; +}; + + + + + + +// 0 arguments -- +template +gmp_args_nm_0* WrapTaskNM(M m) { + return new gmp_args_nm_0 + (m); +} + +// 0 arguments -- +template +gmp_args_nm_0_ret* WrapTaskNMRet(M m, R* r) { + return new gmp_args_nm_0_ret + (m, r); +} + +// 0 arguments -- +template +gmp_args_m_0* WrapTask(C o, M m) { + return new gmp_args_m_0 + (o, m); +} + +// 0 arguments -- +template +gmp_args_m_0_ret* WrapTaskRet(C o, M m, R* r) { + return new gmp_args_m_0_ret + (o, m, r); +} + +// 1 arguments -- +template +gmp_args_nm_1* WrapTaskNM(M m, A0 a0) { + return new gmp_args_nm_1 + (m, a0); +} + +// 1 arguments -- +template +gmp_args_nm_1_ret* WrapTaskNMRet(M m, A0 a0, R* r) { + return new gmp_args_nm_1_ret + (m, a0, r); +} + +// 1 arguments -- +template +gmp_args_m_1* WrapTask(C o, M m, A0 a0) { + return new gmp_args_m_1 + (o, m, a0); +} + +// 1 arguments -- +template +gmp_args_m_1_ret* WrapTaskRet(C o, M m, A0 a0, R* r) { + return new gmp_args_m_1_ret + (o, m, a0, r); +} + +// 2 arguments -- +template +gmp_args_nm_2* WrapTaskNM(M m, A0 a0, A1 a1) { + return new gmp_args_nm_2 + (m, a0, a1); +} + +// 2 arguments -- +template +gmp_args_nm_2_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, R* r) { + return new gmp_args_nm_2_ret + (m, a0, a1, r); +} + +// 2 arguments -- +template +gmp_args_m_2* WrapTask(C o, M m, A0 a0, A1 a1) { + return new gmp_args_m_2 + (o, m, a0, a1); +} + +// 2 arguments -- +template +gmp_args_m_2_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, R* r) { + return new gmp_args_m_2_ret + (o, m, a0, a1, r); +} + +// 3 arguments -- +template +gmp_args_nm_3* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2) { + return new gmp_args_nm_3 + (m, a0, a1, a2); +} + +// 3 arguments -- +template +gmp_args_nm_3_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, R* r) { + return new gmp_args_nm_3_ret + (m, a0, a1, a2, r); +} + +// 3 arguments -- +template +gmp_args_m_3* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2) { + return new gmp_args_m_3 + (o, m, a0, a1, a2); +} + +// 3 arguments -- +template +gmp_args_m_3_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, R* r) { + return new gmp_args_m_3_ret + (o, m, a0, a1, a2, r); +} + +// 4 arguments -- +template +gmp_args_nm_4* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3) { + return new gmp_args_nm_4 + (m, a0, a1, a2, a3); +} + +// 4 arguments -- +template +gmp_args_nm_4_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, R* r) { + return new gmp_args_nm_4_ret + (m, a0, a1, a2, a3, r); +} + +// 4 arguments -- +template +gmp_args_m_4* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3) { + return new gmp_args_m_4 + (o, m, a0, a1, a2, a3); +} + +// 4 arguments -- +template +gmp_args_m_4_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, R* r) { + return new gmp_args_m_4_ret + (o, m, a0, a1, a2, a3, r); +} + +// 5 arguments -- +template +gmp_args_nm_5* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return new gmp_args_nm_5 + (m, a0, a1, a2, a3, a4); +} + +// 5 arguments -- +template +gmp_args_nm_5_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R* r) { + return new gmp_args_nm_5_ret + (m, a0, a1, a2, a3, a4, r); +} + +// 5 arguments -- +template +gmp_args_m_5* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return new gmp_args_m_5 + (o, m, a0, a1, a2, a3, a4); +} + +// 5 arguments -- +template +gmp_args_m_5_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R* r) { + return new gmp_args_m_5_ret + (o, m, a0, a1, a2, a3, a4, r); +} + +// 6 arguments -- +template +gmp_args_nm_6* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { + return new gmp_args_nm_6 + (m, a0, a1, a2, a3, a4, a5); +} + +// 6 arguments -- +template +gmp_args_nm_6_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R* r) { + return new gmp_args_nm_6_ret + (m, a0, a1, a2, a3, a4, a5, r); +} + +// 6 arguments -- +template +gmp_args_m_6* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { + return new gmp_args_m_6 + (o, m, a0, a1, a2, a3, a4, a5); +} + +// 6 arguments -- +template +gmp_args_m_6_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R* r) { + return new gmp_args_m_6_ret + (o, m, a0, a1, a2, a3, a4, a5, r); +} + +// 7 arguments -- +template +gmp_args_nm_7* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { + return new gmp_args_nm_7 + (m, a0, a1, a2, a3, a4, a5, a6); +} + +// 7 arguments -- +template +gmp_args_nm_7_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R* r) { + return new gmp_args_nm_7_ret + (m, a0, a1, a2, a3, a4, a5, a6, r); +} + +// 7 arguments -- +template +gmp_args_m_7* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { + return new gmp_args_m_7 + (o, m, a0, a1, a2, a3, a4, a5, a6); +} + +// 7 arguments -- +template +gmp_args_m_7_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R* r) { + return new gmp_args_m_7_ret + (o, m, a0, a1, a2, a3, a4, a5, a6, r); +} + +// 8 arguments -- +template +gmp_args_nm_8* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) { + return new gmp_args_nm_8 + (m, a0, a1, a2, a3, a4, a5, a6, a7); +} + +// 8 arguments -- +template +gmp_args_nm_8_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R* r) { + return new gmp_args_nm_8_ret + (m, a0, a1, a2, a3, a4, a5, a6, a7, r); +} + +// 8 arguments -- +template +gmp_args_m_8* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) { + return new gmp_args_m_8 + (o, m, a0, a1, a2, a3, a4, a5, a6, a7); +} + +// 8 arguments -- +template +gmp_args_m_8_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R* r) { + return new gmp_args_m_8_ret + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, r); +} + +// 9 arguments -- +template +gmp_args_nm_9* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) { + return new gmp_args_nm_9 + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8); +} + +// 9 arguments -- +template +gmp_args_nm_9_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R* r) { + return new gmp_args_nm_9_ret + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, r); +} + +// 9 arguments -- +template +gmp_args_m_9* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) { + return new gmp_args_m_9 + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8); +} + +// 9 arguments -- +template +gmp_args_m_9_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R* r) { + return new gmp_args_m_9_ret + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, r); +} + +// 10 arguments -- +template +gmp_args_nm_10* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) { + return new gmp_args_nm_10 + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); +} + +// 10 arguments -- +template +gmp_args_nm_10_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R* r) { + return new gmp_args_nm_10_ret + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, r); +} + +// 10 arguments -- +template +gmp_args_m_10* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) { + return new gmp_args_m_10 + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); +} + +// 10 arguments -- +template +gmp_args_m_10_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R* r) { + return new gmp_args_m_10_ret + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, r); +} + +// 11 arguments -- +template +gmp_args_nm_11* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) { + return new gmp_args_nm_11 + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); +} + +// 11 arguments -- +template +gmp_args_nm_11_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R* r) { + return new gmp_args_nm_11_ret + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, r); +} + +// 11 arguments -- +template +gmp_args_m_11* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) { + return new gmp_args_m_11 + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); +} + +// 11 arguments -- +template +gmp_args_m_11_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R* r) { + return new gmp_args_m_11_ret + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, r); +} + +// 12 arguments -- +template +gmp_args_nm_12* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) { + return new gmp_args_nm_12 + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); +} + +// 12 arguments -- +template +gmp_args_nm_12_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R* r) { + return new gmp_args_nm_12_ret + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, r); +} + +// 12 arguments -- +template +gmp_args_m_12* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) { + return new gmp_args_m_12 + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); +} + +// 12 arguments -- +template +gmp_args_m_12_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R* r) { + return new gmp_args_m_12_ret + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, r); +} + +// 13 arguments -- +template +gmp_args_nm_13* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) { + return new gmp_args_nm_13 + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); +} + +// 13 arguments -- +template +gmp_args_nm_13_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R* r) { + return new gmp_args_nm_13_ret + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, r); +} + +// 13 arguments -- +template +gmp_args_m_13* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) { + return new gmp_args_m_13 + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); +} + +// 13 arguments -- +template +gmp_args_m_13_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R* r) { + return new gmp_args_m_13_ret + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, r); +} + +// 14 arguments -- +template +gmp_args_nm_14* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) { + return new gmp_args_nm_14 + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); +} + +// 14 arguments -- +template +gmp_args_nm_14_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R* r) { + return new gmp_args_nm_14_ret + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, r); +} + +// 14 arguments -- +template +gmp_args_m_14* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) { + return new gmp_args_m_14 + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); +} + +// 14 arguments -- +template +gmp_args_m_14_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R* r) { + return new gmp_args_m_14_ret + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, r); +} +