home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wvis0626.zip / warpvision_20020626.zip / wvision.cpp < prev    next >
C/C++ Source or Header  |  2002-06-26  |  32KB  |  1,172 lines

  1. /*
  2.  * WarpVision main
  3.  *
  4.  * Copyleft Alex Strelnikov.
  5.  *
  6.  * WarpVision is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * WarpVision is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  *
  20. */
  21.  
  22. #define INCL_DOS
  23. #define INCL_DOSPROFILE
  24. #define INCL_GPI
  25. #define INCL_WIN
  26. #define INCL_OS2MM
  27.  
  28. #include <os2.h>
  29. #include <os2me.h>
  30.  
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <stdarg.h>
  35. #include <assert.h>
  36.  
  37. #include <mmioos2.h>
  38. #include <dive.h>
  39. #include <fourcc.h>
  40.  
  41. #include <sys\types.h>
  42.  
  43. #include <inttypes.h>
  44.  
  45. #include "libDIVE.h"
  46. #include "libDIVEpm.h"
  47.  
  48. #include "wvision.h"
  49.  
  50. #ifdef __cplusplus
  51. extern "C" {
  52. #endif
  53.  
  54. #include "avcodec.h"
  55. #include "yuv2rgb.h"
  56.  
  57. #include "avifmt.h"
  58. #include "stream.h"
  59. #include "demuxer.h"
  60. #include "stheader.h"
  61.  
  62. #include "codecs.h"
  63. #include "audio\dart.h"
  64. #include "audio\adecode.h"
  65. #include "video\vdecode.h"
  66.  
  67. HMTX demux_mtx;
  68. HMTX dart_cb_mtx;
  69.  
  70. extern DartStruct DART;
  71.  
  72. extern int index_mode;
  73.  
  74. extern audio_header_t audio_header;
  75. extern video_header_t video_header;
  76.  
  77. float audio_time, video_time;
  78.  
  79. #define Q2LL(a) ((ULONG)a.ulHi<<32)|((ULONG)a.ulLo)
  80. //#define singlecadr (TimerFreq/sh_video->fps)
  81.  
  82. void dprintf(char fmt[],...)
  83. {
  84.     return;
  85. }
  86.  
  87. #ifdef __cplusplus
  88. }
  89. #endif
  90.  
  91. //-----------------------------------------
  92. // Global variables
  93. //-----------------------------------------
  94.  
  95. demux_stream_t *d_audio = NULL;
  96. demux_stream_t *d_video = NULL;
  97.  
  98. sh_audio_t *sh_audio = NULL;
  99. sh_video_t *sh_video = NULL;
  100.  
  101. stream_t* stream = NULL;
  102. demuxer_t* demuxer = NULL;
  103.  
  104. int FullScreen = FALSE;
  105. int Shutdown = FALSE;
  106. int ScreenGamma = 0;
  107. int SeekFlag = SEEK_NONE;
  108.  
  109. float SyncCorrection = 0.0;
  110.  
  111. diveWindow *dW;
  112.  
  113. int no_audio;
  114. int Pause = FALSE;
  115. int Mute = FALSE;
  116. int AudioVolume = 0;
  117.  
  118. //-----------------------------------------
  119. // Utility routines
  120. //-----------------------------------------
  121.  
  122. void CheckMenuItem(HWND hMenu, USHORT ulID)
  123. {
  124.     WinSendMsg(hMenu, MM_SETITEMATTR, (MPARAM)ulID,
  125.                MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED));
  126. }
  127.  
  128. extern "C" void CalcAVtime(void)
  129. {
  130.     unsigned int samples;
  131.  
  132.     if (no_audio != TRUE)
  133.     {
  134.         if (sh_audio->audio.dwSampleSize == 0)
  135.         {
  136.             audio_time = d_audio->pts;
  137.         }
  138.         else
  139.         {
  140.             samples = ((ds_tell(d_audio)-sh_audio->a_in_buffer_len) /
  141.                        sh_audio->audio.dwSampleSize);
  142.             samples += sh_audio->audio.dwStart;
  143.  
  144.             audio_time = samples * (float)sh_audio->audio.dwScale /
  145.                          (float)sh_audio->audio.dwRate;
  146.         }
  147.  
  148.         audio_time -= (float)audio_header.audio_buffer_used/sh_audio->i_bps;
  149.         audio_time -= (float)audio_header.dart_buffer_size/sh_audio->o_bps;
  150.  
  151.         video_time = d_video->pts;
  152.  
  153.         audio_time += SyncCorrection;
  154.     }
  155.     else
  156.     {
  157.         video_time = d_video->pts;
  158.         audio_time = video_time;
  159.     }
  160. }
  161.  
  162. //-----------------------------------------
  163. // Gamma adjustment dialog
  164. //-----------------------------------------
  165.  
  166. MRESULT EXPENTRY GammaProc(HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2)
  167. {
  168.     ULONG ulValue;
  169.     char cData[128];
  170.  
  171.     switch (msg)
  172.     {
  173.         case WM_CLOSE:
  174.             WinDismissDlg(hwndDlg, DID_CANCEL);
  175.             break;
  176.  
  177.         case WM_COMMAND:
  178.             switch (SHORT1FROMMP(mp1))
  179.             {
  180.                 case ID_CLOSE:
  181.                     WinDismissDlg(hwndDlg, ID_CLOSE);
  182.                     break;
  183.             }
  184.             break;
  185.  
  186.         case WM_INITDLG:
  187.             {
  188.                 USHORT usValue = (ScreenGamma + 128)/(256/32);
  189.                 WinSendDlgItemMsg(hwndDlg, ID_GAMMA, SLM_SETTICKSIZE,
  190.                                   MPFROM2SHORT(SMA_SETALLTICKS, 6), NULL);
  191.  
  192.                 WinSendDlgItemMsg(hwndDlg, ID_GAMMA, SLM_SETSLIDERINFO,
  193.                                   MPFROM2SHORT(SMA_SLIDERARMPOSITION,
  194.                                                SMA_INCREMENTVALUE),
  195.                                   MPFROMSHORT(usValue));
  196.  
  197.                 sprintf(cData, "Gamma Correction (%d)", ScreenGamma);
  198.                 WinSetWindowText(hwndDlg, cData);
  199.             }
  200.             break;
  201.  
  202.         case WM_CONTROL:
  203.  
  204.             switch (SHORT1FROMMP(mp1))
  205.             {
  206.                 case ID_GAMMA:
  207.                     ulValue = (ULONG)WinSendDlgItemMsg(hwndDlg, ID_GAMMA,
  208.                                                        SLM_QUERYSLIDERINFO,
  209.                                                        MPFROM2SHORT(SMA_SLIDERARMPOSITION,
  210.                                                                     SMA_INCREMENTVALUE),
  211.                                                        NULL);
  212.  
  213.                     ulValue = ulValue * (256/32) - 128;
  214.                     ScreenGamma = ulValue;
  215.                     yuv2rgb_set_gamma(ScreenGamma);
  216.                     sprintf(cData, "Gamma Correction (%d)", ScreenGamma);
  217.                     WinSetWindowText(hwndDlg, cData);
  218.                     break;
  219.             }
  220.  
  221.             break;
  222.  
  223.         default:
  224.             return WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  225.     }
  226.     return (MRESULT) FALSE;
  227. }
  228.  
  229. //-----------------------------------------
  230. // Various handlers
  231. //-----------------------------------------
  232.  
  233. void TerminateHandler(diveWindow*, void *Self)
  234. {
  235.     Shutdown = TRUE;
  236. }
  237.  
  238. void MouseHandler(diveWindow* pWnd, HWND hWnd, void *param, int Button, bool Down,
  239.                   int x, int y, int ShiftFlags)
  240. {
  241.     if(Button == 2)
  242.     {
  243.         HWND hwndPopup;
  244.         POINTL ptlPoint;
  245.  
  246.         HWND hwndFrame = WinQueryWindow(hWnd, QW_PARENT);
  247.  
  248.         hwndPopup = WinLoadMenu(hwndFrame, 0, idDiveMenu);
  249.  
  250.         if(pWnd->isPaused())
  251.             CheckMenuItem(hwndPopup, cmdPause2);
  252.  
  253.         if(!pWnd->isAspectRatioConst())
  254.             CheckMenuItem(hwndPopup, cmdToggleAspect);
  255.  
  256.         if(pWnd->isFullScreen())
  257.             CheckMenuItem(hwndPopup, cmdFullScreen2);
  258.  
  259.         WinQueryPointerPos(HWND_DESKTOP, &ptlPoint);
  260.         WinPopupMenu(HWND_DESKTOP, hwndFrame, hwndPopup,
  261.                      ptlPoint.x, ptlPoint.y, 0,
  262.                      0
  263.                      | PU_NONE
  264.                      | PU_KEYBOARD
  265.                      | PU_MOUSEBUTTON1
  266.                      | PU_MOUSEBUTTON2
  267.                      | PU_HCONSTRAIN
  268.                      | PU_VCONSTRAIN);
  269.     }
  270. }
  271.  
  272. void KeyboardHandler(diveWindow*, void *Self, unsigned char ScanCode,
  273.   unsigned char CharCode, bool Down, unsigned char RepeatCount, int ShiftFlags)
  274. {
  275. //    printf("Key - Scancode(%d) Char(%c) Pressed(%d) Count(%d) ShiftFlags(%04X)\n",
  276. //            ScanCode, CharCode, Down, RepeatCount, ShiftFlags);
  277.  
  278.     if(ScanCode == ScanExit)
  279.     {
  280.         Shutdown = TRUE;
  281.         return;
  282.     }
  283.  
  284.     if(Down != 1)
  285.         return;
  286.  
  287.     switch(ScanCode)
  288.     {
  289.         case ScanFS:
  290.             {
  291.                 if(FullScreen == TRUE)
  292.                 {
  293.                     FullScreen = FALSE;
  294.                     dW->MouseVisible(TRUE);
  295.                 }
  296.                 else
  297.                 {
  298.                     FullScreen = TRUE;
  299.                     dW->MouseVisible(FALSE);
  300.                 }
  301.  
  302.                 dW->Command(cmdFullScreen);
  303.             }
  304.             break;
  305.         case ScanGammaDec:
  306.             if (ScreenGamma > -128)
  307.             {
  308.                 ScreenGamma--;
  309.                 yuv2rgb_set_gamma(ScreenGamma);
  310.             }
  311.             break;
  312.         case ScanGammaInc:
  313.             if (ScreenGamma < 128)
  314.             {
  315.                 ScreenGamma++;
  316.                 yuv2rgb_set_gamma(ScreenGamma);
  317.             }
  318.             break;
  319.         case ScanPause1:
  320.         case ScanPause2:
  321.             if (Pause == TRUE)
  322.             {
  323.                 Pause = FALSE;
  324.  
  325.                 dart_resume();
  326.                 dW->Command(cmdPause);
  327.             }
  328.             else
  329.             {
  330.                 DosRequestMutexSem(dart_cb_mtx, (ULONG)SEM_INDEFINITE_WAIT);
  331.  
  332.                 Pause = TRUE;
  333.  
  334.                 dart_pause();
  335.                 dW->Command(cmdPause);
  336.  
  337.                 DosReleaseMutexSem(dart_cb_mtx);
  338.             }
  339.             break;
  340.         case ScanBack10s:
  341.             SeekFlag = SEEK_BACKWARD_10S;
  342.             break;
  343.         case ScanFwd10s:
  344.             SeekFlag = SEEK_FORWARD_10S;
  345.             break;
  346.         case ScanFwd60s:
  347.             SeekFlag = SEEK_FORWARD_60S;
  348.             break;
  349.         case ScanBack60s:
  350.             SeekFlag = SEEK_BACKWARD_60S;
  351.             break;
  352.         case ScanFwd600s:
  353.             SeekFlag = SEEK_FORWARD_600S;
  354.             break;
  355.         case ScanBack600s:
  356.             SeekFlag = SEEK_BACKWARD_600S;
  357.             break;
  358.         case ScanSyncDec:
  359.             SyncCorrection -= 0.1f;
  360.             break;
  361.         case ScanSyncInc:
  362.             SyncCorrection += 0.1f;
  363.             break;
  364.         case ScanMute:
  365.         if (Mute == FALSE)
  366.             {
  367.                 Mute = TRUE;
  368.  
  369.                 DosRequestMutexSem(dart_cb_mtx, (ULONG)SEM_INDEFINITE_WAIT);
  370.  
  371.                 dart_set_sound_state(Mute);
  372.  
  373.                 DosReleaseMutexSem(dart_cb_mtx);
  374.             }
  375.             else
  376.             {
  377.                 Mute = FALSE;
  378.  
  379.                 DosRequestMutexSem(dart_cb_mtx, (ULONG)SEM_INDEFINITE_WAIT);
  380.  
  381.                 dart_set_sound_state(Mute);
  382.  
  383.                 DosReleaseMutexSem(dart_cb_mtx);
  384.             }
  385.             break;
  386.         case ScanVolumeInc:
  387.             if (AudioVolume < 100)
  388.                 AudioVolume++;
  389.  
  390.             DosRequestMutexSem(dart_cb_mtx, (ULONG)SEM_INDEFINITE_WAIT);
  391.  
  392.             dart_set_volume(AudioVolume);
  393.  
  394.             DosReleaseMutexSem(dart_cb_mtx);
  395.  
  396.             break;
  397.         case ScanVolumeDec:
  398.             if (AudioVolume > 0)
  399.                 AudioVolume--;
  400.  
  401.             DosRequestMutexSem(dart_cb_mtx, (ULONG)SEM_INDEFINITE_WAIT);
  402.  
  403.             dart_set_volume(AudioVolume);
  404.  
  405.             DosReleaseMutexSem(dart_cb_mtx);
  406.  
  407.             break;
  408.     }
  409. }
  410.  
  411. MPARAM CmdHandler(diveWindow* p, void *param, HWND hWnd, MPARAM mp1, MPARAM mp2, int Mode)
  412. {
  413.     if(!Mode)    //Ignore pre-action call
  414.     {
  415.         //Return same command as passed.
  416.         //This allows default command handlers to work properly.
  417.         return mp1;
  418.     }
  419.  
  420.     switch((ULONG) mp1)
  421.     {
  422.         case cmdFullScreen2: KeyboardHandler(0, p, ScanFS, 0, 1, 0, 0); break;
  423.         case cmdPause2     : KeyboardHandler(0, p, ScanPause2, 0, 1, 0, 0); break;
  424.         case cmdSeek10sFwd : KeyboardHandler(0, p, ScanFwd10s, 0, 1, 0, 0); break;
  425.         case cmdSeek60sFwd : KeyboardHandler(0, p, ScanFwd60s, 0, 1, 0, 0); break;
  426.         case cmdSeek10mFwd : KeyboardHandler(0, p, ScanFwd600s, 0, 1, 0, 0); break;
  427.         case cmdSeek10sBack: KeyboardHandler(0, p, ScanBack10s, 0, 1, 0, 0); break;
  428.         case cmdSeek60sBack: KeyboardHandler(0, p, ScanBack60s, 0, 1, 0, 0); break;
  429.         case cmdSeek10mBack: KeyboardHandler(0, p, ScanBack600s, 0, 1, 0, 0); break;
  430.         case cmdGammInc    : KeyboardHandler(0, p, ScanGammaInc, 0, 1, 0, 0); break;
  431.         case cmdGammaDec   : KeyboardHandler(0, p, ScanGammaDec, 0, 1, 0, 0); break;
  432.  
  433.         case cmdGamma:
  434.             {
  435.                 HWND wnd = WinLoadDlg(HWND_DESKTOP, hWnd,
  436.                                       GammaProc, 0, ID_SET_DLG, 0);
  437.                 WinProcessDlg(wnd);
  438.                 WinDestroyWindow(wnd);
  439.             }
  440.             break;
  441.     }
  442.  
  443.     return 0;   //Value does not matter, it's ignored
  444. }
  445.  
  446. //-----------------------------------------
  447. // DART worker
  448. //-----------------------------------------
  449.  
  450. void APIENTRY PlayAudio(ULONG Parm)
  451. {
  452.     dart_play();
  453.  
  454.     while(DART.Stopped != TRUE)
  455.     {
  456.         DosSleep(100);
  457.     }
  458.  
  459.     dart_stop();
  460.  
  461.     no_audio = TRUE;
  462.  
  463.     return;
  464. }
  465.  
  466. //-----------------------------------------
  467. // Video worker
  468. //-----------------------------------------
  469.  
  470. void APIENTRY PlayVideo(ULONG Parm)
  471. {
  472.     int rc;
  473.     ULONG TimerFreq;
  474.     int FrameTimer;
  475.     QWORD Qres;
  476.     unsigned long long StartDec, EndDec;
  477.     float frame_delay;
  478.     ULONG numwait;
  479.     int numcadr;
  480.     int SkipFrame = 0;
  481.     int SkippedFrames = 0;
  482.     ULONG bpl = 0;
  483.     int show_info = -1;
  484.  
  485.     unsigned char *DiveMemory;
  486.  
  487.     DosTmrQueryFreq(&TimerFreq);
  488.     DosTmrQueryTime(&Qres);
  489.     StartDec = Q2LL(Qres);
  490.     FrameTimer = 0;
  491.  
  492.     CalcAVtime();
  493.  
  494.     while(Shutdown == 0)
  495.     {
  496.         DosTmrQueryTime(&Qres);
  497.         EndDec = Q2LL(Qres);
  498.  
  499.         if (no_audio == TRUE)
  500.             CalcAVtime();
  501.  
  502.         frame_delay = (audio_time - video_time) / sh_video->fps;
  503.  
  504.         if (show_info++ > (int)sh_video->fps * 5.0f || show_info < 0)
  505.         {
  506.             printf("A: %5.1f V: %5.1f A-V: %3.2f C: %3.2f \r",
  507.                    audio_time, video_time, audio_time - video_time,
  508.                    SyncCorrection);
  509.  
  510.             fflush(stdout);
  511.  
  512.             show_info = 0;
  513.         }
  514.  
  515.         FrameTimer += (EndDec - StartDec);
  516.  
  517.         if (frame_delay)
  518.         {
  519.             FrameTimer += (TimerFreq/sh_video->fps) * frame_delay;
  520.             frame_delay = 0;
  521.         }
  522.  
  523.         StartDec = EndDec;
  524.  
  525.         numcadr = ((float)FrameTimer)/TimerFreq;
  526.  
  527.         // A and B defines maximum proportion of frames to be skipped.
  528.         // Now for 5 skipped we must show at least 1 real.
  529.         if (numcadr > 2 + max(0, SkippedFrames) / 2)
  530.         {
  531.             SkipFrame = TRUE;
  532.             SkippedFrames++; // A
  533.         }
  534.         else
  535.         if (SkippedFrames > 0)
  536.             SkippedFrames = 0; // B
  537.  
  538.         if (numcadr > 0)
  539.         {
  540.             FrameTimer -= TimerFreq/sh_video->fps;
  541.  
  542.   NextMem:
  543.  
  544.             if (SeekFlag != SEEK_NONE)
  545.             {
  546.                 DosRequestMutexSem(dart_cb_mtx, (ULONG)SEM_INDEFINITE_WAIT);
  547.  
  548.                 switch(SeekFlag)
  549.                 {
  550.                     case SEEK_FORWARD_10S:
  551.                         demux_seek(demuxer, 10, 0);
  552.                     break;
  553.  
  554.                     case SEEK_BACKWARD_10S:
  555.                         demux_seek(demuxer, -10, 0);
  556.                     break;
  557.  
  558.                     case SEEK_FORWARD_60S:
  559.                         demux_seek(demuxer, 60, 0);
  560.                     break;
  561.  
  562.                     case SEEK_BACKWARD_60S:
  563.                         demux_seek(demuxer, -60, 0);
  564.                     break;
  565.  
  566.                     case SEEK_FORWARD_600S:
  567.                         demux_seek(demuxer, 600, 0);
  568.                     break;
  569.  
  570.                     case SEEK_BACKWARD_600S:
  571.                         demux_seek(demuxer, -600, 0);
  572.                     break;
  573.                 }
  574.  
  575.                 DosReleaseMutexSem(dart_cb_mtx);
  576.  
  577.                 SeekFlag = SEEK_NONE;
  578.                 FrameTimer = 0;
  579.                 frame_delay = 0;
  580.                 SkipFrame = FALSE;
  581.  
  582.                 CalcAVtime();
  583.             }
  584.  
  585.             if (Pause == TRUE)
  586.             {
  587.                 DosSleep(2);
  588.                 continue;
  589.             }
  590.  
  591.  
  592.             switch(video_header.codec)
  593.             {
  594.                 case CODEC_FFMPEG:
  595.                 {
  596.                     if ((rc = video_decode(sh_video, NULL, 0)) == -1)
  597.                     {
  598.                         Shutdown = TRUE;
  599.                         break;
  600.                     }
  601.  
  602.                     if (rc == 0 && SkipFrame == FALSE)
  603.                     {
  604.                         DiveMemory = (unsigned char *)dW->BeginPaint(&bpl, DIVE_NEXTBUFFER);
  605.  
  606.                         if (DiveMemory == NULL)
  607.                             continue;
  608.  
  609.                         video_blit(sh_video, DiveMemory, bpl);
  610.  
  611.                         dW->EndPaint();
  612.                         dW->Switch(DIVE_NEXTBUFFER);
  613.                         dW->WaitSwitch();
  614.                     }
  615.                     else
  616.                         SkipFrame = FALSE;
  617.                 }
  618.                 break;
  619.  
  620.                 case CODEC_LIBMPEG2:
  621.                 {
  622.                     if (SkipFrame == FALSE)
  623.                     {
  624.                         DiveMemory = (unsigned char *)dW->BeginPaint(&bpl, DIVE_NEXTBUFFER);
  625.  
  626.                         if (DiveMemory == NULL)
  627.                             continue;
  628.  
  629.                         rc = video_decode(sh_video, DiveMemory, bpl);
  630.  
  631.                         dW->EndPaint();
  632.                         dW->Switch(DIVE_NEXTBUFFER);
  633.                         dW->WaitSwitch();
  634.  
  635.                         if (rc == -1)
  636.                         {
  637.                             Shutdown = TRUE;
  638.                             break;
  639.                         }
  640.                     }
  641.                     else
  642.                         SkipFrame = FALSE;
  643.                 }
  644.                 break;
  645.             }
  646.         }
  647.         else
  648.         {
  649.             DosSleep(1);
  650.         }
  651.     }
  652.  
  653.     dart_stop();
  654.  
  655.     printf("video thread exiting\n");
  656.     fflush(stdout);
  657.  
  658.     return;
  659. }
  660.  
  661. int GetBestDIVEMode(void)
  662. {
  663.     DIVE_CAPS caps;
  664.     FOURCC fourcc;
  665.     char *caps_buffer;
  666.     int i, best_format;
  667.  
  668.     caps_buffer = (char *)malloc(512);
  669.     caps.ulStructLen = sizeof(DIVE_CAPS);
  670.     caps.ulFormatLength = 512;
  671.     caps.pFormatData = caps_buffer;
  672.     caps.ulPlaneCount = 0;
  673.  
  674.     DiveQueryCaps(&caps, DIVE_BUFFER_SCREEN);
  675.  
  676.     best_format = -1;
  677.  
  678. #if 0
  679.     for (i = 0; i < caps.ulInputFormats; i++)
  680.     {
  681.         fourcc = ((FOURCC *) caps.pFormatData)[i];
  682.         printf("%.4s ", (char*)&fourcc);
  683.     }
  684.  
  685.     printf("\n");
  686. #endif
  687.  
  688.     for (i = 0; i < caps.ulInputFormats; i++)
  689.     {
  690.         fourcc = ((FOURCC *) caps.pFormatData)[i];
  691.  
  692.         if (strnicmp((char*)&fourcc, "Y422", 4) == 0)
  693.         {
  694.             best_format = FMT_YUV422;
  695.  
  696.             break;
  697.         }
  698.  
  699.         if (strnicmp((char*)&fourcc, "R565", 4) == 0)
  700.         {
  701.             best_format = FMT_RGB16;
  702.  
  703.             break;
  704.         }
  705.  
  706.         if (strnicmp((char*)&fourcc, "BGR3", 4) == 0)
  707.         {
  708.             best_format = FMT_BGR24;
  709.  
  710.             break;
  711.         }
  712.     }
  713.  
  714.     free(caps_buffer);
  715.  
  716.     return best_format;
  717. }
  718.  
  719. int main(int argc, char *argv[])
  720. {
  721.     PPIB  pib;
  722.     PTIB  tib;
  723.     ULONG OldProcessType;
  724.  
  725.     TID AudioThread, VideoThread;
  726.  
  727.     HWND  WinHandle;
  728.     PMrq  rq;
  729.     FOURCC fccColorFormat;
  730.  
  731.     char  pszTitleText[64];
  732.     int   WindowX, WindowY, WindowWidth, WindowHeight;
  733.     int   SrcWindowWidth, SrcWindowHeight;
  734.     int   rc, outbytes;
  735.  
  736.     int AudioDeviceIndex = 0;
  737.     int AudioResampleFlag = RESAMPLE_NONE;
  738.     int AudioID = -1;
  739.     int VideoID = -1;
  740.     int VideoFormat = -1;
  741.  
  742.     int file_format = DEMUXER_TYPE_UNKNOWN;
  743.  
  744.     int ArgNum;
  745.     int show_info;
  746.     int AudioDisable = FALSE;
  747.     int KeepAspect = FALSE;
  748.     int ForceAspect = FALSE;
  749.     float NewAspect = 1.0;
  750.  
  751.     // Detect the best output format
  752.     VideoFormat = GetBestDIVEMode();
  753.  
  754.     if (argc <= 1) {
  755.  
  756.         printf("Usage: WarpVision [options] movie_file\n\n");
  757.         printf(" Audio options:\n");
  758.         printf("  -noaudio - Disable audio\n");
  759.         printf("  -44100   - Resample audio 48kHz to 44kHz\n");
  760.         printf("  -48000   - Resample any audio samplerate to 48kHz\n");
  761.         printf("  -adevXX  - Select audio device 0...\n");
  762.         printf("  -aidXXX  - Select audio channel\n");
  763.         printf("\n");
  764.         printf(" Video options:\n");
  765.         printf("  -vrgb    - Output decoded frames in RGB16\n");
  766.         printf("  -vbgr    - Output decoded frames in BGR24\n");
  767.         printf("  -vyuv    - Output decoded frames in YUV422\n");
  768.         printf("  -idx     - Rebuild AVI file index\n");
  769.         printf("  -vidXXX  - Select video channel\n");
  770.         printf("  -vaspect - Keep aspect ratio\n");
  771.         printf("  -vasp43  - Force aspect ratio to 4:3\n");
  772.         printf("  -vasp169 - Force aspect ratio to 16:9\n");
  773.  
  774.         exit(1);
  775.     }
  776.  
  777.     printf("Command line:");
  778.  
  779.     for(ArgNum = 0; ArgNum < argc; ArgNum++)
  780.     {
  781.  
  782.         if (strcmp(argv[ArgNum], "-44100") == 0)
  783.             AudioResampleFlag = RESAMPLE_TO_44100;
  784.  
  785.         if (strcmp(argv[ArgNum], "-48000") == 0)
  786.             AudioResampleFlag = RESAMPLE_TO_48000;
  787.  
  788.         if (strncmp(argv[ArgNum], "-adev", 5) == 0)
  789.             AudioDeviceIndex = atoi(argv[ArgNum] + 5);
  790.  
  791.         if (strcmp(argv[ArgNum], "-idx") == 0)
  792.             index_mode = 2; // generate index
  793.  
  794.         if (strcmp(argv[ArgNum], "-noaudio") == 0)
  795.             AudioDisable = TRUE;
  796.  
  797.         if (strcmp(argv[ArgNum], "-vaspect") == 0)
  798.             KeepAspect = TRUE;
  799.  
  800.         if (strcmp(argv[ArgNum], "-vasp43") == 0)
  801.         {
  802.             ForceAspect = TRUE;
  803.             NewAspect = 4.0/3.0;
  804.         }
  805.  
  806.         if (strcmp(argv[ArgNum], "-vasp169") == 0)
  807.         {
  808.             ForceAspect = TRUE;
  809.             NewAspect = 16.0/9.0;
  810.         }
  811.  
  812.         if (strncmp(argv[ArgNum], "-aid", 4) == 0)
  813.             AudioID = atoi(argv[ArgNum] + 4);
  814.  
  815.         if (strncmp(argv[ArgNum], "-vid", 4) == 0)
  816.             VideoID = atoi(argv[ArgNum] + 4);
  817.  
  818.         if (strcmp(argv[ArgNum], "-vrgb") == 0)
  819.             VideoFormat = FMT_RGB16;
  820.  
  821.         if (strcmp(argv[ArgNum], "-vbgr") == 0)
  822.             VideoFormat = FMT_BGR24;
  823.  
  824.         if (strcmp(argv[ArgNum], "-vyuv") == 0)
  825.             VideoFormat = FMT_YUV422;
  826.  
  827.         if (strncmp(argv[ArgNum], "-dvd", 4) == 0)
  828.             dvd_title = atoi(argv[ArgNum] + 4);
  829.  
  830.         if (strncmp(argv[ArgNum], "-chapter", 8) == 0)
  831.             dvd_chapter = atoi(argv[ArgNum] + 8);
  832.  
  833.         if (strncmp(argv[ArgNum], "-angle", 6) == 0)
  834.             dvd_angle = atoi(argv[ArgNum] + 6);
  835.  
  836.         printf(" '%s'",argv[ArgNum]);
  837.     }
  838.  
  839.     printf("\n");
  840.  
  841.     DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MINIMUM, PRTYS_PROCESSTREE);
  842. //    DosSetPriority (PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, PRTYS_PROCESSTREE);
  843.  
  844.     DosGetInfoBlocks (&tib, &pib);
  845.     OldProcessType = pib->pib_ultype;
  846.     pib->pib_ultype = 3;
  847.  
  848.     gdMH = NULLHANDLE;
  849.  
  850.     DosCreateMutexSem(NULL, &demux_mtx, 0, FALSE);
  851.     DosCreateMutexSem(NULL, &dart_cb_mtx, 0, FALSE);
  852.  
  853.     // Init streams
  854.  
  855.     stream = open_stream(argv[argc-1], 0, &file_format);
  856.  
  857.     if(!stream)
  858.     {
  859.         exit(1);
  860.     }
  861.  
  862.     if (AudioDisable == TRUE)
  863.     {
  864.         printf("Audio: disabled\n");
  865.         AudioID = -2; // don't read audio packets
  866.     }
  867.  
  868.     demuxer = demux_open(stream, file_format, AudioID, VideoID, -1);
  869.  
  870.     if(demuxer == NULL)
  871.     {
  872.         printf("Cannot open demuxer\n");
  873.         exit(1);
  874.     }
  875.  
  876.     d_audio = demuxer->audio;
  877.     d_video = demuxer->video;
  878.  
  879.     if (AudioDisable == TRUE)
  880.         sh_audio = NULL;
  881.     else
  882.         sh_audio=(sh_audio_t *)d_audio->sh;
  883.  
  884.     sh_video=(sh_video_t *)d_video->sh;
  885.  
  886.     // Find & init audio codec
  887.  
  888.     if (sh_audio != NULL)
  889.     {
  890.         sh_audio->codec=find_audio_codec(sh_audio->format);
  891.  
  892.         if (sh_audio->codec->codec_supported == TRUE)
  893.         {
  894.             printf("Found audio codec: %s\n", sh_audio->codec->codec_name);
  895.  
  896.             rc = audio_init(sh_audio, AudioDeviceIndex, AudioResampleFlag);
  897.  
  898.             AudioVolume = dart_get_volume();
  899.  
  900.             printf("Audio: sample rate: %d, bit rate: %d kbps, scannels: %d\n",
  901.                    audio_header.sample_rate, audio_header.bit_rate,
  902.                    audio_header.channels);
  903.  
  904.             if (rc != TRUE)
  905.                 no_audio = TRUE;
  906.             else
  907.                 no_audio = FALSE;
  908.         }
  909.         else
  910.         {
  911.             printf("Found audio codec: %s\n", sh_audio->codec->codec_name);
  912.  
  913.             ds_free_packs(d_audio);
  914.             d_audio->id = -2;
  915.             no_audio = TRUE;
  916.             sh_audio = NULL;
  917.             d_audio->sh = NULL;
  918.         }
  919.     }
  920.     else
  921.     {
  922.         ds_free_packs(d_audio);
  923.         d_audio->id = -2;
  924.         no_audio = TRUE;
  925.         sh_audio = NULL;
  926.         d_audio->sh = NULL;
  927.     }
  928.  
  929.     if (sh_video != NULL)
  930.     {
  931.         video_read_properties(sh_video);
  932.  
  933.         switch(sh_video->ds->demuxer->file_format)
  934.         {
  935.             case DEMUXER_TYPE_ASF:
  936.                 sh_video->aspect = 1.0;
  937.  
  938.                 printf("Video: fourcc:[%.4s] size:%dx%d\n",
  939.                        (char *)&sh_video->format,
  940.                        sh_video->disp_w,sh_video->disp_h);
  941.             break;
  942.  
  943.             case DEMUXER_TYPE_AVI:
  944.             case DEMUXER_TYPE_AVI_NI:
  945.             case DEMUXER_TYPE_AVI_NINI:
  946.                 sh_video->aspect = 1.0;
  947.  
  948.                 printf("Video: fourcc:[%.4s] size:%dx%d fps:%5.2f\n",
  949.                        (char *)&sh_video->format, sh_video->disp_w,sh_video->disp_h,
  950.                        sh_video->fps);
  951.             break;
  952.             case DEMUXER_TYPE_MPEG_ES:
  953.             case DEMUXER_TYPE_MPEG_PS:
  954.                 char aspect[8];
  955.  
  956.                 switch(sh_video->aspect_info)
  957.                 {
  958.                     case 2:
  959.                     case 4:
  960.                     case 8:
  961.                     case 12:
  962.                         strcpy(aspect, "4:3");
  963.                     break;
  964.  
  965.                     case 3:
  966.                     case 6:
  967.                         strcpy(aspect, "16:9");
  968.                     break;
  969.  
  970.                     default:
  971.                         strcpy(aspect, "1:1");
  972.                         sh_video->aspect = 1.0;
  973.                     break;
  974.                 }
  975.  
  976.                 printf("Video: MPEG%d size:%dx%d aspect:%d(%s) fps:%5.2f\n",
  977.                        sh_video->format & 0xF,
  978.                        sh_video->disp_w,sh_video->disp_h,
  979.                        sh_video->aspect_info, aspect,
  980.                        sh_video->fps);
  981.  
  982.                 if (KeepAspect == TRUE)
  983.                     sh_video->aspect = 1.0;
  984.  
  985.                 if (ForceAspect == TRUE)
  986.                     sh_video->aspect = NewAspect;
  987.  
  988.             break;
  989.         }
  990.  
  991.         // Find & init video codec
  992.         sh_video->codec=find_video_codec(sh_video->format);
  993.  
  994.         printf("Found video codec: %s\n", sh_video->codec->codec_name);
  995.  
  996.         if (sh_video->codec->codec_supported == FALSE)
  997.             return 1;
  998.     }
  999.  
  1000.     switch(VideoFormat)
  1001.     {
  1002.         case FMT_RGB16:
  1003.             printf("Using RGB16 (R565) for DIVE blitting\n");
  1004.         break;
  1005.  
  1006.         case FMT_BGR24:
  1007.             printf("Using BGR24 (BGR3) for DIVE blitting\n");
  1008.         break;
  1009.  
  1010.         case FMT_YUV422:
  1011.             printf("Using YUV422 (Y422) for DIVE blitting\n");
  1012.         break;
  1013.  
  1014.         default:
  1015.         {
  1016.             printf("Cannot detect usable DIVE mode.\n");
  1017.             printf("Using RGB16 (R565) for DIVE blitting\n");
  1018.             VideoFormat = FMT_RGB16;
  1019.         }
  1020.     }
  1021.  
  1022.     video_header.format = VideoFormat;
  1023.  
  1024.     if (video_init(sh_video, sh_video->codec->codec_type) != 0)
  1025.         exit(1);
  1026.  
  1027.     // DIVE Output video frame format
  1028.  
  1029.     switch(video_header.format)
  1030.     {
  1031.         case FMT_RGB16:
  1032.             fccColorFormat = FOURCC_R565;
  1033.             video_header.format_bpp = 2;
  1034.         break;
  1035.  
  1036.         case FMT_BGR24:
  1037.             fccColorFormat = FOURCC_BGR3;
  1038.             video_header.format_bpp = 3;
  1039.         break;
  1040.  
  1041.         case FMT_YUV422:
  1042.             fccColorFormat = FOURCC_Y422;
  1043.             video_header.format_bpp = 2;
  1044.         break;
  1045.     }
  1046.  
  1047.     // Initialize DIVE
  1048.     if (!gdDiveInitialize ())
  1049.     {
  1050.       printf ("Unable to initialize DIVE\n");
  1051.       exit (1);
  1052.     }
  1053.  
  1054.     // Calc window size
  1055.  
  1056.     WindowX = 10;
  1057.     WindowY = 10;
  1058.     SrcWindowWidth = (sh_video->disp_w + 15) &~ 15;
  1059.     SrcWindowHeight = sh_video->disp_h;
  1060.     WindowWidth = (sh_video->disp_w + 15) &~ 15;
  1061.     WindowHeight = sh_video->disp_h;
  1062.  
  1063.     if (sh_video->aspect != 1.0)
  1064.     {
  1065.         if (((float)WindowHeight * (float)sh_video->aspect) < SrcWindowWidth)
  1066.         { // 4/3
  1067.             WindowHeight = (float)WindowWidth / (float)sh_video->aspect;
  1068.         }
  1069.         else
  1070.         { // 16/9
  1071.             WindowWidth = (float)WindowHeight * (float)sh_video->aspect;
  1072.             WindowWidth = (WindowWidth + 15) &~ 15;
  1073.         }
  1074.  
  1075.         printf("Video aspect correction: %dx%d -> %dx%d\n", sh_video->disp_w, sh_video->disp_h,
  1076.                WindowWidth, WindowHeight);
  1077.     }
  1078.  
  1079.     // Create PM window
  1080.     sprintf(pszTitleText,
  1081.             "WarpVision v0.0.14e (%dx%d)",
  1082.             sh_video->disp_w, sh_video->disp_h);
  1083.  
  1084.     rq.Parm.CreateWindow.Title = pszTitleText;
  1085.     if ((rc = PMcall (pmcmdCreateWindow, &rq)) != pmrcOK)
  1086.     {
  1087.       printf ("Cannot create PM window: no resources bound to executable?\n");
  1088.       return FALSE;
  1089.     }
  1090.  
  1091.     WinHandle = rq.Parm.CreateWindow.Handle;
  1092.  
  1093.     FGVideoMode Mode = // selected mode with double buffering
  1094.     { WindowWidth, WindowHeight, fccColorFormat, 2, SrcWindowWidth, SrcWindowHeight, vmfWindowed };
  1095.  
  1096.     // Create DIVE contect
  1097.     rq.Parm.CreateCtx.Mode = &Mode;
  1098.     if ((rc = PMcall (pmcmdCreateDIVEctx, &rq)) != pmrcOK)
  1099.     {
  1100.       printf ("Cannot create DIVE context\n");
  1101.       return FALSE;
  1102.     }
  1103.  
  1104.     dW = rq.Parm.CreateCtx.dW;
  1105.  
  1106.     // Setup event handlers
  1107.     dW->SetKeyboardHandler(KeyboardHandler, NULL);
  1108.     dW->SetMouseHandler(MouseHandler, NULL);
  1109.     dW->SetTerminateHandler(TerminateHandler, NULL);
  1110.     dW->SetCmdHandler(CmdHandler, NULL);
  1111.  
  1112.     // Bind DIVE context to window
  1113.     rq.Parm.BindCtx.dW = dW;
  1114.     rq.Parm.BindCtx.Handle = WinHandle;
  1115.     rq.Parm.BindCtx.DesktopW = DesktopW;
  1116.     rq.Parm.BindCtx.DesktopH = DesktopH;
  1117.     if ((rc = PMcall (pmcmdBindDIVEctx, &rq)) != pmrcOK)
  1118.     {
  1119.       printf ("Cannot bind DIVE context to window!\n");
  1120.       return FALSE;
  1121.     }
  1122.  
  1123.     if ((WindowWidth != -1) && (WindowHeight != -1))
  1124.     {
  1125.       rq.Parm.Resize.dW = dW;
  1126.       rq.Parm.Resize.Width = WindowWidth;
  1127.       rq.Parm.Resize.Height = WindowHeight;
  1128.       rq.Parm.Resize.Center = TRUE;
  1129.       PMcall (pmcmdResizeWindow, &rq);
  1130.     }
  1131.  
  1132.     // Show window
  1133.     rq.Parm.ShowWin.dW = dW;
  1134.     rq.Parm.ShowWin.State = 1;
  1135.     if ((rc = PMcall (pmcmdShowWindow, &rq)) != pmrcOK)
  1136.       return FALSE;
  1137.  
  1138.     DosCreateThread(&AudioThread,
  1139.                    (PFNTHREAD) PlayAudio,
  1140.                    0, 0L, 32767L);
  1141.  
  1142.     DosCreateThread(&VideoThread,
  1143.                    (PFNTHREAD) PlayVideo,
  1144.                    0, 0L, 32767L);
  1145.  
  1146.     DosWaitThread(&VideoThread, DCWW_WAIT);
  1147.     DosKillThread(AudioThread);
  1148.  
  1149.     DosSleep(200);
  1150.  
  1151.     // Close stream
  1152.     close_stream(stream);
  1153.  
  1154.     // Destroy DIVE context
  1155.     rq.Parm.DestroyCtx.dW = dW;
  1156.     PMcall (pmcmdDestroyDIVEctx, &rq);
  1157.  
  1158.     // Destroy PM window
  1159.     rq.Parm.DestroyWindow.Handle = WinHandle;
  1160.     PMcall (pmcmdDestroyWindow, &rq);
  1161.  
  1162.     // Deallocate DIVE resources
  1163.     gdDiveDeinitialize ();
  1164.  
  1165.     rc = DosCloseMutexSem(demux_mtx);
  1166.     rc = DosCloseMutexSem(dart_cb_mtx);
  1167.  
  1168.     pib->pib_ultype = OldProcessType;
  1169.  
  1170.     return 0;
  1171. }
  1172.