/*****************************************************************************/
/* Copyright (c) 2008 NXP B.V.                                               */
/*                                                                           */
/* This library is free software; you can redistribute it and/or             */
/* modify it under the terms of the GNU Lesser General Public                */
/* License as published by the Free Software Foundation, using               */
/* version 2.1 of the License.                                               */
/*                                                                           */
/* 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   */
/*                                                                           */
/*****************************************************************************/
/*
   NXP STB22X Driver

   Code is derived from TI Davinci driver.

   TI Davinci driver

   (c) Copyright 2007  Telio AG

   Written by Denis Oliver Kropp <dok@directfb.org>

   Code is derived from VMWare driver.

   (c) Copyright 2001-2007  The DirectFB Organization (directfb.org)
   (c) Copyright 2000-2004  Convergence (integrated media) GmbH

   All rights reserved.

   Written by Denis Oliver Kropp <dok@directfb.org>,
              Andreas Hundt <andi@fischlustig.de>,
              Sven Neumann <neo@directfb.org>,
              Ville Syrjälä <syrjala@sci.fi> and
              Claudio Ciccani <klan@users.sf.net>.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   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.
*//**
    @file   phStbDFB_encoder.c
    @brief  Encoder Implementation for DirectFB.

@b  Component:  phStbDFB.

*//*

Rev Date        Author      Comments
--------------------------------------------------------------------------------
  1 20080103    laird       New version for DirectFB 1.1.1
  2 20080716    laird       Adding support for Video layers and 59/94 etc.
  3 20080728    laird       Assert if DENC_CONNECTOR is NONE
  4 20080902    laird       Update Copyright headers.
  5 20080905    neill       Add VGA modes
  6 20080915    batelaan    Fix compilation warning
  7 20080919    laird       Tidy up debug messages.
  8 20081209    neill       Add RGB mode support
  9 20090218    neill       Extend YC/CVBS mode support
 10 20090223    cboudy      Add UDA3000 support
--------------------------------------------------------------------------------
    For consistency and standardisation retain the Section Separators.
*/

/***********************************************
* INCLUDE FILES                                *
************************************************/
#include "phStbDFB_encoder.h"
#include "phStbDFB_utils.h"

/***********************************************
* LOCAL MACROS                                 *
* recommendation only: <MODULE><_WORD>+        *
************************************************/

#define MAX_TABLE_ENTRIES 8

/******************************************************************
* LOCAL TYPEDEFS                                                  *
* recommendation only:                [p]phStbTemplate_<Word>+_t  *
*******************************************************************/
D_DEBUG_DOMAIN( phStbDFB_Encoders, "NXP/STB22X/Encoder", "NXP 22X Encoders" );

/******************************************************************
* STATIC FUNCTION PROTOTYPES                  <Module>_<Word>+    *
*******************************************************************/
/**
 * Local function to add a specified DirectFB connector to the
 * specified Video denc settings.  If the connector is already in the
 * chosen connectors then it returns as well.
 * @param pDencSettings @b IN The denc settings.
 * @param out_connector @b IN The DirectFB out_connector we are adding.
 *                            This must be an individual connector not a
 *                            list
 * @return DFB_OK if already added or we have added.
 *         DFB_LIMITEXCEEDED No space for more connectors.
 */
static DFBResult StbDFB_AddVideoConnector(struct videodenc_var_screeninfo *pDencSettings,
                                          DFBScreenOutputConnectors out_connector);

/**
 * Local function to remove a specified DirectFB connector from the
 * specified Video denc settings.  If the connector is already in the
 * chosen connectors then it returns as well.
 * @param pDencSettings @b IN The denc settings.
 * @param out_connector @b IN The DirectFB out_connector we are adding.
 *                            This must be an individual connector not a
 *                            list
 * @return DFB_OK if already added or we have added.
 *         DFB_LIMITEXCEEDED No space for more connectors.
 */
static DFBResult StbDFB_RemoveVideoConnector(struct videodenc_var_screeninfo *pDencSettings,
                                             DFBScreenOutputConnectors out_connector);

/**
 * Local function to add / remove all the connectors that are
 * required or not for the given configuration.
 *
 * @param pScreenData   @b IN The screen data.
 * @param enocder       @b IN the encoder number to use.
 * @param pDencSettings @b IN The denc settings.
 * @param config        @b IN Direct FB config structure
 * @return DFB_OK if ok, else error.
 */
static DFBResult StbDFB_SetupVideoConnectors(phStbDFB_ScreenData_t *pScreenData,
                                             uint32_t encoder,
                                             struct videodenc_var_screeninfo *pDencSettings,
                                             const DFBScreenEncoderConfig *config);

/******************************************************************
* STATIC DATA                  g[k|p|kp|pk|kpk]<Module>_<Word>+   *
*******************************************************************/

static const uint32_t gamma_table[MAX_TABLE_ENTRIES] = {16, 32, 64, 96, 128, 160, 192, 224};

/**************************************************************************
* EXPORTED DATA                     g[k|p|kp|pk|kpk]phStbTemplate_<Word>+ *
***************************************************************************/

/*******************************************************************************
* FUNCTION IMPLEMENTATION  <Module>[_<Word>+] for static functions             *
*                          tm[<screen>]<Module>[_<Word>+] for exported functions*
********************************************************************************/

/******************************************************************************/
extern DFBResult phStbDFB_InitEncoder(
    CoreScreen *screen,
    void                         *driver_data,
    void                         *screen_data,
    int                           encoder,
    DFBScreenEncoderDescription  *description,
    DFBScreenEncoderConfig       *config )
{
    DFBResult result = DFB_OK;
    phStbDFB_ScreenData_t *pScreenData = (phStbDFB_ScreenData_t*)screen_data;
    String outFormat[PH_STBVIDEOTYPES_MAXIMUMNAMELENGTH];
    bool interlaced;
    phStbVideoRenderer_FrameRate_t frameRate;
    uint32_t conIndex = 0;

    struct videodenc_var_screeninfo dencSettings;

    /* The AV switch (AK470X) settings */
    av_switch_data avSwitchSettings;

    D_DEBUG_ENTER( phStbDFB_Encoders, "");

    /*Out output type*/
    description->type = DSET_TV;

    /*Setup our capabilities*/
    description->caps = PH_STBDFB_MAIN_SCREEN_ENCODER_CAPABILITIES;

    /*First things First, map all of the encoders that are mapped to each renderer.*/
    DFB_RETURN_ON_ERR(phStbDFB_InitVideoDenc(pScreenData,
                                           encoder,
                                           description),
                      "Failed to call StbDFB_InitVideoDenc Error %d\n", err);

    /*Now get the denc setup for the specified encoder this is used in combination with the scart switch
      to determine the current setup of signals etc.
      */
    DFB_RETURN_ON_ERR(phStbDFB_GetDencSetup(pScreenData,
                                          encoder,
                                          &dencSettings),
                      "Failed to call StbDFB_GetDencSetup Error %d\n", err);

    /* Set the tv standard according to the encoder not the renderer*/
    config->tv_standard = CONVERT_TO_DFB_TVSTANDARD(dencSettings.tv_standard);

    /*Need to get the currently chosen output format of the renderer and warn if they do not match*/
    TM_TO_DFB_RETURN_ON_ERR(phStbVideoRenderer_GetOutputFormat(phStbVideoRenderer_DisplayChain_Main,
                                                              (String)outFormat),
                            "Error calling phStbVideoRenderer_GetOutputFormat Renderer(%d) 0x%08x\n",
                            phStbVideoRenderer_DisplayChain_Main, err);
    /*Switch on TV Standard*/
    switch(config->tv_standard)
    {
        case DSETV_PAL_BG:
        case DSETV_PAL_I:
        case DSETV_PAL_M:
        case DSETV_PAL_N:
        case DSETV_PAL_NC:
            if(strncmp((char_t*)outFormat, (char_t*)PH_STBVIDEOTYPES_PAL, strlen((char_t*)PH_STBVIDEOTYPES_PAL)) != 0)
            {
                D_INFO("Encoder Output of 0x%08x (PAL_XXX) does not match the output of renderer %s\n",
                       config->tv_standard,
                       outFormat);
            }
            break;

        case DSETV_NTSC:
        case DSETV_NTSC_M_JPN:
            if(strncmp((char_t*)outFormat, (char_t*)PH_STBVIDEOTYPES_NTSC, strlen((char_t*)PH_STBVIDEOTYPES_NTSC)) != 0)
            {
                D_INFO("Encoder Output of 0x%08x (NTSC_XXX) does not match the output of renderer %s\n",
                       config->tv_standard,
                       outFormat);
            }
            break;

        case DSETV_SECAM:
            if(strncmp((char_t*)outFormat, (char_t*)PH_STBVIDEOTYPES_SECAM, strlen((char_t*)PH_STBVIDEOTYPES_SECAM)) != 0)
            {
                D_INFO("Encoder Output of 0x%08x (SECAM_XXX) does not match the output of renderer %s\n",
                       config->tv_standard,
                       outFormat);
            }
            break;

        case DSETV_DIGITAL:
        default:
            /*no worries*/
            break;
    }

    /*Copy in the current resolution.*/
    config->resolution = CONVERT_TO_DFB_OUTPUT_RESOLUTION(dencSettings.xres, dencSettings.yres);

    /*Now we need to set if we are an interlaced / progressive signal according to current settings*/
    config->scanmode = CONVERT_TO_DFB_SCANTYPE(dencSettings.scantype);

    /* Check if this matches the renderer and give a warning if not.*/
    TM_TO_DFB_RETURN_ON_ERR(phStbVideoRenderer_GetOutputScanType(phStbVideoRenderer_DisplayChain_Main,
                                                                 &interlaced),
                            "Error calling phStbVideoRenderer_GetOutputScanType Renderer(%d) 0x%08x\n",
                            phStbVideoRenderer_DisplayChain_Main, err);

    if(interlaced && (config->scanmode != DSESM_INTERLACED))
    {
        /* Renderer is outputting interlaced and encoder is not*/
        D_INFO("Renderer %d is outputting interlaced and encoder %d is not\n", phStbVideoRenderer_DisplayChain_Main, encoder);
    }
    else if(!interlaced && (config->scanmode != DSESM_PROGRESSIVE))
    {
        /* Renderer is outputting progressive and encoder is not*/
        D_INFO("Renderer %d is outputting progressive and encoder %d is not\n", phStbVideoRenderer_DisplayChain_Main, encoder);
    }

    /*Get the current output frequency and compare to encoder refresh rate.*/
    config->frequency = CONVERT_TO_DFB_REFRESH_RATE(dencSettings.refresh);
    TM_TO_DFB_RETURN_ON_ERR(phStbVideoRenderer_GetOutputFrameRate(phStbVideoRenderer_DisplayChain_Main,
                                                                  &frameRate),
                            "Error calling phStbVideoRenderer_GetOutputFrameRate Renderer(%d) 0x%08x\n",
                            phStbVideoRenderer_DisplayChain_Main, err);

    /*If I have an interlaced output on the renderer i need to double framerate before comparison with encoder
      framerate.*/
    if(interlaced)
    {
        if(frameRate == phStbVideoRenderer_FrameRate_25)
        {
            frameRate = phStbVideoRenderer_FrameRate_50;
        }
        else if(frameRate == phStbVideoRenderer_FrameRate_29_97)
        {
            frameRate = phStbVideoRenderer_FrameRate_59_94;
        }
        else if(frameRate == phStbVideoRenderer_FrameRate_30)
        {
            frameRate = phStbVideoRenderer_FrameRate_60;
        }
    }

    /*Now compare*/
    if((CONVERT_TO_DFB_FRAMERATE(frameRate)) != config->frequency)
    {

        D_INFO("Output Framerate(%x) of Renderer %d does not match that of encoder %d (%x)\n",
               frameRate,
               phStbVideoRenderer_DisplayChain_Main,
               encoder,
               config->frequency);
    }

    /* If we do not have a scart switch then we obviously cannot support SCART outputs but all else if valid*/
    if(phStbDFB_AK470XInstalled() &&
      (description->all_connectors & (DSOC_SCART | DSOC_SCART2)))
    {
        /* Now set up Slow Blanking */
        /* Get the scart switch settings and set up slow blanking options.*/
        DFB_RETURN_ON_ERR(phStbDFB_GetSetupAK470X(&avSwitchSettings),
                          "Failed to call StbDFB_GetSetupAK470X Error %d\n", err);

        /*Indicate that we support slow blanking*/
        config->flags |= DSECONF_SLOW_BLANKING;
        if(strcmp(description->name, "TV") == 0)
        {
            if(avSwitchSettings.attribute[TV_OUTPUT].src_select == SRC_PRIMARY)
            {
                //Now set the blanking default for the TV_OUTPUT and store the level in slow_blanking setting
                config->slow_blanking |= CONVERT_TO_DFB_SLOWBLANKING(avSwitchSettings.attribute[TV_OUTPUT].slow_blanking);
            }
            if(avSwitchSettings.attribute[VCR_OUTPUT].src_select == SRC_PRIMARY)
            {
                //Now set the blanking default for the VCR_OUTPUT and store the level in slow_blanking setting
                config->slow_blanking |= CONVERT_TO_DFB_SLOWBLANKING(avSwitchSettings.attribute[VCR_OUTPUT].slow_blanking);
            }
        }
        else if(strcmp(description->name, "DC_DVO") == 0)
        {
            if(avSwitchSettings.attribute[TV_OUTPUT].src_select == SRC_SECONDARY)
            {
                //Now set the blanking default for the TV_OUTPUT and store the level in slow_blanking setting
                config->slow_blanking |= CONVERT_TO_DFB_SLOWBLANKING(avSwitchSettings.attribute[TV_OUTPUT].slow_blanking);
            }
            if(avSwitchSettings.attribute[VCR_OUTPUT].src_select == SRC_SECONDARY)
            {
                //Now set the blanking default for the VCR_OUTPUT and store the level in slow_blanking setting
                config->slow_blanking |= CONVERT_TO_DFB_SLOWBLANKING(avSwitchSettings.attribute[VCR_OUTPUT].slow_blanking);
            }
        }

        /*After checking both outputs we may have a situation where we have two sets of blanking settings if so warn them*/
        if(((avSwitchSettings.attribute[TV_OUTPUT].slow_blanking) !=
           (avSwitchSettings.attribute[VCR_OUTPUT].slow_blanking)) &&
           ((avSwitchSettings.attribute[TV_OUTPUT].src_select) ==
            (avSwitchSettings.attribute[VCR_OUTPUT].src_select)))
        {
            D_INFO("The AK470X TV_OUTPUT Blanking signal is different to the VCR_OUTPUT blanking "
                   "signal yet they have the same source\n");
        }
    }

    /*Now use the videodenc framework and find out what connectors are supported.*/
    for(conIndex = 0; conIndex < VIDEODENC_CONNECTORS_MAX; conIndex++)
    {
        if(dencSettings.chosen_connectors[conIndex].in_use)
        {
            /* We have a connector that is in use.  It is the drivers
               responsibility to make sure that the chosen connectors was set up properly
               when the video denc module was started.  We just blindly read them.*/
            config->out_connectors |= CONVERT_TO_DFB_OUTPUT_CONNECTOR(dencSettings.chosen_connectors[conIndex].type,
                                                                      dencSettings.chosen_connectors[conIndex].connector_id);
        }
    }
    /* now find out the output signal.*/
    switch(dencSettings.output_signal)
    {
        case (VIDEODENC_OUTSIGNAL_CVBS|VIDEODENC_OUTSIGNAL_YC):
            config->out_signals |= (DSOS_CVBS|DSOS_YC);
            break;

        case VIDEODENC_OUTSIGNAL_CVBS:
            config->out_signals |= DSOS_CVBS;
            break;

        case VIDEODENC_OUTSIGNAL_YC:
            config->out_signals |= DSOS_YC;
            break;

        case VIDEODENC_OUTSIGNAL_YPRPB:
            config->out_signals |= DSOS_YCBCR;
            break;

        case VIDEODENC_OUTSIGNAL_RGB:
            if(config->out_connectors & DSOC_VGA)
            {
                config->out_signals |= DSOS_VGA;
            }
            else
            {
                config->out_signals |= DSOS_RGB;
            }
            break;

        case VIDEODENC_OUTSIGNAL_DIGITAL:
            if(config->out_connectors & DSOC_HDMI)
            {
                config->out_signals |= DSOS_HDMI;
            }
            else
            {
                config->out_signals |= DSOS_656;
            }
            break;
        default:
            break;
    }

    /* Set up macrovision */
    config->macrovision = DSEM_OFF;
    /* Set up CGMS */
    config->cgms = DSECGMS_OFF;
    /* Set up WSS */
    config->wss.enable = DSEWG_DISABLE;
    config->wss.aspect_ratio = DSEWAR_ASPECT_RATIO_FF_4TO3;
    config->wss.mode = DSEWM_MODE_CAMERA;
    config->wss.sbt = DSEWS_NO_SUBTITLES_WITHIN_TELETEXT;
    config->wss.sbt_type = DSEWSM_SBT_TYPE_NO_OPEN;
    config->wss.colour = DSEWCC_STANDARD_CODING;
    config->wss.helper = DSEWH_NO_HELPER;
    config->wss.surround = DSEWSS_NO_SURROUND_SOUND;
    config->wss.copyright = DSEWC_NO_COPYRIGHT_OR_UNKNOWN;
    config->wss.generation = DSEWG_COPYING_NOT_RESTRICTED;

    /*Indicate what has changed. .*/
    config->flags |= (DSECONF_CONNECTORS | DSECONF_OUT_SIGNALS | DSECONF_TV_STANDARD | DSECONF_RESOLUTION | DSECONF_FREQUENCY | DSECONF_SCANMODE | DSECONF_MACROVISION | DSECONF_CGMS | DSECONF_WSS);

    /*Indicate that the encoder colour settings can be adjusted */
    config->flags |= DSECONF_ADJUSTMENT;

    D_DEBUG_EXIT( phStbDFB_Encoders, "Default Output 0x%08x, Scantype 0x%08x, FrameRate 0x%08x connectors 0x%08x=> 0x%x",
                  config->tv_standard,
                  config->scanmode,
                  config->frequency,
                  config->out_connectors,
                  result);

    return result;
}

/******************************************************************************/

extern DFBResult phStbDFB_TestEncoderConfig(
    CoreScreen                   *screen,
    void                         *driver_data,
    void                         *screen_data,
    int                           encoder,
    const DFBScreenEncoderConfig *config,
    DFBScreenEncoderConfigFlags  *failed)
{
    DFBResult result = DFB_OK;
    phStbDFB_ScreenData_t *pScreenData = (phStbDFB_ScreenData_t*)screen_data;
    struct videodenc_var_screeninfo dencSettings;
    bool foundMatch = false;

    D_DEBUG_ENTER( phStbDFB_Encoders, "");

    /*If any flags are set other than the supported flags then or them to
      failed value and return*/
    if (config->flags & ~PH_STBDFB_MAIN_SCREEN_ENCODER_CONFIGFLAGS)
    {
        *failed |= ~PH_STBDFB_MAIN_SCREEN_ENCODER_CONFIGFLAGS;
        result = DFB_UNSUPPORTED;
        goto RETURN;
    }
    if(config->flags & (DSECONF_TV_STANDARD | DSECONF_CONNECTORS | DSECONF_OUT_SIGNALS | DSECONF_RESOLUTION | DSECONF_MACROVISION | DSECONF_CGMS | DSECONF_WSS))
    {
        /*Now get the denc setup for the specified encoder this is used in combination with the scart switch
          to determine the current setup of signals etc.
          */
        DFB_RETURN_ON_ERR(phStbDFB_GetDencSetup(pScreenData,
                                     encoder,
                                     &dencSettings),
                          "Failed to call StbDFB_GetDencSetup Error %d\n", err);

        if (config->flags & DSECONF_RESOLUTION)
        {
            dencSettings.tv_standard = VIDEODENC_TV_STANDARD_DIGITAL;
            /*Now check if scantype, resolution and frequency are supported by our renderer.*/
            switch(config->resolution)
            {
                case DSOR_720_480:
                    /*support both i / p at 60*/
                    if(config->frequency == DSEF_60HZ)
                    {
                        if(config->scanmode == DSESM_PROGRESSIVE)
                        {
                            foundMatch = true;
                        }
                        else if(config->scanmode == DSESM_INTERLACED)
                        {
                            foundMatch = true;
                            dencSettings.tv_standard = CONVERT_FROM_DFB_TVSTANDARD(config->tv_standard);
                        }
                    }
                    else
                    {
                        if(config->frequency == DSEF_59_94HZ)
                        {
                            if(config->scanmode == DSESM_PROGRESSIVE)
                            {
                                foundMatch = true;
                            }
                        }
                    }
                    break;

                case DSOR_720_576:
                    /*support both i / p at 60*/
                    if(config->frequency == DSEF_60HZ)
                    {
                        if(config->scanmode == DSESM_PROGRESSIVE)
                        {
                            foundMatch = true;
                        }
                    }
                    else if(config->frequency == DSEF_50HZ)
                    {
                        if(config->scanmode == DSESM_PROGRESSIVE)
                        {
                            foundMatch = true;
                        }
                        else if(config->scanmode == DSESM_INTERLACED)
                        {
                            foundMatch = true;
                            dencSettings.tv_standard = CONVERT_FROM_DFB_TVSTANDARD(config->tv_standard);
                        }
                    }
                    break;

                case DSOR_640_480:
                    /*support p at 60*/
                    if ((config->frequency == DSEF_60HZ && config->scanmode == DSESM_PROGRESSIVE))
                    {
                        foundMatch = true;
                    }
                    break;

                case DSOR_800_600:
                    /*support p at 75*/
                    if ((config->frequency == DSEF_75HZ && config->scanmode == DSESM_PROGRESSIVE))
                    {
                        foundMatch = true;
                    }
                    break;

                case DSOR_1024_768:
                    /*support p at 75*/
                    if ((config->frequency == DSEF_75HZ && config->scanmode == DSESM_PROGRESSIVE))
                    {
                        foundMatch = true;
                    }
                    break;

                case DSOR_1280_768:
                    /*support p at 60*/
                    if ((config->frequency == DSEF_60HZ && config->scanmode == DSESM_PROGRESSIVE))
                    {
                        foundMatch = true;
                    }

                case DSOR_1280_800:
                    /*support p at 60*/
                    if ((config->frequency == DSEF_60HZ && config->scanmode == DSESM_PROGRESSIVE))
                    {
                        foundMatch = true;
                    }

                case DSOR_1360_768:
                    /*support p at 60*/
                    if ((config->frequency == DSEF_60HZ && config->scanmode == DSESM_PROGRESSIVE))
                    {
                        foundMatch = true;
                    }
                    break;

                case DSOR_1280_720:
                    /*support both p at 50/60*/
                    if ((config->frequency == DSEF_60HZ && config->scanmode == DSESM_PROGRESSIVE) ||
                        (config->frequency == DSEF_59_94HZ && config->scanmode == DSESM_PROGRESSIVE) ||
                        (config->frequency == DSEF_50HZ && config->scanmode == DSESM_PROGRESSIVE))
                    {
                        foundMatch = true;
                    }
                    break;

                case DSOR_1920_1080:
                    /*support both i and p at 50/60 and p at 29.97*/
                    if((config->frequency == DSEF_60HZ) ||
                       (config->frequency == DSEF_59_94HZ) ||
                       (config->frequency == DSEF_50HZ) ||
                       (config->frequency == DSEF_29_97HZ && config->scanmode == DSESM_PROGRESSIVE))
                    {
                        foundMatch = true;
                    }
                    break;

                case DSOR_1152_864:
                case DSOR_1280_960:
                case DSOR_1280_1024:
                case DSOR_1400_1050:
                case DSOR_1600_1200:
                default:
                    break;
            }
            /*Get xres and yres from DFB output*/
            dencSettings.xres = CONVERT_FROM_OUTPUT_RESOLUTION_TO_X(config->resolution);
            dencSettings.yres = CONVERT_FROM_OUTPUT_RESOLUTION_TO_Y(config->resolution);
            dencSettings.refresh = CONVERT_FROM_DFB_REFRESH_RATE(config->frequency);
            dencSettings.scantype = CONVERT_FROM_DFB_SCANTYPE(config->scanmode);
            dencSettings.output_signal = CONVERT_FROM_DFB_OUTPUT_SIGNAL(config->out_signals);

            if(!foundMatch)
            {
                D_DEBUG_AT( phStbDFB_Encoders, " -> config->resolution 0x%08x: config->frequency 0x%08x: config->scanmode 0x%08x: Not supported\n",
                            config->resolution,
                            config->frequency,
                            config->scanmode);

                *failed |= (DSECONF_RESOLUTION | DSECONF_FREQUENCY | DSECONF_SCANMODE);
                result = DFB_UNSUPPORTED;
                goto RETURN;
            }
        }

        if(config->flags & DSECONF_MACROVISION)
        {
            switch (config->macrovision)
            {
                case(DSEM_AGC_AND_2L_CSP) :
                    dencSettings.macro_type = VIDEODENC_MACROVISION_TYPE_2_LINE;
                    break;
                case(DSEM_AGC_AND_4L_CSP) :
                    dencSettings.macro_type = VIDEODENC_MACROVISION_TYPE_4_LINE;
                    break;
                case(DSEM_AGC_ONLY) :
                    dencSettings.macro_type = VIDEODENC_MACROVISION_TYPE_AGC;
                    break;
                default:
                    dencSettings.macro_type = VIDEODENC_MACROVISION_TYPE_DISABLE;
                    break;
            }
        }

        if(config->flags & DSECONF_CGMS)
        {
            switch (config->cgms)
            {
                case(DSECGMS_NO_COPY_RESTRICTION) :
                    dencSettings.cgms_type = VIDEODENC_CGMS_NO_COPY_RESTRICTION;
                    break;
                case(DSECGMS_COPY_NO_MORE) :
                    dencSettings.cgms_type = VIDEODENC_CGMS_COPY_NO_MORE;
                    break;
                case(DSECGMS_COPY_ONCE_ALLOWED) :
                    dencSettings.cgms_type = VIDEODENC_CGMS_COPY_ONCE_ALLOWED;
                    break;
                case(DSECGMS_NO_COPYING_PERMITTED) :
                    dencSettings.cgms_type = VIDEODENC_CGMS_NO_COPYING_PERMITTED;
                    break;
                default:
                    dencSettings.cgms_type = VIDEODENC_CGMS_DISABLE;
                    break;
            }
        }

        if(config->flags & DSECONF_WSS)
        {
            dencSettings.wss_type.enable = config->wss.enable;

            switch (config->wss.aspect_ratio)
            {
                case(DSEWAR_ASPECT_RATIO_LB_14TO9_CTR) :
                    dencSettings.wss_type.aspect = VIDEODENC_ASPECT_RATIO_LB_14TO9_CTR;
                    break;
                case(DSEWAR_ASPECT_RATIO_LB_14TO9_TOP) :
                    dencSettings.wss_type.aspect = VIDEODENC_ASPECT_RATIO_LB_14TO9_TOP;
                    break;
                case(DSEWAR_ASPECT_RATIO_LB_16TO9_CTR) :
                    dencSettings.wss_type.aspect = VIDEODENC_ASPECT_RATIO_LB_16TO9_CTR;
                    break;
                case(DSEWAR_ASPECT_RATIO_LB_16TO9_TOP) :
                    dencSettings.wss_type.aspect = VIDEODENC_ASPECT_RATIO_LB_16TO9_TOP;
                    break;
                case(DSEWAR_ASPECT_RATIO_LB_P16TO9_CTR) :
                    dencSettings.wss_type.aspect = VIDEODENC_ASPECT_RATIO_LB_P16TO9_CTR;
                    break;
                case(DSEWAR_ASPECT_RATIO_FF_14TO9_CTR) :
                    dencSettings.wss_type.aspect = VIDEODENC_ASPECT_RATIO_FF_14TO9_CTR;
                    break;
                case(DSEWAR_ASPECT_RATIO_FF_16TO9) :
                    dencSettings.wss_type.aspect = VIDEODENC_ASPECT_RATIO_FF_16TO9;
                    break;
                default:
                    dencSettings.wss_type.aspect = VIDEODENC_ASPECT_RATIO_FF_4TO3;
                    break;
            }

            switch (config->wss.mode)
            {
                case(DSEWM_MODE_FILM) :
                    dencSettings.wss_type.mode = VIDEODENC_MODE_FILM;
                    break;
                default:
                    dencSettings.wss_type.mode = VIDEODENC_MODE_CAMERA;
                    break;
            }

            dencSettings.wss_type.motion_adaptive_colour = (config->wss.colour == DSEWCC_MOTION_ADAPTATIVE_COLOUR_PLUS);
            dencSettings.wss_type.helper = (config->wss.helper == DSEWH_MODULATED_HELPER);
            dencSettings.wss_type.subtitles_enabled = (config->wss.sbt == DSEWS_SUBTITLES_WITHIN_TELETEXT);
            switch (config->wss.sbt_type)
            {
                case(DSEWSM_SBT_TYPE_INSIDE_IMAGE) :
                    dencSettings.wss_type.subtitle_type = VIDEODENC_SBT_TYPE_INSIDE_IMAGE;
                    break;
                case(DSEWSM_SBT_TYPE_OUTSIDE_IMAGE) :
                    dencSettings.wss_type.subtitle_type = VIDEODENC_SBT_TYPE_OUTSIDE_IMAGE;
                    break;
                default:
                    dencSettings.wss_type.subtitle_type = VIDEODENC_SBT_TYPE_NO_OPEN;
                    break;
            }
            dencSettings.wss_type.surround_sound = (config->wss.surround == DSEWSS_SURROUND_SOUND_MODE);
            dencSettings.wss_type.copyright = (config->wss.copyright == DSEWC_COPYRIGHT_ASSERTED);
            dencSettings.wss_type.copy_restricted = (config->wss.generation == DSEWG_COPYING_RESTRICTED);
        }

        dencSettings.activate = VIDEODENC_ACTIVATE_TEST;
        result = StbDFB_SetupVideoConnectors(pScreenData,
                                             encoder,
                                             &dencSettings,
                                             config);

        /* We have got the settings, changed the output signal and added any new connectors
           that were requested.  We now need to check if this is supported.*/
        DFB_RETURN_ON_ERR(phStbDFB_SetupDenc(pScreenData,
                                             encoder,
                                             &dencSettings),
                          "Failed to call StbDFB_SetupDenc (Renderer %d:%d) %d", phStbVideoRenderer_DisplayChain_Main, encoder, err);

        if(result != DFB_OK)
        {
            D_DEBUG_AT( phStbDFB_Encoders, " -> One of the following options was not supported (DSECONF_CONNECTORS | DSECONF_OUT_SIGNALS | DSECONF_RESOLUTION)\n");

            *failed |= (DSECONF_CONNECTORS | DSECONF_OUT_SIGNALS | DSECONF_RESOLUTION);
            result = DFB_UNSUPPORTED;
            goto RETURN;
        }
    }

    /*They have changed the blanking mode*/
    if(config->flags & DSECONF_SLOW_BLANKING)
    {
        /*We are setting slow blanking on TV_OUTPUT*/
        if(config->out_connectors & DSOC_SCART)
        {
            if(config->slow_blanking & DSOSB_MONITOR)
            {
                /*Cannot SLOW Monitor on TV_OUTPUT*/
                D_INFO("Cannot DSOSB_MONITOR on TV SCART (DSOC_SCART)\n");

                *failed |= (DSECONF_SLOW_BLANKING);
                result = DFB_UNSUPPORTED;
                goto RETURN;
            }
        }
        if(config->out_connectors & DSOC_SCART2)
        {
            if(config->slow_blanking & DSOSB_FOLLOW)
            {
                /*Cannot SLOW Follow on VCR_OUTPUT*/
                D_INFO("Cannot use DSOSB_FOLLOW on VCR SCART (DSOC_SCART2)\n");

                *failed |= (DSECONF_SLOW_BLANKING);
                result = DFB_UNSUPPORTED;
                goto RETURN;
            }
        }
    }
RETURN:
    D_DEBUG_EXIT( phStbDFB_Encoders, "result => 0x%08x", result);
    return result;
}

/******************************************************************************/
extern DFBResult phStbDFB_SetEncoderConfig(
    CoreScreen                   *screen,
    void                         *driver_data,
    void                         *screen_data,
    int                           encoder,
    const DFBScreenEncoderConfig *config)
{
    DFBResult result = DFB_OK;
    phStbDFB_ScreenData_t *pScreenData = (phStbDFB_ScreenData_t*)screen_data;
    String vidMode = NULL;
    bool update = false;
    struct videodenc_var_screeninfo dencSettings;

    D_DEBUG_ENTER( phStbDFB_Encoders, "config->flags 0x%08x config->connectors 0x%08x\n",
                   config->flags,
                   config->out_connectors);

    DFB_RETURN_ON_ERR(phStbDFB_GetDencSetup(pScreenData,
                                          encoder,
                                          &dencSettings),
                      "Failed to call StbDFB_GetDencSetup(Renderer %d) %d", phStbVideoRenderer_DisplayChain_Main, err);

    if(config->flags & (DSECONF_CONNECTORS | DSECONF_OUT_SIGNALS))
    {
        DFB_RETURN_ON_ERR(StbDFB_SetupVideoConnectors(pScreenData,
                                                      encoder,
                                                      &dencSettings,
                                                      config),
                          "Failed to call StbDFB_SetupVideoConnectors(Renderer %d) %d", phStbVideoRenderer_DisplayChain_Main, err);
        update = true;
    }//(DSECONF_CONNECTORS | DSECONF_OUT_SIGNALS)

    if(config->flags & (DSECONF_TV_STANDARD | DSECONF_SCANMODE | DSECONF_FREQUENCY | DSECONF_RESOLUTION))
    {
        struct videodenc_var_screeninfo requestedSettings;
        if (config->flags & DSECONF_RESOLUTION)
        {
            requestedSettings.tv_standard = VIDEODENC_TV_STANDARD_DIGITAL;
            switch(config->resolution)
            {
                case DSOR_720_480:
                    /*support both i / p at 60*/
                    if(config->frequency == DSEF_60HZ)
                    {
                        if(config->scanmode == DSESM_PROGRESSIVE)
                        {
                            vidMode = PH_STBVIDEOTYPES_720_480_60P;
                        }
                        else if(config->scanmode == DSESM_INTERLACED)
                        {
                            if (config->tv_standard == DSETV_PAL_M)
                            {
                                vidMode = PH_STBVIDEOTYPES_PAL_60;
                            }
                            else
                            {
                                vidMode = PH_STBVIDEOTYPES_NTSC;
                            }
                            requestedSettings.tv_standard = CONVERT_FROM_DFB_TVSTANDARD(config->tv_standard);
                        }
                    }
                    else
                    {
                        if(config->frequency == DSEF_59_94HZ)
                        {
                            if(config->scanmode == DSESM_PROGRESSIVE)
                            {
                                vidMode = PH_STBVIDEOTYPES_720_480_59_94P;
                            }
                        }
                    }
                    break;

                case DSOR_720_576:
                    /*support both i / p at 60*/
                    if(config->frequency == DSEF_60HZ)
                    {
                        if(config->scanmode == DSESM_PROGRESSIVE)
                        {
                            vidMode = PH_STBVIDEOTYPES_720_576_60P;
                        }
                        else
                        {
                            vidMode = PH_STBVIDEOTYPES_PAL_60;
                            requestedSettings.tv_standard = CONVERT_FROM_DFB_TVSTANDARD(config->tv_standard);
                        }
                    }
                    else if(config->frequency == DSEF_50HZ)
                    {
                        if(config->scanmode == DSESM_PROGRESSIVE)
                        {
                            vidMode = PH_STBVIDEOTYPES_720_576_50P;
                        }
                        else if(config->scanmode == DSESM_INTERLACED)
                        {
                            if (config->tv_standard == DSETV_SECAM)
                            {
                                vidMode = PH_STBVIDEOTYPES_SECAM;
                            }
                            else
                            {
                                vidMode = PH_STBVIDEOTYPES_PAL;
                            }
                            requestedSettings.tv_standard = CONVERT_FROM_DFB_TVSTANDARD(config->tv_standard);
                        }
                    }
                    break;

                case DSOR_640_480:
                if(config->scanmode == DSESM_PROGRESSIVE)
                {
                    /*support p at 60 */
                    if(config->frequency == DSEF_60HZ)
                    {
                        vidMode = PH_STBVIDEOTYPES_640_480_60P;
                    }
                }
                break;

                case DSOR_800_600:
                    if(config->scanmode == DSESM_PROGRESSIVE)
                    {
                        /*support p at 75 */
                        if(config->frequency == DSEF_75HZ)
                        {
                            vidMode = PH_STBVIDEOTYPES_800_600_75P;
                        }
                    }
                    break;

                case DSOR_1024_768:
                    if(config->scanmode == DSESM_PROGRESSIVE)
                    {
                        /*support p at 75 */
                        if(config->frequency == DSEF_75HZ)
                        {
                            vidMode = PH_STBVIDEOTYPES_1024_768_75P;
                        }
                    }
                    break;

                case DSOR_1280_768:
                    if(config->scanmode == DSESM_PROGRESSIVE)
                    {
                        /*support p at 60 */
                        if(config->frequency == DSEF_60HZ)
                        {
                            vidMode = PH_STBVIDEOTYPES_1280_768_60P;
                        }
                    }
                    break;


                case DSOR_1280_800:
                    if(config->scanmode == DSESM_PROGRESSIVE)
                    {
                        /*support p at 60 */
                        if(config->frequency == DSEF_60HZ)
                        {
                            vidMode = PH_STBVIDEOTYPES_1280_800_60P;
                        }
                    }
                    break;

                case DSOR_1360_768:
                    if(config->scanmode == DSESM_PROGRESSIVE)
                    {
                        /*support p at 60 */
                        if(config->frequency == DSEF_60HZ)
                        {
                            vidMode = PH_STBVIDEOTYPES_1360_768_60P;
                        }
                    }
                    break;

                case DSOR_1280_720:
                    if(config->scanmode == DSESM_PROGRESSIVE)
                    {
                        /*support p at 50/60/59.94 */
                        if(config->frequency == DSEF_60HZ)
                        {
                            vidMode = PH_STBVIDEOTYPES_1280_720_60P;
                        }
                        else
                        if(config->frequency == DSEF_59_94HZ)
                        {
                            vidMode = PH_STBVIDEOTYPES_1280_720_59_94P;
                        }
                        else
                        if(config->frequency == DSEF_50HZ)
                        {
                            vidMode = PH_STBVIDEOTYPES_1280_720_50P;
                        }
                    }
                    break;

                case DSOR_1920_1080:
					/*support i at 50/60/59.94*/
					if(config->frequency == DSEF_60HZ)
					{
                    	if(config->scanmode == DSESM_INTERLACED)
                    		vidMode = PH_STBVIDEOTYPES_1920_1080_60i;
                    	else
                    		vidMode = PH_STBVIDEOTYPES_1920_1080_60p;
					}
					else
					if(config->frequency == DSEF_59_94HZ)
					{
                    	if(config->scanmode == DSESM_INTERLACED)
                    		vidMode = PH_STBVIDEOTYPES_1920_1080_59_94i;
                    	else
                    		vidMode = PH_STBVIDEOTYPES_1920_1080_59_94p;
					}
					else
					if(config->frequency == DSEF_50HZ)
					{
                    	if(config->scanmode == DSESM_INTERLACED)
							vidMode = PH_STBVIDEOTYPES_1920_1080_50i;
						else
							vidMode = PH_STBVIDEOTYPES_1920_1080_50p;
					}
                    else if(config->frequency == DSEF_29_97HZ)
                    {
                    	if(config->scanmode != DSESM_INTERLACED)
                            vidMode = PH_STBVIDEOTYPES_1920_1080_29_97p;
                    }
                    break;

                case DSOR_1152_864:
                case DSOR_1280_960:
                case DSOR_1280_1024:
                case DSOR_1400_1050:
                case DSOR_1600_1200:
                default:
                    break;

            }

            requestedSettings.xres = CONVERT_FROM_OUTPUT_RESOLUTION_TO_X(config->resolution);
            requestedSettings.yres = CONVERT_FROM_OUTPUT_RESOLUTION_TO_Y(config->resolution);
            requestedSettings.refresh = CONVERT_FROM_DFB_REFRESH_RATE(config->frequency);
            requestedSettings.scantype = CONVERT_FROM_DFB_SCANTYPE(config->scanmode);
            requestedSettings.output_signal = CONVERT_FROM_DFB_OUTPUT_SIGNAL(config->out_signals);

            /* Check to see if the display mode has changed */
            if ( (requestedSettings.xres != dencSettings.xres) ||
                 (requestedSettings.yres != dencSettings.yres) ||
                 (requestedSettings.scantype != dencSettings.scantype) ||
                 (requestedSettings.refresh != dencSettings.refresh) ||
                 (requestedSettings.output_signal != dencSettings.output_signal) ||
                 (requestedSettings.tv_standard != dencSettings.tv_standard) )
            {
                if(vidMode != NULL)
                {
                    TM_TO_DFB_RETURN_ON_ERR(phStbVideoRenderer_SetOutputFormat(phStbVideoRenderer_DisplayChain_Main,
                                                                               vidMode),
                                            "Error calling phStbVideoRenderer_SetOutputFormat (videoMode=%s) 0x%08x\n",
                                            vidMode, err);
                }
                dencSettings.xres = requestedSettings.xres;
                dencSettings.yres = requestedSettings.yres;
                dencSettings.refresh = requestedSettings.refresh;
                dencSettings.scantype = requestedSettings.scantype;
                dencSettings.output_signal = requestedSettings.output_signal;
                dencSettings.tv_standard = requestedSettings.tv_standard;
                update = true;
            }
        }
    } //config->flags & (DSECONF_TV_STANDARD | DSECONF_SCANMODE | DSECONF_FREQUENCY | DSECONF_RESOLUTION)

    if(config->flags & DSECONF_MACROVISION)
    {
        switch (config->macrovision)
        {
            case(DSEM_AGC_AND_2L_CSP) :
                dencSettings.macro_type = VIDEODENC_MACROVISION_TYPE_2_LINE;
                break;
            case(DSEM_AGC_AND_4L_CSP) :
                dencSettings.macro_type = VIDEODENC_MACROVISION_TYPE_4_LINE;
                break;
            case(DSEM_AGC_ONLY) :
                dencSettings.macro_type = VIDEODENC_MACROVISION_TYPE_AGC;
                break;
            default:
                dencSettings.macro_type = VIDEODENC_MACROVISION_TYPE_DISABLE;
                break;
        }
        update = true;
    }

    if(config->flags & DSECONF_CGMS)
    {
        switch (config->cgms)
        {
            case(DSECGMS_NO_COPY_RESTRICTION) :
                dencSettings.cgms_type = VIDEODENC_CGMS_NO_COPY_RESTRICTION;
                break;
            case(DSECGMS_COPY_NO_MORE) :
                dencSettings.cgms_type = VIDEODENC_CGMS_COPY_NO_MORE;
                break;
            case(DSECGMS_COPY_ONCE_ALLOWED) :
                dencSettings.cgms_type = VIDEODENC_CGMS_COPY_ONCE_ALLOWED;
                break;
            case(DSECGMS_NO_COPYING_PERMITTED) :
                dencSettings.cgms_type = VIDEODENC_CGMS_NO_COPYING_PERMITTED;
                break;
            default:
                dencSettings.cgms_type = VIDEODENC_CGMS_DISABLE;
                break;
        }
        update = true;
    }

    if(config->flags & DSECONF_WSS)
    {
        dencSettings.wss_type.enable = config->wss.enable;

        switch (config->wss.aspect_ratio)
        {
            case(DSEWAR_ASPECT_RATIO_LB_14TO9_CTR) :
                dencSettings.wss_type.aspect = VIDEODENC_ASPECT_RATIO_LB_14TO9_CTR;
                break;
            case(DSEWAR_ASPECT_RATIO_LB_14TO9_TOP) :
                dencSettings.wss_type.aspect = VIDEODENC_ASPECT_RATIO_LB_14TO9_TOP;
                break;
            case(DSEWAR_ASPECT_RATIO_LB_16TO9_CTR) :
                dencSettings.wss_type.aspect = VIDEODENC_ASPECT_RATIO_LB_16TO9_CTR;
                break;
            case(DSEWAR_ASPECT_RATIO_LB_16TO9_TOP) :
                dencSettings.wss_type.aspect = VIDEODENC_ASPECT_RATIO_LB_16TO9_TOP;
                break;
            case(DSEWAR_ASPECT_RATIO_LB_P16TO9_CTR) :
                dencSettings.wss_type.aspect = VIDEODENC_ASPECT_RATIO_LB_P16TO9_CTR;
                break;
            case(DSEWAR_ASPECT_RATIO_FF_14TO9_CTR) :
                dencSettings.wss_type.aspect = VIDEODENC_ASPECT_RATIO_FF_14TO9_CTR;
                break;
            case(DSEWAR_ASPECT_RATIO_FF_16TO9) :
                dencSettings.wss_type.aspect = VIDEODENC_ASPECT_RATIO_FF_16TO9;
                break;
            default:
                dencSettings.wss_type.aspect = VIDEODENC_ASPECT_RATIO_FF_4TO3;
                break;
        }

        switch (config->wss.mode)
        {
            case(DSEWM_MODE_FILM) :
                dencSettings.wss_type.mode = VIDEODENC_MODE_FILM;
                break;
            default:
                dencSettings.wss_type.mode = VIDEODENC_MODE_CAMERA;
                break;
        }

        dencSettings.wss_type.motion_adaptive_colour = (config->wss.colour == DSEWCC_MOTION_ADAPTATIVE_COLOUR_PLUS);
        dencSettings.wss_type.helper = (config->wss.helper == DSEWH_MODULATED_HELPER);
        dencSettings.wss_type.subtitles_enabled = (config->wss.sbt == DSEWS_SUBTITLES_WITHIN_TELETEXT);
        switch (config->wss.sbt_type)
        {
            case(DSEWSM_SBT_TYPE_INSIDE_IMAGE) :
                dencSettings.wss_type.subtitle_type = VIDEODENC_SBT_TYPE_INSIDE_IMAGE;
                break;
            case(DSEWSM_SBT_TYPE_OUTSIDE_IMAGE) :
                dencSettings.wss_type.subtitle_type = VIDEODENC_SBT_TYPE_OUTSIDE_IMAGE;
                break;
            default:
                dencSettings.wss_type.subtitle_type = VIDEODENC_SBT_TYPE_NO_OPEN;
                break;
        }
        dencSettings.wss_type.surround_sound = (config->wss.surround == DSEWSS_SURROUND_SOUND_MODE);
        dencSettings.wss_type.copyright = (config->wss.copyright == DSEWC_COPYRIGHT_ASSERTED);
        dencSettings.wss_type.copy_restricted = (config->wss.generation == DSEWG_COPYING_RESTRICTED);
        update = true;
    }

    if (update)
    {
        dencSettings.activate = VIDEODENC_ACTIVATE_NOW;
        DFB_RETURN_ON_ERR(phStbDFB_SetupDenc(pScreenData,
                                           encoder,
                                           &dencSettings),
                          "Failed to call StbDFB_SetupDenc (Renderer %d:%d) %d", phStbVideoRenderer_DisplayChain_Main, encoder, err);
    }

    /* Slow blanking handling */
    if(phStbDFB_AK470XInstalled())
    {
        /* The AV switch (AK470X) settings */
        av_switch_data avSwitchSettings;
        bool ak470xUpdated = false;

        DFB_RETURN_ON_ERR(phStbDFB_GetSetupAK470X(&avSwitchSettings),
                          "Failed to call StbDFB_GetSetupAK470X => %d", err);

        if (config->flags & DSECONF_OUT_SIGNALS)
        {
            /*Setup all the necessary settings for the TV_OUTPUT*/
            if(config->out_connectors & DSOC_SCART)
            {
                /*Set the ak470x display mode*/
                if(dencSettings.output_signal == VIDEODENC_OUTSIGNAL_RGB)
                {
                    avSwitchSettings.attribute[TV_OUTPUT].display_mode = MODE_RGB;
                }
                else
                if(dencSettings.output_signal == VIDEODENC_OUTSIGNAL_CVBS)
                {
                    avSwitchSettings.attribute[TV_OUTPUT].display_mode = MODE_CVBS;
                }
                else
                {
                    avSwitchSettings.attribute[TV_OUTPUT].display_mode = MODE_YC;
                }
                ak470xUpdated = true;
            }
        }

        /*They have changed the blanking mode*/
        if(config->flags & DSECONF_SLOW_BLANKING)
        {
            blanking_enum blanking;

            /*Convert from DFB blanking to local signal*/
            blanking = CONVERT_FROM_DFB_SLOWBLANKING(config->slow_blanking);

            /*Setup all the necessary settings for the TV_OUTPUT*/
            if(config->out_connectors & DSOC_SCART)
            {
                /*Set the ak470x vid signal mode*/
                if((avSwitchSettings.attribute[TV_OUTPUT].slow_blanking != blanking))
                {
                    avSwitchSettings.attribute[TV_OUTPUT].slow_blanking = blanking;
                    ak470xUpdated = true;
                }
            }
            /*Setup all the necessary settings for the VCR_OUTPUT*/
            if(config->out_connectors & DSOC_SCART2)
            {
                /*Set the ak470x vid signal mode*/
                if((avSwitchSettings.attribute[VCR_OUTPUT].slow_blanking != blanking))
                {
                    avSwitchSettings.attribute[VCR_OUTPUT].slow_blanking = blanking;
                    ak470xUpdated = true;
                }
            }
        } //config->flags & DSECONF_SLOW_BLANKING

        /*Write the settings to the board*/
        if(ak470xUpdated)
        {
            DFB_RETURN_ON_ERR(phStbDFB_SetupAK470X(&avSwitchSettings),
                              "Failed to call StbDFB_SetupAK470X (Renderer %d) %d", phStbVideoRenderer_DisplayChain_Main, err);
        }
    } //StbDFB_AK470XInstalled()

    /* Slow blanking handling */
    if(phStbDFB_UDA3000Installed())
    {
        /* The AV switch (UDA3000) settings */
        phStbScartSwitch_data_t avSwitchSettings;
        bool uda3000Updated = false;

        DFB_RETURN_ON_ERR(phStbDFB_GetSetupUDA3000(&avSwitchSettings),
                          "Failed to call StbDFB_GetSetupUDA3000 => %d", err);

        if (config->flags & DSECONF_OUT_SIGNALS)
        {
            /* Setup all the necessary settings for the TV_OUTPUT */
            if(config->out_connectors & DSOC_SCART)
            {
                /* Set the uda3000 display mode */
                if(dencSettings.output_signal == VIDEODENC_OUTSIGNAL_RGB)
                {
                    avSwitchSettings.attribute[TV_OUTPUT].display_mode = MODE_RGB;
                }
                else
                if(dencSettings.output_signal == VIDEODENC_OUTSIGNAL_CVBS)
                {
                    avSwitchSettings.attribute[TV_OUTPUT].display_mode = MODE_CVBS;
                }
                else
                {
                    avSwitchSettings.attribute[TV_OUTPUT].display_mode = MODE_YC;
                }
                uda3000Updated = true;
            }
        }

        /* They have changed the blanking mode */
        if(config->flags & DSECONF_SLOW_BLANKING)
        {
            blanking_enum blanking;

            /*Convert from DFB blanking to local signal*/
            blanking = CONVERT_FROM_DFB_SLOWBLANKING(config->slow_blanking);

            /*Setup all the necessary settings for the TV_OUTPUT*/
            if(config->out_connectors & DSOC_SCART)
            {
                /*Set the ak470x vid signal mode*/
                if((avSwitchSettings.attribute[TV_OUTPUT].slow_blanking != blanking))
                {
                    avSwitchSettings.attribute[TV_OUTPUT].slow_blanking = blanking;
                    uda3000Updated = true;
                }
            }
            /*Setup all the necessary settings for the VCR_OUTPUT*/
            if(config->out_connectors & DSOC_SCART2)
            {
                /*Set the ak470x vid signal mode*/
                if((avSwitchSettings.attribute[VCR_OUTPUT].slow_blanking != blanking))
                {
                    avSwitchSettings.attribute[VCR_OUTPUT].slow_blanking = blanking;
                    uda3000Updated = true;
                }
            }
        } //config->flags & DSECONF_SLOW_BLANKING

        /*Write the settings to the board*/
        if(uda3000Updated)
        {
            DFB_RETURN_ON_ERR(phStbDFB_SetupUDA3000(&avSwitchSettings),
                              "Failed to call StbDFB_SetupUDA3000 (Renderer %d) %d", phStbVideoRenderer_DisplayChain_Main, err);
        }
    } //StbDFB_UDA3000Installed()

    /*They have changed the colour adjustment mode*/
    if(config->flags & DSECONF_ADJUSTMENT)
    {
        if (config->adjustment.flags & DCAF_GAMMA)
        {
            uint32_t i;
            int err;
            uint32_t gammaValues[MAX_TABLE_ENTRIES];

            for(i=0; i<MAX_TABLE_ENTRIES; i++)
            {
                double ratio = (double)((double)gamma_table[i] / (double)gamma_table[MAX_TABLE_ENTRIES-1]);

                gammaValues[i] = (uint32_t) ((pow(ratio, config->adjustment.gamma) * (double)gamma_table[MAX_TABLE_ENTRIES-1]) + 0.5);
            }

            err = phStbDFB_SetupDencGamma(pScreenData, encoder, gammaValues);

            if (err != 0)
            {
                DBG_ASSERT2(err == 0, ("err=0x%x\n", err));
                result = DFB_FAILURE;
            }
        }
    }

    D_DEBUG_EXIT( phStbDFB_Encoders, "result => 0x%08x", result);
    return result;
}

/******************************************************************************/
static DFBResult StbDFB_SetupVideoConnectors(phStbDFB_ScreenData_t *pScreenData,
                                             uint32_t encoder,
                                             struct videodenc_var_screeninfo *pDencSettings,
                                             const DFBScreenEncoderConfig *config)
{
    DFBResult result = DFB_OK;
    /*For each DFB connector add it to var screeninfo (unless already there in which case
      return as already supported.
      */
    if(config->out_connectors & DSOC_VGA)
    {
        result = StbDFB_AddVideoConnector(pDencSettings, DSOC_VGA);
        D_ASSERT(result == DFB_OK);
    }
    else
    {
        /*remove any VGA connector*/
        result = StbDFB_RemoveVideoConnector(pDencSettings, DSOC_VGA);
        D_ASSERT(result == DFB_OK);
    }
    if(config->out_connectors & DSOC_SCART)
    {
        result = StbDFB_AddVideoConnector(pDencSettings, DSOC_SCART);
        D_ASSERT(result == DFB_OK);
    }
    else
    {
        /*remove any DSOC_SCART connector*/
        result = StbDFB_RemoveVideoConnector(pDencSettings, DSOC_SCART);
        D_ASSERT(result == DFB_OK);
    }
    if(config->out_connectors & DSOC_SCART2)
    {
        result = StbDFB_AddVideoConnector(pDencSettings, DSOC_SCART2);
        D_ASSERT(result == DFB_OK);
    }
    else
    {
        /*remove any DSOC_SCART2 connector*/
        result = StbDFB_RemoveVideoConnector(pDencSettings, DSOC_SCART2);
        D_ASSERT(result == DFB_OK);
    }
    if(config->out_connectors & DSOC_YC)
    {
        result = StbDFB_AddVideoConnector(pDencSettings, DSOC_YC);
        D_ASSERT(result == DFB_OK);
    }
    else
    {
        /*remove any DSOC_YC connector*/
        result = StbDFB_RemoveVideoConnector(pDencSettings, DSOC_YC);
        D_ASSERT(result == DFB_OK);
    }
    if(config->out_connectors & DSOC_CVBS)
    {
        result = StbDFB_AddVideoConnector(pDencSettings, DSOC_CVBS);
        D_ASSERT(result == DFB_OK);
    }
    else
    {
        /*remove any DSOC_CVBS connector*/
        result = StbDFB_RemoveVideoConnector(pDencSettings, DSOC_CVBS);
        D_ASSERT(result == DFB_OK);
    }
    if(config->out_connectors & DSOC_COMPONENT)
    {
        result = StbDFB_AddVideoConnector(pDencSettings, DSOC_COMPONENT);
        D_ASSERT(result == DFB_OK);
    }
    else
    {
        /*remove any DSOC_COMPONENT connector*/
        result = StbDFB_RemoveVideoConnector(pDencSettings, DSOC_COMPONENT);
        D_ASSERT(result == DFB_OK);
    }
    if(config->out_connectors & DSOC_HDMI)
    {
        result = StbDFB_AddVideoConnector(pDencSettings, DSOC_HDMI);
        D_ASSERT(result == DFB_OK);
    }
    else
    {
        /*remove any DSOC_HDMI connector*/
        result = StbDFB_RemoveVideoConnector(pDencSettings, DSOC_HDMI);
        D_ASSERT(result == DFB_OK);
    }
    pDencSettings->output_signal = CONVERT_FROM_DFB_OUTPUT_SIGNAL(config->out_signals);

    return result;
}

/******************************************************************************/
static DFBResult StbDFB_AddVideoConnector(struct videodenc_var_screeninfo *pDencSettings,
                                          DFBScreenOutputConnectors out_connector)
{
    uint32_t conIndex;
    bool foundMatch = false;
    videodenc_outputconnector_type_t video_denc_connector;

    /*Assume that the connector is not a multiple of connectors this macro does a check.*/
    video_denc_connector = CONVERT_FROM_DFB_OUTPUT_CONNECTOR(out_connector);
    D_ASSERT(video_denc_connector != VIDEODENC_CONNECTOR_NONE);

    for(conIndex = 0; conIndex < VIDEODENC_CONNECTORS_MAX; conIndex++)
    {
        if(pDencSettings->chosen_connectors[conIndex].in_use)
        {
            /* Does is match*/
            switch(pDencSettings->chosen_connectors[conIndex].type)
            {
                case VIDEODENC_CONNECTOR_SINGLE_RCA:
                    if(out_connector == DSOC_CVBS)
                    {
                        foundMatch = true;
                    }
                    break;

                /* As we are about to change the scart switch make sure formats match of output and scart switch*/
                case VIDEODENC_CONNECTOR_SCART:
                    /*Could be either scart one or scart 2*/
                    if(pDencSettings->chosen_connectors[conIndex].connector_id == 0)
                    {
                        if(out_connector == DSOC_SCART)
                        {
                            foundMatch = true;
                        }
                    }
                    else if(pDencSettings->chosen_connectors[conIndex].connector_id == 1)
                    {
                        if(out_connector == DSOC_SCART2)
                        {
                            foundMatch = true;
                        }
                    }
                    break;

                case VIDEODENC_CONNECTOR_MINI_DIN:
                    if(out_connector == DSOC_YC)
                    {
                        foundMatch = true;
                    }
                    break;

                case VIDEODENC_CONNECTOR_TRIPLE_RCA:
                    if(out_connector == DSOC_COMPONENT)
                    {
                        foundMatch = true;
                    }
                    break;

                case VIDEODENC_CONNECTOR_HDMI:
                    if(out_connector == DSOC_HDMI)
                    {
                        foundMatch = true;
                    }
                    break;

                case VIDEODENC_CONNECTOR_VGA:
                case VIDEODENC_CONNECTOR_DVI:
                case VIDEODENC_CONNECTOR_LVDS:

                case VIDEODENC_CONNECTOR_NONE:
                default:
                    break;
            }
        }
        /*We have found a match so can return imediately*/
        if(foundMatch)
        {
            return DFB_OK;
        }
    }
    if(!foundMatch)
    {
        /*No existing connector found so find first free one and add it.*/
        for(conIndex = 0; conIndex < VIDEODENC_CONNECTORS_MAX; conIndex++)
        {
            if(!pDencSettings->chosen_connectors[conIndex].in_use)
            {
                /*Empty slot found*/
                pDencSettings->chosen_connectors[conIndex].type = video_denc_connector;
                pDencSettings->chosen_connectors[conIndex].connector_id = 0;
                if(out_connector & DSOC_SCART2)
                {
                    pDencSettings->chosen_connectors[conIndex].connector_id = 1;
                }
                pDencSettings->chosen_connectors[conIndex].in_use = 1;
                return DFB_OK;
            }
        }
    }
    /* Could not add it*/
    return DFB_LIMITEXCEEDED;
}

/******************************************************************************/
static DFBResult StbDFB_RemoveVideoConnector(struct videodenc_var_screeninfo *pDencSettings,
                                             DFBScreenOutputConnectors out_connector)
{
    uint32_t conIndex;
    bool foundMatch = false;
    videodenc_outputconnector_type_t video_denc_connector;

    /*Assume that the connector is not a multiple of connectors this macro does a check.*/
    video_denc_connector = CONVERT_FROM_DFB_OUTPUT_CONNECTOR(out_connector);
    D_ASSERT(video_denc_connector != VIDEODENC_CONNECTOR_NONE);

    for(conIndex = 0; conIndex < VIDEODENC_CONNECTORS_MAX; conIndex++)
    {
        if(pDencSettings->chosen_connectors[conIndex].in_use)
        {
            /* Does is match*/
            switch(pDencSettings->chosen_connectors[conIndex].type)
            {
                case VIDEODENC_CONNECTOR_SINGLE_RCA:
                    if(out_connector == DSOC_CVBS)
                    {
                        foundMatch = true;
                    }
                    break;

                /* As we are about to change the scart switch make sure formats match of output and scart switch*/
                case VIDEODENC_CONNECTOR_SCART:
                    /*Could be either scart one or scart 2*/
                    if(pDencSettings->chosen_connectors[conIndex].connector_id == 0)
                    {
                        if(out_connector == DSOC_SCART)
                        {
                            foundMatch = true;
                        }
                    }
                    else if(pDencSettings->chosen_connectors[conIndex].connector_id == 1)
                    {
                        if(out_connector == DSOC_SCART2)
                        {
                            foundMatch = true;
                        }
                    }
                    break;

                case VIDEODENC_CONNECTOR_MINI_DIN:
                    if(out_connector == DSOC_YC)
                    {
                        foundMatch = true;
                    }
                    break;

                case VIDEODENC_CONNECTOR_TRIPLE_RCA:
                    if(out_connector == DSOC_COMPONENT)
                    {
                        foundMatch = true;
                    }
                    break;

                case VIDEODENC_CONNECTOR_HDMI:
                    if(out_connector == DSOC_HDMI)
                    {
                        foundMatch = true;
                    }
                    break;

                case VIDEODENC_CONNECTOR_VGA:
                case VIDEODENC_CONNECTOR_DVI:
                case VIDEODENC_CONNECTOR_LVDS:

                case VIDEODENC_CONNECTOR_NONE:
                default:
                    break;
            }
        }
        /*We have found a match so can return imediately*/
        if(foundMatch)
        {
            /* Mark as not needed */
            pDencSettings->chosen_connectors[conIndex].in_use = 0;
            return DFB_OK;
        }
    }
    /* Could not add it*/
    return DFB_OK;
}
