<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: seinitializer_nssimpl.cxx,v $
 *
 *  $Revision: 1.16 $
 *
 *  last change: $Author: obo $ $Date: 2006-07-13 08:10:36 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 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
 *
 ************************************************************************/

/*
 * Turn off DEBUG Assertions
 */
#ifdef _DEBUG
    #define _DEBUG_WAS_DEFINED _DEBUG
    #undef _DEBUG
#else
    #undef _DEBUG_WAS_DEFINED
#endif

/*
 * and turn off the additional virtual methods which are part of some interfaces when compiled
 * with debug
 */
#ifdef DEBUG
    #define DEBUG_WAS_DEFINED DEBUG
    #undef DEBUG
#else
    #undef DEBUG_WAS_DEFINED
#endif

#include <sal/types.h>

#include <tools/debug.hxx>
#include <rtl/logfile.hxx>

#include "seinitializer_nssimpl.hxx"

#include "securityenvironment_nssimpl.hxx"

#ifndef _COM_SUN_STAR_MOZILLA_XMOZILLABOOTSTRAP_HPP_
#include <com/sun/star/mozilla/XMozillaBootstrap.hpp>
#endif

#include "nspr.h"
#include "prtypes.h"
#include "pk11func.h"
#ifdef SYSTEM_MOZILLA
#include "nssrenam.h"
#endif
#include "cert.h"
#include "cryptohi.h"
#include "certdb.h"
#include "nss.h"

namespace cssu = com::sun::star::uno;
namespace cssl = com::sun::star::lang;
namespace cssxc = com::sun::star::xml::crypto;

using namespace com::sun::star;

#define SERVICE_NAME "com.sun.star.xml.crypto.SEInitializer"
#define IMPLEMENTATION_NAME "com.sun.star.xml.security.bridge.xmlsec.SEInitializer_NssImpl"
#define SECURITY_ENVIRONMENT "com.sun.star.xml.crypto.SecurityEnvironment"
#define SECURITY_CONTEXT "com.sun.star.xml.crypto.XMLSecurityContext"

bool nsscrypto_initialize( const char* token ) {
    static char initialized = 0 ;

    //PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1 ) ;
    if( !initialized ) {
        PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 1 ) ;

        if( NSS_Init( token ) != SECSuccess )
            return false ;

        initialized = 1 ;
    }

    return true ;
}

void nsscrypto_finalize() {
    PK11_LogoutAll();
    NSS_Shutdown();
}

bool getMozillaCurrentProfile(
    const com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > &rxMSF,
    rtl::OUString& profilePath)
{
    /*
     * first, try to get the profile from "MOZILLA_CERTIFICATE_FOLDER"
     */
        char * env = getenv("MOZILLA_CERTIFICATE_FOLDER");
        if (env)
        {
            profilePath = rtl::OUString::createFromAscii( env );
            RTL_LOGFILE_PRODUCT_TRACE1( "XMLSEC: Using env MOZILLA_CERTIFICATE_FOLDER: %s", rtl::OUStringToOString( profilePath, RTL_TEXTENCODING_ASCII_US ).getStr() );
            return true;
        }
        else
        {
            RTL_LOGFILE_TRACE( "getMozillaCurrentProfile: Using MozillaBootstrap..." );
        mozilla::MozillaProductType productTypes[4] = {
            mozilla::MozillaProductType_Thunderbird,
            mozilla::MozillaProductType_Mozilla,
            mozilla::MozillaProductType_Firefox,
            mozilla::MozillaProductType_Default };
        int nProduct = 4;

        uno::Reference<uno::XInterface> xInstance = rxMSF->createInstance(
            ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.mozilla.MozillaBootstrap")) );
        OSL_ENSURE( xInstance.is(), "failed to create instance" );

        uno::Reference<mozilla::XMozillaBootstrap> xMozillaBootstrap
            =  uno::Reference<mozilla::XMozillaBootstrap>(xInstance,uno::UNO_QUERY);
        OSL_ENSURE( xMozillaBootstrap.is(), "failed to create instance" );

        if (xMozillaBootstrap.is())
        {
            for (int i=0; i<nProduct; i++)
            {
                ::rtl::OUString profile = xMozillaBootstrap->getDefaultProfile(productTypes[i]);

                RTL_LOGFILE_TRACE2( "getMozillaCurrentProfile: getDefaultProfile [%i] returns %s", i, rtl::OUStringToOString( profile, RTL_TEXTENCODING_ASCII_US ).getStr() );

                if (profile != NULL && profile.getLength()>0)
                {
                    profilePath = xMozillaBootstrap->getProfilePath(productTypes[i],profile);
                    RTL_LOGFILE_PRODUCT_TRACE1( "XMLSEC: Using Mozilla Profile: %s", rtl::OUStringToOString( profilePath, RTL_TEXTENCODING_ASCII_US ).getStr() );
                    return true;
                }
            }
        }

        RTL_LOGFILE_PRODUCT_TRACE( "XMLSEC: No Mozilla Profile found!" );
        return false;
    }
}

SEInitializer_NssImpl::SEInitializer_NssImpl(
    const com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > &rxMSF)
    :mxMSF( rxMSF )
{
}

SEInitializer_NssImpl::~SEInitializer_NssImpl()
{
}

/* XSEInitializer */
cssu::Reference< cssxc::XXMLSecurityContext > SAL_CALL
    SEInitializer_NssImpl::createSecurityContext(
    const rtl::OUString& sCertDB )
    throw (cssu::RuntimeException)
{
    CERTCertDBHandle    *pCertHandle = NULL ;

    rtl::OString sCertDir;
    if( sCertDB.getLength() )
    {
        sCertDir = rtl::OString(sCertDB, sCertDB.getLength(), RTL_TEXTENCODING_ASCII_US);
    }
    else
    {
        static rtl::OString* pDefaultCertDir = NULL;
        if ( !pDefaultCertDir )
        {
            pDefaultCertDir = new rtl::OString;
            rtl::OUString ouCertDir;

            if ( getMozillaCurrentProfile(mxMSF, ouCertDir) )
                *pDefaultCertDir = rtl::OString(ouCertDir, ouCertDir.getLength(), RTL_TEXTENCODING_ASCII_US);
        }
        sCertDir = *pDefaultCertDir;

    }

    if( !sCertDir.getLength() )
    {
        RTL_LOGFILE_TRACE( "XMLSEC: Error - No certificate directory!" );
        // return NULL;
    }

    /* Initialize NSPR and NSS */
    /* Replaced with new methods by AF. ----
    //PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1 ) ;
    PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 1 ) ;

    if (NSS_Init(sCertDir.getStr()) != SECSuccess )
    {
        PK11_LogoutAll();
        return NULL;
    }
    ----*/
    if( !nsscrypto_initialize( sCertDir.getStr() ) )
    {
        RTL_LOGFILE_TRACE( "XMLSEC: Error - nsscrypto_initialize() failed." );
        if ( NSS_NoDB_Init(NULL) != SECSuccess )
        {
            RTL_LOGFILE_TRACE( "XMLSEC: NSS_NoDB_Init also failed, NSS Security not available!" );
            return NULL;
        }
        else
        {
            RTL_LOGFILE_TRACE( "XMLSEC: NSS_NoDB_Init works, enough for verifying signatures..." );
        }
    }
    else
        atexit( nsscrypto_finalize ) ;

    pCertHandle = CERT_GetDefaultCertDB() ;

    try
    {
        /* Build XML Security Context */
        const rtl::OUString sSecyrutyContext ( RTL_CONSTASCII_USTRINGPARAM( SECURITY_CONTEXT ) );
        cssu::Reference< cssxc::XXMLSecurityContext > xSecCtx( mxMSF->createInstance ( sSecyrutyContext ), cssu::UNO_QUERY );
        if( !xSecCtx.is() )
            return NULL;

        const rtl::OUString sSecyrutyEnvironment ( RTL_CONSTASCII_USTRINGPARAM( SECURITY_ENVIRONMENT ) );
        cssu::Reference< cssxc::XSecurityEnvironment > xSecEnv( mxMSF->createInstance ( sSecyrutyEnvironment ), cssu::UNO_QUERY );
        cssu::Reference< cssl::XUnoTunnel > xEnvTunnel( xSecEnv , cssu::UNO_QUERY ) ;
        if( !xEnvTunnel.is() )
            return NULL;
        SecurityEnvironment_NssImpl* pSecEnv = ( SecurityEnvironment_NssImpl* )xEnvTunnel->getSomething(
            SecurityEnvironment_NssImpl::getUnoTunnelId() ) ;
        pSecEnv->setCertDb(pCertHandle);

        sal_Int32 n = xSecCtx->addSecurityEnvironment(xSecEnv);
        //originally the SecurityEnvironment with the internal slot was set as default
        xSecCtx->setDefaultSecurityEnvironmentIndex( n );
        return xSecCtx;
    }
    catch( cssu::Exception& )
    {
        //PK11_LogoutAll();
        //NSS_Shutdown();
        return NULL;
    }
}

void SAL_CALL SEInitializer_NssImpl::freeSecurityContext( const cssu::Reference< cssxc::XXMLSecurityContext >& securityContext )
    throw (cssu::RuntimeException)
{
    /*
     * because the security context will free all its content when it
     * is destructed, so here no free process for the security context
     * is needed.
     */
    //PK11_LogoutAll();
    //NSS_Shutdown();
}

rtl::OUString SEInitializer_NssImpl_getImplementationName ()
    throw (cssu::RuntimeException)
{

    return rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( IMPLEMENTATION_NAME ) );
}

sal_Bool SAL_CALL SEInitializer_NssImpl_supportsService( const rtl::OUString& ServiceName )
    throw (cssu::RuntimeException)
{
    return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ));
}

cssu::Sequence< rtl::OUString > SAL_CALL SEInitializer_NssImpl_getSupportedServiceNames(  )
    throw (cssu::RuntimeException)
{
    cssu::Sequence < rtl::OUString > aRet(1);
    rtl::OUString* pArray = aRet.getArray();
    pArray[0] =  rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) );
    return aRet;
}
#undef SERVICE_NAME

cssu::Reference< cssu::XInterface > SAL_CALL SEInitializer_NssImpl_createInstance( const cssu::Reference< cssl::XMultiServiceFactory > & rSMgr)
    throw( cssu::Exception )
{
    return (cppu::OWeakObject*) new SEInitializer_NssImpl(rSMgr);
}

/* XServiceInfo */
rtl::OUString SAL_CALL SEInitializer_NssImpl::getImplementationName(  )
    throw (cssu::RuntimeException)
{
    return SEInitializer_NssImpl_getImplementationName();
}
sal_Bool SAL_CALL SEInitializer_NssImpl::supportsService( const rtl::OUString& rServiceName )
    throw (cssu::RuntimeException)
{
    return SEInitializer_NssImpl_supportsService( rServiceName );
}
cssu::Sequence< rtl::OUString > SAL_CALL SEInitializer_NssImpl::getSupportedServiceNames(  )
    throw (cssu::RuntimeException)
{
    return SEInitializer_NssImpl_getSupportedServiceNames();
}

<commit_msg>INTEGRATION: CWS pchfix02 (1.16.6); FILE MERGED 2006/09/01 18:00:56 kaib 1.16.6.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: seinitializer_nssimpl.cxx,v $
 *
 *  $Revision: 1.17 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 14:45:55 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmlsecurity.hxx"

/*
 * Turn off DEBUG Assertions
 */
#ifdef _DEBUG
    #define _DEBUG_WAS_DEFINED _DEBUG
    #undef _DEBUG
#else
    #undef _DEBUG_WAS_DEFINED
#endif

/*
 * and turn off the additional virtual methods which are part of some interfaces when compiled
 * with debug
 */
#ifdef DEBUG
    #define DEBUG_WAS_DEFINED DEBUG
    #undef DEBUG
#else
    #undef DEBUG_WAS_DEFINED
#endif

#include <sal/types.h>

#include <tools/debug.hxx>
#include <rtl/logfile.hxx>

#include "seinitializer_nssimpl.hxx"

#include "securityenvironment_nssimpl.hxx"

#ifndef _COM_SUN_STAR_MOZILLA_XMOZILLABOOTSTRAP_HPP_
#include <com/sun/star/mozilla/XMozillaBootstrap.hpp>
#endif

#include "nspr.h"
#include "prtypes.h"
#include "pk11func.h"
#ifdef SYSTEM_MOZILLA
#include "nssrenam.h"
#endif
#include "cert.h"
#include "cryptohi.h"
#include "certdb.h"
#include "nss.h"

namespace cssu = com::sun::star::uno;
namespace cssl = com::sun::star::lang;
namespace cssxc = com::sun::star::xml::crypto;

using namespace com::sun::star;

#define SERVICE_NAME "com.sun.star.xml.crypto.SEInitializer"
#define IMPLEMENTATION_NAME "com.sun.star.xml.security.bridge.xmlsec.SEInitializer_NssImpl"
#define SECURITY_ENVIRONMENT "com.sun.star.xml.crypto.SecurityEnvironment"
#define SECURITY_CONTEXT "com.sun.star.xml.crypto.XMLSecurityContext"

bool nsscrypto_initialize( const char* token ) {
    static char initialized = 0 ;

    //PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1 ) ;
    if( !initialized ) {
        PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 1 ) ;

        if( NSS_Init( token ) != SECSuccess )
            return false ;

        initialized = 1 ;
    }

    return true ;
}

void nsscrypto_finalize() {
    PK11_LogoutAll();
    NSS_Shutdown();
}

bool getMozillaCurrentProfile(
    const com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > &rxMSF,
    rtl::OUString& profilePath)
{
    /*
     * first, try to get the profile from "MOZILLA_CERTIFICATE_FOLDER"
     */
        char * env = getenv("MOZILLA_CERTIFICATE_FOLDER");
        if (env)
        {
            profilePath = rtl::OUString::createFromAscii( env );
            RTL_LOGFILE_PRODUCT_TRACE1( "XMLSEC: Using env MOZILLA_CERTIFICATE_FOLDER: %s", rtl::OUStringToOString( profilePath, RTL_TEXTENCODING_ASCII_US ).getStr() );
            return true;
        }
        else
        {
            RTL_LOGFILE_TRACE( "getMozillaCurrentProfile: Using MozillaBootstrap..." );
        mozilla::MozillaProductType productTypes[4] = {
            mozilla::MozillaProductType_Thunderbird,
            mozilla::MozillaProductType_Mozilla,
            mozilla::MozillaProductType_Firefox,
            mozilla::MozillaProductType_Default };
        int nProduct = 4;

        uno::Reference<uno::XInterface> xInstance = rxMSF->createInstance(
            ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.mozilla.MozillaBootstrap")) );
        OSL_ENSURE( xInstance.is(), "failed to create instance" );

        uno::Reference<mozilla::XMozillaBootstrap> xMozillaBootstrap
            =  uno::Reference<mozilla::XMozillaBootstrap>(xInstance,uno::UNO_QUERY);
        OSL_ENSURE( xMozillaBootstrap.is(), "failed to create instance" );

        if (xMozillaBootstrap.is())
        {
            for (int i=0; i<nProduct; i++)
            {
                ::rtl::OUString profile = xMozillaBootstrap->getDefaultProfile(productTypes[i]);

                RTL_LOGFILE_TRACE2( "getMozillaCurrentProfile: getDefaultProfile [%i] returns %s", i, rtl::OUStringToOString( profile, RTL_TEXTENCODING_ASCII_US ).getStr() );

                if (profile != NULL && profile.getLength()>0)
                {
                    profilePath = xMozillaBootstrap->getProfilePath(productTypes[i],profile);
                    RTL_LOGFILE_PRODUCT_TRACE1( "XMLSEC: Using Mozilla Profile: %s", rtl::OUStringToOString( profilePath, RTL_TEXTENCODING_ASCII_US ).getStr() );
                    return true;
                }
            }
        }

        RTL_LOGFILE_PRODUCT_TRACE( "XMLSEC: No Mozilla Profile found!" );
        return false;
    }
}

SEInitializer_NssImpl::SEInitializer_NssImpl(
    const com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > &rxMSF)
    :mxMSF( rxMSF )
{
}

SEInitializer_NssImpl::~SEInitializer_NssImpl()
{
}

/* XSEInitializer */
cssu::Reference< cssxc::XXMLSecurityContext > SAL_CALL
    SEInitializer_NssImpl::createSecurityContext(
    const rtl::OUString& sCertDB )
    throw (cssu::RuntimeException)
{
    CERTCertDBHandle    *pCertHandle = NULL ;

    rtl::OString sCertDir;
    if( sCertDB.getLength() )
    {
        sCertDir = rtl::OString(sCertDB, sCertDB.getLength(), RTL_TEXTENCODING_ASCII_US);
    }
    else
    {
        static rtl::OString* pDefaultCertDir = NULL;
        if ( !pDefaultCertDir )
        {
            pDefaultCertDir = new rtl::OString;
            rtl::OUString ouCertDir;

            if ( getMozillaCurrentProfile(mxMSF, ouCertDir) )
                *pDefaultCertDir = rtl::OString(ouCertDir, ouCertDir.getLength(), RTL_TEXTENCODING_ASCII_US);
        }
        sCertDir = *pDefaultCertDir;

    }

    if( !sCertDir.getLength() )
    {
        RTL_LOGFILE_TRACE( "XMLSEC: Error - No certificate directory!" );
        // return NULL;
    }

    /* Initialize NSPR and NSS */
    /* Replaced with new methods by AF. ----
    //PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1 ) ;
    PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 1 ) ;

    if (NSS_Init(sCertDir.getStr()) != SECSuccess )
    {
        PK11_LogoutAll();
        return NULL;
    }
    ----*/
    if( !nsscrypto_initialize( sCertDir.getStr() ) )
    {
        RTL_LOGFILE_TRACE( "XMLSEC: Error - nsscrypto_initialize() failed." );
        if ( NSS_NoDB_Init(NULL) != SECSuccess )
        {
            RTL_LOGFILE_TRACE( "XMLSEC: NSS_NoDB_Init also failed, NSS Security not available!" );
            return NULL;
        }
        else
        {
            RTL_LOGFILE_TRACE( "XMLSEC: NSS_NoDB_Init works, enough for verifying signatures..." );
        }
    }
    else
        atexit( nsscrypto_finalize ) ;

    pCertHandle = CERT_GetDefaultCertDB() ;

    try
    {
        /* Build XML Security Context */
        const rtl::OUString sSecyrutyContext ( RTL_CONSTASCII_USTRINGPARAM( SECURITY_CONTEXT ) );
        cssu::Reference< cssxc::XXMLSecurityContext > xSecCtx( mxMSF->createInstance ( sSecyrutyContext ), cssu::UNO_QUERY );
        if( !xSecCtx.is() )
            return NULL;

        const rtl::OUString sSecyrutyEnvironment ( RTL_CONSTASCII_USTRINGPARAM( SECURITY_ENVIRONMENT ) );
        cssu::Reference< cssxc::XSecurityEnvironment > xSecEnv( mxMSF->createInstance ( sSecyrutyEnvironment ), cssu::UNO_QUERY );
        cssu::Reference< cssl::XUnoTunnel > xEnvTunnel( xSecEnv , cssu::UNO_QUERY ) ;
        if( !xEnvTunnel.is() )
            return NULL;
        SecurityEnvironment_NssImpl* pSecEnv = ( SecurityEnvironment_NssImpl* )xEnvTunnel->getSomething(
            SecurityEnvironment_NssImpl::getUnoTunnelId() ) ;
        pSecEnv->setCertDb(pCertHandle);

        sal_Int32 n = xSecCtx->addSecurityEnvironment(xSecEnv);
        //originally the SecurityEnvironment with the internal slot was set as default
        xSecCtx->setDefaultSecurityEnvironmentIndex( n );
        return xSecCtx;
    }
    catch( cssu::Exception& )
    {
        //PK11_LogoutAll();
        //NSS_Shutdown();
        return NULL;
    }
}

void SAL_CALL SEInitializer_NssImpl::freeSecurityContext( const cssu::Reference< cssxc::XXMLSecurityContext >& securityContext )
    throw (cssu::RuntimeException)
{
    /*
     * because the security context will free all its content when it
     * is destructed, so here no free process for the security context
     * is needed.
     */
    //PK11_LogoutAll();
    //NSS_Shutdown();
}

rtl::OUString SEInitializer_NssImpl_getImplementationName ()
    throw (cssu::RuntimeException)
{

    return rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( IMPLEMENTATION_NAME ) );
}

sal_Bool SAL_CALL SEInitializer_NssImpl_supportsService( const rtl::OUString& ServiceName )
    throw (cssu::RuntimeException)
{
    return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ));
}

cssu::Sequence< rtl::OUString > SAL_CALL SEInitializer_NssImpl_getSupportedServiceNames(  )
    throw (cssu::RuntimeException)
{
    cssu::Sequence < rtl::OUString > aRet(1);
    rtl::OUString* pArray = aRet.getArray();
    pArray[0] =  rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) );
    return aRet;
}
#undef SERVICE_NAME

cssu::Reference< cssu::XInterface > SAL_CALL SEInitializer_NssImpl_createInstance( const cssu::Reference< cssl::XMultiServiceFactory > & rSMgr)
    throw( cssu::Exception )
{
    return (cppu::OWeakObject*) new SEInitializer_NssImpl(rSMgr);
}

/* XServiceInfo */
rtl::OUString SAL_CALL SEInitializer_NssImpl::getImplementationName(  )
    throw (cssu::RuntimeException)
{
    return SEInitializer_NssImpl_getImplementationName();
}
sal_Bool SAL_CALL SEInitializer_NssImpl::supportsService( const rtl::OUString& rServiceName )
    throw (cssu::RuntimeException)
{
    return SEInitializer_NssImpl_supportsService( rServiceName );
}
cssu::Sequence< rtl::OUString > SAL_CALL SEInitializer_NssImpl::getSupportedServiceNames(  )
    throw (cssu::RuntimeException)
{
    return SEInitializer_NssImpl_getSupportedServiceNames();
}

<|endoftext|>


<commit_before>065b246e-2748-11e6-bc09-e0f84713e7b8<commit_msg>This'll fix that<commit_after>066729f8-2748-11e6-96ea-e0f84713e7b8<|endoftext|>


<commit_before>db53c2c2-ad5a-11e7-b6c6-ac87a332f658<commit_msg>Backup, rebase this later<commit_after>dbdf1517-ad5a-11e7-bb83-ac87a332f658<|endoftext|>


<commit_before>#include <bits/stdc++.h>

using namespace std;

const int SIZE = 32;
const int NEURONS = 2;
const int TRAIN_ITER = 1;
const double sigma = 0.8;

double alpha = .05;

#define f first
#define s second

typedef pair<int,int> ii;

struct Matrix{
  int digit;
  double cells[SIZE][SIZE];
  Matrix(){}
  Matrix(double _cells[SIZE][SIZE]){
    memcpy(cells,_cells,sizeof cells);
  }
  Matrix(double _cells[SIZE][SIZE],int _digit){
    digit = _digit;
    memcpy(cells,_cells,sizeof cells);
  }
  Matrix operator-(Matrix &o){
    double r[SIZE][SIZE];
    for(int i = 0; i < SIZE; i++)
      for(int j = 0; j < SIZE; j++)
        r[i][j] = cells[i][j]-o[i][j];
    return Matrix(r);
  }
  Matrix operator+(Matrix &o){
    double r[SIZE][SIZE];
    for(int i = 0; i < SIZE; i++)
      for(int j = 0; j < SIZE; j++)
        r[i][j] = cells[i][j]+o[i][j];
    return Matrix(r);
  }
  Matrix operator*(double scale){
    double r[SIZE][SIZE];
    for(int i = 0; i < SIZE; i++)
      for(int j = 0; j < SIZE; j++)
        r[i][j] = cells[i][j]*scale;
    return Matrix(r);
  }
  double* operator[](int i){
    return cells[i];
  }
  void print(bool trunc){
    for(int i = 0; i < SIZE; i++){
      for(int j = 0; j < SIZE; j++)
        if(trunc) printf("%d ",(int)(cells[i][j]+0.5));
        else printf("%.4lf ",cells[i][j]);
      printf("\n");
    }
  }
};

double sq_euclidean_distance(Matrix &a,Matrix &b){
  double sq_distance = 0.;
  for(int i = 0; i < SIZE; i++){
    for(int j = 0; j < SIZE; j++){
      double dij = a[i][j] - b[i][j];
      sq_distance += dij*dij;
    }
  }
  return sq_distance;
}

double sq_euclidean_distance(ii a,ii b){
  double dx = a.f-b.f;
  double dy = a.s-b.s;
  return dx*dx+dy*dy;
}

vector<Matrix> train,test;
Matrix neurons[NEURONS][NEURONS];
void read_digits(vector<Matrix> &m,FILE *src){
  int a;
  fscanf(src,"%d\n",&a);
  for (int i = 0,c; i < a; i++) {
    double digit[SIZE][SIZE];
    for(int j = 0; j < SIZE; j++){
      for(int k = 0; k < SIZE; k++){
        fscanf(src," %c",&c);
        digit[j][k] = c-'0';
      }
    }
    fscanf(src,"  %c ",&c);
    m.push_back(Matrix(digit,c-'0'));
  }
}

void init_neurons(){
  printf("Inicializando rede.\n");
  srand(time(NULL));
  for(int i = 0; i < NEURONS; i++)
    for(int i2 = 0; i2 < NEURONS; i2++)
      for(int j = 0; j < SIZE; j++)
        for(int k = 0; k < SIZE; k++)
          neurons[i][i2][j][k] = ((double)rand()) / RAND_MAX;
}

ii closest_neuron(Matrix &m){
  ii BMU;
  double min_dist = SIZE*SIZE;
  for(int j = 0; j < NEURONS; j++)
    for(int j2 = 0; j2 < NEURONS; j2++){
      double dist_ji = sq_euclidean_distance(m,neurons[j][j2]);
      if(dist_ji < min_dist){
        BMU = ii(j,j2);
        min_dist = dist_ji;
      }
    }
  return BMU;
}

vector<int> randomic_order(int n){
  list<int> elem;
  for(int i = 0; i < n; i++) elem.push_back(i);
  vector<int> order;
  while(!elem.empty()){
    auto it = elem.begin();
    advance(it,rand()%elem.size());
    order.push_back(*it);
    elem.erase(it);
  }
  return order;
}

void train_neurons(){
  vector<int> training_order = randomic_order(train.size());
  for(int i = 0; i < (int)train.size(); i++){
    ii BMU = closest_neuron(train[training_order[i]]);
    //updating the neighborhood of BMU.
    for(int j = 0; j < NEURONS; j++){
      double dist = sq_euclidean_distance(BMU,ii(j,BMU.s));
      if(dist > 20.*sigma ) continue;
      for(int j2 = 0; j2 < NEURONS; j2++){
        double dist = sq_euclidean_distance(BMU,ii(j,j2));
        if(dist > 20.*sigma ) continue;
        Matrix shift = (train[training_order[i]]-neurons[j][j2])*pow(M_E, -dist/sigma)*alpha;
        neurons[j][j2] = neurons[j][j2] + shift;
      }
    }
  }
}

int matches[NEURONS][NEURONS];
void print_matches(){
  int frequence[10];
  memset(frequence,0,sizeof(frequence));
  for(int i = 0; i < NEURONS; i++){
    for(int i2 = 0; i2 < NEURONS; i2++){
      int mn = 0;
      double mn_dist = sq_euclidean_distance(neurons[i][i2],train[mn]);
      for(int j = 1; j < (int)train.size(); j++){
        double dist = sq_euclidean_distance(neurons[i][i2],train[j]);
        if(mn_dist > dist){
          mn = j;
          mn_dist = dist;
        }
      }
      //printf("%d %d\n",i,i2);
      //neurons[i][i2].print(true);
      //printf("\n");
      //train[mn].print(true);
      frequence[train[mn].digit]++;
      matches[i][i2] = train[mn].digit;
      //printf("\n");
    }
  }
  for(int i = 0; i < 10; i++) printf("%d %d\n",i,frequence[i]);
  for(int i = 0; i < NEURONS; i++){
    for(int i2 = 0; i2 < NEURONS; i2++)
      printf("%d ",matches[i][i2]);
    printf("\n");
  }
}

void load_neurons(string dir){
  printf("Carregando rede.\n");
  FILE *neurons_file = fopen(dir.c_str(),"r");
  for(int i = 0; i < NEURONS; i++)
    for(int i2 = 0; i2 < NEURONS; i2++){
      double digit[SIZE][SIZE];
      for(int j = 0; j < SIZE; j++)
        for(int k = 0; k < SIZE; k++)
          fscanf(neurons_file," %lf",&digit[j][k]);
      neurons[i][i2] = Matrix(digit);
    }
  fclose(neurons_file);
}

void save_neurons(string dir){
  printf("Salvando rede.\n");
  FILE *neurons_file = fopen(dir.c_str(),"w");
  for(int i = 0; i < NEURONS; i++)
    for(int i2 = 0; i2 < NEURONS; i2++){
      for(int j = 0; j < SIZE; j++){
        fprintf(neurons_file,"%lf",neurons[i][i2][j][0]);
        for(int k = 1; k < SIZE; k++)
          fprintf(neurons_file," %lf",neurons[i][i2][j][k]);
        fprintf(neurons_file,"\n");
      }
      fprintf(neurons_file,"\n");
    }
  fclose(neurons_file);
}

//--tes path/to/test/file
//--tra path/to/training/file
//--lnet path/to/load/trained_neurons/file
//--snet path/to/save/trained_neurons/file
int main(int argc, char const *argv[]) {
  map<string,string> param;
  for(int i = 1; i < argc; i += 2) param[argv[i]] = argv[i+1];
  if(param.find("--lnet") != param.end()) load_neurons(param["--lnet"]);
  else init_neurons();
  if(param.find("--tra") != param.end()){
    //reading training set
    FILE *training_file = fopen(param["--tra"].c_str(),"r");
    read_digits(train,training_file);
    fclose(training_file);
    //for(int l = 0; alpha > 0 && l < TRAIN_ITER; l++, alpha -= .00001)
      //train_neurons();
    print_matches();
  }
  if(param.find("--tes") != param.end()){
    //reading testing set
    FILE *testing_file = fopen(param["--tes"].c_str(),"r");
    read_digits(test,testing_file);
    fclose(testing_file);
  }
  if(param.find("--snet") != param.end()) save_neurons(param["--snet"]);
  return 0;
}
<commit_msg>Dynamic sigma.<commit_after>#include <bits/stdc++.h>

using namespace std;

const int SIZE = 32;
const int NEURONS = 20;
const int TRAIN_ITER = 1000;
double sigma = 2;

double alpha = .05;

#define f first
#define s second

typedef pair<int,int> ii;

struct Matrix{
  int digit;
  double cells[SIZE][SIZE];
  Matrix(){}
  Matrix(double _cells[SIZE][SIZE]){
    memcpy(cells,_cells,sizeof cells);
  }
  Matrix(double _cells[SIZE][SIZE],int _digit){
    digit = _digit;
    memcpy(cells,_cells,sizeof cells);
  }
  Matrix operator-(Matrix &o){
    double r[SIZE][SIZE];
    for(int i = 0; i < SIZE; i++)
      for(int j = 0; j < SIZE; j++)
        r[i][j] = cells[i][j]-o[i][j];
    return Matrix(r);
  }
  Matrix operator+(Matrix &o){
    double r[SIZE][SIZE];
    for(int i = 0; i < SIZE; i++)
      for(int j = 0; j < SIZE; j++)
        r[i][j] = cells[i][j]+o[i][j];
    return Matrix(r);
  }
  Matrix operator*(double scale){
    double r[SIZE][SIZE];
    for(int i = 0; i < SIZE; i++)
      for(int j = 0; j < SIZE; j++)
        r[i][j] = cells[i][j]*scale;
    return Matrix(r);
  }
  double* operator[](int i){
    return cells[i];
  }
  void print(bool trunc){
    for(int i = 0; i < SIZE; i++){
      for(int j = 0; j < SIZE; j++)
        if(trunc) printf("%d ",(int)(cells[i][j]+0.5));
        else printf("%.4lf ",cells[i][j]);
      printf("\n");
    }
  }
};

double sq_euclidean_distance(Matrix &a,Matrix &b){
  double sq_distance = 0.;
  for(int i = 0; i < SIZE; i++){
    for(int j = 0; j < SIZE; j++){
      double dij = a[i][j] - b[i][j];
      sq_distance += dij*dij;
    }
  }
  return sq_distance;
}

double sq_euclidean_distance(ii a,ii b){
  double dx = a.f-b.f;
  double dy = a.s-b.s;
  return dx*dx+dy*dy;
}

vector<Matrix> train;
Matrix neurons[NEURONS][NEURONS];
void read_digits(vector<Matrix> &m,FILE *src){
  int a;
  char line[SIZE+10];
  fscanf(src,"%d\n",&a);
  for (int i = 0; i < a; i++) {
    double digit[SIZE][SIZE];
    for(int j = 0; j < SIZE; j++){
      fgets(line,SIZE+10,src);
      for(int k = 0; k < SIZE; k++)
        digit[j][k] = line[k]-'0';
    }
    fgets(line,SIZE,src);
    m.push_back(Matrix(digit,line[1]-'0'));
  }
}

void init_neurons(){
  printf("Inicializando rede.\n");
  srand(time(NULL));
  for(int i = 0; i < NEURONS; i++)
    for(int i2 = 0; i2 < NEURONS; i2++)
      for(int j = 0; j < SIZE; j++)
        for(int k = 0; k < SIZE; k++)
          neurons[i][i2][j][k] = ((double)rand()) / RAND_MAX;
}

ii closest_neuron(Matrix &m){
  ii BMU;
  double min_dist = SIZE*SIZE;
  for(int j = 0; j < NEURONS; j++)
    for(int j2 = 0; j2 < NEURONS; j2++){
      double dist_ji = sq_euclidean_distance(m,neurons[j][j2]);
      if(dist_ji < min_dist){
        BMU = ii(j,j2);
        min_dist = dist_ji;
      }
    }
  return BMU;
}

vector<int> randomic_order(int n){
  list<int> elem;
  for(int i = 0; i < n; i++) elem.push_back(i);
  vector<int> order;
  while(!elem.empty()){
    auto it = elem.begin();
    advance(it,rand()%elem.size());
    order.push_back(*it);
    elem.erase(it);
  }
  return order;
}

void train_neurons(){
  vector<int> training_order = randomic_order(train.size());
  for(int i = 0; i < (int)train.size(); i++){
    ii BMU = closest_neuron(train[training_order[i]]);
    //updating the neighborhood of BMU.
    for(int j = 0; j < NEURONS; j++){
      double dist = sq_euclidean_distance(BMU,ii(j,BMU.s));
      if(dist > 20.*sigma ) continue;
      for(int j2 = 0; j2 < NEURONS; j2++){
        double dist = sq_euclidean_distance(BMU,ii(j,j2));
        if(dist > 20.*sigma ) continue;
        Matrix shift = (train[training_order[i]]-neurons[j][j2])*pow(M_E, -dist/sigma)*alpha;
        neurons[j][j2] = neurons[j][j2] + shift;
      }
    }
  }
}

void print_matches(vector<Matrix> & digits){
  int frequence[10];
  memset(frequence,0,sizeof(frequence));
  int matches[NEURONS][NEURONS];
  for(int i = 0; i < NEURONS; i++){
    for(int i2 = 0; i2 < NEURONS; i2++){
      int mn = 0;
      double mn_dist = sq_euclidean_distance(neurons[i][i2],digits[mn]);
      for(int j = 1; j < (int)digits.size(); j++){
        double dist = sq_euclidean_distance(neurons[i][i2],digits[j]);
        if(mn_dist > dist){
          mn = j;
          mn_dist = dist;
        }
      }
      frequence[digits[mn].digit]++;
      matches[i][i2] = digits[mn].digit;
    }
  }
  for(int i = 0; i < 10; i++) printf("%d %d\n",i,frequence[i]);
  for(int i = 0; i < NEURONS; i++){
    for(int i2 = 0; i2 < NEURONS; i2++)
      printf("%d ",matches[i][i2]);
    printf("\n");
  }
}

void load_neurons(string dir){
  printf("Carregando rede.\n");
  FILE *neurons_file = fopen(dir.c_str(),"r");
  for(int i = 0; i < NEURONS; i++)
    for(int i2 = 0; i2 < NEURONS; i2++){
      double digit[SIZE][SIZE];
      for(int j = 0; j < SIZE; j++)
        for(int k = 0; k < SIZE; k++)
          fscanf(neurons_file," %lf",&digit[j][k]);
      neurons[i][i2] = Matrix(digit);
    }
  fclose(neurons_file);
}

void save_neurons(string dir){
  printf("Salvando rede.\n");
  FILE *neurons_file = fopen(dir.c_str(),"w");
  for(int i = 0; i < NEURONS; i++)
    for(int i2 = 0; i2 < NEURONS; i2++){
      for(int j = 0; j < SIZE; j++){
        fprintf(neurons_file,"%lf",neurons[i][i2][j][0]);
        for(int k = 1; k < SIZE; k++)
          fprintf(neurons_file," %lf",neurons[i][i2][j][k]);
        fprintf(neurons_file,"\n");
      }
      fprintf(neurons_file,"\n");
    }
  fclose(neurons_file);
}

//--tes path/to/test/file
//--tra path/to/training/file
//--lnet path/to/load/trained_neurons/file
//--snet path/to/save/trained_neurons/file
int main(int argc, char const *argv[]) {
  map<string,string> param;
  for(int i = 1; i < argc; i += 2) param[argv[i]] = argv[i+1];
  if(param.find("--lnet") != param.end()) load_neurons(param["--lnet"]);
  else init_neurons();
  if(param.find("--tra") != param.end()){
    //reading training set
    FILE *training_file = fopen(param["--tra"].c_str(),"r");
    read_digits(train,training_file);
    fclose(training_file);
    for(int l = 0; alpha > 0 && l < TRAIN_ITER; l++, alpha -= .000025, sigma -= .0015){
      printf("Iteração: %d, alpha: %lf\n",l,alpha);
      train_neurons();
    }
    print_matches(train);
  }
  if(param.find("--tes") != param.end()){
    vector<Matrix> test;
    //reading testing set
    FILE *testing_file = fopen(param["--tes"].c_str(),"r");
    read_digits(test,testing_file);
    fclose(testing_file);

    print_matches(test);
  }
  if(param.find("--snet") != param.end()) save_neurons(param["--snet"]);
  return 0;
}<|endoftext|>


<commit_before>9873c491-2747-11e6-85e9-e0f84713e7b8<commit_msg>new flies<commit_after>987f5063-2747-11e6-82f0-e0f84713e7b8<|endoftext|>


<commit_before>bebc59c0-2747-11e6-a730-e0f84713e7b8<commit_msg>OKAY this time it should work<commit_after>bed21fa8-2747-11e6-97c6-e0f84713e7b8<|endoftext|>


<commit_before>a01b683a-2747-11e6-934b-e0f84713e7b8<commit_msg>Fixed that one bug<commit_after>a02a6d80-2747-11e6-806a-e0f84713e7b8<|endoftext|>


<commit_before>
#include "FFmpegImageStream.hpp"
#include "FFmpegAudioStream.hpp"

#include <OpenThreads/ScopedLock>
#include <osg/Notify>

#include <memory>

namespace osgFFmpeg {

FFmpegImageStream::FFmpegImageStream() :
    m_decoder(0),
    m_commands(0),
    m_frame_published_flag(false)
{
    setOrigin(osg::Image::TOP_LEFT);

    std::auto_ptr<FFmpegDecoder> decoder(new FFmpegDecoder);
    std::auto_ptr<CommandQueue> commands(new CommandQueue);

    m_decoder = decoder.release();
    m_commands = commands.release();
}

FFmpegImageStream::FFmpegImageStream(const FFmpegImageStream & image, const osg::CopyOp & copyop) :
    osg::ImageStream(image, copyop)
{
    // TODO: probably incorrect or incomplete
}

FFmpegImageStream::~FFmpegImageStream()
{
    osg::notify(osg::INFO)<<"Destructing FFmpegImageStream..."<<std::endl;

    quit(true);

    osg::notify(osg::INFO)<<"Have done quit"<<std::endl;

    // release athe audio streams to make sure that the decoder doesn't retain any external
    // refences.
    getAudioStreams().clear();

    // destroy the decoder and associated threads
    m_decoder = 0;

    delete m_commands;

    osg::notify(osg::INFO)<<"Destructed FFMpegImageStream."<<std::endl;
}

bool FFmpegImageStream::open(const std::string & filename)
{
    setFileName(filename);

    if (! m_decoder->open(filename))
        return false;

    setImage(
        m_decoder->video_decoder().width(), m_decoder->video_decoder().height(), 1, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE,
        const_cast<unsigned char *>(m_decoder->video_decoder().image()), NO_DELETE
    );

    setPixelAspectRatio(m_decoder->video_decoder().pixelAspectRatio());

    m_decoder->video_decoder().setUserData(this);
    m_decoder->video_decoder().setPublishCallback(publishNewFrame);

    if (m_decoder->audio_decoder().validContext())
    {
        osg::notify(osg::NOTICE)<<"Attaching FFmpegAudioStream"<<std::endl;

        getAudioStreams().push_back(new FFmpegAudioStream(m_decoder.get()));
    }

    _status = PAUSED;
    applyLoopingMode();

    start(); // start thread

    return true;
}

void FFmpegImageStream::play()
{
    m_commands->push(CMD_PLAY);

#if 0
    // Wait for at least one frame to be published before returning the call
    OpenThreads::ScopedLock<Mutex> lock(m_mutex);

    while (duration() > 0 && ! m_frame_published_flag)
        m_frame_published_cond.wait(&m_mutex);

#endif
}

void FFmpegImageStream::pause()
{
    m_commands->push(CMD_PAUSE);
}

void FFmpegImageStream::rewind()
{
    m_commands->push(CMD_REWIND);
}

void FFmpegImageStream::quit(bool waitForThreadToExit)
{
    // Stop the packet producer thread
    if (isRunning())
    {
        m_commands->push(CMD_STOP);

        if (waitForThreadToExit)
            join();
    }

    // Close the decoder (i.e. flush the decoder packet queues)
    m_decoder->close(waitForThreadToExit);
}

double FFmpegImageStream::getLength() const
{
    return m_decoder->duration();
}

double FFmpegImageStream::getFrameRate() const
{
    return m_decoder->video_decoder().frameRate();
}

bool FFmpegImageStream::isImageTranslucent() const
{
    return m_decoder->video_decoder().alphaChannel();
}

void FFmpegImageStream::run()
{
    try
    {
        bool done = false;

        while (! done)
        {
            if (_status == PLAYING)
            {
                bool no_cmd;
                const Command cmd = m_commands->timedPop(no_cmd, 1);

                if (no_cmd)
                {
                    m_decoder->readNextPacket();
                }
                else
                    done = ! handleCommand(cmd);
            }
            else
            {
                done = ! handleCommand(m_commands->pop());
            }
        }
    }

    catch (const std::exception & error)
    {
        osg::notify(osg::WARN) << "FFmpegImageStream::run : " << error.what() << std::endl;
    }

    catch (...)
    {
        osg::notify(osg::WARN) << "FFmpegImageStream::run : unhandled exception" << std::endl;
    }

    osg::notify(osg::NOTICE)<<"Finished FFmpegImageStream::run()"<<std::endl;
}

void FFmpegImageStream::applyLoopingMode()
{
    m_decoder->loop(getLoopingMode() == LOOPING);
}

bool FFmpegImageStream::handleCommand(const Command cmd)
{
    switch (cmd)
    {
    case CMD_PLAY:
        cmdPlay();
        return true;

    case CMD_PAUSE:
        cmdPause();
        return true;

    case CMD_REWIND:
        cmdRewind();
        return true;

    case CMD_STOP:
        return false;

    default:
        assert(false);
        return false;
    }
}

void FFmpegImageStream::cmdPlay()
{
    if (_status == PAUSED)
    {
        if (! m_decoder->audio_decoder().isRunning())
            m_decoder->audio_decoder().start();

        if (! m_decoder->video_decoder().isRunning())
            m_decoder->video_decoder().start();
    }

    _status = PLAYING;
}

void FFmpegImageStream::cmdPause()
{
    if (_status == PLAYING)
    {

    }

    _status = PAUSED;
}

void FFmpegImageStream::cmdRewind()
{
    m_decoder->rewind();
}

void FFmpegImageStream::publishNewFrame(const FFmpegDecoderVideo &, void * user_data)
{
    FFmpegImageStream * const this_ = reinterpret_cast<FFmpegImageStream*>(user_data);

#if 1
    this_->setImage(
        this_->m_decoder->video_decoder().width(), this_->m_decoder->video_decoder().height(), 1, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE,
        const_cast<unsigned char *>(this_->m_decoder->video_decoder().image()), NO_DELETE
    );
#else
    /** \bug If viewer.realize() hasn't been already called, this doesn't work? */
    this_->dirty();
#endif

    OpenThreads::ScopedLock<Mutex> lock(this_->m_mutex);

    if (! this_->m_frame_published_flag)
    {
        this_->m_frame_published_flag = true;
        this_->m_frame_published_cond.signal();
    }
}

} // namespace osgFFmpeg
<commit_msg>Added check against a minimual video size of 10x10 to prevent problems with swscale reporting errors and crashing on small video dimensionsline, and those below, will be ignored--<commit_after>
#include "FFmpegImageStream.hpp"
#include "FFmpegAudioStream.hpp"

#include <OpenThreads/ScopedLock>
#include <osg/Notify>

#include <memory>

namespace osgFFmpeg {

FFmpegImageStream::FFmpegImageStream() :
    m_decoder(0),
    m_commands(0),
    m_frame_published_flag(false)
{
    setOrigin(osg::Image::TOP_LEFT);

    std::auto_ptr<FFmpegDecoder> decoder(new FFmpegDecoder);
    std::auto_ptr<CommandQueue> commands(new CommandQueue);

    m_decoder = decoder.release();
    m_commands = commands.release();
}

FFmpegImageStream::FFmpegImageStream(const FFmpegImageStream & image, const osg::CopyOp & copyop) :
    osg::ImageStream(image, copyop)
{
    // TODO: probably incorrect or incomplete
}

FFmpegImageStream::~FFmpegImageStream()
{
    osg::notify(osg::INFO)<<"Destructing FFmpegImageStream..."<<std::endl;

    quit(true);

    osg::notify(osg::INFO)<<"Have done quit"<<std::endl;

    // release athe audio streams to make sure that the decoder doesn't retain any external
    // refences.
    getAudioStreams().clear();

    // destroy the decoder and associated threads
    m_decoder = 0;

    delete m_commands;

    osg::notify(osg::INFO)<<"Destructed FFMpegImageStream."<<std::endl;
}

bool FFmpegImageStream::open(const std::string & filename)
{
    setFileName(filename);

    if (! m_decoder->open(filename))
        return false;

    setImage(
        m_decoder->video_decoder().width(), m_decoder->video_decoder().height(), 1, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE,
        const_cast<unsigned char *>(m_decoder->video_decoder().image()), NO_DELETE
    );

    setPixelAspectRatio(m_decoder->video_decoder().pixelAspectRatio());

    osg::notify(osg::NOTICE)<<"ffmpeg::open("<<filename<<") size("<<s()<<", "<<t()<<") aspect ratio "<<m_decoder->video_decoder().pixelAspectRatio()<<std::endl;

#if 1
    // swscale is reported errors and then crashing when rescaling video of size less than 10 by 10.
    if (s()<=10 || t()<=10) return false;
#endif

    m_decoder->video_decoder().setUserData(this);
    m_decoder->video_decoder().setPublishCallback(publishNewFrame);

    if (m_decoder->audio_decoder().validContext())
    {
        osg::notify(osg::NOTICE)<<"Attaching FFmpegAudioStream"<<std::endl;

        getAudioStreams().push_back(new FFmpegAudioStream(m_decoder.get()));
    }

    _status = PAUSED;
    applyLoopingMode();

    start(); // start thread

    return true;
}

void FFmpegImageStream::play()
{
    m_commands->push(CMD_PLAY);

#if 0
    // Wait for at least one frame to be published before returning the call
    OpenThreads::ScopedLock<Mutex> lock(m_mutex);

    while (duration() > 0 && ! m_frame_published_flag)
        m_frame_published_cond.wait(&m_mutex);

#endif
}

void FFmpegImageStream::pause()
{
    m_commands->push(CMD_PAUSE);
}

void FFmpegImageStream::rewind()
{
    m_commands->push(CMD_REWIND);
}

void FFmpegImageStream::quit(bool waitForThreadToExit)
{
    // Stop the packet producer thread
    if (isRunning())
    {
        m_commands->push(CMD_STOP);

        if (waitForThreadToExit)
            join();
    }

    // Close the decoder (i.e. flush the decoder packet queues)
    m_decoder->close(waitForThreadToExit);
}

double FFmpegImageStream::getLength() const
{
    return m_decoder->duration();
}

double FFmpegImageStream::getFrameRate() const
{
    return m_decoder->video_decoder().frameRate();
}

bool FFmpegImageStream::isImageTranslucent() const
{
    return m_decoder->video_decoder().alphaChannel();
}

void FFmpegImageStream::run()
{
    try
    {
        bool done = false;

        while (! done)
        {
            if (_status == PLAYING)
            {
                bool no_cmd;
                const Command cmd = m_commands->timedPop(no_cmd, 1);

                if (no_cmd)
                {
                    m_decoder->readNextPacket();
                }
                else
                    done = ! handleCommand(cmd);
            }
            else
            {
                done = ! handleCommand(m_commands->pop());
            }
        }
    }

    catch (const std::exception & error)
    {
        osg::notify(osg::WARN) << "FFmpegImageStream::run : " << error.what() << std::endl;
    }

    catch (...)
    {
        osg::notify(osg::WARN) << "FFmpegImageStream::run : unhandled exception" << std::endl;
    }

    osg::notify(osg::NOTICE)<<"Finished FFmpegImageStream::run()"<<std::endl;
}

void FFmpegImageStream::applyLoopingMode()
{
    m_decoder->loop(getLoopingMode() == LOOPING);
}

bool FFmpegImageStream::handleCommand(const Command cmd)
{
    switch (cmd)
    {
    case CMD_PLAY:
        cmdPlay();
        return true;

    case CMD_PAUSE:
        cmdPause();
        return true;

    case CMD_REWIND:
        cmdRewind();
        return true;

    case CMD_STOP:
        return false;

    default:
        assert(false);
        return false;
    }
}

void FFmpegImageStream::cmdPlay()
{
    if (_status == PAUSED)
    {
        if (! m_decoder->audio_decoder().isRunning())
            m_decoder->audio_decoder().start();

        if (! m_decoder->video_decoder().isRunning())
            m_decoder->video_decoder().start();
    }

    _status = PLAYING;
}

void FFmpegImageStream::cmdPause()
{
    if (_status == PLAYING)
    {

    }

    _status = PAUSED;
}

void FFmpegImageStream::cmdRewind()
{
    m_decoder->rewind();
}

void FFmpegImageStream::publishNewFrame(const FFmpegDecoderVideo &, void * user_data)
{
    FFmpegImageStream * const this_ = reinterpret_cast<FFmpegImageStream*>(user_data);

#if 1
    this_->setImage(
        this_->m_decoder->video_decoder().width(), this_->m_decoder->video_decoder().height(), 1, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE,
        const_cast<unsigned char *>(this_->m_decoder->video_decoder().image()), NO_DELETE
    );
#else
    /** \bug If viewer.realize() hasn't been already called, this doesn't work? */
    this_->dirty();
#endif

    OpenThreads::ScopedLock<Mutex> lock(this_->m_mutex);

    if (! this_->m_frame_published_flag)
    {
        this_->m_frame_published_flag = true;
        this_->m_frame_published_cond.signal();
    }
}

} // namespace osgFFmpeg
<|endoftext|>


<commit_before>#include <ios>
#include <stack>

#include <boost/algorithm/string.hpp>

#include "move.hpp"
#include "state.hpp"
#include "random_agent.hpp"
#include "mcts_agent.hpp"
#include "notation.hpp"

#define fmt boost::format

class Game {
  std::stack<State> history;

public:
  State& current_state() {
    return history.top();
  }

  Color color_to_move() {
    return current_state().us;
  }

  Game() {
    history = std::stack<State>();
    history.emplace();
  }

  void make_move(Move move) {
    history.push(State(current_state()));
    current_state().make_move(move);
  }

  void undo() {
    history.pop();
  }

  void setboard(std::string fen) {
    // not sure about when setboard will be called. assuming after "new"
    // and before anything that modifies the state.
    history = std::stack<State>();
    history.emplace(fen);
  }
};

const std::vector<std::string> features = {
  "done=0",
  "ping=1",
  "setboard=1",
  "playother=1",
  "san=1",
  "usermove=1",
  "time=0",
  "draw=1",
  "sigint=0",
  "sigterm=0",
  "reuse=1",
  "analyze=0",
  "myname=\"mc-chess\"", // TODO: version
  "feature=\"normal\"",
  "colors=0",
  "ics=0",
  "name=0",
  "pause=1",
  "nps=0",
  "debug=1",
  "memory=0",
  "smp=0",
  "done=1",
};

void interface_with(std::istream& in, std::ostream& out) {
  out.setf(std::ios::unitbuf);

  unsigned time_budget = 60;

  bool debug = false;

  // if present, this is the path to a file where the agent is to be serialized.
  boost::optional<std::string> path_to_storage = std::string("/home/tim/code/mc-chess/serialized_mcts_agent");

  Game game;
  MCTSAgent agent(2);
  if (path_to_storage && file_readable(*path_to_storage))
    agent.load_yourself(*path_to_storage);

  boost::optional<Color> agent_color;

  boost::future<void> future_quit;
  boost::future<Move> future_decision;
  boost::future<std::string> future_command;

  auto protocol_debug = [&](std::string s) {
    if (debug)
      out << "#" << s << std::endl;
  };

  auto recv_command = [&]() {
    std::string line;
    if (!std::getline(in, line))
      future_quit = boost::make_ready_future();
    protocol_debug("<xboard> " + line);
    return line;
  };

  auto send_command = [&](std::string line) {
    protocol_debug("<engine> " + line);
    out << line << std::endl;
  };

  auto report_illegal = [&](std::string move) {
    send_command("Illegal move: " + move);
  };

  auto report_error = [&](std::string class_, std::string instance) {
    send_command("Error (" + class_ + "): " + instance);
  };

  auto protocol_assert = [&](bool condition, std::string message) {
    if (!condition)
      report_error("protocol assumption violated", message);
  };

  typedef std::vector<std::string> ARGV;

  std::function<void(std::vector<std::string>)> do_nothing = [&](ARGV argv){};
  std::function<void(std::vector<std::string>)> unsupported = [&](ARGV argv){
    report_error("unsupported", argv[0]);
  };

  std::map<std::string, std::function<void(std::vector<std::string>)> > handlers = {
    {"xboard", do_nothing},
    {"protover", [&](ARGV argv) {
        for (auto feature: features)
          send_command("feature " + feature);
      }},
    // TODO: handle these as soon as we get a use case
    {"accepted", do_nothing},
    {"rejected", unsupported},
    {"new", [&](ARGV argv) {
        protocol_assert(!agent_color, "expected \"new\" only in force mode");
        game = Game();
        agent_color = colors::black;
        agent.set_state(game.current_state());
      }},
    {"variant", unsupported},
    {"quit", [&](ARGV argv) {
        agent.abort_decision();
        agent.stop_pondering();
        future_quit = boost::make_ready_future();
      }},
    {"random", do_nothing},
    {"force", [&](ARGV argv) {
        agent_color = boost::none;
        agent.abort_decision();
        agent.stop_pondering();
      }},
    {"go", [&](ARGV argv) {
        agent_color = game.color_to_move();
        agent.set_state(game.current_state());
        agent.start_pondering();
        future_decision = agent.start_decision(time_budget);
      }},
    {"playother", [&](ARGV argv) {
        protocol_assert(!agent_color, "expected \"playother\" only in force mode");
        agent_color = colors::opposite(game.color_to_move());
      }},
    {"level", unsupported},
    {"st", unsupported},
    {"sd", unsupported},
    {"nps", unsupported},
    {"time", unsupported},
    {"otim", unsupported},
    {"usermove", [&](ARGV argv) {
        protocol_assert(!agent_color || agent_color != game.color_to_move(),
                        "usermove during engine's turn");
        Move move;
        try {
          move = notation::algebraic::parse(argv[1], game.current_state());
        } catch (notation::algebraic::OverdeterminedException& e) {
          report_illegal(argv[1]);
          return;
        } catch (notation::algebraic::UnderdeterminedException& e) {
          report_error("ambiguous move", argv[1]);
          return;
        }
        game.make_move(move);
        if (agent_color) {
          agent.advance_state(move);
          agent.start_pondering();
          future_decision = agent.start_decision(time_budget);
        }
      }},
    {"?", [&](ARGV argv) {
        agent.finalize_decision();
      }},
    {"ping", [&](ARGV argv) {
        if (future_decision.valid())
          future_decision.wait();
        send_command("pong " + argv[1]);
      }},
    {"draw", [&](ARGV argv) {
        protocol_assert(agent_color, "\"draw\" when engine not assigned to any color");
        agent.set_state(game.current_state());
        if (agent.accept_draw(*agent_color))
          send_command("offer draw");
      }},
    {"result", [&](ARGV argv) {
        agent.idle();
      }},
    {"setboard", [&](ARGV argv) {
        protocol_assert(!agent_color, "expected \"setboard\" only in force mode");
        std::string fen = boost::algorithm::join(ARGV(argv.begin() + 1, argv.end()), " ");
        game.setboard(fen);
        agent.set_state(game.current_state());
      }},
    {"edit", unsupported},
    {"hint", unsupported},
    {"bk", do_nothing},
    {"undo", [&](ARGV argv) {
        protocol_assert(!agent_color, "expected \"undo\" only in force mode");
        game.undo();
        agent.set_state(game.current_state());
      }},
    {"remove", [&](ARGV argv) {
        protocol_assert(!agent_color || agent_color != game.color_to_move(),
                        "expected \"remove\" only during user's turn");
        game.undo();
        game.undo();
        agent.set_state(game.current_state());
      }},
    {"hard", do_nothing},
    {"easy", do_nothing},
    {"post", do_nothing},
    {"nopost", do_nothing},
    {"analyze", unsupported},
    {"name", do_nothing},
    {"rating", do_nothing},
    {"ics", unsupported},
    {"computer", do_nothing},
    {"pause", [&](ARGV argv) {
        agent.pause();
      }},
    {"resume", [&](ARGV argv) {
        agent.resume();
      }},
    // this could prove to be useful
    {"memory", unsupported},
    {"cores", unsupported},
    {"egtpath", do_nothing},
    {"option", do_nothing},
  };

  auto handle_decision = [&](){
    Move move = future_decision.get();
    send_command("move " + notation::coordinate::format(move));
    game.make_move(move);
    agent.advance_state(move);
    if (path_to_storage)
      agent.save_yourself(*path_to_storage);
    // there has to be a better way to make sure we don't keep redetecting
    // the same future decision value, but i don't know it.  really, the
    // wait_for_any function should wait for any one of them to turn from
    // not-yet-ready to ready, but the manual says that's not how it works.
    // so, replace the ready future with one that will never be ready.
    // i considered keeping a set of futures that need waiting for, and then
    // simply removing processed futures.  but the futures have different
    // value types so we can't store them in a single container unless we use
    // something like boost::variant and then we need a boost::visitor and a
    // boost::welcome_committee and a boost::mayor to ceremonially snip a
    // ribbon with a giant pair of scissors and...  what was the question?
    future_decision = boost::async([]() -> Move {
        sleep_forever();
        throw std::runtime_error("greetings, time traveler!");
      });
  };

  auto handle_command = [&]() {
    std::string line = future_command.get();
    std::vector<std::string> argv;
    boost::algorithm::split(argv, line, boost::algorithm::is_any_of("\t "), boost::token_compress_on);
    std::function<void(ARGV)> handler;
    try {
      handler = handlers.at(argv[0]);
    } catch (std::out_of_range& e) {
      protocol_assert(false, "unknown command: " + line);
      goto after_handler;
    }
    handler(argv);

    after_handler:
    future_command = boost::async(recv_command);
  };

  future_command = boost::async(recv_command);
  while (true) {
    unsigned short ifuture;
    try {
      ifuture = boost::wait_for_any(future_quit, future_decision, future_command);
    } catch (boost::thread_interrupted&) {
    }

    switch (ifuture) {
    case 0:
      goto quit;
      break;
    case 1:
      handle_decision();
      break;
    case 2:
      handle_command();
      break;
    }

    ifuture = -1;
  }

  quit:
  ;
}

int main(int argc, char* argv[]) {
  interface_with(std::cin, std::cout);
}
<commit_msg>path to storage as command-line argument<commit_after>#include <ios>
#include <stack>

#include <boost/algorithm/string.hpp>

#include "move.hpp"
#include "state.hpp"
#include "random_agent.hpp"
#include "mcts_agent.hpp"
#include "notation.hpp"

#define fmt boost::format

class Game {
  std::stack<State> history;

public:
  State& current_state() {
    return history.top();
  }

  Color color_to_move() {
    return current_state().us;
  }

  Game() {
    history = std::stack<State>();
    history.emplace();
  }

  void make_move(Move move) {
    history.push(State(current_state()));
    current_state().make_move(move);
  }

  void undo() {
    history.pop();
  }

  void setboard(std::string fen) {
    // not sure about when setboard will be called. assuming after "new"
    // and before anything that modifies the state.
    history = std::stack<State>();
    history.emplace(fen);
  }
};

const std::vector<std::string> features = {
  "done=0",
  "ping=1",
  "setboard=1",
  "playother=1",
  "san=1",
  "usermove=1",
  "time=0",
  "draw=1",
  "sigint=0",
  "sigterm=0",
  "reuse=1",
  "analyze=0",
  "myname=\"mc-chess\"", // TODO: version
  "feature=\"normal\"",
  "colors=0",
  "ics=0",
  "name=0",
  "pause=1",
  "nps=0",
  "debug=1",
  "memory=0",
  "smp=0",
  "done=1",
};

int main(int argc, char* argv[]) {
  std::istream& in = std::cin;
  std::ostream& out = std::cout;

  out.setf(std::ios::unitbuf);

  unsigned time_budget = 60;

  bool debug = false;

  // if present, this is the path to a file where the agent is to be serialized.
  boost::optional<std::string> path_to_storage;
  if (argc > 0)
    path_to_storage = std::string(argv[1]);

  Game game;
  MCTSAgent agent(2);
  if (path_to_storage && file_readable(*path_to_storage))
    agent.load_yourself(*path_to_storage);

  boost::optional<Color> agent_color;

  boost::future<void> future_quit;
  boost::future<Move> future_decision;
  boost::future<std::string> future_command;

  auto protocol_debug = [&](std::string s) {
    if (debug)
      out << "#" << s << std::endl;
  };

  auto recv_command = [&]() {
    std::string line;
    if (!std::getline(in, line))
      future_quit = boost::make_ready_future();
    protocol_debug("<xboard> " + line);
    return line;
  };

  auto send_command = [&](std::string line) {
    protocol_debug("<engine> " + line);
    out << line << std::endl;
  };

  auto report_illegal = [&](std::string move) {
    send_command("Illegal move: " + move);
  };

  auto report_error = [&](std::string class_, std::string instance) {
    send_command("Error (" + class_ + "): " + instance);
  };

  auto protocol_assert = [&](bool condition, std::string message) {
    if (!condition)
      report_error("protocol assumption violated", message);
  };

  typedef std::vector<std::string> ARGV;

  std::function<void(std::vector<std::string>)> do_nothing = [&](ARGV argv){};
  std::function<void(std::vector<std::string>)> unsupported = [&](ARGV argv){
    report_error("unsupported", argv[0]);
  };

  std::map<std::string, std::function<void(std::vector<std::string>)> > handlers = {
    {"xboard", do_nothing},
    {"protover", [&](ARGV argv) {
        for (auto feature: features)
          send_command("feature " + feature);
      }},
    // TODO: handle these as soon as we get a use case
    {"accepted", do_nothing},
    {"rejected", unsupported},
    {"new", [&](ARGV argv) {
        protocol_assert(!agent_color, "expected \"new\" only in force mode");
        game = Game();
        agent_color = colors::black;
        agent.set_state(game.current_state());
      }},
    {"variant", unsupported},
    {"quit", [&](ARGV argv) {
        agent.abort_decision();
        agent.stop_pondering();
        future_quit = boost::make_ready_future();
      }},
    {"random", do_nothing},
    {"force", [&](ARGV argv) {
        agent_color = boost::none;
        agent.abort_decision();
        agent.stop_pondering();
      }},
    {"go", [&](ARGV argv) {
        agent_color = game.color_to_move();
        agent.set_state(game.current_state());
        agent.start_pondering();
        future_decision = agent.start_decision(time_budget);
      }},
    {"playother", [&](ARGV argv) {
        protocol_assert(!agent_color, "expected \"playother\" only in force mode");
        agent_color = colors::opposite(game.color_to_move());
      }},
    {"level", unsupported},
    {"st", unsupported},
    {"sd", unsupported},
    {"nps", unsupported},
    {"time", unsupported},
    {"otim", unsupported},
    {"usermove", [&](ARGV argv) {
        protocol_assert(!agent_color || agent_color != game.color_to_move(),
                        "usermove during engine's turn");
        Move move;
        try {
          move = notation::algebraic::parse(argv[1], game.current_state());
        } catch (notation::algebraic::OverdeterminedException& e) {
          report_illegal(argv[1]);
          return;
        } catch (notation::algebraic::UnderdeterminedException& e) {
          report_error("ambiguous move", argv[1]);
          return;
        }
        game.make_move(move);
        if (agent_color) {
          agent.advance_state(move);
          agent.start_pondering();
          future_decision = agent.start_decision(time_budget);
        }
      }},
    {"?", [&](ARGV argv) {
        agent.finalize_decision();
      }},
    {"ping", [&](ARGV argv) {
        if (future_decision.valid())
          future_decision.wait();
        send_command("pong " + argv[1]);
      }},
    {"draw", [&](ARGV argv) {
        protocol_assert(agent_color, "\"draw\" when engine not assigned to any color");
        agent.set_state(game.current_state());
        if (agent.accept_draw(*agent_color))
          send_command("offer draw");
      }},
    {"result", [&](ARGV argv) {
        agent.idle();
      }},
    {"setboard", [&](ARGV argv) {
        protocol_assert(!agent_color, "expected \"setboard\" only in force mode");
        std::string fen = boost::algorithm::join(ARGV(argv.begin() + 1, argv.end()), " ");
        game.setboard(fen);
        agent.set_state(game.current_state());
      }},
    {"edit", unsupported},
    {"hint", unsupported},
    {"bk", do_nothing},
    {"undo", [&](ARGV argv) {
        protocol_assert(!agent_color, "expected \"undo\" only in force mode");
        game.undo();
        agent.set_state(game.current_state());
      }},
    {"remove", [&](ARGV argv) {
        protocol_assert(!agent_color || agent_color != game.color_to_move(),
                        "expected \"remove\" only during user's turn");
        game.undo();
        game.undo();
        agent.set_state(game.current_state());
      }},
    {"hard", do_nothing},
    {"easy", do_nothing},
    {"post", do_nothing},
    {"nopost", do_nothing},
    {"analyze", unsupported},
    {"name", do_nothing},
    {"rating", do_nothing},
    {"ics", unsupported},
    {"computer", do_nothing},
    {"pause", [&](ARGV argv) {
        agent.pause();
      }},
    {"resume", [&](ARGV argv) {
        agent.resume();
      }},
    // this could prove to be useful
    {"memory", unsupported},
    {"cores", unsupported},
    {"egtpath", do_nothing},
    {"option", do_nothing},
  };

  auto handle_decision = [&](){
    Move move = future_decision.get();
    send_command("move " + notation::coordinate::format(move));
    game.make_move(move);
    agent.advance_state(move);
    if (path_to_storage)
      agent.save_yourself(*path_to_storage);
    // there has to be a better way to make sure we don't keep redetecting
    // the same future decision value, but i don't know it.  really, the
    // wait_for_any function should wait for any one of them to turn from
    // not-yet-ready to ready, but the manual says that's not how it works.
    // so, replace the ready future with one that will never be ready.
    // i considered keeping a set of futures that need waiting for, and then
    // simply removing processed futures.  but the futures have different
    // value types so we can't store them in a single container unless we use
    // something like boost::variant and then we need a boost::visitor and a
    // boost::welcome_committee and a boost::mayor to ceremonially snip a
    // ribbon with a giant pair of scissors and...  what was the question?
    future_decision = boost::async([]() -> Move {
        sleep_forever();
        throw std::runtime_error("greetings, time traveler!");
      });
  };

  auto handle_command = [&]() {
    std::string line = future_command.get();
    std::vector<std::string> argv;
    boost::algorithm::split(argv, line, boost::algorithm::is_any_of("\t "), boost::token_compress_on);
    std::function<void(ARGV)> handler;
    try {
      handler = handlers.at(argv[0]);
    } catch (std::out_of_range& e) {
      protocol_assert(false, "unknown command: " + line);
      goto after_handler;
    }
    handler(argv);

    after_handler:
    future_command = boost::async(recv_command);
  };

  future_command = boost::async(recv_command);
  while (true) {
    unsigned short ifuture;
    try {
      ifuture = boost::wait_for_any(future_quit, future_decision, future_command);
    } catch (boost::thread_interrupted&) {
    }

    switch (ifuture) {
    case 0:
      goto quit;
      break;
    case 1:
      handle_decision();
      break;
    case 2:
      handle_command();
      break;
    }

    ifuture = -1;
  }

  quit:
  ;
}
<|endoftext|>


<commit_before>a7eed482-2747-11e6-a2d0-e0f84713e7b8<commit_msg>having coffee<commit_after>a803ac38-2747-11e6-a68b-e0f84713e7b8<|endoftext|>


<commit_before>#include "context.h"
#include "renderer.h"
#include "glm/glm.hpp"

int main(int argc, char** argv)
{
	Renderer renderer;
	Context context(renderer);

    printf("%d, %d\n", sizeof(glm::vec3), sizeof(float));
    context.init(1024, 768, "voitures", 0);
    while (context.eventLoop())
    {
        context.clean();
        context.show();
    }

    return 0;
}
<commit_msg>Jeu de voitures trop de ouf \!\!\!<commit_after>#include "context.h"
#include "renderer.h"
#include "glm/glm.hpp"

int main(int argc, char** argv)
{
	Renderer renderer;
	Context context(renderer);

    context.init(1024, 768, "Jeu de voitures trop de ouf !!!", 0);
    while (context.eventLoop())
    {
        context.clean();
        context.show();
    }

    return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip>
#include <time.h>
#include <fstream>
#include <cstring>

using namespace std;

/**
 * Functions initialization
 */
void quickSort(int *array, int firstElementNumder, int lastElementNumder);
void insertionSort(int *array, int elementsCount);
void bubbleSort(int *array, int elementsCount);
void fillArray(int *array, int elementsCount);
void print(int *array, int elementsCount);
void arrayDuplicator(int arrayIn[], int arrayOut[], int elementsCount);
void write(int *array, int elementsCount, char *fileName);

int main() {
    int elementsCount;
    cout << "Enter array elements count: ";
    cin >> elementsCount;

    srand(time(NULL));
    clock_t timerClock = 0;
    double sortTime[3];
    int *array = new int[elementsCount];
    int *arrayTemp = new int[elementsCount];
    fillArray(array, elementsCount);

    write(array, elementsCount, "array");
    arrayDuplicator(array, arrayTemp, elementsCount);

    timerClock = clock();
    quickSort(arrayTemp, 0, elementsCount - 1);
    timerClock = clock() - timerClock;
    write(arrayTemp, elementsCount, "quickSort");
    sortTime[0] = (((double) timerClock) / (double) CLOCKS_PER_SEC) * 1000;
    cout << "Clock quickSort: " << sortTime[0] << " milliseconds" << "\n\n";

    arrayDuplicator(array, arrayTemp, elementsCount);

    timerClock = clock();
    insertionSort(arrayTemp, elementsCount);
    timerClock = clock() - timerClock;
    write(arrayTemp, elementsCount, "insertionSort");
    sortTime[1] = (((double) timerClock) / (double) CLOCKS_PER_SEC) * 1000;
    cout << "Clock insertionSort: " << sortTime[1] << " milliseconds" << "\n\n";

    arrayDuplicator(array, arrayTemp, elementsCount);

    timerClock = clock();
    bubbleSort(arrayTemp, elementsCount);
    timerClock = clock() - timerClock;
    write(arrayTemp, elementsCount, "bubbleSort");
    sortTime[2] = (((double) timerClock) / (double) CLOCKS_PER_SEC) * 1000;
    cout << "Clock bubbleSort: " << sortTime[2] << " milliseconds" << "\n\n";

    system("pause");
    return 0;
}

/**
 * @brief quickSort
 * @param array
 * @param firstElementNumder
 * @param lastElementNumder
 */
void quickSort(int *array, int firstElementNumder, int lastElementNumder) {
    int mid, count;
    int f = firstElementNumder, l = lastElementNumder;
    mid = array[(f + l) / 2];
    do {
        while (array[f] < mid) f++;
        while (array[l] > mid) l--;
        if (f <= l) {
            count = array[f];
            array[f] = array[l];
            array[l] = count;
            f++;
            l--;
        }
    } while (f < l);
    if (firstElementNumder < l) quickSort(array, firstElementNumder, l);
    if (f < lastElementNumder) quickSort(array, f, lastElementNumder);
}

/**
 * @brief insertionSort
 * @param array
 * @param elementsCount
 */
void insertionSort(int *array, int elementsCount) {
    for (int firstElementNumder = 1; firstElementNumder < elementsCount; firstElementNumder++) {
        for (int numberElement = firstElementNumder; numberElement > 0
                                                     &&
                                                     array[numberElement - 1] > array[numberElement]; numberElement--) {
            array[numberElement - 1] = array[numberElement - 1] + array[numberElement];
            array[numberElement] = array[numberElement - 1] - array[numberElement];
            array[numberElement - 1] = array[numberElement - 1] - array[numberElement];
        }
    }
}

/**
 * @brief bubbleSort
 * @param array
 * @param elementsCount
 */
void bubbleSort(int *array, int elementsCount) {
    bool sorted = false;
    while (!sorted) {
        sorted = true;
        for (int numberElement = 0; numberElement < (elementsCount - 1); numberElement++)
            if (array[numberElement] > array[numberElement + 1]) {
                array[numberElement + 1] = array[numberElement + 1] + array[numberElement];
                array[numberElement] = array[numberElement + 1] - array[numberElement];
                array[numberElement + 1] = array[numberElement + 1] - array[numberElement];
                sorted = false;
            }
    }
}

/**
 * @brief fillArray
 * @param array
 * @param elementsCount
 */
void fillArray(int *array, int elementsCount) {
    for (int numberElement = 0; numberElement < elementsCount; numberElement++) {
        array[numberElement] = rand() % 65535;
    }
}

/**
 * @brief print
 * @param array
 * @param elementsCount
 */
void print(int *array, int elementsCount) {
    for (int numberElement = 0; numberElement < elementsCount; numberElement++) {
        cout << setw(2) << array[numberElement] << "  ";
    }
    cout << endl;
}

/**
 * @brief arrayDuplicator void
 * @param arrayIn array
 * @param arrayOut array
 * @param elementsCount int
 */
void arrayDuplicator(int arrayIn[], int arrayOut[], int elementsCount) {
    for (int numberElement = 0; numberElement < elementsCount; numberElement++) {
        arrayOut[numberElement] = arrayIn[numberElement];
    }
}

/**
 * @brief write
 * @param array
 * @param elementsCount
 * @param fileName
 */
void write(int *array, int elementsCount, char *fileName) {
    ofstream fileStream;

    char fileTimePrefix[256];
    time_t seconds = time(NULL);
    tm *timeinfo = localtime(&seconds);
    strftime(fileTimePrefix, 128, "%d%m%Y_%I%M%S-", timeinfo);

    strcat(fileTimePrefix,fileName);
    strcat(fileTimePrefix,".csv");

    cout<<fileTimePrefix<<endl;
    fileStream.open(fileTimePrefix, ios_base::out | ios_base::trunc);
    for (int i = 0; i < elementsCount; i++) {
        fileStream << array[i] << ';' << endl;
    }
    fileStream.close();
}
<commit_msg>Add QT time<commit_after>#include <iostream>
#include <iomanip>
#include <time.h>
#include <fstream>
#include <cstring>
#include <QElapsedTimer>

using namespace std;

/**
 * Functions initialization
 */
void quickSort(int *array, int firstElementNumder, int lastElementNumder);
void insertionSort(int *array, int elementsCount);
void bubbleSort(int *array, int elementsCount);
void fillArray(int *array, int elementsCount);
void print(int *array, int elementsCount);
void arrayDuplicator(int arrayIn[], int arrayOut[], int elementsCount);
void write(int *array, int elementsCount, char *fileName);

int main() {
    int elementsCount;
    cout << "Enter array elements count: ";
    cin >> elementsCount;

    QElapsedTimer timer;
    srand(time(NULL));
    clock_t timerClock = 0;
    double sortTime[3];
    int *array = new int[elementsCount];
    int *arrayTemp = new int[elementsCount];
    fillArray(array, elementsCount);

    write(array, elementsCount, "array");
    arrayDuplicator(array, arrayTemp, elementsCount);

    timerClock = clock();
    timer.start();
    quickSort(arrayTemp, 0, elementsCount - 1);
    timerClock = clock() - timerClock;
    write(arrayTemp, elementsCount, "quickSort");
    sortTime[0] = (((double) timerClock) / (double) CLOCKS_PER_SEC) * 1000;
    cout << "Clock quickSort: " << sortTime[0] << " milliseconds" << "\n";
    cout << "QElapsedTimer quickSort: " << timer.elapsed() << " milliseconds" << "\n\n";

    arrayDuplicator(array, arrayTemp, elementsCount);

    timer.restart();
    timerClock = clock();
    insertionSort(arrayTemp, elementsCount);
    timerClock = clock() - timerClock;
    write(arrayTemp, elementsCount, "insertionSort");
    sortTime[1] = (((double) timerClock) / (double) CLOCKS_PER_SEC) * 1000;
    cout << "Clock insertionSort: " << sortTime[1] << " milliseconds" << "\n";
    cout << "QElapsedTimer quickSort: " << timer.elapsed() << " milliseconds" << "\n\n";

    arrayDuplicator(array, arrayTemp, elementsCount);

    timer.restart();
    timerClock = clock();
    bubbleSort(arrayTemp, elementsCount);
    timerClock = clock() - timerClock;
    write(arrayTemp, elementsCount, "bubbleSort");
    sortTime[2] = (((double) timerClock) / (double) CLOCKS_PER_SEC) * 1000;
    cout << "Clock bubbleSort: " << sortTime[2] << " milliseconds" << "\n";
    cout << "QElapsedTimer quickSort: " << timer.elapsed() << " milliseconds" << "\n\n";

    system("pause");
    return 0;
}

/**
 * @brief quickSort
 * @param array
 * @param firstElementNumder
 * @param lastElementNumder
 */
void quickSort(int *array, int firstElementNumder, int lastElementNumder) {
    int mid, count;
    int f = firstElementNumder, l = lastElementNumder;
    mid = array[(f + l) / 2];
    do {
        while (array[f] < mid) f++;
        while (array[l] > mid) l--;
        if (f <= l) {
            count = array[f];
            array[f] = array[l];
            array[l] = count;
            f++;
            l--;
        }
    } while (f < l);
    if (firstElementNumder < l) quickSort(array, firstElementNumder, l);
    if (f < lastElementNumder) quickSort(array, f, lastElementNumder);
}

/**
 * @brief insertionSort
 * @param array
 * @param elementsCount
 */
void insertionSort(int *array, int elementsCount) {
    for (int firstElementNumder = 1; firstElementNumder < elementsCount; firstElementNumder++) {
        for (int numberElement = firstElementNumder; numberElement > 0
            && array[numberElement - 1] > array[numberElement]; numberElement--) {
            array[numberElement - 1] = array[numberElement - 1] + array[numberElement];
            array[numberElement] = array[numberElement - 1] - array[numberElement];
            array[numberElement - 1] = array[numberElement - 1] - array[numberElement];
        }
    }
}

/**
 * @brief bubbleSort
 * @param array
 * @param elementsCount
 */
void bubbleSort(int *array, int elementsCount) {
    bool sorted = false;
    while (!sorted) {
        sorted = true;
        for (int numberElement = 0; numberElement < (elementsCount - 1); numberElement++)
            if (array[numberElement] > array[numberElement + 1]) {
                array[numberElement + 1] = array[numberElement + 1] + array[numberElement];
                array[numberElement] = array[numberElement + 1] - array[numberElement];
                array[numberElement + 1] = array[numberElement + 1] - array[numberElement];
                sorted = false;
            }
    }
}

/**
 * @brief fillArray
 * @param array
 * @param elementsCount
 */
void fillArray(int *array, int elementsCount) {
    for (int numberElement = 0; numberElement < elementsCount; numberElement++) {
        array[numberElement] = rand() % 65535;
    }
}

/**
 * @brief print
 * @param array
 * @param elementsCount
 */
void print(int *array, int elementsCount) {
    for (int numberElement = 0; numberElement < elementsCount; numberElement++) {
        cout << setw(2) << array[numberElement] << "  ";
    }
    cout << endl;
}

/**
 * @brief arrayDuplicator void
 * @param arrayIn array
 * @param arrayOut array
 * @param elementsCount int
 */
void arrayDuplicator(int arrayIn[], int arrayOut[], int elementsCount) {
    for (int numberElement = 0; numberElement < elementsCount; numberElement++) {
        arrayOut[numberElement] = arrayIn[numberElement];
    }
}

/**
 * @brief write
 * @param array
 * @param elementsCount
 * @param fileName
 */
void write(int *array, int elementsCount, char *fileName) {
    ofstream fileStream;

    char fileTimePrefix[256];
    time_t seconds = time(NULL);
    tm *timeinfo = localtime(&seconds);
    strftime(fileTimePrefix, 128, "%d%m%Y_%I%M%S-", timeinfo);

    strcat(fileTimePrefix,fileName);
    strcat(fileTimePrefix,".csv");

    cout<<fileTimePrefix<<endl;
    fileStream.open(fileTimePrefix, ios_base::out | ios_base::trunc);
    for (int i = 0; i < elementsCount; i++) {
        fileStream << array[i] << ';' << endl;
    }
    fileStream.close();
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2017 musikcube team
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright notice,
//      this list of conditions and the following disclaimer.
//
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//
//    * Neither the name of the author nor the names of other contributors may
//      be used to endorse or promote products derived from this software
//      without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////

#include "FfmpegDecoder.h"
#include <algorithm>

#define BUFFER_SIZE 4096
#define PROBE_SIZE 32768

using namespace musik::core::sdk;

static int readCallback(void* opaque, uint8_t* buffer, int bufferSize) {
    FfmpegDecoder* decoder = static_cast<FfmpegDecoder*>(opaque);
    if (decoder && decoder->Stream()) {
        auto count = decoder->Stream()->Read(buffer, (PositionType) bufferSize);
        return (count > 1) ? count : AVERROR_EOF;
    }
    return 0;
}

static int writeCallback(void* opaque, uint8_t* buffer, int bufferSize) {
    return 0;
}

static int64_t seekCallback(void* opaque, int64_t offset, int whence) {
    FfmpegDecoder* decoder = static_cast<FfmpegDecoder*>(opaque);
    if (decoder && decoder->Stream()) {
        IDataStream* stream = decoder->Stream();
        switch (whence) {
            case AVSEEK_SIZE:
                return stream->Length();
                break;
            case SEEK_SET:
                stream->SetPosition((PositionType) offset);
                break;
            case SEEK_CUR:
                stream->SetPosition(stream->Position() + (PositionType) offset);
                break;
            case SEEK_END:
                stream->SetPosition(stream->Length() - 1);
                break;
        }

        return stream->Position();
    }
    return 0;
}

FfmpegDecoder::FfmpegDecoder() {
    this->stream = nullptr;
    this->streamId = -1;
    this->duration = -1.0f;
    this->ioContext = nullptr;
    this->formatContext = nullptr;
    this->codecContext = nullptr;
    this->decodedFrame = nullptr;
    this->resampler = nullptr;
    this->bufferSize = FF_INPUT_BUFFER_PADDING_SIZE + BUFFER_SIZE;
    this->buffer = new unsigned char[this->bufferSize];
    this->decodedFrame = av_frame_alloc();
    av_init_packet(&this->packet);
}

FfmpegDecoder::~FfmpegDecoder() {
    this->Reset();
    delete[] this->buffer;
    this->buffer = nullptr;
    av_free_packet(&this->packet);
    av_frame_free(&this->decodedFrame);
    this->decodedFrame = nullptr;

    if (this->resampler) {
        swr_free(&this->resampler);
        this->resampler = nullptr;
    }
}

void FfmpegDecoder::Release() {
    delete this;
}

double FfmpegDecoder::SetPosition(double seconds) {
    if (this->ioContext && this->formatContext && this->codecContext) {
        AVStream* stream = this->formatContext->streams[this->streamId];
        AVRational baseQ = { 1, AV_TIME_BASE };
        int64_t pts = av_rescale_q((int64_t)(seconds * AV_TIME_BASE), baseQ, stream->time_base);
        avcodec_flush_buffers(this->codecContext);
        if (av_seek_frame(this->formatContext, this->streamId, pts, 0) >= 0) {
            return seconds;
        }
    }
    return -1.0f;
}

bool FfmpegDecoder::GetBuffer(IBuffer *buffer) {
    if (this->ioContext) {
        buffer->SetSampleRate((long) this->rate);
        buffer->SetChannels((long) this->channels);

        if (!av_read_frame(this->formatContext, &this->packet)) {
            int frameDecoded = 0;

            avcodec_decode_audio4(
                this->codecContext,
                this->decodedFrame,
                &frameDecoded,
                &this->packet);

            av_free_packet(&this->packet);

            if (frameDecoded) {
                int samples = this->decodedFrame->nb_samples;
                int channels = this->codecContext->channels;
                auto inFormat = this->codecContext->sample_fmt;
                auto inLayout = this->codecContext->channel_layout;

                int decodedSize = av_samples_get_buffer_size(
                    nullptr, channels, samples, inFormat, 1);

                if (decodedSize > 0) {
                    buffer->SetSamples(samples * channels);

                    if (!this->resampler) {
                        this->resampler = swr_alloc();

                        swr_alloc_set_opts(
                            this->resampler,
                            inLayout,
                            AV_SAMPLE_FMT_FLT,
                            this->rate,
                            inLayout,
                            inFormat,
                            this->rate,
                            0,
                            nullptr);

                        swr_init(this->resampler);
                    }

                    uint8_t* outData = (uint8_t*) buffer->BufferPointer();
                    const uint8_t** inData = (const uint8_t**) this->decodedFrame->extended_data;
                    swr_convert(this->resampler, &outData, samples, inData, samples);
                }
                else {
                    buffer->SetSamples(0);
                }
            }

            av_frame_unref(this->decodedFrame);
            return true;
        }
    }
    return false;
}

double FfmpegDecoder::GetDuration() {
    return this->duration;
}

void FfmpegDecoder::Reset() {
    if (this->ioContext) {
        av_free(this->ioContext);
        this->ioContext = nullptr;
    }
    if (this->formatContext) {
        avformat_close_input(&this->formatContext);
        this->formatContext = nullptr;
    }
    if (this->codecContext) {
        avcodec_close(this->codecContext);
        this->codecContext = nullptr;
    }
    this->streamId = -1;
}

bool FfmpegDecoder::Open(musik::core::sdk::IDataStream *stream) {
    if (stream->Seekable() && this->ioContext == nullptr) {
        this->stream = stream;

        this->ioContext = avio_alloc_context(
            this->buffer,
            this->bufferSize,
            0,
            this,
            readCallback,
            writeCallback,
            seekCallback);

        if (this->ioContext != nullptr) {
            this->streamId = -1;
            this->formatContext = avformat_alloc_context();
            this->formatContext->pb = this->ioContext;
            this->formatContext->flags = AVFMT_FLAG_CUSTOM_IO;

            unsigned char probe[PROBE_SIZE];
            size_t count = stream->Read(probe, PROBE_SIZE);
            stream->SetPosition(0);

            AVProbeData probeData = { 0 };
            probeData.buf = probe;
            probeData.buf_size = count;
            probeData.filename = "";

            this->formatContext->iformat = av_probe_input_format(&probeData, 1);

            if (this->formatContext->iformat) {
                if (avformat_open_input(&this->formatContext, "", nullptr, nullptr) == 0) {
                    if (avformat_find_stream_info(this->formatContext, nullptr) >= 0) {
                        for (unsigned i = 0; i < this->formatContext->nb_streams; i++) {
                            if (this->formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
                                this->streamId = (int) i;
                                break;
                            }
                        }
                    }

                    if (this->streamId != -1) {
                        this->codecContext = this->formatContext->streams[this->streamId]->codec;
                        //if (codecContext) {
                        //    this->codecContext->request_sample_fmt = AV_SAMPLE_FMT_FLT;
                        //    AVCodec* codec = avcodec_find_decoder(codecContext->codec_id);
                        //    if (codec) {
                        //        if (avcodec_open2(codecContext, codec, nullptr) < 0) {
                        //            goto reset_and_fail;
                        //        }
                        //    }
                        //}

                        auto stream = this->formatContext->streams[this->streamId];
                        this->rate = stream->codec->sample_rate;
                        this->channels = stream->codec->channels;
                        this->duration = (double) this->formatContext->duration / (double) AV_TIME_BASE;
                        return true;
                    }
                }
            }
        }
    }

reset_and_fail:
    this->Reset();
    return false;
}

bool FfmpegDecoder::Exhausted() {
    return false;
}<commit_msg>Fixed an order-of-operations bug that was leading to a double free in the ffmpeg decoder. Also patched up a memory leak -- we weren't completely freeing the formatContext.<commit_after>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2017 musikcube team
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright notice,
//      this list of conditions and the following disclaimer.
//
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//
//    * Neither the name of the author nor the names of other contributors may
//      be used to endorse or promote products derived from this software
//      without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////

#include "FfmpegDecoder.h"
#include <algorithm>

#define BUFFER_SIZE 4096
#define PROBE_SIZE 32768

using namespace musik::core::sdk;

static int readCallback(void* opaque, uint8_t* buffer, int bufferSize) {
    FfmpegDecoder* decoder = static_cast<FfmpegDecoder*>(opaque);
    if (decoder && decoder->Stream()) {
        auto count = decoder->Stream()->Read(buffer, (PositionType) bufferSize);
        return (count > 1) ? count : AVERROR_EOF;
    }
    return 0;
}

static int writeCallback(void* opaque, uint8_t* buffer, int bufferSize) {
    return 0;
}

static int64_t seekCallback(void* opaque, int64_t offset, int whence) {
    FfmpegDecoder* decoder = static_cast<FfmpegDecoder*>(opaque);
    if (decoder && decoder->Stream()) {
        IDataStream* stream = decoder->Stream();
        switch (whence) {
            case AVSEEK_SIZE:
                return stream->Length();
                break;
            case SEEK_SET:
                stream->SetPosition((PositionType) offset);
                break;
            case SEEK_CUR:
                stream->SetPosition(stream->Position() + (PositionType) offset);
                break;
            case SEEK_END:
                stream->SetPosition(stream->Length() - 1);
                break;
        }

        return stream->Position();
    }
    return 0;
}

FfmpegDecoder::FfmpegDecoder() {
    this->stream = nullptr;
    this->streamId = -1;
    this->duration = -1.0f;
    this->ioContext = nullptr;
    this->formatContext = nullptr;
    this->codecContext = nullptr;
    this->decodedFrame = nullptr;
    this->resampler = nullptr;
    this->bufferSize = FF_INPUT_BUFFER_PADDING_SIZE + BUFFER_SIZE;
    this->buffer = new unsigned char[this->bufferSize];
    this->decodedFrame = av_frame_alloc();
    av_init_packet(&this->packet);
}

FfmpegDecoder::~FfmpegDecoder() {
    this->Reset();

    delete[] this->buffer;
    this->buffer = nullptr;
    av_free_packet(&this->packet);
    av_frame_free(&this->decodedFrame);
    this->decodedFrame = nullptr;

    if (this->resampler) {
        swr_free(&this->resampler);
        this->resampler = nullptr;
    }
}

void FfmpegDecoder::Release() {
    delete this;
}

double FfmpegDecoder::SetPosition(double seconds) {
    if (this->ioContext && this->formatContext && this->codecContext) {
        AVStream* stream = this->formatContext->streams[this->streamId];
        AVRational baseQ = { 1, AV_TIME_BASE };
        int64_t pts = av_rescale_q((int64_t)(seconds * AV_TIME_BASE), baseQ, stream->time_base);
        avcodec_flush_buffers(this->codecContext);
        if (av_seek_frame(this->formatContext, this->streamId, pts, 0) >= 0) {
            return seconds;
        }
    }
    return -1.0f;
}

bool FfmpegDecoder::GetBuffer(IBuffer *buffer) {
    if (this->ioContext) {
        buffer->SetSampleRate((long) this->rate);
        buffer->SetChannels((long) this->channels);

        if (!av_read_frame(this->formatContext, &this->packet)) {
            int frameDecoded = 0;

            avcodec_decode_audio4(
                this->codecContext,
                this->decodedFrame,
                &frameDecoded,
                &this->packet);

            av_free_packet(&this->packet);

            if (frameDecoded) {
                int samples = this->decodedFrame->nb_samples;
                int channels = this->codecContext->channels;
                auto inFormat = this->codecContext->sample_fmt;
                auto inLayout = this->codecContext->channel_layout;

                int decodedSize = av_samples_get_buffer_size(
                    nullptr, channels, samples, inFormat, 1);

                if (decodedSize > 0) {
                    buffer->SetSamples(samples * channels);

                    if (!this->resampler) {
                        this->resampler = swr_alloc();

                        swr_alloc_set_opts(
                            this->resampler,
                            inLayout,
                            AV_SAMPLE_FMT_FLT,
                            this->rate,
                            inLayout,
                            inFormat,
                            this->rate,
                            0,
                            nullptr);

                        swr_init(this->resampler);
                    }

                    uint8_t* outData = (uint8_t*) buffer->BufferPointer();
                    const uint8_t** inData = (const uint8_t**) this->decodedFrame->extended_data;
                    swr_convert(this->resampler, &outData, samples, inData, samples);
                }
                else {
                    buffer->SetSamples(0);
                }
            }

            av_frame_unref(this->decodedFrame);
            return true;
        }
    }
    return false;
}

double FfmpegDecoder::GetDuration() {
    return this->duration;
}

void FfmpegDecoder::Reset() {
    if (this->ioContext) {
        av_free(this->ioContext);
        this->ioContext = nullptr;
    }
    if (this->codecContext) {
        avcodec_flush_buffers(this->codecContext);

        auto stream = this->formatContext->streams[this->streamId];
        if (stream != nullptr) {
            avcodec_close(this->codecContext);
        }

        this->codecContext = nullptr;
    }
    if (this->formatContext) {
        avformat_close_input(&this->formatContext);
        avformat_free_context(this->formatContext);
        this->formatContext = nullptr;
    }
    this->streamId = -1;
}

bool FfmpegDecoder::Open(musik::core::sdk::IDataStream *stream) {
    if (stream->Seekable() && this->ioContext == nullptr) {
        this->stream = stream;

        this->ioContext = avio_alloc_context(
            this->buffer,
            this->bufferSize,
            0,
            this,
            readCallback,
            writeCallback,
            seekCallback);

        if (this->ioContext != nullptr) {
            this->streamId = -1;
            this->formatContext = avformat_alloc_context();
            this->formatContext->pb = this->ioContext;
            this->formatContext->flags = AVFMT_FLAG_CUSTOM_IO;

            unsigned char probe[PROBE_SIZE];
            size_t count = stream->Read(probe, PROBE_SIZE);
            stream->SetPosition(0);

            AVProbeData probeData = { 0 };
            probeData.buf = probe;
            probeData.buf_size = count;
            probeData.filename = "";

            this->formatContext->iformat = av_probe_input_format(&probeData, 1);

            if (this->formatContext->iformat) {
                if (avformat_open_input(&this->formatContext, "", nullptr, nullptr) == 0) {
                    if (avformat_find_stream_info(this->formatContext, nullptr) >= 0) {
                        for (unsigned i = 0; i < this->formatContext->nb_streams; i++) {
                            if (this->formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
                                this->streamId = (int) i;
                                break;
                            }
                        }
                    }

                    if (this->streamId != -1) {
                        this->codecContext = this->formatContext->streams[this->streamId]->codec;
                        if (codecContext) {
                            this->codecContext->request_sample_fmt = AV_SAMPLE_FMT_FLT;
                            AVCodec* codec = avcodec_find_decoder(codecContext->codec_id);
                            if (codec) {
                                if (avcodec_open2(codecContext, codec, nullptr) < 0) {
                                    goto reset_and_fail;
                                }
                            }
                        }

                        auto stream = this->formatContext->streams[this->streamId];
                        this->rate = stream->codec->sample_rate;
                        this->channels = stream->codec->channels;
                        this->duration = (double) this->formatContext->duration / (double) AV_TIME_BASE;
                        return true;
                    }
                }
            }
        }
    }

reset_and_fail:
    this->Reset();
    return false;
}

bool FfmpegDecoder::Exhausted() {
    return false;
}<|endoftext|>


<commit_before>b8b4893d-4b02-11e5-b914-28cfe9171a43<commit_msg>( ͡° ͜ʖ ͡°)<commit_after>b8c14457-4b02-11e5-b4a9-28cfe9171a43<|endoftext|>