<commit_before>/*************************************************************************
 *
 *  $RCSfile: chpfld.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: mba $ $Date: 2002-05-27 14:32:25 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifdef PRECOMPILED
#include "core_pch.hxx"
#endif

#pragma hdrstop

#ifndef _COM_SUN_STAR_TEXT_CHAPTERFORMAT_HPP_
#include <com/sun/star/text/ChapterFormat.hpp>
#endif

#ifndef _DOC_HXX
#include <doc.hxx>
#endif
#ifndef _FRAME_HXX
#include <frame.hxx>        // SwChapterFieldType::ChangeExpansion()
#endif
#ifndef _PAM_HXX
#include <pam.hxx>          // fuer GetBodyTxtNode
#endif
#ifndef _NDTXT_HXX
#include <ndtxt.hxx>
#endif
#ifndef _CHPFLD_HXX
#include <chpfld.hxx>
#endif
#ifndef _EXPFLD_HXX
#include <expfld.hxx>       // fuer GetBodyTxtNode
#endif
#ifndef _UNOFLDMID_H
#include <unofldmid.h>
#endif

using namespace ::com::sun::star;

/*--------------------------------------------------------------------
    Beschreibung: SwChapterFieldType
 --------------------------------------------------------------------*/

SwChapterFieldType::SwChapterFieldType()
    : SwFieldType( RES_CHAPTERFLD )
{
}

SwFieldType* SwChapterFieldType::Copy() const
{
    return new SwChapterFieldType();
}

/*--------------------------------------------------------------------
    Beschreibung: Kapittelfeld
 --------------------------------------------------------------------*/

SwChapterField::SwChapterField(SwChapterFieldType* pTyp, sal_uInt32 nFmt)
    : SwField(pTyp, nFmt), nLevel( 0 )
{}

String SwChapterField::Expand() const
{
    String sStr( sNumber );
    switch( GetFormat() )
    {
        case CF_TITLE:      sStr = sTitle;  break;

        case CF_NUMBER:
        case CF_NUM_TITLE:  sStr.Insert( sPre, 0 );
                            sStr += sPost;
                            if( CF_NUM_TITLE == GetFormat() )
                                sStr += sTitle;
                            break;

        case CF_NUM_NOPREPST_TITLE: sStr += sTitle; break;
    }
    return sStr;
}

SwField* SwChapterField::Copy() const
{
    SwChapterField *pTmp =
        new SwChapterField((SwChapterFieldType*)GetTyp(), GetFormat());
    pTmp->nLevel = nLevel;
    pTmp->sTitle = sTitle;
    pTmp->sNumber = sNumber;
    pTmp->sPost = sPost;
    pTmp->sPre = sPre;

    return pTmp;
}

void SwChapterField::ChangeExpansion( const SwFrm* pFrm,
                                      const SwTxtNode* pTxtNd,
                                      sal_Bool bSrchNum )
{
    ASSERT( pFrm, "in welchem Frame stehe ich denn?" )
    SwDoc* pDoc = (SwDoc*)pTxtNd->GetDoc();
    SwPosition aPos( pDoc->GetNodes().GetEndOfContent() );

    if( pFrm->IsInDocBody() )
        aPos.nNode = *pTxtNd;
    else if( 0 == (pTxtNd = GetBodyTxtNode( *pDoc, aPos, *pFrm )) )
        // kein TxtNode (Formatierung Kopf/Fusszeile)
        return;

    ASSERT( pTxtNd, "Wo steht das Feld" );
    pTxtNd = pTxtNd->FindOutlineNodeOfLevel( nLevel );
    if( pTxtNd )
    {
        if( bSrchNum )
        {
            const SwTxtNode* pONd = pTxtNd;
            do {
                if( pONd && pONd->GetTxtColl() )
                {
                    BYTE nPrevLvl = nLevel;
                    nLevel = GetRealLevel( pONd->GetTxtColl()->
                                            GetOutlineLevel() );
                    if( nPrevLvl < nLevel )
                        nLevel = nPrevLvl;
                    else if( SVX_NUM_NUMBER_NONE != pDoc->GetOutlineNumRule()
                            ->Get( nLevel ).GetNumberingType() )
                    {
                        pTxtNd = pONd;
                        break;
                    }

                    if( !nLevel-- )
                        break;
                    pONd = pTxtNd->FindOutlineNodeOfLevel( nLevel );
                }
                else
                    break;
            } while( sal_True );
        }

        const SwNodeNum& rNum = *pTxtNd->GetOutlineNum();
        // nur die Nummer besorgen, ohne Pre-/Post-fixstrings
        sNumber = pDoc->GetOutlineNumRule()->MakeNumString( rNum, sal_False );

        if( NO_NUM > rNum.GetLevel() && !( NO_NUMLEVEL & rNum.GetLevel() ) )
        {
            const SwNumFmt& rNFmt = pDoc->GetOutlineNumRule()->Get( rNum.GetLevel() );
            sPost = rNFmt.GetSuffix();
            sPre = rNFmt.GetPrefix();
        }
        else
            sPost = aEmptyStr, sPre = aEmptyStr;

        sTitle = pTxtNd->GetExpandTxt();

        for( xub_StrLen i = 0; i < sTitle.Len(); ++i )
            if( ' ' > sTitle.GetChar( i ) )
                sTitle.Erase( i--, 1 );
    }
    else
    {
        sNumber = aEmptyStr;
        sTitle = aEmptyStr;
        sPost = aEmptyStr;
        sPre = aEmptyStr;
    }
}

/*-----------------05.03.98 16:19-------------------

--------------------------------------------------*/
BOOL SwChapterField::QueryValue( com::sun::star::uno::Any& rAny, BYTE nMId ) const
{
    nMId &= ~CONVERT_TWIPS;
    switch( nMId )
    {
    case FIELD_PROP_BYTE1:
        rAny <<= (sal_Int8)nLevel;
        break;

    case FIELD_PROP_USHORT1:
        {
            sal_Int16 nRet;
            switch( GetFormat() )
            {
                case CF_NUMBER: nRet = text::ChapterFormat::NUMBER; break;
                case CF_TITLE:  nRet = text::ChapterFormat::NAME; break;
                case CF_NUMBER_NOPREPST:
                    nRet = text::ChapterFormat::DIGIT;
                break;
                case CF_NUM_NOPREPST_TITLE:
                    nRet = text::ChapterFormat::NO_PREFIX_SUFFIX;
                break;
                case CF_NUM_TITLE:
                default:        nRet = text::ChapterFormat::NAME_NUMBER;
            }
            rAny <<= nRet;
        }
        break;

    default:
        DBG_ERROR("illegal property");
    }
    return sal_True;
}
/*-----------------05.03.98 16:19-------------------

--------------------------------------------------*/
BOOL SwChapterField::PutValue( const com::sun::star::uno::Any& rAny, BYTE nMId )
{
    BOOL bRet = TRUE;
    nMId &= ~CONVERT_TWIPS;
    switch( nMId )
    {
    case FIELD_PROP_BYTE1:
        sal_Int8 nTmp;
        rAny >>= nTmp;
        if(nTmp >= 0 && nTmp < MAXLEVEL)
            nLevel = nTmp;
        else
            bRet = FALSE;
        break;

    case FIELD_PROP_USHORT1:
        {
            sal_Int16 nVal;
            rAny >>= nVal;
            switch( nVal )
            {
                case text::ChapterFormat::NAME: SetFormat(CF_TITLE); break;
                case text::ChapterFormat::NUMBER:  SetFormat(CF_NUMBER); break;
                case text::ChapterFormat::NO_PREFIX_SUFFIX:
                            SetFormat(CF_NUM_NOPREPST_TITLE);
                break;
                case text::ChapterFormat::DIGIT:
                        SetFormat(CF_NUMBER_NOPREPST);
                break;
                //case text::ChapterFormat::NAME_NUMBER:
                default:        SetFormat(CF_NUM_TITLE);
            }
        }
        break;

    default:
        DBG_ERROR("illegal property");
        bRet = FALSE;
    }
    return bRet;
}
<commit_msg>INTEGRATION: CWS os8 (1.5.148); FILE MERGED 2003/04/03 07:10:38 os 1.5.148.1: #108583# precompiled headers removed<commit_after>/*************************************************************************
 *
 *  $RCSfile: chpfld.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: vg $ $Date: 2003-04-17 14:04:28 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#pragma hdrstop

#ifndef _COM_SUN_STAR_TEXT_CHAPTERFORMAT_HPP_
#include <com/sun/star/text/ChapterFormat.hpp>
#endif

#ifndef _DOC_HXX
#include <doc.hxx>
#endif
#ifndef _FRAME_HXX
#include <frame.hxx>        // SwChapterFieldType::ChangeExpansion()
#endif
#ifndef _PAM_HXX
#include <pam.hxx>          // fuer GetBodyTxtNode
#endif
#ifndef _NDTXT_HXX
#include <ndtxt.hxx>
#endif
#ifndef _CHPFLD_HXX
#include <chpfld.hxx>
#endif
#ifndef _EXPFLD_HXX
#include <expfld.hxx>       // fuer GetBodyTxtNode
#endif
#ifndef _UNOFLDMID_H
#include <unofldmid.h>
#endif

using namespace ::com::sun::star;

/*--------------------------------------------------------------------
    Beschreibung: SwChapterFieldType
 --------------------------------------------------------------------*/

SwChapterFieldType::SwChapterFieldType()
    : SwFieldType( RES_CHAPTERFLD )
{
}

SwFieldType* SwChapterFieldType::Copy() const
{
    return new SwChapterFieldType();
}

/*--------------------------------------------------------------------
    Beschreibung: Kapittelfeld
 --------------------------------------------------------------------*/

SwChapterField::SwChapterField(SwChapterFieldType* pTyp, sal_uInt32 nFmt)
    : SwField(pTyp, nFmt), nLevel( 0 )
{}

String SwChapterField::Expand() const
{
    String sStr( sNumber );
    switch( GetFormat() )
    {
        case CF_TITLE:      sStr = sTitle;  break;

        case CF_NUMBER:
        case CF_NUM_TITLE:  sStr.Insert( sPre, 0 );
                            sStr += sPost;
                            if( CF_NUM_TITLE == GetFormat() )
                                sStr += sTitle;
                            break;

        case CF_NUM_NOPREPST_TITLE: sStr += sTitle; break;
    }
    return sStr;
}

SwField* SwChapterField::Copy() const
{
    SwChapterField *pTmp =
        new SwChapterField((SwChapterFieldType*)GetTyp(), GetFormat());
    pTmp->nLevel = nLevel;
    pTmp->sTitle = sTitle;
    pTmp->sNumber = sNumber;
    pTmp->sPost = sPost;
    pTmp->sPre = sPre;

    return pTmp;
}

void SwChapterField::ChangeExpansion( const SwFrm* pFrm,
                                      const SwTxtNode* pTxtNd,
                                      sal_Bool bSrchNum )
{
    ASSERT( pFrm, "in welchem Frame stehe ich denn?" )
    SwDoc* pDoc = (SwDoc*)pTxtNd->GetDoc();
    SwPosition aPos( pDoc->GetNodes().GetEndOfContent() );

    if( pFrm->IsInDocBody() )
        aPos.nNode = *pTxtNd;
    else if( 0 == (pTxtNd = GetBodyTxtNode( *pDoc, aPos, *pFrm )) )
        // kein TxtNode (Formatierung Kopf/Fusszeile)
        return;

    ASSERT( pTxtNd, "Wo steht das Feld" );
    pTxtNd = pTxtNd->FindOutlineNodeOfLevel( nLevel );
    if( pTxtNd )
    {
        if( bSrchNum )
        {
            const SwTxtNode* pONd = pTxtNd;
            do {
                if( pONd && pONd->GetTxtColl() )
                {
                    BYTE nPrevLvl = nLevel;
                    nLevel = GetRealLevel( pONd->GetTxtColl()->
                                            GetOutlineLevel() );
                    if( nPrevLvl < nLevel )
                        nLevel = nPrevLvl;
                    else if( SVX_NUM_NUMBER_NONE != pDoc->GetOutlineNumRule()
                            ->Get( nLevel ).GetNumberingType() )
                    {
                        pTxtNd = pONd;
                        break;
                    }

                    if( !nLevel-- )
                        break;
                    pONd = pTxtNd->FindOutlineNodeOfLevel( nLevel );
                }
                else
                    break;
            } while( sal_True );
        }

        const SwNodeNum& rNum = *pTxtNd->GetOutlineNum();
        // nur die Nummer besorgen, ohne Pre-/Post-fixstrings
        sNumber = pDoc->GetOutlineNumRule()->MakeNumString( rNum, sal_False );

        if( NO_NUM > rNum.GetLevel() && !( NO_NUMLEVEL & rNum.GetLevel() ) )
        {
            const SwNumFmt& rNFmt = pDoc->GetOutlineNumRule()->Get( rNum.GetLevel() );
            sPost = rNFmt.GetSuffix();
            sPre = rNFmt.GetPrefix();
        }
        else
            sPost = aEmptyStr, sPre = aEmptyStr;

        sTitle = pTxtNd->GetExpandTxt();

        for( xub_StrLen i = 0; i < sTitle.Len(); ++i )
            if( ' ' > sTitle.GetChar( i ) )
                sTitle.Erase( i--, 1 );
    }
    else
    {
        sNumber = aEmptyStr;
        sTitle = aEmptyStr;
        sPost = aEmptyStr;
        sPre = aEmptyStr;
    }
}

/*-----------------05.03.98 16:19-------------------

--------------------------------------------------*/
BOOL SwChapterField::QueryValue( com::sun::star::uno::Any& rAny, BYTE nMId ) const
{
    nMId &= ~CONVERT_TWIPS;
    switch( nMId )
    {
    case FIELD_PROP_BYTE1:
        rAny <<= (sal_Int8)nLevel;
        break;

    case FIELD_PROP_USHORT1:
        {
            sal_Int16 nRet;
            switch( GetFormat() )
            {
                case CF_NUMBER: nRet = text::ChapterFormat::NUMBER; break;
                case CF_TITLE:  nRet = text::ChapterFormat::NAME; break;
                case CF_NUMBER_NOPREPST:
                    nRet = text::ChapterFormat::DIGIT;
                break;
                case CF_NUM_NOPREPST_TITLE:
                    nRet = text::ChapterFormat::NO_PREFIX_SUFFIX;
                break;
                case CF_NUM_TITLE:
                default:        nRet = text::ChapterFormat::NAME_NUMBER;
            }
            rAny <<= nRet;
        }
        break;

    default:
        DBG_ERROR("illegal property");
    }
    return sal_True;
}
/*-----------------05.03.98 16:19-------------------

--------------------------------------------------*/
BOOL SwChapterField::PutValue( const com::sun::star::uno::Any& rAny, BYTE nMId )
{
    BOOL bRet = TRUE;
    nMId &= ~CONVERT_TWIPS;
    switch( nMId )
    {
    case FIELD_PROP_BYTE1:
        sal_Int8 nTmp;
        rAny >>= nTmp;
        if(nTmp >= 0 && nTmp < MAXLEVEL)
            nLevel = nTmp;
        else
            bRet = FALSE;
        break;

    case FIELD_PROP_USHORT1:
        {
            sal_Int16 nVal;
            rAny >>= nVal;
            switch( nVal )
            {
                case text::ChapterFormat::NAME: SetFormat(CF_TITLE); break;
                case text::ChapterFormat::NUMBER:  SetFormat(CF_NUMBER); break;
                case text::ChapterFormat::NO_PREFIX_SUFFIX:
                            SetFormat(CF_NUM_NOPREPST_TITLE);
                break;
                case text::ChapterFormat::DIGIT:
                        SetFormat(CF_NUMBER_NOPREPST);
                break;
                //case text::ChapterFormat::NAME_NUMBER:
                default:        SetFormat(CF_NUM_TITLE);
            }
        }
        break;

    default:
        DBG_ERROR("illegal property");
        bRet = FALSE;
    }
    return bRet;
}
<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2018 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#undef NDEBUG // do all assertions in this file

//ospray
#include "ospray/camera/Camera.h"
#include "ospray/common/Data.h"
#include "ospray/lights/Light.h"
#include "ospray/transferFunction/TransferFunction.h"
//mpiCommon
#include "mpiCommon/MPICommon.h"
//ospray_mpi
#include "mpi/MPIDistributedDevice.h"
#include "mpi/fb/DistributedFrameBuffer.h"
#include "mpi/render/MPILoadBalancer.h"

//distributed objects
#include "render/distributed/DistributedRaycast.h"
#include "common/DistributedModel.h"

#ifdef OPEN_MPI
# include <thread>
//# define _GNU_SOURCE
# include <sched.h>
#endif

namespace ospray {
  namespace mpi {

    // Helper functions ///////////////////////////////////////////////////////

    template <typename OSPRAY_TYPE, typename API_TYPE>
    inline API_TYPE createLocalObject(const char *type)
    {
      auto *instance = OSPRAY_TYPE::createInstance(type);
      return (API_TYPE)instance;
    }

    template <typename OSPRAY_TYPE, typename API_TYPE>
    inline API_TYPE createDistributedObject(const char *type)
    {
      auto *instance = OSPRAY_TYPE::createInstance(type);
      instance->refInc();

      ObjectHandle handle;
      handle.assign(instance);

      return (API_TYPE)(int64)handle;
    }

    template <typename OSPRAY_TYPE>
    inline OSPRAY_TYPE& lookupDistributedObject(OSPObject obj)
    {
      auto &handle = reinterpret_cast<ObjectHandle&>(obj);
      auto *object = (OSPRAY_TYPE*)handle.lookup();

      if (!object)
        throw std::runtime_error("#dmpi: ObjectHandle doesn't exist!");

      return *object;
    }

    template <typename OSPRAY_TYPE>
    inline OSPRAY_TYPE* lookupObject(OSPObject obj)
    {
      auto &handle = reinterpret_cast<ObjectHandle&>(obj);
      if (handle.defined()) {
        return (OSPRAY_TYPE*)handle.lookup();
      } else {
        return (OSPRAY_TYPE*)obj;
      }
    }

    static void embreeErrorFunc(void *, const RTCError code, const char* str)
    {
      postStatusMsg() << "#osp: embree internal error " << code << " : " << str;
      throw std::runtime_error("embree internal error '" +std::string(str)+"'");
    }

    // MPIDistributedDevice definitions ///////////////////////////////////////

    MPIDistributedDevice::~MPIDistributedDevice()
    {
      if (shouldFinalizeMPI) {
        try {
          MPI_CALL(Finalize());
        } catch (...) {
          //TODO: anything to do here? try-catch added to silence a warning...
        }
      }
    }

    void MPIDistributedDevice::commit()
    {
      if (!initialized) {
        int _ac = 1;
        const char *_av[] = {"ospray_mpi_distributed_device"};

        MPI_Comm *setComm = static_cast<MPI_Comm*>(getParamVoidPtr("worldCommunicator", nullptr));
        shouldFinalizeMPI = mpicommon::init(&_ac, _av, setComm == nullptr);

        if (setComm) {
          MPI_CALL(Comm_dup(*setComm, &mpicommon::world.comm));
          MPI_CALL(Comm_rank(mpicommon::world.comm, &mpicommon::world.rank));
          MPI_CALL(Comm_size(mpicommon::world.comm, &mpicommon::world.size));
        }

        embreeDevice = rtcNewDevice(generateEmbreeDeviceCfg(*this).c_str());

        rtcDeviceSetErrorFunction2(embreeDevice, embreeErrorFunc, nullptr);

        RTCError erc = rtcDeviceGetError(embreeDevice);
        if (erc != RTC_NO_ERROR) {
          // why did the error function not get called !?
          postStatusMsg() << "#osp:init: embree internal error number " << erc;
          assert(erc == RTC_NO_ERROR);
        }

        initialized = true;
      }

      Device::commit();

      masterRank = getParam1i("masterRank", 0);

      TiledLoadBalancer::instance =
                      make_unique<staticLoadBalancer::Distributed>();
    }

    OSPFrameBuffer
    MPIDistributedDevice::frameBufferCreate(const vec2i &size,
                                            const OSPFrameBufferFormat mode,
                                            const uint32 channels)
    {
      const bool hasDepthBuffer    = channels & OSP_FB_DEPTH;
      const bool hasAccumBuffer    = channels & OSP_FB_ACCUM;
      const bool hasVarianceBuffer = channels & OSP_FB_VARIANCE;

      ObjectHandle handle;

      auto *instance = new DistributedFrameBuffer(size, handle, mode,
                                                  hasDepthBuffer,
                                                  hasAccumBuffer,
                                                  hasVarianceBuffer,
                                                  true);
      instance->refInc();

      handle.assign(instance);

      return (OSPFrameBuffer)(int64)handle;
    }

    const void*
    MPIDistributedDevice::frameBufferMap(OSPFrameBuffer _fb,
                                         OSPFrameBufferChannel channel)
    {
      if (!mpicommon::IamTheMaster())
        throw std::runtime_error("Can only map framebuffer on the master!");

      auto &fb = lookupDistributedObject<FrameBuffer>(_fb);

      switch (channel) {
      case OSP_FB_COLOR: return fb.mapColorBuffer();
      case OSP_FB_DEPTH: return fb.mapDepthBuffer();
      default: return nullptr;
      }
    }

    void MPIDistributedDevice::frameBufferUnmap(const void *mapped,
                                                OSPFrameBuffer _fb)
    {
      auto &fb = lookupDistributedObject<FrameBuffer>(_fb);
      fb.unmap(mapped);
    }

    void MPIDistributedDevice::frameBufferClear(OSPFrameBuffer _fb,
                                                const uint32 fbChannelFlags)
    {
      auto &fb = lookupDistributedObject<FrameBuffer>(_fb);
      fb.clear(fbChannelFlags);
    }

    OSPModel MPIDistributedDevice::newModel()
    {
      auto *instance = new DistributedModel;
      instance->refInc();

      ObjectHandle handle;
      handle.assign(instance);

      return (OSPModel)(int64)handle;
    }

    void MPIDistributedDevice::commit(OSPObject _object)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->commit();
    }

    void MPIDistributedDevice::addGeometry(OSPModel _model,
                                           OSPGeometry _geometry)
    {
      auto &model = lookupDistributedObject<Model>(_model);
      auto *geom  = lookupObject<Geometry>(_geometry);

      model.geometry.push_back(geom);
    }

    void MPIDistributedDevice::addVolume(OSPModel _model, OSPVolume _volume)
    {
      auto &model  = lookupDistributedObject<Model>(_model);
      auto *volume = lookupObject<Volume>(_volume);

      model.volume.push_back(volume);
    }

    OSPData MPIDistributedDevice::newData(size_t nitems, OSPDataType format,
                                          const void *init, int flags)
    {
      auto *instance = new Data(nitems, format, init, flags);
      instance->refInc();
      return (OSPData)instance;
    }

    void MPIDistributedDevice::setVoidPtr(OSPObject _object,
                                          const char *bufName,
                                          void *v)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::removeParam(OSPObject _object, const char *name)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->removeParam(name);
    }

    int MPIDistributedDevice::setRegion(OSPVolume _volume, const void *source,
                                        const vec3i &index, const vec3i &count)
    {
      auto *volume = (Volume*)_volume;
      return volume->setRegion(source, index, count);
    }

    void MPIDistributedDevice::setString(OSPObject _object,
                                         const char *bufName,
                                         const char *s)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->findParam(bufName, true)->set(s);
    }

    int MPIDistributedDevice::loadModule(const char *name)
    {
      return loadLocalModule(name);
    }

    void MPIDistributedDevice::setFloat(OSPObject _object,
                                        const char *bufName,
                                        const float f)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->findParam(bufName, true)->set(f);
    }

    void MPIDistributedDevice::setInt(OSPObject _object,
                                      const char *bufName,
                                      const int i)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->findParam(bufName, true)->set(i);
    }

    void MPIDistributedDevice::setVec2f(OSPObject _object,
                                        const char *bufName,
                                        const vec2f &v)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setVec3f(OSPObject _object,
                                        const char *bufName,
                                        const vec3f &v)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setVec4f(OSPObject _object,
                                        const char *bufName,
                                        const vec4f &v)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setVec2i(OSPObject _object,
                                        const char *bufName,
                                        const vec2i &v)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setVec3i(OSPObject _object,
                                        const char *bufName,
                                        const vec3i &v)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setObject(OSPObject _object,
                                         const char *bufName,
                                         OSPObject _value)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      auto *value  = lookupObject<ManagedObject>(_value);
      object->set(bufName, value);
    }

    OSPPixelOp MPIDistributedDevice::newPixelOp(const char *type)
    {
      return createDistributedObject<PixelOp, OSPPixelOp>(type);
    }

    void MPIDistributedDevice::setPixelOp(OSPFrameBuffer _fb, OSPPixelOp _op)
    {
      auto &fb = lookupDistributedObject<FrameBuffer>(_fb);
      auto &op = lookupDistributedObject<PixelOp>(_op);
      fb.pixelOp = op.createInstance(&fb, fb.pixelOp.ptr);
    }

    OSPRenderer MPIDistributedDevice::newRenderer(const char *type)
    {
      return createDistributedObject<Renderer, OSPRenderer>(type);
    }

    OSPCamera MPIDistributedDevice::newCamera(const char *type)
    {
      return createLocalObject<Camera, OSPCamera>(type);
    }

    OSPVolume MPIDistributedDevice::newVolume(const char *type)
    {
      return createLocalObject<Volume, OSPVolume>(type);
    }

    OSPGeometry MPIDistributedDevice::newGeometry(const char *type)
    {
      return createLocalObject<Geometry, OSPGeometry>(type);
    }

    OSPMaterial MPIDistributedDevice::newMaterial(OSPRenderer, const char *)
    {
      NOT_IMPLEMENTED;
    }

    OSPTransferFunction
    MPIDistributedDevice::newTransferFunction(const char *type)
    {
      return createLocalObject<TransferFunction,
                               OSPTransferFunction>(type);
    }

    OSPLight MPIDistributedDevice::newLight(OSPRenderer _renderer,
                                            const char *type)
    {
      auto &renderer = lookupDistributedObject<Renderer>(_renderer);
      auto *light    = renderer.createLight(type);

      if (light == nullptr)
        light = Light::createLight(type);

      if (light) {
        return (OSPLight)light;
      } else {
        return nullptr;
      }
    }

    void MPIDistributedDevice::removeGeometry(OSPModel _model,
                                              OSPGeometry _geometry)
    {
      auto &model = lookupDistributedObject<Model>(_model);
      auto *geom  = lookupObject<Geometry>(_geometry);

      //TODO: confirm this works?
      model.geometry.erase(std::remove(model.geometry.begin(),
                                       model.geometry.end(),
                                       Ref<Geometry>(geom)));
    }

    void MPIDistributedDevice::removeVolume(OSPModel _model, OSPVolume _volume)
    {
      auto &model  = lookupDistributedObject<Model>(_model);
      auto *volume = lookupObject<Volume>(_volume);

      //TODO: confirm this works?
      model.volume.erase(std::remove(model.volume.begin(),
                                     model.volume.end(),
                                     Ref<Volume>(volume)));
    }

    float MPIDistributedDevice::renderFrame(OSPFrameBuffer _fb,
                                            OSPRenderer _renderer,
                                            const uint32 fbChannelFlags)
    {
      auto &fb       = lookupDistributedObject<FrameBuffer>(_fb);
      auto &renderer = lookupDistributedObject<Renderer>(_renderer);
      auto result    = renderer.renderFrame(&fb, fbChannelFlags);
      mpicommon::world.barrier();
      return result;
    }

    void MPIDistributedDevice::release(OSPObject _obj)
    {
      if (!_obj) return;
      auto *obj = lookupObject<ManagedObject>(_obj);
      obj->refDec();
    }

    void MPIDistributedDevice::setMaterial(OSPGeometry, OSPMaterial)
    {
      NOT_IMPLEMENTED;
    }

    OSPTexture2D MPIDistributedDevice::newTexture2D(
      const vec2i &,
      const OSPTextureFormat,
      void *,
      const uint32
    )
    {
      NOT_IMPLEMENTED;
    }

    void MPIDistributedDevice::sampleVolume(float **,
                                            OSPVolume,
                                            const vec3f *,
                                            const size_t &)
    {
      NOT_IMPLEMENTED;
    }

    OSP_REGISTER_DEVICE(MPIDistributedDevice, mpi_distributed_device);
    OSP_REGISTER_DEVICE(MPIDistributedDevice, mpi_distributed);

  } // ::ospray::mpi
} // ::ospray
<commit_msg>Fix setString in MPI distributed device<commit_after>// ======================================================================== //
// Copyright 2009-2018 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#undef NDEBUG // do all assertions in this file

//ospray
#include "ospray/camera/Camera.h"
#include "ospray/common/Data.h"
#include "ospray/lights/Light.h"
#include "ospray/transferFunction/TransferFunction.h"
//mpiCommon
#include "mpiCommon/MPICommon.h"
//ospray_mpi
#include "mpi/MPIDistributedDevice.h"
#include "mpi/fb/DistributedFrameBuffer.h"
#include "mpi/render/MPILoadBalancer.h"

//distributed objects
#include "render/distributed/DistributedRaycast.h"
#include "common/DistributedModel.h"

#ifdef OPEN_MPI
# include <thread>
//# define _GNU_SOURCE
# include <sched.h>
#endif

namespace ospray {
  namespace mpi {

    // Helper functions ///////////////////////////////////////////////////////

    template <typename OSPRAY_TYPE, typename API_TYPE>
    inline API_TYPE createLocalObject(const char *type)
    {
      auto *instance = OSPRAY_TYPE::createInstance(type);
      return (API_TYPE)instance;
    }

    template <typename OSPRAY_TYPE, typename API_TYPE>
    inline API_TYPE createDistributedObject(const char *type)
    {
      auto *instance = OSPRAY_TYPE::createInstance(type);
      instance->refInc();

      ObjectHandle handle;
      handle.assign(instance);

      return (API_TYPE)(int64)handle;
    }

    template <typename OSPRAY_TYPE>
    inline OSPRAY_TYPE& lookupDistributedObject(OSPObject obj)
    {
      auto &handle = reinterpret_cast<ObjectHandle&>(obj);
      auto *object = (OSPRAY_TYPE*)handle.lookup();

      if (!object)
        throw std::runtime_error("#dmpi: ObjectHandle doesn't exist!");

      return *object;
    }

    template <typename OSPRAY_TYPE>
    inline OSPRAY_TYPE* lookupObject(OSPObject obj)
    {
      auto &handle = reinterpret_cast<ObjectHandle&>(obj);
      if (handle.defined()) {
        return (OSPRAY_TYPE*)handle.lookup();
      } else {
        return (OSPRAY_TYPE*)obj;
      }
    }

    static void embreeErrorFunc(void *, const RTCError code, const char* str)
    {
      postStatusMsg() << "#osp: embree internal error " << code << " : " << str;
      throw std::runtime_error("embree internal error '" +std::string(str)+"'");
    }

    // MPIDistributedDevice definitions ///////////////////////////////////////

    MPIDistributedDevice::~MPIDistributedDevice()
    {
      if (shouldFinalizeMPI) {
        try {
          MPI_CALL(Finalize());
        } catch (...) {
          //TODO: anything to do here? try-catch added to silence a warning...
        }
      }
    }

    void MPIDistributedDevice::commit()
    {
      if (!initialized) {
        int _ac = 1;
        const char *_av[] = {"ospray_mpi_distributed_device"};

        MPI_Comm *setComm = static_cast<MPI_Comm*>(getParamVoidPtr("worldCommunicator", nullptr));
        shouldFinalizeMPI = mpicommon::init(&_ac, _av, setComm == nullptr);

        if (setComm) {
          MPI_CALL(Comm_dup(*setComm, &mpicommon::world.comm));
          MPI_CALL(Comm_rank(mpicommon::world.comm, &mpicommon::world.rank));
          MPI_CALL(Comm_size(mpicommon::world.comm, &mpicommon::world.size));
        }

        embreeDevice = rtcNewDevice(generateEmbreeDeviceCfg(*this).c_str());

        rtcDeviceSetErrorFunction2(embreeDevice, embreeErrorFunc, nullptr);

        RTCError erc = rtcDeviceGetError(embreeDevice);
        if (erc != RTC_NO_ERROR) {
          // why did the error function not get called !?
          postStatusMsg() << "#osp:init: embree internal error number " << erc;
          assert(erc == RTC_NO_ERROR);
        }

        initialized = true;
      }

      Device::commit();

      masterRank = getParam1i("masterRank", 0);

      TiledLoadBalancer::instance =
                      make_unique<staticLoadBalancer::Distributed>();
    }

    OSPFrameBuffer
    MPIDistributedDevice::frameBufferCreate(const vec2i &size,
                                            const OSPFrameBufferFormat mode,
                                            const uint32 channels)
    {
      const bool hasDepthBuffer    = channels & OSP_FB_DEPTH;
      const bool hasAccumBuffer    = channels & OSP_FB_ACCUM;
      const bool hasVarianceBuffer = channels & OSP_FB_VARIANCE;

      ObjectHandle handle;

      auto *instance = new DistributedFrameBuffer(size, handle, mode,
                                                  hasDepthBuffer,
                                                  hasAccumBuffer,
                                                  hasVarianceBuffer,
                                                  true);
      instance->refInc();

      handle.assign(instance);

      return (OSPFrameBuffer)(int64)handle;
    }

    const void*
    MPIDistributedDevice::frameBufferMap(OSPFrameBuffer _fb,
                                         OSPFrameBufferChannel channel)
    {
      if (!mpicommon::IamTheMaster())
        throw std::runtime_error("Can only map framebuffer on the master!");

      auto &fb = lookupDistributedObject<FrameBuffer>(_fb);

      switch (channel) {
      case OSP_FB_COLOR: return fb.mapColorBuffer();
      case OSP_FB_DEPTH: return fb.mapDepthBuffer();
      default: return nullptr;
      }
    }

    void MPIDistributedDevice::frameBufferUnmap(const void *mapped,
                                                OSPFrameBuffer _fb)
    {
      auto &fb = lookupDistributedObject<FrameBuffer>(_fb);
      fb.unmap(mapped);
    }

    void MPIDistributedDevice::frameBufferClear(OSPFrameBuffer _fb,
                                                const uint32 fbChannelFlags)
    {
      auto &fb = lookupDistributedObject<FrameBuffer>(_fb);
      fb.clear(fbChannelFlags);
    }

    OSPModel MPIDistributedDevice::newModel()
    {
      auto *instance = new DistributedModel;
      instance->refInc();

      ObjectHandle handle;
      handle.assign(instance);

      return (OSPModel)(int64)handle;
    }

    void MPIDistributedDevice::commit(OSPObject _object)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->commit();
    }

    void MPIDistributedDevice::addGeometry(OSPModel _model,
                                           OSPGeometry _geometry)
    {
      auto &model = lookupDistributedObject<Model>(_model);
      auto *geom  = lookupObject<Geometry>(_geometry);

      model.geometry.push_back(geom);
    }

    void MPIDistributedDevice::addVolume(OSPModel _model, OSPVolume _volume)
    {
      auto &model  = lookupDistributedObject<Model>(_model);
      auto *volume = lookupObject<Volume>(_volume);

      model.volume.push_back(volume);
    }

    OSPData MPIDistributedDevice::newData(size_t nitems, OSPDataType format,
                                          const void *init, int flags)
    {
      auto *instance = new Data(nitems, format, init, flags);
      instance->refInc();
      return (OSPData)instance;
    }

    void MPIDistributedDevice::setVoidPtr(OSPObject _object,
                                          const char *bufName,
                                          void *v)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::removeParam(OSPObject _object, const char *name)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->removeParam(name);
    }

    int MPIDistributedDevice::setRegion(OSPVolume _volume, const void *source,
                                        const vec3i &index, const vec3i &count)
    {
      auto *volume = (Volume*)_volume;
      return volume->setRegion(source, index, count);
    }

    void MPIDistributedDevice::setString(OSPObject _object,
                                         const char *bufName,
                                         const char *s)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->findParam(bufName, true)->set(std::string(s));
    }

    int MPIDistributedDevice::loadModule(const char *name)
    {
      return loadLocalModule(name);
    }

    void MPIDistributedDevice::setFloat(OSPObject _object,
                                        const char *bufName,
                                        const float f)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->findParam(bufName, true)->set(f);
    }

    void MPIDistributedDevice::setInt(OSPObject _object,
                                      const char *bufName,
                                      const int i)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->findParam(bufName, true)->set(i);
    }

    void MPIDistributedDevice::setVec2f(OSPObject _object,
                                        const char *bufName,
                                        const vec2f &v)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setVec3f(OSPObject _object,
                                        const char *bufName,
                                        const vec3f &v)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setVec4f(OSPObject _object,
                                        const char *bufName,
                                        const vec4f &v)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setVec2i(OSPObject _object,
                                        const char *bufName,
                                        const vec2i &v)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setVec3i(OSPObject _object,
                                        const char *bufName,
                                        const vec3i &v)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      object->findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setObject(OSPObject _object,
                                         const char *bufName,
                                         OSPObject _value)
    {
      auto *object = lookupObject<ManagedObject>(_object);
      auto *value  = lookupObject<ManagedObject>(_value);
      object->set(bufName, value);
    }

    OSPPixelOp MPIDistributedDevice::newPixelOp(const char *type)
    {
      return createDistributedObject<PixelOp, OSPPixelOp>(type);
    }

    void MPIDistributedDevice::setPixelOp(OSPFrameBuffer _fb, OSPPixelOp _op)
    {
      auto &fb = lookupDistributedObject<FrameBuffer>(_fb);
      auto &op = lookupDistributedObject<PixelOp>(_op);
      fb.pixelOp = op.createInstance(&fb, fb.pixelOp.ptr);
    }

    OSPRenderer MPIDistributedDevice::newRenderer(const char *type)
    {
      return createDistributedObject<Renderer, OSPRenderer>(type);
    }

    OSPCamera MPIDistributedDevice::newCamera(const char *type)
    {
      return createLocalObject<Camera, OSPCamera>(type);
    }

    OSPVolume MPIDistributedDevice::newVolume(const char *type)
    {
      return createLocalObject<Volume, OSPVolume>(type);
    }

    OSPGeometry MPIDistributedDevice::newGeometry(const char *type)
    {
      return createLocalObject<Geometry, OSPGeometry>(type);
    }

    OSPMaterial MPIDistributedDevice::newMaterial(OSPRenderer, const char *)
    {
      NOT_IMPLEMENTED;
    }

    OSPTransferFunction
    MPIDistributedDevice::newTransferFunction(const char *type)
    {
      return createLocalObject<TransferFunction,
                               OSPTransferFunction>(type);
    }

    OSPLight MPIDistributedDevice::newLight(OSPRenderer _renderer,
                                            const char *type)
    {
      auto &renderer = lookupDistributedObject<Renderer>(_renderer);
      auto *light    = renderer.createLight(type);

      if (light == nullptr)
        light = Light::createLight(type);

      if (light) {
        return (OSPLight)light;
      } else {
        return nullptr;
      }
    }

    void MPIDistributedDevice::removeGeometry(OSPModel _model,
                                              OSPGeometry _geometry)
    {
      auto &model = lookupDistributedObject<Model>(_model);
      auto *geom  = lookupObject<Geometry>(_geometry);

      //TODO: confirm this works?
      model.geometry.erase(std::remove(model.geometry.begin(),
                                       model.geometry.end(),
                                       Ref<Geometry>(geom)));
    }

    void MPIDistributedDevice::removeVolume(OSPModel _model, OSPVolume _volume)
    {
      auto &model  = lookupDistributedObject<Model>(_model);
      auto *volume = lookupObject<Volume>(_volume);

      //TODO: confirm this works?
      model.volume.erase(std::remove(model.volume.begin(),
                                     model.volume.end(),
                                     Ref<Volume>(volume)));
    }

    float MPIDistributedDevice::renderFrame(OSPFrameBuffer _fb,
                                            OSPRenderer _renderer,
                                            const uint32 fbChannelFlags)
    {
      auto &fb       = lookupDistributedObject<FrameBuffer>(_fb);
      auto &renderer = lookupDistributedObject<Renderer>(_renderer);
      auto result    = renderer.renderFrame(&fb, fbChannelFlags);
      mpicommon::world.barrier();
      return result;
    }

    void MPIDistributedDevice::release(OSPObject _obj)
    {
      if (!_obj) return;
      auto *obj = lookupObject<ManagedObject>(_obj);
      obj->refDec();
    }

    void MPIDistributedDevice::setMaterial(OSPGeometry, OSPMaterial)
    {
      NOT_IMPLEMENTED;
    }

    OSPTexture2D MPIDistributedDevice::newTexture2D(
      const vec2i &,
      const OSPTextureFormat,
      void *,
      const uint32
    )
    {
      NOT_IMPLEMENTED;
    }

    void MPIDistributedDevice::sampleVolume(float **,
                                            OSPVolume,
                                            const vec3f *,
                                            const size_t &)
    {
      NOT_IMPLEMENTED;
    }

    OSP_REGISTER_DEVICE(MPIDistributedDevice, mpi_distributed_device);
    OSP_REGISTER_DEVICE(MPIDistributedDevice, mpi_distributed);

  } // ::ospray::mpi
} // ::ospray
<|endoftext|>


<commit_before>/**
 * Appcelerator Titanium - licensed under the Apache Public License 2
 * see LICENSE in the root folder for details on the license.
 * Copyright (c) 2008 Appcelerator, Inc. All Rights Reserved.
 */
#include "../ui_module.h"
#include <math.h>
#define ID_INPUT_FIELD 101

namespace ti
{
	std::map<DWORD, Win32PopupDialog*> Win32PopupDialog::popups;

	class DialogTemplate
	{
	public:
		LPCDLGTEMPLATE Template()
		{
			return (LPCDLGTEMPLATE)&v[0];
		}

		void AlignToDword()
		{
			if (v.size() % 4) Write(NULL, 4 - (v.size() % 4));
		}

		void Write(LPCVOID pvWrite, DWORD cbWrite)
		{
			v.insert(v.end(), cbWrite, 0);
			if (pvWrite)
			{
				CopyMemory(&v[v.size() - cbWrite], pvWrite, cbWrite);
			}
		}

		template<typename T> void Write(T t)
		{
			Write(&t, sizeof(T));
		}

		void WriteString(LPCWSTR psz)
		{
			Write(psz, (lstrlenW(psz) + 1) * sizeof(WCHAR));
		}

	private:
		std::vector<BYTE> v;
	};

	Win32PopupDialog::Win32PopupDialog(HWND windowHandle) :
		windowHandle(windowHandle),
		showInputText(false),
		showCancelButton(false),
		result(IDNO)
	{
	}

	Win32PopupDialog::~Win32PopupDialog()
	{
	}

	int Win32PopupDialog::Show()
	{
		popups[GetCurrentThreadId()] = this;
		ShowMessageBox(windowHandle);

		return result;
	}

	/*static*/
	void Win32PopupDialog::HandleOKClick(HWND dialog)
	{
		TCHAR textEntered[MAX_INPUT_LENGTH];
		GetDlgItemText(dialog, ID_INPUT_FIELD, textEntered, MAX_INPUT_LENGTH);

		Win32PopupDialog* popupDialog = popups[GetCurrentThreadId()];
		if (popupDialog)
		{
			std::wstring textEnteredW = textEntered;
			std::string textEnteredU = ::WideToUTF8(textEnteredW);
			popupDialog->inputText.clear();
			popupDialog->inputText.append(textEnteredU);
			popupDialog->result = IDOK;
		}
		else
		{
			std::cerr << "unable to find popup dialog for current thread" << std::endl;
		}
	}

	/*static*/
	INT_PTR CALLBACK Win32PopupDialog::Callback(HWND dialog, UINT message, WPARAM wParam, LPARAM lParam)
	{
		switch (message)
		{
			case WM_INITDIALOG:
			{
				Win32PopupDialog* popupDialog = popups[GetCurrentThreadId()];
				HWND parentWindow = (popupDialog == NULL ? NULL : popupDialog->windowHandle);
				if (parentWindow == NULL)
				{
					parentWindow = GetDesktopWindow();
				}

				RECT parentRect, dialogRect;
				GetWindowRect(parentWindow, &parentRect);
				GetWindowRect(dialog, &dialogRect);
				int x = parentRect.left + (parentRect.right - parentRect.left) / 2;
				int y = parentRect.top + (parentRect.bottom - parentRect.top) / 2;
				x -= (dialogRect.right - dialogRect.left) / 2;
				y -= (dialogRect.bottom - dialogRect.top) / 2;

				SetWindowPos(dialog, HWND_TOP, x, y, 0, 0, SWP_NOSIZE);

				if (popupDialog->showInputText)
				{
					if (GetDlgCtrlID((HWND) wParam) != ID_INPUT_FIELD)
					{
						HWND inputText = GetDlgItem(dialog, ID_INPUT_FIELD);
						SetFocus(inputText);
						SendMessage(inputText, EM_SETSEL,
							0, popupDialog->inputText.length());
						return FALSE;
					}
				}

				return TRUE;
			}
			case WM_COMMAND:
				if(GET_WM_COMMAND_ID(wParam, lParam) == IDOK)
				{
					Win32PopupDialog::HandleOKClick(dialog);
					EndDialog(dialog, 0);
				}
				else if(GET_WM_COMMAND_ID(wParam, lParam) == IDCANCEL)
				{
					EndDialog(dialog, 0);
				}
				break;
		}

		return FALSE;
	}

	int Win32PopupDialog::CountMatches(std::string& message, const char *token)
	{
		int matches = 0;
		size_t pos = 0, tokenSize = strlen(token);
		while (pos != std::string::npos)
		{
			pos = message.find(token, pos);
			if (pos != std::string::npos)
			{
				matches++;
				pos += tokenSize;
			}
		}
		return matches;
	}

	BOOL Win32PopupDialog::ShowMessageBox(HWND hwnd)
	{
		BOOL fSuccess = FALSE;
		HDC hdc = GetDC(hwnd);

		if (hdc)
		{
			NONCLIENTMETRICSW nonClientMetrics = { sizeof(NONCLIENTMETRICSW) };
			if (SystemParametersInfoW(
				SPI_GETNONCLIENTMETRICS, 0, &nonClientMetrics, 0))
			{
				DialogTemplate tmp;
				std::wstring wideTitle(::UTF8ToWide(title));
				std::wstring wideInputText;
				if (this->showInputText)
					wideInputText.assign(::UTF8ToWide(inputText));

				int controlCount = 2;	// at minimum, static label and OK button
				if (this->showCancelButton)
					controlCount++;
				if (this->showInputText)
					controlCount++;

				int messageLines = 0;
				int newlines = CountMatches(message, "\n");
				int tabs = CountMatches(message, "\t");
				int spaces = CountMatches(message, " ");

				if (newlines == 0 && tabs == 0 && spaces == 0)
				{
					std::string tempMessage(message);
					if (tempMessage.length() != 0)
					{
						int insertAt = 60;
						int count = 0;

						std::string::iterator it = tempMessage.begin();
						for (; it < tempMessage.end(); it++)
						{
							count++;
							if (count == 60)
							{
								count = 0;
								message.insert(insertAt, "\n");
								insertAt += 60;
							}
						}
					}
				}

				std::wstring wideMessage(::UTF8ToWide(message));
				messageLines = message.length() / 60;
				messageLines += ((int) ceil((double)tabs / 14));
				messageLines += newlines;

				if (tabs == 0 || newlines == 0)
					messageLines++;

				int labelHeight = 14;
				int width = 200;
				int margin = 10;
				int buttonWidth = 50;
				int buttonHeight = 14;
				int inputHeight = 14;
				int messageHeight = (messageLines * 12) + (messageLines * margin);
				int height = messageHeight + 56;

				if (!this->showInputText)
				{
					height -= (inputHeight + margin);
				}

				// Write out the extended dialog template header
				tmp.Write<WORD>(1); // dialog version
				tmp.Write<WORD>(0xFFFF); // extended dialog template
				tmp.Write<DWORD>(0); // help ID
				tmp.Write<DWORD>(0); // extended style
				tmp.Write<DWORD>(WS_CAPTION | WS_BORDER | DS_ABSALIGN | DS_SETFONT);
				tmp.Write<WORD>(controlCount); // number of controls
				tmp.Write<WORD>(32); // X
				tmp.Write<WORD>(32); // Y
				tmp.Write<WORD>(width); // width
				tmp.Write<WORD>(height); // height
				tmp.WriteString(L""); // no menu
				tmp.WriteString(L""); // default dialog class
				//tmp.WriteString(pszTitle); // title
				tmp.WriteString(wideTitle.c_str()); // title

				// Next comes the font description.
				// See text for discussion of fancy formula.

				if (nonClientMetrics.lfMessageFont.lfHeight < 0)
				{
					int dpi = GetDeviceCaps(hdc, LOGPIXELSY);
					nonClientMetrics.lfMessageFont.lfHeight =
						-MulDiv(nonClientMetrics.lfMessageFont.lfHeight, 72, dpi);
				}
				tmp.Write<WORD>((WORD)nonClientMetrics.lfMessageFont.lfHeight); // point
				tmp.Write<WORD>((WORD)nonClientMetrics.lfMessageFont.lfWeight); // weight
				tmp.Write<BYTE>(nonClientMetrics.lfMessageFont.lfItalic); // Italic
				tmp.Write<BYTE>(nonClientMetrics.lfMessageFont.lfCharSet); // CharSet
				tmp.WriteString(nonClientMetrics.lfMessageFont.lfFaceName);

				// First control - static label
				tmp.AlignToDword();
				tmp.Write<DWORD>(0); // help id
				tmp.Write<DWORD>(0); // window extended style
				tmp.Write<DWORD>(WS_CHILD | WS_VISIBLE | SS_LEFT); // style
				tmp.Write<WORD>(margin); // x
				tmp.Write<WORD>(margin); // y
				tmp.Write<WORD>(width - (2 * margin)); // width
				//tmp.Write<WORD>(labelHeight); // height
				tmp.Write<WORD>(messageHeight); // height
				tmp.Write<DWORD>(-1); // control ID
				tmp.Write<DWORD>(0x0082FFFF); // static
				//tmp.Write<DWORD>(SS_LEFT);
				tmp.WriteString(wideMessage.c_str()); // text
				tmp.Write<WORD>(0); // no extra data

				// Second control - the OK button.
				tmp.AlignToDword();
				tmp.Write<DWORD>(0); // help id
				tmp.Write<DWORD>(0); // window extended style
				tmp.Write<DWORD>(WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON); // style
				tmp.Write<WORD>(width - margin - buttonWidth); // x
				tmp.Write<WORD>(height - margin - buttonHeight); // y
				tmp.Write<WORD>(buttonWidth); // width
				tmp.Write<WORD>(buttonHeight); // height
				tmp.Write<DWORD>(IDOK); // control ID
				tmp.Write<DWORD>(0x0080FFFF); // button class atom
				tmp.WriteString(L"OK"); // text
				tmp.Write<WORD>(0); // no extra data

				if (this->showCancelButton)
				{
					// The Cancel button
					tmp.AlignToDword();
					tmp.Write<DWORD>(0); // help id
					tmp.Write<DWORD>(0); // window extended style
					tmp.Write<DWORD>(WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON); // style
					tmp.Write<WORD>(width - 2 * margin - 2 * buttonWidth); // x
					tmp.Write<WORD>(height - margin - buttonHeight); // y
					tmp.Write<WORD>(buttonWidth); // width
					tmp.Write<WORD>(buttonHeight); // height
					tmp.Write<DWORD>(IDCANCEL); // control ID
					tmp.Write<DWORD>(0x0080FFFF); // button class atom
					tmp.WriteString(L"Cancel"); // text
					tmp.Write<WORD>(0); // no extra data
				}

				if (this->showInputText)
				{
					// The input field
					tmp.AlignToDword();
					tmp.Write<DWORD>(0); // help id
					tmp.Write<DWORD>(0); // window extended style
					tmp.Write<DWORD>(ES_LEFT | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE); // style
					tmp.Write<WORD>(margin); // x
					tmp.Write<WORD>(margin + labelHeight + margin); // y
					tmp.Write<WORD>(width - (2 * margin)); // width
					tmp.Write<WORD>(inputHeight); // height
					tmp.Write<DWORD>(ID_INPUT_FIELD); // control ID
					tmp.Write<DWORD>(0x0081FFFF); // edit  class atom
					tmp.WriteString(wideInputText.c_str()); // text
					tmp.Write<WORD>(0); // no extra data
				}

				// Template is ready - go display it.
				fSuccess = DialogBoxIndirect(
					GetModuleHandle(NULL),
					tmp.Template(),
					hwnd,
					&Win32PopupDialog::Callback) >= 0;
			}
			ReleaseDC(NULL, hdc); // fixed 11 May
		}
		return fSuccess;
	}
}
<commit_msg>Swap the OK and Cancel buttons on the Win32 prompt and confirm.<commit_after>/**
 * Appcelerator Titanium - licensed under the Apache Public License 2
 * see LICENSE in the root folder for details on the license.
 * Copyright (c) 2008 Appcelerator, Inc. All Rights Reserved.
 */
#include "../ui_module.h"
#include <math.h>
#define ID_INPUT_FIELD 101

namespace ti
{
	std::map<DWORD, Win32PopupDialog*> Win32PopupDialog::popups;

	class DialogTemplate
	{
	public:
		LPCDLGTEMPLATE Template()
		{
			return (LPCDLGTEMPLATE)&v[0];
		}

		void AlignToDword()
		{
			if (v.size() % 4) Write(NULL, 4 - (v.size() % 4));
		}

		void Write(LPCVOID pvWrite, DWORD cbWrite)
		{
			v.insert(v.end(), cbWrite, 0);
			if (pvWrite)
			{
				CopyMemory(&v[v.size() - cbWrite], pvWrite, cbWrite);
			}
		}

		template<typename T> void Write(T t)
		{
			Write(&t, sizeof(T));
		}

		void WriteString(LPCWSTR psz)
		{
			Write(psz, (lstrlenW(psz) + 1) * sizeof(WCHAR));
		}

	private:
		std::vector<BYTE> v;
	};

	Win32PopupDialog::Win32PopupDialog(HWND windowHandle) :
		windowHandle(windowHandle),
		showInputText(false),
		showCancelButton(false),
		result(IDNO)
	{
	}

	Win32PopupDialog::~Win32PopupDialog()
	{
	}

	int Win32PopupDialog::Show()
	{
		popups[GetCurrentThreadId()] = this;
		ShowMessageBox(windowHandle);

		return result;
	}

	/*static*/
	void Win32PopupDialog::HandleOKClick(HWND dialog)
	{
		TCHAR textEntered[MAX_INPUT_LENGTH];
		GetDlgItemText(dialog, ID_INPUT_FIELD, textEntered, MAX_INPUT_LENGTH);

		Win32PopupDialog* popupDialog = popups[GetCurrentThreadId()];
		if (popupDialog)
		{
			std::wstring textEnteredW = textEntered;
			std::string textEnteredU = ::WideToUTF8(textEnteredW);
			popupDialog->inputText.clear();
			popupDialog->inputText.append(textEnteredU);
			popupDialog->result = IDOK;
		}
		else
		{
			std::cerr << "unable to find popup dialog for current thread" << std::endl;
		}
	}

	/*static*/
	INT_PTR CALLBACK Win32PopupDialog::Callback(HWND dialog, UINT message, WPARAM wParam, LPARAM lParam)
	{
		switch (message)
		{
			case WM_INITDIALOG:
			{
				Win32PopupDialog* popupDialog = popups[GetCurrentThreadId()];
				HWND parentWindow = (popupDialog == NULL ? NULL : popupDialog->windowHandle);
				if (parentWindow == NULL)
				{
					parentWindow = GetDesktopWindow();
				}

				RECT parentRect, dialogRect;
				GetWindowRect(parentWindow, &parentRect);
				GetWindowRect(dialog, &dialogRect);
				int x = parentRect.left + (parentRect.right - parentRect.left) / 2;
				int y = parentRect.top + (parentRect.bottom - parentRect.top) / 2;
				x -= (dialogRect.right - dialogRect.left) / 2;
				y -= (dialogRect.bottom - dialogRect.top) / 2;

				SetWindowPos(dialog, HWND_TOP, x, y, 0, 0, SWP_NOSIZE);

				if (popupDialog->showInputText)
				{
					if (GetDlgCtrlID((HWND) wParam) != ID_INPUT_FIELD)
					{
						HWND inputText = GetDlgItem(dialog, ID_INPUT_FIELD);
						SetFocus(inputText);
						SendMessage(inputText, EM_SETSEL,
							0, popupDialog->inputText.length());
						return FALSE;
					}
				}

				return TRUE;
			}
			case WM_COMMAND:
				if(GET_WM_COMMAND_ID(wParam, lParam) == IDOK)
				{
					Win32PopupDialog::HandleOKClick(dialog);
					EndDialog(dialog, 0);
				}
				else if(GET_WM_COMMAND_ID(wParam, lParam) == IDCANCEL)
				{
					EndDialog(dialog, 0);
				}
				break;
		}

		return FALSE;
	}

	int Win32PopupDialog::CountMatches(std::string& message, const char *token)
	{
		int matches = 0;
		size_t pos = 0, tokenSize = strlen(token);
		while (pos != std::string::npos)
		{
			pos = message.find(token, pos);
			if (pos != std::string::npos)
			{
				matches++;
				pos += tokenSize;
			}
		}
		return matches;
	}

	BOOL Win32PopupDialog::ShowMessageBox(HWND hwnd)
	{
		BOOL fSuccess = FALSE;
		HDC hdc = GetDC(hwnd);

		if (hdc)
		{
			NONCLIENTMETRICSW nonClientMetrics = { sizeof(NONCLIENTMETRICSW) };
			if (SystemParametersInfoW(
				SPI_GETNONCLIENTMETRICS, 0, &nonClientMetrics, 0))
			{
				DialogTemplate tmp;
				std::wstring wideTitle(::UTF8ToWide(title));
				std::wstring wideInputText;
				if (this->showInputText)
					wideInputText.assign(::UTF8ToWide(inputText));

				int controlCount = 2;	// at minimum, static label and OK button
				if (this->showCancelButton)
					controlCount++;
				if (this->showInputText)
					controlCount++;

				int messageLines = 0;
				int newlines = CountMatches(message, "\n");
				int tabs = CountMatches(message, "\t");
				int spaces = CountMatches(message, " ");

				if (newlines == 0 && tabs == 0 && spaces == 0)
				{
					std::string tempMessage(message);
					if (tempMessage.length() != 0)
					{
						int insertAt = 60;
						int count = 0;

						std::string::iterator it = tempMessage.begin();
						for (; it < tempMessage.end(); it++)
						{
							count++;
							if (count == 60)
							{
								count = 0;
								message.insert(insertAt, "\n");
								insertAt += 60;
							}
						}
					}
				}

				std::wstring wideMessage(::UTF8ToWide(message));
				messageLines = message.length() / 60;
				messageLines += ((int) ceil((double)tabs / 14));
				messageLines += newlines;

				if (tabs == 0 || newlines == 0)
					messageLines++;

				int labelHeight = 14;
				int width = 200;
				int margin = 10;
				int buttonWidth = 50;
				int buttonHeight = 14;
				int inputHeight = 14;
				int messageHeight = (messageLines * 12) + (messageLines * margin);
				int height = messageHeight + 56;

				if (!this->showInputText)
				{
					height -= (inputHeight + margin);
				}

				// Write out the extended dialog template header
				tmp.Write<WORD>(1); // dialog version
				tmp.Write<WORD>(0xFFFF); // extended dialog template
				tmp.Write<DWORD>(0); // help ID
				tmp.Write<DWORD>(0); // extended style
				tmp.Write<DWORD>(WS_CAPTION | WS_BORDER | DS_ABSALIGN | DS_SETFONT);
				tmp.Write<WORD>(controlCount); // number of controls
				tmp.Write<WORD>(32); // X
				tmp.Write<WORD>(32); // Y
				tmp.Write<WORD>(width); // width
				tmp.Write<WORD>(height); // height
				tmp.WriteString(L""); // no menu
				tmp.WriteString(L""); // default dialog class
				//tmp.WriteString(pszTitle); // title
				tmp.WriteString(wideTitle.c_str()); // title

				// Next comes the font description.
				// See text for discussion of fancy formula.

				if (nonClientMetrics.lfMessageFont.lfHeight < 0)
				{
					int dpi = GetDeviceCaps(hdc, LOGPIXELSY);
					nonClientMetrics.lfMessageFont.lfHeight =
						-MulDiv(nonClientMetrics.lfMessageFont.lfHeight, 72, dpi);
				}
				tmp.Write<WORD>((WORD)nonClientMetrics.lfMessageFont.lfHeight); // point
				tmp.Write<WORD>((WORD)nonClientMetrics.lfMessageFont.lfWeight); // weight
				tmp.Write<BYTE>(nonClientMetrics.lfMessageFont.lfItalic); // Italic
				tmp.Write<BYTE>(nonClientMetrics.lfMessageFont.lfCharSet); // CharSet
				tmp.WriteString(nonClientMetrics.lfMessageFont.lfFaceName);

				// First control - static label
				tmp.AlignToDword();
				tmp.Write<DWORD>(0); // help id
				tmp.Write<DWORD>(0); // window extended style
				tmp.Write<DWORD>(WS_CHILD | WS_VISIBLE | SS_LEFT); // style
				tmp.Write<WORD>(margin); // x
				tmp.Write<WORD>(margin); // y
				tmp.Write<WORD>(width - (2 * margin)); // width
				//tmp.Write<WORD>(labelHeight); // height
				tmp.Write<WORD>(messageHeight); // height
				tmp.Write<DWORD>(-1); // control ID
				tmp.Write<DWORD>(0x0082FFFF); // static
				//tmp.Write<DWORD>(SS_LEFT);
				tmp.WriteString(wideMessage.c_str()); // text
				tmp.Write<WORD>(0); // no extra data

				// Second control - the OK button.
				tmp.AlignToDword();
				tmp.Write<DWORD>(0); // help id
				tmp.Write<DWORD>(0); // window extended style
				tmp.Write<DWORD>(WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON); // style
				tmp.Write<WORD>(width - margin - buttonWidth); // x
				tmp.Write<WORD>(height - margin - buttonHeight); // y
				tmp.Write<WORD>(buttonWidth); // width
				tmp.Write<WORD>(buttonHeight); // height
				tmp.Write<DWORD>(IDCANCEL); // control ID
				tmp.Write<DWORD>(0x0080FFFF); // button class atom
				tmp.WriteString(L"Cancel"); // text
				tmp.Write<WORD>(0); // no extra data

				if (this->showCancelButton)
				{
					// The Cancel button
					tmp.AlignToDword();
					tmp.Write<DWORD>(0); // help id
					tmp.Write<DWORD>(0); // window extended style
					tmp.Write<DWORD>(WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON); // style
					tmp.Write<WORD>(width - 2 * margin - 2 * buttonWidth); // x
					tmp.Write<WORD>(height - margin - buttonHeight); // y
					tmp.Write<WORD>(buttonWidth); // width
					tmp.Write<WORD>(buttonHeight); // height
					tmp.Write<DWORD>(IDOK); // control ID
					tmp.Write<DWORD>(0x0080FFFF); // button class atom
					tmp.WriteString(L"OK"); // text
					tmp.Write<WORD>(0); // no extra data
				}

				if (this->showInputText)
				{
					// The input field
					tmp.AlignToDword();
					tmp.Write<DWORD>(0); // help id
					tmp.Write<DWORD>(0); // window extended style
					tmp.Write<DWORD>(ES_LEFT | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE); // style
					tmp.Write<WORD>(margin); // x
					tmp.Write<WORD>(margin + labelHeight + margin); // y
					tmp.Write<WORD>(width - (2 * margin)); // width
					tmp.Write<WORD>(inputHeight); // height
					tmp.Write<DWORD>(ID_INPUT_FIELD); // control ID
					tmp.Write<DWORD>(0x0081FFFF); // edit  class atom
					tmp.WriteString(wideInputText.c_str()); // text
					tmp.Write<WORD>(0); // no extra data
				}

				// Template is ready - go display it.
				fSuccess = DialogBoxIndirect(
					GetModuleHandle(NULL),
					tmp.Template(),
					hwnd,
					&Win32PopupDialog::Callback) >= 0;
			}
			ReleaseDC(NULL, hdc); // fixed 11 May
		}
		return fSuccess;
	}
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <algorithm>  // std::max

#include "api/video/video_bitrate_allocator.h"
#include "common_types.h"  // NOLINT(build/include)
#include "common_video/libyuv/include/webrtc_libyuv.h"
#include "modules/video_coding/encoded_frame.h"
#include "modules/video_coding/include/video_codec_interface.h"
#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
#include "modules/video_coding/utility/quality_scaler.h"
#include "modules/video_coding/video_coding_impl.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "system_wrappers/include/clock.h"

namespace webrtc {
namespace vcm {

VideoSender::VideoSender(Clock* clock,
                         EncodedImageCallback* post_encode_callback)
    : _encoder(nullptr),
      _mediaOpt(clock),
      _encodedFrameCallback(post_encode_callback, &_mediaOpt),
      post_encode_callback_(post_encode_callback),
      _codecDataBase(&_encodedFrameCallback),
      frame_dropper_enabled_(true),
      current_codec_(),
      encoder_params_({VideoBitrateAllocation(), 0, 0, 0}),
      encoder_has_internal_source_(false),
      next_frame_types_(1, kVideoFrameDelta) {
  _mediaOpt.Reset();
  // Allow VideoSender to be created on one thread but used on another, post
  // construction. This is currently how this class is being used by at least
  // one external project (diffractor).
  sequenced_checker_.Detach();
}

VideoSender::~VideoSender() {}

// Register the send codec to be used.
int32_t VideoSender::RegisterSendCodec(const VideoCodec* sendCodec,
                                       uint32_t numberOfCores,
                                       uint32_t maxPayloadSize) {
  RTC_DCHECK(sequenced_checker_.CalledSequentially());
  rtc::CritScope lock(&encoder_crit_);
  if (sendCodec == nullptr) {
    return VCM_PARAMETER_ERROR;
  }

  bool ret =
      _codecDataBase.SetSendCodec(sendCodec, numberOfCores, maxPayloadSize);

  // Update encoder regardless of result to make sure that we're not holding on
  // to a deleted instance.
  _encoder = _codecDataBase.GetEncoder();
  // Cache the current codec here so they can be fetched from this thread
  // without requiring the _sendCritSect lock.
  current_codec_ = *sendCodec;

  if (!ret) {
    RTC_LOG(LS_ERROR) << "Failed to initialize set encoder with codec type '"
                      << sendCodec->codecType << "'.";
    return VCM_CODEC_ERROR;
  }

  // SetSendCodec succeeded, _encoder should be set.
  RTC_DCHECK(_encoder);

  int numLayers;
  if (sendCodec->codecType == kVideoCodecVP8) {
    numLayers = sendCodec->VP8().numberOfTemporalLayers;
  } else if (sendCodec->codecType == kVideoCodecVP9) {
    numLayers = sendCodec->VP9().numberOfTemporalLayers;
  } else if (sendCodec->codecType == kVideoCodecGeneric &&
             sendCodec->numberOfSimulcastStreams > 0) {
    // This is mainly for unit testing, disabling frame dropping.
    // TODO(sprang): Add a better way to disable frame dropping.
    numLayers = sendCodec->simulcastStream[0].numberOfTemporalLayers;
  } else {
    numLayers = 1;
  }

  // If we have screensharing and we have layers, we disable frame dropper.
  bool disable_frame_dropper =
      numLayers > 1 && sendCodec->mode == VideoCodecMode::kScreensharing;
  if (disable_frame_dropper) {
    _mediaOpt.EnableFrameDropper(false);
  } else if (frame_dropper_enabled_) {
    _mediaOpt.EnableFrameDropper(true);
  }

  {
    rtc::CritScope cs(&params_crit_);
    next_frame_types_.clear();
    next_frame_types_.resize(VCM_MAX(sendCodec->numberOfSimulcastStreams, 1),
                             kVideoFrameKey);
    // Cache InternalSource() to have this available from IntraFrameRequest()
    // without having to acquire encoder_crit_ (avoid blocking on encoder use).
    encoder_has_internal_source_ = _encoder->InternalSource();
  }

  RTC_LOG(LS_VERBOSE) << " max bitrate " << sendCodec->maxBitrate
                      << " start bitrate " << sendCodec->startBitrate
                      << " max frame rate " << sendCodec->maxFramerate
                      << " max payload size " << maxPayloadSize;
  _mediaOpt.SetEncodingData(sendCodec->maxBitrate * 1000,
                            sendCodec->startBitrate * 1000,
                            sendCodec->maxFramerate);
  return VCM_OK;
}

// Register an external decoder object.
// This can not be used together with external decoder callbacks.
void VideoSender::RegisterExternalEncoder(VideoEncoder* externalEncoder,
                                          bool internalSource /*= false*/) {
  RTC_DCHECK(sequenced_checker_.CalledSequentially());

  rtc::CritScope lock(&encoder_crit_);

  if (externalEncoder == nullptr) {
    _codecDataBase.DeregisterExternalEncoder();
    {
      // Make sure the VCM doesn't use the de-registered codec
      rtc::CritScope params_lock(&params_crit_);
      _encoder = nullptr;
      encoder_has_internal_source_ = false;
    }
    return;
  }
  _codecDataBase.RegisterExternalEncoder(externalEncoder,
                                         internalSource);
}

EncoderParameters VideoSender::UpdateEncoderParameters(
    const EncoderParameters& params,
    VideoBitrateAllocator* bitrate_allocator,
    uint32_t target_bitrate_bps) {
  uint32_t video_target_rate_bps = _mediaOpt.SetTargetRates(target_bitrate_bps);
  uint32_t input_frame_rate = _mediaOpt.InputFrameRate();
  if (input_frame_rate == 0)
    input_frame_rate = current_codec_.maxFramerate;

  VideoBitrateAllocation bitrate_allocation;
  // Only call allocators if bitrate > 0 (ie, not suspended), otherwise they
  // might cap the bitrate to the min bitrate configured.
  if (target_bitrate_bps > 0) {
    if (bitrate_allocator) {
      bitrate_allocation = bitrate_allocator->GetAllocation(
          video_target_rate_bps, input_frame_rate);
    } else {
      DefaultVideoBitrateAllocator default_allocator(current_codec_);
      bitrate_allocation = default_allocator.GetAllocation(
          video_target_rate_bps, input_frame_rate);
    }
  }
  EncoderParameters new_encoder_params = {bitrate_allocation, params.loss_rate,
                                          params.rtt, input_frame_rate};
  return new_encoder_params;
}

void VideoSender::UpdateChannelParameters(
    VideoBitrateAllocator* bitrate_allocator,
    VideoBitrateAllocationObserver* bitrate_updated_callback) {
  VideoBitrateAllocation target_rate;
  {
    rtc::CritScope cs(&params_crit_);
    encoder_params_ =
        UpdateEncoderParameters(encoder_params_, bitrate_allocator,
                                encoder_params_.target_bitrate.get_sum_bps());
    target_rate = encoder_params_.target_bitrate;
  }
  if (bitrate_updated_callback && target_rate.get_sum_bps() > 0)
    bitrate_updated_callback->OnBitrateAllocationUpdated(target_rate);
}

int32_t VideoSender::SetChannelParameters(
    uint32_t target_bitrate_bps,
    uint8_t loss_rate,
    int64_t rtt,
    VideoBitrateAllocator* bitrate_allocator,
    VideoBitrateAllocationObserver* bitrate_updated_callback) {
  EncoderParameters encoder_params;
  encoder_params.loss_rate = loss_rate;
  encoder_params.rtt = rtt;
  encoder_params = UpdateEncoderParameters(encoder_params, bitrate_allocator,
                                           target_bitrate_bps);
  if (bitrate_updated_callback && target_bitrate_bps > 0) {
    bitrate_updated_callback->OnBitrateAllocationUpdated(
        encoder_params.target_bitrate);
  }

  bool encoder_has_internal_source;
  {
    rtc::CritScope cs(&params_crit_);
    encoder_params_ = encoder_params;
    encoder_has_internal_source = encoder_has_internal_source_;
  }

  // For encoders with internal sources, we need to tell the encoder directly,
  // instead of waiting for an AddVideoFrame that will never come (internal
  // source encoders don't get input frames).
  if (encoder_has_internal_source) {
    rtc::CritScope cs(&encoder_crit_);
    if (_encoder) {
      SetEncoderParameters(encoder_params, encoder_has_internal_source);
    }
  }

  return VCM_OK;
}

void VideoSender::SetEncoderParameters(EncoderParameters params,
                                       bool has_internal_source) {
  // |target_bitrate == 0 | means that the network is down or the send pacer is
  // full. We currently only report this if the encoder has an internal source.
  // If the encoder does not have an internal source, higher levels are expected
  // to not call AddVideoFrame. We do this since its unclear how current
  // encoder implementations behave when given a zero target bitrate.
  // TODO(perkj): Make sure all known encoder implementations handle zero
  // target bitrate and remove this check.
  if (!has_internal_source && params.target_bitrate.get_sum_bps() == 0)
    return;

  if (params.input_frame_rate == 0) {
    // No frame rate estimate available, use default.
    params.input_frame_rate = current_codec_.maxFramerate;
  }
  if (_encoder != nullptr)
    _encoder->SetEncoderParameters(params);
}

// Add one raw video frame to the encoder, blocking.
int32_t VideoSender::AddVideoFrame(const VideoFrame& videoFrame,
                                   const CodecSpecificInfo* codecSpecificInfo) {
  EncoderParameters encoder_params;
  std::vector<FrameType> next_frame_types;
  bool encoder_has_internal_source = false;
  {
    rtc::CritScope lock(&params_crit_);
    encoder_params = encoder_params_;
    next_frame_types = next_frame_types_;
    encoder_has_internal_source = encoder_has_internal_source_;
  }
  rtc::CritScope lock(&encoder_crit_);
  if (_encoder == nullptr)
    return VCM_UNINITIALIZED;
  SetEncoderParameters(encoder_params, encoder_has_internal_source);
  if (_mediaOpt.DropFrame()) {
    RTC_LOG(LS_VERBOSE) << "Drop Frame "
                        << "target bitrate "
                        << encoder_params.target_bitrate.get_sum_bps()
                        << " loss rate " << encoder_params.loss_rate << " rtt "
                        << encoder_params.rtt << " input frame rate "
                        << encoder_params.input_frame_rate;
    post_encode_callback_->OnDroppedFrame(
        EncodedImageCallback::DropReason::kDroppedByMediaOptimizations);
    return VCM_OK;
  }
  // TODO(pbos): Make sure setting send codec is synchronized with video
  // processing so frame size always matches.
  if (!_codecDataBase.MatchesCurrentResolution(videoFrame.width(),
                                               videoFrame.height())) {
    RTC_LOG(LS_ERROR)
        << "Incoming frame doesn't match set resolution. Dropping.";
    return VCM_PARAMETER_ERROR;
  }
  VideoFrame converted_frame = videoFrame;
  const VideoFrameBuffer::Type buffer_type =
      converted_frame.video_frame_buffer()->type();
  const bool is_buffer_type_supported =
      buffer_type == VideoFrameBuffer::Type::kI420 ||
      (buffer_type == VideoFrameBuffer::Type::kNative &&
       _encoder->SupportsNativeHandle());
  if (!is_buffer_type_supported) {
    // This module only supports software encoding.
    // TODO(pbos): Offload conversion from the encoder thread.
    rtc::scoped_refptr<I420BufferInterface> converted_buffer(
        converted_frame.video_frame_buffer()->ToI420());

    if (!converted_buffer) {
      RTC_LOG(LS_ERROR) << "Frame conversion failed, dropping frame.";
      return VCM_PARAMETER_ERROR;
    }
    converted_frame = VideoFrame(converted_buffer,
                                 converted_frame.timestamp(),
                                 converted_frame.render_time_ms(),
                                 converted_frame.rotation());
  }
  int32_t ret =
      _encoder->Encode(converted_frame, codecSpecificInfo, next_frame_types);
  if (ret < 0) {
    RTC_LOG(LS_ERROR) << "Failed to encode frame. Error code: " << ret;
    return ret;
  }

  {
    rtc::CritScope lock(&params_crit_);
    // Change all keyframe requests to encode delta frames the next time.
    for (size_t i = 0; i < next_frame_types_.size(); ++i) {
      // Check for equality (same requested as before encoding) to not
      // accidentally drop a keyframe request while encoding.
      if (next_frame_types[i] == next_frame_types_[i])
        next_frame_types_[i] = kVideoFrameDelta;
    }
  }
  return VCM_OK;
}

int32_t VideoSender::IntraFrameRequest(size_t stream_index) {
  {
    rtc::CritScope lock(&params_crit_);
    if (stream_index >= next_frame_types_.size()) {
      return -1;
    }
    next_frame_types_[stream_index] = kVideoFrameKey;
    if (!encoder_has_internal_source_)
      return VCM_OK;
  }
  // TODO(pbos): Remove when InternalSource() is gone. Both locks have to be
  // held here for internal consistency, since _encoder could be removed while
  // not holding encoder_crit_. Checks have to be performed again since
  // params_crit_ was dropped to not cause lock-order inversions with
  // encoder_crit_.
  rtc::CritScope lock(&encoder_crit_);
  rtc::CritScope params_lock(&params_crit_);
  if (stream_index >= next_frame_types_.size())
    return -1;
  if (_encoder != nullptr && _encoder->InternalSource()) {
    // Try to request the frame if we have an external encoder with
    // internal source since AddVideoFrame never will be called.
    if (_encoder->RequestFrame(next_frame_types_) == WEBRTC_VIDEO_CODEC_OK) {
      // Try to remove just-performed keyframe request, if stream still exists.
      next_frame_types_[stream_index] = kVideoFrameDelta;
    }
  }
  return VCM_OK;
}

int32_t VideoSender::EnableFrameDropper(bool enable) {
  rtc::CritScope lock(&encoder_crit_);
  frame_dropper_enabled_ = enable;
  _mediaOpt.EnableFrameDropper(enable);
  return VCM_OK;
}
}  // namespace vcm
}  // namespace webrtc
<commit_msg>Add field trial for disabling FrameDropper.<commit_after>/*
 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <algorithm>  // std::max

#include "api/video/video_bitrate_allocator.h"
#include "common_types.h"  // NOLINT(build/include)
#include "common_video/libyuv/include/webrtc_libyuv.h"
#include "modules/video_coding/encoded_frame.h"
#include "modules/video_coding/include/video_codec_interface.h"
#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
#include "modules/video_coding/utility/quality_scaler.h"
#include "modules/video_coding/video_coding_impl.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "system_wrappers/include/clock.h"
#include "system_wrappers/include/field_trial.h"

namespace webrtc {
namespace vcm {

namespace {

constexpr char kFrameDropperFieldTrial[] = "WebRTC-FrameDropper";

}  // namespace

VideoSender::VideoSender(Clock* clock,
                         EncodedImageCallback* post_encode_callback)
    : _encoder(nullptr),
      _mediaOpt(clock),
      _encodedFrameCallback(post_encode_callback, &_mediaOpt),
      post_encode_callback_(post_encode_callback),
      _codecDataBase(&_encodedFrameCallback),
      frame_dropper_enabled_(true),
      current_codec_(),
      encoder_params_({VideoBitrateAllocation(), 0, 0, 0}),
      encoder_has_internal_source_(false),
      next_frame_types_(1, kVideoFrameDelta) {
  _mediaOpt.Reset();
  // Allow VideoSender to be created on one thread but used on another, post
  // construction. This is currently how this class is being used by at least
  // one external project (diffractor).
  sequenced_checker_.Detach();
}

VideoSender::~VideoSender() {}

// Register the send codec to be used.
int32_t VideoSender::RegisterSendCodec(const VideoCodec* sendCodec,
                                       uint32_t numberOfCores,
                                       uint32_t maxPayloadSize) {
  RTC_DCHECK(sequenced_checker_.CalledSequentially());
  rtc::CritScope lock(&encoder_crit_);
  if (sendCodec == nullptr) {
    return VCM_PARAMETER_ERROR;
  }

  bool ret =
      _codecDataBase.SetSendCodec(sendCodec, numberOfCores, maxPayloadSize);

  // Update encoder regardless of result to make sure that we're not holding on
  // to a deleted instance.
  _encoder = _codecDataBase.GetEncoder();
  // Cache the current codec here so they can be fetched from this thread
  // without requiring the _sendCritSect lock.
  current_codec_ = *sendCodec;

  if (!ret) {
    RTC_LOG(LS_ERROR) << "Failed to initialize set encoder with codec type '"
                      << sendCodec->codecType << "'.";
    return VCM_CODEC_ERROR;
  }

  // SetSendCodec succeeded, _encoder should be set.
  RTC_DCHECK(_encoder);

  int numLayers;
  if (sendCodec->codecType == kVideoCodecVP8) {
    numLayers = sendCodec->VP8().numberOfTemporalLayers;
  } else if (sendCodec->codecType == kVideoCodecVP9) {
    numLayers = sendCodec->VP9().numberOfTemporalLayers;
  } else if (sendCodec->codecType == kVideoCodecGeneric &&
             sendCodec->numberOfSimulcastStreams > 0) {
    // This is mainly for unit testing, disabling frame dropping.
    // TODO(sprang): Add a better way to disable frame dropping.
    numLayers = sendCodec->simulcastStream[0].numberOfTemporalLayers;
  } else {
    numLayers = 1;
  }

  // If we have screensharing and we have layers, we disable frame dropper.
  const bool disable_frame_dropper =
      field_trial::IsDisabled(kFrameDropperFieldTrial) ||
      (numLayers > 1 && sendCodec->mode == VideoCodecMode::kScreensharing);
  if (disable_frame_dropper) {
    _mediaOpt.EnableFrameDropper(false);
  } else if (frame_dropper_enabled_) {
    _mediaOpt.EnableFrameDropper(true);
  }

  {
    rtc::CritScope cs(&params_crit_);
    next_frame_types_.clear();
    next_frame_types_.resize(VCM_MAX(sendCodec->numberOfSimulcastStreams, 1),
                             kVideoFrameKey);
    // Cache InternalSource() to have this available from IntraFrameRequest()
    // without having to acquire encoder_crit_ (avoid blocking on encoder use).
    encoder_has_internal_source_ = _encoder->InternalSource();
  }

  RTC_LOG(LS_VERBOSE) << " max bitrate " << sendCodec->maxBitrate
                      << " start bitrate " << sendCodec->startBitrate
                      << " max frame rate " << sendCodec->maxFramerate
                      << " max payload size " << maxPayloadSize;
  _mediaOpt.SetEncodingData(sendCodec->maxBitrate * 1000,
                            sendCodec->startBitrate * 1000,
                            sendCodec->maxFramerate);
  return VCM_OK;
}

// Register an external decoder object.
// This can not be used together with external decoder callbacks.
void VideoSender::RegisterExternalEncoder(VideoEncoder* externalEncoder,
                                          bool internalSource /*= false*/) {
  RTC_DCHECK(sequenced_checker_.CalledSequentially());

  rtc::CritScope lock(&encoder_crit_);

  if (externalEncoder == nullptr) {
    _codecDataBase.DeregisterExternalEncoder();
    {
      // Make sure the VCM doesn't use the de-registered codec
      rtc::CritScope params_lock(&params_crit_);
      _encoder = nullptr;
      encoder_has_internal_source_ = false;
    }
    return;
  }
  _codecDataBase.RegisterExternalEncoder(externalEncoder,
                                         internalSource);
}

EncoderParameters VideoSender::UpdateEncoderParameters(
    const EncoderParameters& params,
    VideoBitrateAllocator* bitrate_allocator,
    uint32_t target_bitrate_bps) {
  uint32_t video_target_rate_bps = _mediaOpt.SetTargetRates(target_bitrate_bps);
  uint32_t input_frame_rate = _mediaOpt.InputFrameRate();
  if (input_frame_rate == 0)
    input_frame_rate = current_codec_.maxFramerate;

  VideoBitrateAllocation bitrate_allocation;
  // Only call allocators if bitrate > 0 (ie, not suspended), otherwise they
  // might cap the bitrate to the min bitrate configured.
  if (target_bitrate_bps > 0) {
    if (bitrate_allocator) {
      bitrate_allocation = bitrate_allocator->GetAllocation(
          video_target_rate_bps, input_frame_rate);
    } else {
      DefaultVideoBitrateAllocator default_allocator(current_codec_);
      bitrate_allocation = default_allocator.GetAllocation(
          video_target_rate_bps, input_frame_rate);
    }
  }
  EncoderParameters new_encoder_params = {bitrate_allocation, params.loss_rate,
                                          params.rtt, input_frame_rate};
  return new_encoder_params;
}

void VideoSender::UpdateChannelParameters(
    VideoBitrateAllocator* bitrate_allocator,
    VideoBitrateAllocationObserver* bitrate_updated_callback) {
  VideoBitrateAllocation target_rate;
  {
    rtc::CritScope cs(&params_crit_);
    encoder_params_ =
        UpdateEncoderParameters(encoder_params_, bitrate_allocator,
                                encoder_params_.target_bitrate.get_sum_bps());
    target_rate = encoder_params_.target_bitrate;
  }
  if (bitrate_updated_callback && target_rate.get_sum_bps() > 0)
    bitrate_updated_callback->OnBitrateAllocationUpdated(target_rate);
}

int32_t VideoSender::SetChannelParameters(
    uint32_t target_bitrate_bps,
    uint8_t loss_rate,
    int64_t rtt,
    VideoBitrateAllocator* bitrate_allocator,
    VideoBitrateAllocationObserver* bitrate_updated_callback) {
  EncoderParameters encoder_params;
  encoder_params.loss_rate = loss_rate;
  encoder_params.rtt = rtt;
  encoder_params = UpdateEncoderParameters(encoder_params, bitrate_allocator,
                                           target_bitrate_bps);
  if (bitrate_updated_callback && target_bitrate_bps > 0) {
    bitrate_updated_callback->OnBitrateAllocationUpdated(
        encoder_params.target_bitrate);
  }

  bool encoder_has_internal_source;
  {
    rtc::CritScope cs(&params_crit_);
    encoder_params_ = encoder_params;
    encoder_has_internal_source = encoder_has_internal_source_;
  }

  // For encoders with internal sources, we need to tell the encoder directly,
  // instead of waiting for an AddVideoFrame that will never come (internal
  // source encoders don't get input frames).
  if (encoder_has_internal_source) {
    rtc::CritScope cs(&encoder_crit_);
    if (_encoder) {
      SetEncoderParameters(encoder_params, encoder_has_internal_source);
    }
  }

  return VCM_OK;
}

void VideoSender::SetEncoderParameters(EncoderParameters params,
                                       bool has_internal_source) {
  // |target_bitrate == 0 | means that the network is down or the send pacer is
  // full. We currently only report this if the encoder has an internal source.
  // If the encoder does not have an internal source, higher levels are expected
  // to not call AddVideoFrame. We do this since its unclear how current
  // encoder implementations behave when given a zero target bitrate.
  // TODO(perkj): Make sure all known encoder implementations handle zero
  // target bitrate and remove this check.
  if (!has_internal_source && params.target_bitrate.get_sum_bps() == 0)
    return;

  if (params.input_frame_rate == 0) {
    // No frame rate estimate available, use default.
    params.input_frame_rate = current_codec_.maxFramerate;
  }
  if (_encoder != nullptr)
    _encoder->SetEncoderParameters(params);
}

// Add one raw video frame to the encoder, blocking.
int32_t VideoSender::AddVideoFrame(const VideoFrame& videoFrame,
                                   const CodecSpecificInfo* codecSpecificInfo) {
  EncoderParameters encoder_params;
  std::vector<FrameType> next_frame_types;
  bool encoder_has_internal_source = false;
  {
    rtc::CritScope lock(&params_crit_);
    encoder_params = encoder_params_;
    next_frame_types = next_frame_types_;
    encoder_has_internal_source = encoder_has_internal_source_;
  }
  rtc::CritScope lock(&encoder_crit_);
  if (_encoder == nullptr)
    return VCM_UNINITIALIZED;
  SetEncoderParameters(encoder_params, encoder_has_internal_source);
  if (_mediaOpt.DropFrame()) {
    RTC_LOG(LS_VERBOSE) << "Drop Frame "
                        << "target bitrate "
                        << encoder_params.target_bitrate.get_sum_bps()
                        << " loss rate " << encoder_params.loss_rate << " rtt "
                        << encoder_params.rtt << " input frame rate "
                        << encoder_params.input_frame_rate;
    post_encode_callback_->OnDroppedFrame(
        EncodedImageCallback::DropReason::kDroppedByMediaOptimizations);
    return VCM_OK;
  }
  // TODO(pbos): Make sure setting send codec is synchronized with video
  // processing so frame size always matches.
  if (!_codecDataBase.MatchesCurrentResolution(videoFrame.width(),
                                               videoFrame.height())) {
    RTC_LOG(LS_ERROR)
        << "Incoming frame doesn't match set resolution. Dropping.";
    return VCM_PARAMETER_ERROR;
  }
  VideoFrame converted_frame = videoFrame;
  const VideoFrameBuffer::Type buffer_type =
      converted_frame.video_frame_buffer()->type();
  const bool is_buffer_type_supported =
      buffer_type == VideoFrameBuffer::Type::kI420 ||
      (buffer_type == VideoFrameBuffer::Type::kNative &&
       _encoder->SupportsNativeHandle());
  if (!is_buffer_type_supported) {
    // This module only supports software encoding.
    // TODO(pbos): Offload conversion from the encoder thread.
    rtc::scoped_refptr<I420BufferInterface> converted_buffer(
        converted_frame.video_frame_buffer()->ToI420());

    if (!converted_buffer) {
      RTC_LOG(LS_ERROR) << "Frame conversion failed, dropping frame.";
      return VCM_PARAMETER_ERROR;
    }
    converted_frame = VideoFrame(converted_buffer,
                                 converted_frame.timestamp(),
                                 converted_frame.render_time_ms(),
                                 converted_frame.rotation());
  }
  int32_t ret =
      _encoder->Encode(converted_frame, codecSpecificInfo, next_frame_types);
  if (ret < 0) {
    RTC_LOG(LS_ERROR) << "Failed to encode frame. Error code: " << ret;
    return ret;
  }

  {
    rtc::CritScope lock(&params_crit_);
    // Change all keyframe requests to encode delta frames the next time.
    for (size_t i = 0; i < next_frame_types_.size(); ++i) {
      // Check for equality (same requested as before encoding) to not
      // accidentally drop a keyframe request while encoding.
      if (next_frame_types[i] == next_frame_types_[i])
        next_frame_types_[i] = kVideoFrameDelta;
    }
  }
  return VCM_OK;
}

int32_t VideoSender::IntraFrameRequest(size_t stream_index) {
  {
    rtc::CritScope lock(&params_crit_);
    if (stream_index >= next_frame_types_.size()) {
      return -1;
    }
    next_frame_types_[stream_index] = kVideoFrameKey;
    if (!encoder_has_internal_source_)
      return VCM_OK;
  }
  // TODO(pbos): Remove when InternalSource() is gone. Both locks have to be
  // held here for internal consistency, since _encoder could be removed while
  // not holding encoder_crit_. Checks have to be performed again since
  // params_crit_ was dropped to not cause lock-order inversions with
  // encoder_crit_.
  rtc::CritScope lock(&encoder_crit_);
  rtc::CritScope params_lock(&params_crit_);
  if (stream_index >= next_frame_types_.size())
    return -1;
  if (_encoder != nullptr && _encoder->InternalSource()) {
    // Try to request the frame if we have an external encoder with
    // internal source since AddVideoFrame never will be called.
    if (_encoder->RequestFrame(next_frame_types_) == WEBRTC_VIDEO_CODEC_OK) {
      // Try to remove just-performed keyframe request, if stream still exists.
      next_frame_types_[stream_index] = kVideoFrameDelta;
    }
  }
  return VCM_OK;
}

int32_t VideoSender::EnableFrameDropper(bool enable) {
  rtc::CritScope lock(&encoder_crit_);
  frame_dropper_enabled_ = enable;
  _mediaOpt.EnableFrameDropper(enable);
  return VCM_OK;
}
}  // namespace vcm
}  // namespace webrtc
<|endoftext|>