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

Copyright Datapath Ltd. 2009.

File:    VisionCmd.cpp

Purpose: 

History:
         31 JAN 09    RL   Created.
         06 OCT 09    RL   Removed the requirement for a 'PinID'.

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

#include <streams.h>
#include <tchar.h>
#include <stddef.h>

#include <cmdline.h>

#ifdef USER_MODE_STREAMING
#include <DGC133UM.h> // Use User-mode streaming interfaces
#else
#include <DGC133ST.h> // Use Kernel streaming interfaces
#endif

#include <VisionCmd.h>
#include <VisionPin.h>
#include <VisionUtil.h>

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

/* Subformat strings */
static const TCHAR
   RGB32[] = TEXT("rgb32"),
   RGB24[] = TEXT("rgb24"),
   RGB565[] = TEXT("rgb565"),
   RGB555[] = TEXT("rgb555"),
   RGB8[] = TEXT("rgb8"),
   YUY2[] = TEXT("yuy2"),
   UYVY[] = TEXT("uyvy"),
   YVYU[] = TEXT("yvyu"),
   NV12[] = TEXT("nv12");

/* Command strings */
static const TCHAR
   FPS[] = TEXT("fps"),
   Buffer[] = TEXT("buffer"),
   Window[] = TEXT("window"),
   Subformat[] = TEXT("subformat"),
   Input[] = TEXT("input"),
   Channel[] = TEXT("channel");

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

CMDLNERRFN  CommandLineErrorFn;

unsigned long
CommandLineErrorFn (
   unsigned long  error,
   LPCTSTR        pKeyword,
   int            nKeywordChars,
   LPCTSTR        pValue,
   int            nValueChars,
   int            nParameter,
   PKEYWORDTODATA pKeywordToData,
   PVOID          pVoid )
{
   return 1;
}

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

static unsigned long
ExtractSubformat (
   LPCTSTR pValue,
   int     nValueChars,
   PVOID   pData,
   PVOID   pVoid )
{
   PCOMMANDLINE pCommandLine = (PCOMMANDLINE)pData;
   
   if ( _tcsicmp ( RGB32, pValue ) == 0 )
   {
      pCommandLine->flags |= CMD_FLAGS_SUBTYPE_RGB32;
      memcpy (&pCommandLine->subformat, &MEDIASUBTYPE_RGB32, sizeof(GUID));
   }
   else if ( _tcsicmp ( RGB565, pValue ) == 0 )
   {
      pCommandLine->flags |= CMD_FLAGS_SUBTYPE_RGB565;
      memcpy (&pCommandLine->subformat, &MEDIASUBTYPE_RGB565, sizeof(GUID));
   }
   else if ( _tcsicmp ( RGB8, pValue ) == 0 )
   {
      pCommandLine->flags |= CMD_FLAGS_SUBTYPE_RGB8;
      memcpy (&pCommandLine->subformat, &MEDIASUBTYPE_RGB8, sizeof(GUID));
   }
   else if ( _tcsicmp ( RGB555, pValue ) == 0 )
   {
      pCommandLine->flags |= CMD_FLAGS_SUBTYPE_RGB555;
      memcpy (&pCommandLine->subformat, &MEDIASUBTYPE_RGB555, sizeof(GUID));
   }
   else if ( _tcsicmp ( RGB24, pValue ) == 0 )
   {
      pCommandLine->flags |= CMD_FLAGS_SUBTYPE_RGB24;
      memcpy (&pCommandLine->subformat, &MEDIASUBTYPE_RGB24, sizeof(GUID));
   }
   else if ( _tcsicmp ( YUY2, pValue ) == 0 )
   {
      pCommandLine->flags |= CMD_FLAGS_SUBTYPE_YUY2;
      memcpy (&pCommandLine->subformat, &MEDIASUBTYPE_YUY2, sizeof(GUID));
   }
   else if ( _tcsicmp ( UYVY, pValue ) == 0 )
   {
      pCommandLine->flags |= CMD_FLAGS_SUBTYPE_UYVY;
      memcpy (&pCommandLine->subformat, &MEDIASUBTYPE_UYVY, sizeof(GUID));
   }
   else if ( _tcsicmp ( YVYU, pValue ) == 0 )
   {
      pCommandLine->flags |= CMD_FLAGS_SUBTYPE_YVYU;
      memcpy (&pCommandLine->subformat, &MEDIASUBTYPE_YVYU, sizeof(GUID));
   }
   else if ( _tcsicmp ( NV12, pValue ) == 0 )
   {
      pCommandLine->flags |= CMD_FLAGS_SUBTYPE_NV12;
      memcpy (&pCommandLine->subformat, &MEDIASUBTYPE_NV12, sizeof(GUID));
   }

   return 0;
}

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

static unsigned long
ExtractBuffer (
   LPCTSTR pValue,
   int     nChars,
   PVOID   pData,
   PVOID   pVoid )
{
   unsigned long  error;
   PCOMMANDLINE   pCommandLine;
   
   pCommandLine = (PCOMMANDLINE)pData;

   error = ExtractTLWH ( pValue, nChars, (PVOID)2, pVoid );
   if ( error == 0 )
   {
      pCommandLine->flags |= CMD_FLAGS_BUFFER_SIZE;
   }

   return 0;
}

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

static unsigned long
ExtractWindow (
   LPCTSTR pValue,
   int     nChars,
   PVOID   pData,
   PVOID   pVoid )
{
   unsigned long  error;
   PCOMMANDLINE   pCommandLine;
   
   pCommandLine = (PCOMMANDLINE)pData;

   error = ExtractTLWH ( pValue, nChars, (PVOID)4, pVoid );
   if ( error == 0 )
   {
      pCommandLine->flags |= CMD_FLAGS_WINDOW_POSITION;
   }

   return 0;
}

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

static unsigned long
ExtractInput (
   LPCTSTR pValue,
   int     nChars,
   PVOID   pData,
   PVOID   pVoid )
{
   unsigned long  error;
   PCOMMANDLINE   pCommandLine;
   
   pCommandLine = (PCOMMANDLINE)pData;

   error = ExtractLong ( pValue, nChars, NULL, pVoid );
   if ( error == 0 )
   {
      pCommandLine->flags |= CMD_FLAGS_INPUT_SOURCE;
   }

   return 0;
}

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

static unsigned long
ExtractChannel (
   LPCTSTR pValue,
   int     nChars,
   PVOID   pData,
   PVOID   pVoid )
{
   unsigned long  error;
   PCOMMANDLINE   pCommandLine;
   
   pCommandLine = (PCOMMANDLINE)pData;
   
   error = ExtractLong ( pValue, nChars, NULL, pVoid );
   if ( error == 0 )
   {
      pCommandLine->flags |= CMD_FLAGS_CHANNEL_SOURCE;
   }
   
   return 0;
}

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

static unsigned long
ExtractFPS (
   LPCTSTR pValue,
   int     nChars,
   PVOID   pData,
   PVOID   pVoid )
{
   unsigned long  error;
   PCOMMANDLINE   pCommandLine;
   
   pCommandLine = (PCOMMANDLINE)pData;

   error = ExtractLong ( pValue, nChars, NULL, pVoid );
   if ( error == 0 )
   {
      pCommandLine->flags |= CMD_FLAGS_CAPTURE_RATE;
   }

   return 0;
}

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

BOOL
ProcessCommandLine(
   LPCTSTR        lpStrCommandLine,
   PCOMMANDLINE   pCommandLine)
{
   KEYWORDTODATA  keywordToData[] = 
   {
      { Subformat, ExtractSubformat, offsetof ( COMMANDLINE, subformat ), pCommandLine },
      { Buffer, ExtractBuffer, offsetof ( COMMANDLINE, buffer ), pCommandLine },
      { Window, ExtractWindow, offsetof ( COMMANDLINE, window ), pCommandLine },
      { Input, ExtractInput, offsetof ( COMMANDLINE, input ), pCommandLine },
      { Channel, ExtractChannel, offsetof ( COMMANDLINE, channel ), pCommandLine },
      { FPS, ExtractFPS, offsetof ( COMMANDLINE, fps ), pCommandLine },

      { NULL, NULL, 0, NULL },
   };

   pCommandLine->flags =  0;

   ParseCommandLine ( (LPTSTR)lpStrCommandLine, keywordToData, pCommandLine,
         CommandLineErrorFn );

   return TRUE;
}

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

BOOL
SetCommandLine(
   HWND           hWnd,
   LPCTSTR        pTitle,
   PCOMMANDLINE   pCommandLine,
   IBaseFilter    *pSrcFilter,
   LPCTSTR        pPinName)
{
   HRESULT hr;
   AM_MEDIA_TYPE *pmt;

   if (!pCommandLine->flags)
      return FALSE;

   if(!pSrcFilter)
   {
      ErrorMessage(hWnd, pTitle, TEXT("Invalid source filter."), E_POINTER);
      return FALSE;
   }
   // Get on the wire media type.
   if ( GetCurrentMediaType(pSrcFilter, &pmt, pPinName) != S_OK )
      return FALSE;

   // Set colour space compression.
   if (pCommandLine->flags & CMD_FLAGS_SUBTYPE_RGB32)
   {
      hr = SetColourSpace(pSrcFilter, pPinName, &MEDIASUBTYPE_RGB32, &pmt);
      if (FAILED(hr))
         ErrorMessage(hWnd, pTitle, TEXT("Failed to set colour space."), hr);
   }
   else if (pCommandLine->flags & CMD_FLAGS_SUBTYPE_RGB24)
   {
      hr = SetColourSpace(pSrcFilter, pPinName, &MEDIASUBTYPE_RGB24, &pmt);
      if (FAILED(hr))
         ErrorMessage(hWnd, pTitle, TEXT("Failed to set colour space."), hr);
   }
   else if (pCommandLine->flags & CMD_FLAGS_SUBTYPE_RGB555)
   {
      hr = SetColourSpace(pSrcFilter, pPinName, &MEDIASUBTYPE_RGB555, &pmt);
      if (FAILED(hr))
         ErrorMessage(hWnd, pTitle, TEXT("Failed to set colour space."), hr);
   }
   else if (pCommandLine->flags & CMD_FLAGS_SUBTYPE_RGB565)
   {
      hr = SetColourSpace(pSrcFilter, pPinName, &MEDIASUBTYPE_RGB565, &pmt);
      if (FAILED(hr))
         ErrorMessage(hWnd, pTitle, TEXT("Failed to set colour space."), hr);
   }
   else if (pCommandLine->flags & CMD_FLAGS_SUBTYPE_RGB8)
   {
      hr = SetColourSpace(pSrcFilter, pPinName, &MEDIASUBTYPE_RGB8, &pmt);
      if (FAILED(hr))
         ErrorMessage(hWnd, pTitle, TEXT("Failed to set colour space."), hr);
   }
   else if (pCommandLine->flags & CMD_FLAGS_SUBTYPE_YUY2)
   {
      hr = SetColourSpace(pSrcFilter, pPinName, &MEDIASUBTYPE_YUY2, &pmt);
      if (FAILED(hr))
         ErrorMessage(hWnd, pTitle, TEXT("Failed to set colour space."), hr);
   }
   else if (pCommandLine->flags & CMD_FLAGS_SUBTYPE_UYVY)
   {
      hr = SetColourSpace(pSrcFilter, pPinName, &MEDIASUBTYPE_UYVY, &pmt);
      if (FAILED(hr))
         ErrorMessage(hWnd, pTitle, TEXT("Failed to set colour space."), hr);
   }
   else if (pCommandLine->flags & CMD_FLAGS_SUBTYPE_YVYU)
   {
      hr = SetColourSpace(pSrcFilter, pPinName, &MEDIASUBTYPE_YVYU, &pmt);
      if (FAILED(hr))
         ErrorMessage(hWnd, pTitle, TEXT("Failed to set colour space."), hr);
   }
   else if (pCommandLine->flags & CMD_FLAGS_SUBTYPE_NV12)
   {
      hr = SetColourSpace(pSrcFilter, pPinName, &MEDIASUBTYPE_NV12, &pmt);
      if (FAILED(hr))
         ErrorMessage(hWnd, pTitle, TEXT("Failed to set colour space."), hr);
   }
   // Set the capture buffer size.
   if (pCommandLine->flags & CMD_FLAGS_BUFFER_SIZE)
   {
      hr = SetBufferSize(pCommandLine->buffer.x, pCommandLine->buffer.y, pmt);
      if (FAILED(hr))
         ErrorMessage(hWnd, pTitle, TEXT("Failed to set buffer size."), hr);
   }
   // Set the capture rate in frames per second.
   if (pCommandLine->flags & CMD_FLAGS_CAPTURE_RATE)
   {
      hr = SetFrameRate(pCommandLine->fps, pmt);
      if (FAILED(hr))
         ErrorMessage(hWnd, pTitle, TEXT("Failed to set capture rate."), hr);
   }
   // Set the requested Media Type.
   hr = SetPinMediaType(pSrcFilter, pmt, pPinName);
   // It is our responsibility to free the AM_MEDIA_TYPE memory.
   DeleteMediaType(pmt);
   if (FAILED(hr))
   {
      ErrorMessage(hWnd, pTitle, TEXT("Failed to set requested Media Type."), hr);
      return FALSE;
   }
   else
      return TRUE;
}

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