/*************************************************************************************/
/*
 * File name:  MILEncodeDecode.cpp
 * Location: See Matrox Example Launcher in the MIL Control Center
 * 
 *
 * Synopsis:   This example demonstrates how to encode a video stream using Matrox Encode Filter.
 *             It also explains how to generate an avi file with sound from an external source.
 *             Once the file is generated, it shows how to decompress the file using Matrox Decode Filter.
 *
 *             This program creates a DirectShow graph,
 *             adds a user selected video and audio capture filter to the graph,
 *             adds an encode filter, an AVI muxer, a file writer and connects all of those.
 *
 * Requirements: If using Visual Studio 2005 (Not required for more recent versions):
 *                   Windows SDK (http://msdn.microsoft.com/en-us/bb980924.aspx)
 *                   Run the Windows SDK Configuration tool (http://blogs.msdn.com/b/windowssdk/archive/2008/03/01/integrating-windows-sdk-and-vs-with-new-sdk-configuration-tool.aspx)
 *                   Patch for Visual Studio 2005 SP1 available from: http://support.microsoft.com/kb/949009/.
 *
 * Copyright (C) Matrox Electronic Systems Ltd., 1992-2020.
 * All Rights Reserved
 */

//#include <mil.h>
#include "stdio.h"


/* Include for the FilterGraph Manager class.
 * It contains the function necessary to insert filters and control them. */
#include "..\..\CommonWrapper\C++\FilterGraphWrapper.h"
#include "MILEncodeWrapper.h"
#include "MILDecodeWrapper.h"

#include "..\..\CommonWrapper\C++\DirectShowHelper.h"

HRESULT EncodeFromGrab();

HRESULT DecodeFromFile();

/* Main function.*/
/* --------------*/
int main(void)
   {
   HRESULT hr = S_OK;
   MosPrintf(MIL_TEXT("Matrox Encode and Decode DirectShow filter example:\n"));
   MosPrintf(MIL_TEXT("---------------------------------------------------\n"));
   MosPrintf(MIL_TEXT("\n"));
   MosPrintf(MIL_TEXT("Matrox Encode DirectShow filter section.\n"));
   MosPrintf(MIL_TEXT("----------------------------------------\n"));
   MosPrintf(MIL_TEXT("This section will try to add a video capture filter\n"));
   MosPrintf(MIL_TEXT("and an audio capture filter to the graph.\n"));
   MosPrintf(MIL_TEXT("It will encode the video data using \"Matrox Encode\" filter.\n"));
   MosPrintf(MIL_TEXT("The compressed stream will be muxed with the audio input into an avi file.\n"));
   MosPrintf(MIL_TEXT("Both sources will also be rendered using default renderer.\n"));
   MosPrintf(MIL_TEXT("\n"));

   hr = EncodeFromGrab();
   if (hr == S_FALSE)
      goto end;

   MosPrintf(MIL_TEXT("\n"));
   MosPrintf(MIL_TEXT("Matrox Decode DirectShow filter section.\n"));
   MosPrintf(MIL_TEXT("----------------------------------------\n"));
   MosPrintf(MIL_TEXT("This section will read the file encoded previously\n"));
   MosPrintf(MIL_TEXT("and decode the video stream using \"Matrox Decode\" filter.\n"));
   MosPrintf(MIL_TEXT("All stream from the avi file will use default renderer.\n"));
   MosPrintf(MIL_TEXT("\n"));

   hr = DecodeFromFile();
   if (hr == S_FALSE)
      goto end;

   MosPrintf(MIL_TEXT("\nPress <Enter> to end."));
   MosGetch();

end:
   MosPrintf(MIL_TEXT("\n"));
   return 0;
   }

HRESULT EncodeFromGrab()
   {
   HRESULT hr = S_OK;
   FilterGraphWrapper      WrapperFilterGraph;
   MilCompressionWrapper   WrapperCompressionFilter;

   /* Start building the Filter Graph using the wrapper. */
   WrapperFilterGraph.InitGraph();

   BOOL bVideoCaptureFilterSelected = FALSE;
   BOOL bAudioCaptureFilterSelected = FALSE;
   if (WrapperFilterGraph.IsInitialized())
      {
      HRESULT hr = S_OK;

      CComPtr<IBaseFilter> selectedVideoCaptureFilter = NULL;
      CComPtr<IPin>        selectedVideoCapturePin = NULL;

      CComPtr<IBaseFilter> selectedAudioCaptureFilter = NULL;
      CComPtr<IPin>        selectedAudioCapturePin = NULL;

      CComPtr<IPin>  CompressionOutputPin = NULL;

      CComPtr<IBaseFilter> AudioInfinitePinTeeFilter = NULL;

      CComPtr<IBaseFilter> AviMuxFilter = NULL;
      CComPtr<IPin> AviMuxOutputPin = NULL;

      CComPtr<IBaseFilter> FileWriterFilter = NULL;


      /* ----------------------------------------------------------------------*/
      /* Select the desired video source from the list.                        */
      /* ----------------------------------------------------------------------*/
      if (FilterFormCategoryCount(CLSID_VideoInputDeviceCategory) == 0)
         {
         MosPrintf(MIL_TEXT("\nERROR\n\n"));
         MosPrintf(MIL_TEXT("No video capture filters are available.\n"));
         MosPrintf(MIL_TEXT("Make sure the desired filter is properly installed.\n"));
         MosPrintf(MIL_TEXT("Press <Enter> to end.\n"));
         MosGetch();

         /* Release all remaining DirectShow interfaces. */
         WrapperFilterGraph.UninitGraph();
         return S_FALSE;
         }

      LPCWSTR selectedCaptureFilterName = new WCHAR[1024];
      MosPrintf(MIL_TEXT("Select a video capture source from the list:\n"));
      bVideoCaptureFilterSelected = SelectFilterFromCategory(CLSID_VideoInputDeviceCategory, &selectedVideoCaptureFilter, selectedCaptureFilterName);
      if (bVideoCaptureFilterSelected && !selectedVideoCaptureFilter)
         {
         MosPrintf(MIL_TEXT("\nERROR\n\n"));
         MosPrintf(MIL_TEXT("The selected filter creation failed.\n"));
         MosPrintf(MIL_TEXT("Make sure the desired filter is properly installed and configured.\n"));
         MosPrintf(MIL_TEXT("Press <Enter> to end.\n"));
         MosGetch();

         /* Release all remaining DirectShow interfaces. */
         selectedVideoCaptureFilter = NULL;
         WrapperFilterGraph.UninitGraph();
         return S_FALSE;
         }

      if (bVideoCaptureFilterSelected && selectedVideoCaptureFilter)
         {
         /* Adds the video capture filter to the Filter Graph. */
         WrapperFilterGraph.InsertFilter(selectedVideoCaptureFilter, selectedCaptureFilterName, &selectedVideoCapturePin);
         }

      /* Free the selected video capture filter name string. */
      if (selectedCaptureFilterName)
         {
         delete [] selectedCaptureFilterName;
         selectedCaptureFilterName = NULL;
         }

      if (!bVideoCaptureFilterSelected)
         {
         MosPrintf(MIL_TEXT("\nPress <Enter> to end.\n"));
         MosGetch();

         /* Release all remaining DirectShow interfaces. */
         WrapperFilterGraph.UninitGraph();
         return S_FALSE;
         }

      /* ----------------------------------------------------------------------*/
      /* Select the desired audio source from the list.                        */
      /* ----------------------------------------------------------------------*/
      if (FilterFormCategoryCount(CLSID_AudioInputDeviceCategory))
         {
         LPCWSTR selectedAudioCaptureFilterName = new WCHAR[1024];
         MosPrintf(MIL_TEXT("Select an audio capture source from the list:\n"));
         bAudioCaptureFilterSelected = SelectFilterFromCategory(CLSID_AudioInputDeviceCategory, &selectedAudioCaptureFilter, selectedAudioCaptureFilterName);

         if (bAudioCaptureFilterSelected && !selectedAudioCaptureFilter)
            {
            MosPrintf(MIL_TEXT("\n"));
            MosPrintf(MIL_TEXT("The selected audio filter creation failed.\n"));
            MosPrintf(MIL_TEXT("Make sure the desired filter is properly installed and configured.\n"));
            MosPrintf(MIL_TEXT("Operation will continue without audio.\n"));
            }

         if (bAudioCaptureFilterSelected && selectedAudioCaptureFilter)
            {
            /* Adds the audio capture filter to the Filter Graph. */
            WrapperFilterGraph.InsertFilter(selectedAudioCaptureFilter, selectedAudioCaptureFilterName, &selectedAudioCapturePin);
            }

         /* Free the selected audio capture filter name string. */
         if (selectedAudioCaptureFilterName)
            {
            delete [] selectedAudioCaptureFilterName;
            selectedAudioCaptureFilterName = NULL;
            }
         }

      /* ----------------------------------------------------------------------*/
      /* Allocated and insert the compression filter                           */
      /* ----------------------------------------------------------------------*/
      hr = WrapperCompressionFilter.AllocateFilter();
      if (SUCCEEDED(hr))
         {
         hr = WrapperFilterGraph.InsertFilter(WrapperCompressionFilter.GetFilterInterface(), L"Matrox Encode", &CompressionOutputPin);
         }
      else
         {
         MosPrintf(MIL_TEXT("\nERROR\n\n"));
         MosPrintf(MIL_TEXT("\"Matrox Encode\" filter creation failed.\n"));
         MosPrintf(MIL_TEXT("Make sure the filter is properly registered in \n"));
         MosPrintf(MIL_TEXT("MILConfig under \"Benchmarks and Utilities/DirectShow\"\n\n"));
         MosPrintf(MIL_TEXT("Press <Enter> to end.\n"));
         MosGetch();

         /* Release all remaining DirectShow interfaces. */
         selectedVideoCaptureFilter = NULL;
         selectedVideoCapturePin = NULL;
         selectedAudioCaptureFilter = NULL;
         selectedAudioCapturePin = NULL;
         WrapperFilterGraph.UninitGraph();
         return S_FALSE;
         }

      /* ----------------------------------------------------------------------*/
      /* Create the helper filters.                                            */
      /* ----------------------------------------------------------------------*/
      if (selectedAudioCaptureFilter)
         {
         hr = CoCreateInstance(CLSID_InfTee,
                               NULL,
                               CLSCTX_INPROC_SERVER,
                               IID_IBaseFilter,
                               (void**)&AudioInfinitePinTeeFilter);
         if (SUCCEEDED(hr))
            {
            WrapperFilterGraph.InsertFilter(AudioInfinitePinTeeFilter, L"Audio Infinite Pin Tee", NULL);
            }
         }

      /* Automatically connects the Video Capture filter output pin
      * to any Renderer filter added to the graph or default:
      * "Selected Video Capture Filter" => "Pin Tee" => "Renderer".
      * "Selected Audio CaptureFilter" => "Pin Tee" => "Renderer".
      */
      WrapperFilterGraph.Connect(selectedVideoCapturePin, WrapperCompressionFilter.GetFilterInterface());
      WrapperFilterGraph.Connect(selectedAudioCapturePin, AudioInfinitePinTeeFilter);

      WrapperFilterGraph.Render(selectedVideoCaptureFilter);
      WrapperFilterGraph.Render(AudioInfinitePinTeeFilter);

      /* ----------------------------------------------------------------------*/
      /* Create the file managing filters.                                     */
      /* ----------------------------------------------------------------------*/
      hr = CoCreateInstance(CLSID_AviDest,
                            NULL,
                            CLSCTX_INPROC_SERVER,
                            IID_IBaseFilter,
                            (void**)&AviMuxFilter);
      if (SUCCEEDED(hr))
         {
         WrapperFilterGraph.InsertFilter(AviMuxFilter, L"Avi Mux", &AviMuxOutputPin);
         }

      hr = CoCreateInstance(CLSID_FileWriter,
                            NULL,
                            CLSCTX_INPROC_SERVER,
                            IID_IBaseFilter,
                            (void**)&FileWriterFilter);

      if (SUCCEEDED(hr))
         {
         hr = WrapperFilterGraph.InsertFilter(FileWriterFilter, L"MilDSFEncode.avi", NULL);

         LPTSTR sTempPath = new TCHAR[MAX_PATH + 1];
         LPTSTR sOutFile = new TCHAR[MAX_PATH + 1];
         GetTempPath(MAX_PATH + 1, sTempPath);
         MosSprintf(sOutFile, MAX_PATH + 1, MIL_TEXT("%s%s"), sTempPath, MIL_TEXT("MilDSFEncode.avi"));
         if (sTempPath)
            {
            delete [] sTempPath;
            sTempPath = NULL;
            }

         CComPtr<IFileSinkFilter> FileSinkFilter = NULL;
         FileWriterFilter->QueryInterface(IID_IFileSinkFilter, (void**)&FileSinkFilter);
         FileSinkFilter->SetFileName(sOutFile, NULL);

         if (sOutFile)
            {
            delete [] sOutFile;
            sOutFile = NULL;
            }

         LPTSTR sFileName = NULL;
         FileSinkFilter->GetCurFile(&sFileName, NULL);
         if (sFileName)
            {
            MosPrintf(MIL_TEXT("Output file path: %s\n\n"), sFileName);
            CoTaskMemFree(sFileName);
            }


         FileSinkFilter = NULL;
         }

      /* Connects the Compression output pin to the AVI Muxer
         * "Video Pin Tee Filter" => "Compression" => "AVI MUX" => "File Writter".
         * "Audio Pin Tee Filter" ==================/
         */
      WrapperFilterGraph.Connect(CompressionOutputPin, AviMuxFilter);
      WrapperFilterGraph.Connect(AudioInfinitePinTeeFilter, AviMuxFilter);
      WrapperFilterGraph.Connect(AviMuxOutputPin, FileWriterFilter);

      /* Release the Video Capture related interfaces. */
      selectedVideoCaptureFilter = NULL;
      selectedVideoCapturePin = NULL;

      /* Release the Audio Capture Related interfaces. */
      selectedAudioCaptureFilter = NULL;
      selectedAudioCapturePin = NULL;

      /* Release the helper interfaces. */
      AudioInfinitePinTeeFilter = NULL;

      /* Release the file managing interfaces. */
      AviMuxFilter = NULL;
      AviMuxOutputPin = NULL;
      FileWriterFilter = NULL;

      CompressionOutputPin = NULL;
      }

   /* If all filters are connected properly,
    * Media control starts and is stopped by user. */
   if (WrapperFilterGraph.IsInitialized() && bVideoCaptureFilterSelected)
      {
      /* Starts the Graph.*/
      hr = WrapperFilterGraph.StartGraph();
      if (hr == S_OK)
         {
         MosPrintf(MIL_TEXT("Encoding graph is running and saving to file.\n"));
         MosPrintf(MIL_TEXT("\nPress <Enter> to stop graph.\n"));

         MosGetch();
         }
      else
         {
         MosPrintf(MIL_TEXT("Graph failed to start properly\n"));
         }

      /* Stops the Graph. */
      WrapperFilterGraph.StopGraph();
      }

   /* Release all remaining DirectShow interfaces. */
   WrapperCompressionFilter.ReleaseFilter();
   WrapperFilterGraph.UninitGraph();
   return hr;
   }

HRESULT DecodeFromFile()
   {
   HRESULT hr = S_OK;
   FilterGraphWrapper      WrapperFilterGraph;
   MilDecompressionWrapper WrapperDecompressionFilter;

   /* Start building the Filter Graph using the wrapper. */
   WrapperFilterGraph.InitGraph();

   if (WrapperFilterGraph.IsInitialized())
      {
      CComPtr<IBaseFilter> sourceFileFilter = NULL;

      /* ----------------------------------------------------------------------*/
      /* Open and insert the source file filter                                */
      /* ----------------------------------------------------------------------*/
      hr = CoCreateInstance(CLSID_AsyncReader,
                            NULL,
                            CLSCTX_INPROC_SERVER,
                            IID_IBaseFilter,
                            (void**)&sourceFileFilter);

      if (SUCCEEDED(hr))
         {
         WrapperFilterGraph.InsertFilter(sourceFileFilter, L"MilDSFEncode.avi", NULL);

         LPTSTR sTempPath = new TCHAR[MAX_PATH + 1];
         LPTSTR sInFile = new TCHAR[MAX_PATH + 1];
         GetTempPath(MAX_PATH + 1, sTempPath);
         MosSprintf(sInFile, MAX_PATH + 1, MIL_TEXT("%s%s"), sTempPath, MIL_TEXT("MilDSFEncode.avi"));
         if (sTempPath)
            {
            delete [] sTempPath;
            sTempPath = NULL;
            }

         CComPtr<IFileSourceFilter> FileSourceFilter = NULL;
         sourceFileFilter->QueryInterface(IID_IFileSourceFilter, (void**)&FileSourceFilter);
         hr = FileSourceFilter->Load(sInFile, NULL);
         if (sInFile)
            {
            delete [] sInFile;
            sInFile = NULL;
            }

         LPTSTR sFileName = NULL;
         FileSourceFilter->GetCurFile(&sFileName, NULL);
         if (sFileName)
            {
            MosPrintf(MIL_TEXT("Input file path: %s\n\n"), sFileName);
            CoTaskMemFree(sFileName);
            }

         FileSourceFilter = NULL;
         }

      if (hr != S_OK)
         {
         sourceFileFilter = NULL;
         MosPrintf(MIL_TEXT("\nFile could not be opened.\n"));
         MosPrintf(MIL_TEXT("\nPress <Enter> to end.\n"));
         MosGetch();

         /* Release all remaining DirectShow interfaces. */
         WrapperFilterGraph.UninitGraph();
         return S_FALSE;
         }

      /* ----------------------------------------------------------------------*/
      /* Allocated and insert the compression filter                           */
      /* ----------------------------------------------------------------------*/
      hr = WrapperDecompressionFilter.AllocateFilter();
      if (SUCCEEDED(hr))
         {
         hr = WrapperFilterGraph.InsertFilter(WrapperDecompressionFilter.GetFilterInterface(), L"Matrox Decode", NULL);
         }
      else
         {
         MosPrintf(MIL_TEXT("\nERROR\n\n"));
         MosPrintf(MIL_TEXT("\"Matrox Decode\" filter creation failed.\n"));
         MosPrintf(MIL_TEXT("Make sure the filter is properly registered in \n"));
         MosPrintf(MIL_TEXT("MILConfig under \"Benchmarks and Utilities/DirectShow\"\n\n"));
         MosPrintf(MIL_TEXT("Press <Enter> to end.\n"));
         MosGetch();

         /* Release all remaining DirectShow interfaces. */
         sourceFileFilter = NULL;
         WrapperFilterGraph.UninitGraph();
         return S_FALSE;
         }

      /* Automatically connects all filters present.
      */
      WrapperFilterGraph.Render(sourceFileFilter);

      /* Release the file managing interfaces. */
      sourceFileFilter = NULL;
      }

   /* If all filters are connected properly,
   * Media control starts and is stopped by user. */
   if (WrapperFilterGraph.IsInitialized())
      {
      /* Starts the Graph.*/
      WrapperFilterGraph.StartGraph();

      MosPrintf(MIL_TEXT("Decoding graph is running.\n"));
      MosPrintf(MIL_TEXT("\nPress <Enter> to stop graph.\n"));

      MosGetch();

      /* Stops the Graph. */
      WrapperFilterGraph.StopGraph();
      }

   /* Release all remaining DirectShow interfaces. */
   WrapperDecompressionFilter.ReleaseFilter();
   WrapperFilterGraph.UninitGraph();
   return hr;
   }