home *** CD-ROM | disk | FTP | other *** search
/ Pleasure 76 / OTACD76.bin / archive / game / PsrSDK16a / PsrSDK16a.lzh / Sample / PsrStrCd / Plugin.c < prev   
C/C++ Source or Header  |  2000-12-02  |  26KB  |  805 lines

  1. /******************************************************************************/
  2. /*                                          */
  3. /* [PSストリームアクセスプラグイン]                          */
  4. /*                                          */
  5. /*    FILE NAME    : Plugin.c                             */
  6. /*    FUNCTION    : 標準STRアクセス (CD-ROM用)                  */
  7. /*                                          */
  8. /*    FUNCTIONS        | an outline                      */
  9. /*    --------------------------+-------------------------------------------- */
  10. /*    PsrQueryPlugin()    | プラグイン情報の取得                  */
  11. /*    PsrIsSupportCDBegin()    | CDサポート判定 開始処理              */
  12. /*    PsrIsSupportCDEnd()    | CDサポート判定 終了処理              */
  13. /*    PsrIsSupportCDSector()    | CDサポート判定 セクタ通知              */
  14. /*    PsrIsSupportCDResult()    | CDサポート判定 結果取得              */
  15. /*    PsrGetStrDataInfo()    | ストリームデータ情報の取得              */
  16. /*    PsrOpenCD()        | CDストリームのオープン              */
  17. /*    PsrClose()        | ストリームデータのクローズ              */
  18. /*    PsrRead()        | ストリームデータの読み取り              */
  19. /*    PsrSeek()        | 読み取り位置の設定                  */
  20. /*                                          */
  21. /*    HISTORY        | Comment                | Name          */
  22. /*    ------------------+---------------------------------------+------------ */
  23. /*    2000.06.16    | 新規作成                | ふぃろ      */
  24. /*    2000.06.27    | CD-DAトラックを含むCDにも対応    1.01    | ふぃろ      */
  25. /*    2000.06.27    | CD-DAトラックはスキップ    1.01    | ふぃろ      */
  26. /*    2000.06.27    | ダミーセクタの認識処理追加    1.01    | ふぃろ      */
  27. /*    2000.06.30    | 単位セクタ数の不良の対策    1.01    | ふぃろ      */
  28. /*    2000.07.03    | ダミーセクタ認識処理の強化    1.02    | ふぃろ      */
  29. /*    2000.07.06    | BSヘッダチェック (FF7対応)    1.03    | ふぃろ      */
  30. /*    2000.07.11    | PSRPLUGIN構造体の変更        1.10    | ふぃろ      */
  31. /*    2000.07.12    | CD解析中断用処理の追加    1.10    | ふぃろ      */
  32. /*    2000.07.12    | サンプリングレートの判定    1.10    | ふぃろ      */
  33. /*    2000.07.15    | フレームレート誤認識        1.11    | ふぃろ      */
  34. /*    2000.07.16    | オーディオ判定        1.11    | ふぃろ      */
  35. /*    2000.07.19    | フレームレート判定(0.5step)    1.12    | ふぃろ      */
  36. /*    2000.07.20    | STR終端判定強化        1.13    | ふぃろ      */
  37. /*    2000.07.23    | 0割り(暫定対策)        1.14    | ふぃろ      */
  38. /*    2000.08.03    | 可変フレームレート対策    1.20    | ふぃろ      */
  39. /*    2000.08.08    | 誤認識対策            1.21    | ふぃろ      */
  40. /*    2000.08.10    | 誤認識対策 (その2)        1.22    | ふぃろ      */
  41. /*    2000.08.26    | CD読み取り速度設定        1.23    | ふぃろ      */
  42. /*    2000.10.28    | プラグイン仕様変更        1.30    | ふぃろ      */
  43. /*    2000.11.25    | 複数同時格納形を除外する処理    1.31    | ふぃろ      */
  44. /*    2000.12.03    | IKI形式のサポート        1.31    | ふぃろ      */
  45. /*                                          */
  46. /*            (C) Copyright ふぃろ 2000. All rights reserved.       */
  47. /******************************************************************************/
  48.  
  49. #include <stdio.h>
  50. #include <string.h>
  51. #include <malloc.h>
  52. #include <Windows.h>
  53.  
  54. #include "CdAccess.h"
  55. #include "PSRP.h"
  56.  
  57.  
  58. #define _NumAUDIOBUFF        8
  59. #define _MaxSEARCH        24
  60. //#define _SpinSPEED        -1
  61. #define _SpinSPEED        8
  62.  
  63.  
  64. typedef struct {    // セクター構造 ----------------------------------------
  65.     BYTE        abSync[12];        // CD-ROM XA 同期
  66.     BYTE        abHeader[4];        // CD-ROM XA ヘッダー
  67.     BYTE        abSubHeader[8];        // CD-ROM XA サブ・ヘッダー
  68.                         //  [01014280]x2 or [01016400]x2
  69.     USHORT        usStatus;        // 0110 xxxx xxxx VVVV  ex:6001
  70.                         //    x : Reserved for system
  71.                         //    V : Version
  72.     USHORT        usDataType;        // S--- ---- ---- ----    ex:8001
  73.                         //  S : 1=system-defained format
  74.                         //      0=user-defained format
  75.     USHORT        usSectorNo;        // セクター番号    0~
  76.     USHORT        usNumSector;        // セクター数 / フレーム
  77.     ULONG        ulFrameNo;        // フレーム番号    1~
  78.     ULONG        ulLength;        // フレーム当りのデータ長
  79.     USHORT        usWidth;        // イメージ幅
  80.     USHORT        usHeight;        // イメージ高さ
  81.     ULONG        ulMovieHeadM;        // Reserved for system
  82.     ULONG        ulMovieHeadV;        // Reserved for system
  83.     ULONG        ulReserved;        // 0000 fixed
  84.     USHORT        ausMovie[0x3F0];
  85.     BYTE        abEdc[4];        // CD-ROM XA EDC
  86.     BYTE        abEcc[276];        // CD-ROM XA ECC
  87. } _TSECTOR, *_PTSECTOR;
  88.  
  89.  
  90. typedef struct {    // ストリーム情報 --------------------------------------
  91.     DWORD        dwBeginNo;    // データ開始セクタ番号
  92.     DWORD        dwLastMovieNo;    // 最後の動画セクタ番号
  93.     DWORD        dwFastAudioNo;    // 最初の音声セクタ番号
  94.     DWORD        dwLastAudioNo;    // 最後の音声セクタ番号
  95.  
  96.     BYTE        abAudioSH[4];    // 音声セクタのサブヘッダ
  97.     DWORD        nStepAudio;    // 音声セクタの間隔
  98.     DWORD        nNumAudio;    // 音声セクタ数
  99.  
  100.     DWORD        nNumFrame;    // フレーム数
  101.     SIZE        szFrame;    // フレームサイズ
  102.     DWORD        nSyncAudio;    // 動画連動音声セクタ数
  103.     DWORD        nSyncFrame;    // 音声連動フレーム数
  104.     DWORD        dwSize;        // データサイズ            1.30
  105.     USHORT        usDataType;    // 動画のデータタイプ        1.31
  106.  
  107.     WORD        wMinFrame;    // 最小フレームセクタ数
  108.     WORD        wMaxFrame;    // 最大フレームセクタ数
  109. } _TSTREAM, *_PTSTREAM;
  110.  
  111.  
  112. typedef struct {    // ストリーム探索ハンドルの内容 ------------------------
  113.     BOOL        fFindout;    // 発見フラグ
  114.     DWORD        dwPreBeginNo;    // 直前のフレームの開始セクタ番号
  115.     DWORD        nNumAudio;    // dwPreBeginNoからのオーディオセクタ数
  116.     INT        iBuffer;    // ストリームバッファ数
  117.     INT        iNum;        // ストリーム数
  118.     _PTSTREAM    pstr;        // ストリーム情報群
  119. } _TFIND, *_PTFIND;
  120.  
  121.  
  122. typedef struct {    // ストリームハンドルの内容 ----------------------------
  123.     HANDLE        hCdrom;        // CD-ROMハンドル
  124.     PSRSTREAMINFO    str;        // ストリームデータ情報
  125.     DWORD        nStepAudio;    // オーディオセクタ間隔
  126.     _PTSECTOR    apaudio[_NumAUDIOBUFF];    // 退避オーディオセクタ
  127. } _THANDLE, *_PTHANDLE;
  128.  
  129.  
  130. enum { _TypeUNKNOW, _TypeDUMMY, _TypeAUDIO, _TypeMOVIE };
  131.  
  132.  
  133.  
  134. //****--------------------------------------------------------------------------
  135. //****    _psrGetFrameRate() : フレームレートの取得
  136. //****--------------------------------------------------------------------------
  137.  
  138. static WORD    _strGetFrameRate(SIZE szFrame, DWORD nMinSect, DWORD nMaxSect) {
  139.     DWORD        nMBlock, nReso, nLength;
  140.     WORD        wReso, wLength;
  141.  
  142.  
  143.     nMBlock    = ((szFrame.cx + 15) / 16) * ((szFrame.cy + 15) / 16);
  144.     nReso    = 90000 / nMBlock;
  145.     if(nReso < 150)        wReso = 75;
  146.     else if(nReso < 300)    wReso = 150;
  147.     else if(nReso < 600)    wReso = 300;
  148.     else             wReso = 600;
  149.  
  150.     nLength    = (nMinSect + nMaxSect) * (0x7e0 / 2);
  151.     if(nLength > 20 * 1024)        wLength = 75;
  152.     else if(nLength > 10 * 1024)    wLength = 150;
  153.     else if(nLength >  5 * 1024)    wLength = 300;
  154.     else                wLength = 600;
  155.  
  156.     return min(wReso, wLength);
  157. }
  158.  
  159. /******************************************************************************/
  160. /*                                          */
  161. /*    PsrQueryPlugin() : プラグイン情報の取得                      */
  162. /*                                          */
  163. /******************************************************************************/
  164.  
  165. CEXPORT    VOID    PsrQueryPlugin(
  166.     LPPSRPLUGIN    lpPlugin)    // プラグイン情報取得バッファアドレス
  167. {
  168.     strcpy(lpPlugin->aName,      "STR CD-ROM");
  169.     strcpy(lpPlugin->aCopyright, "Copyright (c) Fyiro 2000.");
  170.     lpPlugin->usVersion         = 131;
  171.     lpPlugin->usIsSupportVersion = 102;
  172.     lpPlugin->usSystemVersion    = PSR_SYSTEMVERSION;
  173.     strcpy(lpPlugin->aSiteName, "Fyiro's Garage");        // 1.30
  174.     strcpy(lpPlugin->aSiteUrl, "http://homepage2.nifty.com/~mkb/");    // 1.30
  175. }
  176.  
  177.  
  178.  
  179. /******************************************************************************/
  180. /*                                          */
  181. /*    PsrIsSupportCDBegin() : CDサポート判定 開始処理                  */
  182. /*                                          */
  183. /******************************************************************************/
  184.  
  185. CEXPORT HANDLE    PsrIsSupportCDBegin(
  186.     INT        iNumToc,    // TOCの数
  187.     LPTOCENTRY    lptoc)        // TOC
  188. {
  189.     _PTFIND        pfind;
  190.     INT        i;
  191.  
  192.  
  193.             // DAトラックのみのCDは処理対象外! ---------------------
  194.     for(i=0; i<iNumToc; i++) {
  195.         if(lptoc[i].bAdr & 0x04)    break;
  196.     }
  197.     if(i == iNumToc)    return NULL;
  198.  
  199.     if(!(pfind = malloc(sizeof(_TFIND))))    return NULL;
  200.  
  201.             // ハンドルの作成と初期設定 ----------------------------
  202.     pfind->fFindout    = FALSE;
  203.     pfind->iBuffer    = 10;
  204.     pfind->iNum    = 0;
  205.     pfind->pstr    = malloc(sizeof(_TSTREAM) * pfind->iBuffer);
  206.     if(!pfind->pstr) {
  207.         free(pfind);
  208.         return NULL;
  209.     }
  210.     return pfind;
  211. }
  212.  
  213.  
  214.  
  215. /******************************************************************************/
  216. /*                                          */
  217. /*    PsrIsSupportCDEnd() : CDサポート判定 終了処理                  */
  218. /*                                          */
  219. /******************************************************************************/
  220.  
  221. CEXPORT    VOID    PsrIsSupportCDEnd(
  222.     HANDLE        hIsCD)        // CDサポート判定ハンドル
  223. {
  224.     _PTFIND        pfind;
  225.  
  226.  
  227.     if(!(pfind = hIsCD))    return;
  228.     free(pfind->pstr);
  229.     free(pfind);
  230. }
  231.  
  232. /******************************************************************************/
  233. /*                                          */
  234. /*    PsrIsSupportCDSector() : CDサポート判定 セクタ通知              */
  235. /*                                          */
  236. /******************************************************************************/
  237.  
  238. CEXPORT    BOOL    PsrIsSupportCDSector(
  239.     HANDLE        hIsCD,        // CDサポート判定ハンドル
  240.     TOCENTRY    toc,        // TOC
  241.     DWORD        nSector,    // セクタ番号
  242.     PVOID        pvSector)    // セクタ
  243. {
  244.     _PTFIND        pfind;
  245.     _PTSECTOR    psector;
  246.     _PTSTREAM    pstr;
  247.     BOOL        fBegin;
  248.     INT        iType, i;
  249.     WORD        wNum;
  250.     DWORD        dwLastSector;
  251.  
  252.  
  253.     if(!(pfind = hIsCD))    return FALSE;
  254.     if(!(toc.bAdr & 0x04))    return FALSE;        // CD-DA
  255.     if(!(psector = pvSector)) {
  256.         if(pfind->fFindout) {
  257.             pfind->fFindout = FALSE;
  258.             pstr = &pfind->pstr[pfind->iNum - 1];
  259.             if((pstr->nNumFrame == 1) ||
  260.                (pstr->dwFastAudioNo && !pstr->nStepAudio)) {
  261.                 pfind->iNum --;
  262.             }
  263.         }
  264.         return FALSE;
  265.     }
  266.  
  267.             // ストリームのセクタか ? ------------------------------
  268.     iType = _TypeUNKNOW;
  269.     if((psector->abSubHeader[2] & 0x64) == 0x64) {
  270.         iType = _TypeAUDIO;
  271.     } else {
  272.         if((psector->usStatus & 0x00f0) == 0x0060 &&
  273.            (psector->usDataType & 0x8000) &&
  274.            psector->ulFrameNo &&
  275.            psector->usNumSector <= 20 &&
  276.            psector->usNumSector && !psector->ulReserved) {
  277.             iType = _TypeMOVIE;
  278.         }
  279.     }
  280.  
  281.     fBegin = FALSE;    // 先頭セクタか ? --------------------------------------
  282.     if(iType == _TypeMOVIE) {
  283.         if(!psector->usSectorNo && psector->ulFrameNo == 1) {
  284.             for(i=0; i<_MaxSEARCH; i++) {
  285.                 if(psector->ausMovie[i+1] == 0x3800)    break;
  286.             }
  287.             if(psector->ausMovie[i+1] == 0x3800 &&    // MAGIC
  288.                (psector->ausMovie[i+3] <= 3 ||    // FLC or VLC
  289.                (psector->ausMovie[i+2] == psector->usWidth &&
  290.                 psector->ausMovie[i+3] == psector->usHeight)))
  291.                 fBegin = TRUE;
  292.             else    iType = _TypeUNKNOW;
  293.         }
  294.     }
  295.     if(!pfind->fFindout && !fBegin)    iType = _TypeUNKNOW;
  296.     if(iType == _TypeAUDIO && pfind->fFindout) {
  297.         pstr = &pfind->pstr[pfind->iNum - 1];
  298.         if(pstr->nNumAudio &&
  299.            memcmp(pstr->abAudioSH, psector->abSubHeader, 4) != 0) {
  300.             iType = _TypeUNKNOW;
  301.         }
  302.     }
  303.     if(iType == _TypeUNKNOW) {
  304.         if(!psector->usStatus)    iType = _TypeDUMMY;
  305.     }
  306.     if(iType == _TypeDUMMY)    return TRUE;
  307.  
  308. // ストリームが発見されている場合 **********************************************
  309.  
  310.     if(pfind->fFindout) {
  311.         pstr = &pfind->pstr[pfind->iNum - 1];
  312.         dwLastSector = max(pstr->dwLastMovieNo, pstr->dwLastAudioNo);
  313.  
  314.             // データの終わり --------------------------------------
  315.             //    1. ストリームの開始セクタの場合 ----------------
  316.             //    2. すっごく離れた位置のセクタの場合 ------------
  317.             //    3. ストリームでないセクタの場合 ----------------
  318.         if(fBegin || nSector - dwLastSector > 32 || iType == _TypeUNKNOW) {
  319.             pfind->fFindout = FALSE;
  320.             if((pstr->nNumFrame == 1) ||
  321.                (pstr->dwFastAudioNo && !pstr->nStepAudio)) {
  322.                 pfind->iNum --;
  323.             }
  324.         }
  325.  
  326.             // 動画セクタ ------------------------------------------
  327.         else if(iType == _TypeMOVIE) {
  328.             if(pstr->usDataType != psector->usDataType) {    // 1.31
  329.                 pfind->fFindout = FALSE;        // 1.31
  330.                 pfind->iNum --;                // 1.31
  331.                 return TRUE;                // 1.31
  332.             }                        // 1.31
  333.  
  334.             pstr->dwLastMovieNo    = nSector;
  335.             if(psector->usSectorNo == 0) {
  336.                 pstr->nNumFrame    = psector->ulFrameNo;
  337.                 pstr->szFrame.cx = max(pstr->szFrame.cx,
  338.                             psector->usWidth);
  339.                 pstr->szFrame.cy = max(pstr->szFrame.cy,
  340.                             psector->usHeight);
  341.  
  342.                 wNum  = (WORD)(nSector - pfind->dwPreBeginNo);
  343.                 wNum -= (WORD)pfind->nNumAudio;
  344.                 pstr->wMinFrame = min(pstr->wMinFrame, wNum);
  345.                 pstr->wMaxFrame = max(pstr->wMaxFrame, wNum);
  346.                 pstr->dwSize    += psector->ulLength;    // 1.30
  347.                 pfind->dwPreBeginNo    = nSector;
  348.                 pfind->nNumAudio    = 0;
  349.             }
  350.             if(pstr->nNumAudio &&
  351.                nSector - pstr->dwLastAudioNo < pstr->nStepAudio) {
  352.                 pstr->nSyncAudio = pstr->nNumAudio;
  353.                 pstr->nSyncFrame = pstr->nNumFrame;
  354.             }
  355.         }
  356.  
  357.         else {    // 音声セクタ ------------------------------------------
  358.             if(!pstr->nNumAudio) {
  359.                 pstr->dwFastAudioNo = nSector;
  360.                 pstr->nStepAudio    = nSector - pstr->dwBeginNo;
  361.                 memcpy(pstr->abAudioSH, psector->abSubHeader, 4);
  362.             }
  363.             else if(pstr->nNumAudio == 1) {
  364.                 pstr->nStepAudio = nSector - pstr->dwFastAudioNo;
  365.             }
  366.             pstr->dwLastAudioNo = nSector;
  367.             pstr->dwSize    += 0x900;            // 1.30
  368.             pstr->nNumAudio ++;
  369.             pfind->nNumAudio ++;
  370.         }
  371.  
  372.             // データの終わり --------------------------------------
  373.         if(psector->abSubHeader[2] == 0x89) {
  374.             pstr = &pfind->pstr[pfind->iNum - 1];
  375.             pfind->fFindout = FALSE;
  376.             if((pstr->nNumFrame == 1) ||
  377.                (pstr->dwFastAudioNo && !pstr->nStepAudio)) {
  378.                 pfind->iNum --;
  379.             }
  380.         }
  381.     }
  382.  
  383. // ストリームが発見されていない場合 ********************************************
  384.  
  385.             // ストリームが見つかった! -----------------------------
  386.     if(!pfind->fFindout && fBegin) {
  387.         if(pfind->iBuffer == pfind->iNum) {
  388.             pfind->iBuffer += 10;
  389.             pstr = realloc(pfind->pstr,
  390.                     sizeof(_TSTREAM) * pfind->iBuffer);
  391.             if(!pstr) {
  392.                 pfind->iBuffer -= 10;
  393.                 return TRUE;    // とりあえず正常終了
  394.             }
  395.             pfind->pstr = pstr;
  396.         }
  397.  
  398.         pstr = &pfind->pstr[pfind->iNum];
  399.         pstr->dwBeginNo        = nSector;
  400.         pstr->dwLastMovieNo    = nSector;
  401.         pstr->dwFastAudioNo    = 0;
  402.         pstr->dwLastAudioNo    = 0;
  403.         pstr->nStepAudio    = 0;
  404.         pstr->nNumAudio        = 0;
  405.         pstr->nNumFrame        = 1;
  406.         pstr->szFrame.cx    = psector->usWidth;
  407.         pstr->szFrame.cy    = psector->usHeight;
  408.         pstr->nSyncAudio    = 0;
  409.         pstr->nSyncFrame    = 0;
  410.         pstr->dwSize        = psector->ulLength;        // 1.30
  411.         pstr->usDataType    = psector->usDataType;        // 1.31
  412.         pstr->wMinFrame        = 0xffff;
  413.         pstr->wMaxFrame        = 0;
  414.  
  415.         pfind->fFindout        = TRUE;
  416.         pfind->dwPreBeginNo    = nSector;
  417.         pfind->nNumAudio    = 0;
  418.         pfind->iNum ++;
  419.     }
  420.  
  421.     return TRUE;
  422. }
  423.  
  424. /******************************************************************************/
  425. /*                                          */
  426. /*    PsrIsSupportCDResult() : CDサポート判定 結果取得              */
  427. /*                                          */
  428. /******************************************************************************/
  429.  
  430. CEXPORT    INT    PsrIsSupportCDResult(
  431.     HANDLE        hIsCD,        // CDサポート判定ハンドル
  432.     INT        iIndex,        // ストリームインデックス
  433.     LPPSRSTREAMINFO    lpStreamInfo)    // ストリームデータ情報
  434. {
  435.     _PTFIND        pfind;
  436.     _PTSTREAM    pstr;
  437.     DWORD        dwLast, nChannels, nSampleRate, nSample;
  438.     DWORD        dwTime, dwAudio, dwMovie;
  439.     WORD        wFps;
  440.  
  441.  
  442.     if(!(pfind = hIsCD))        return 0;
  443.     if(pfind->iNum <= iIndex)    return -1;
  444.     if(!lpStreamInfo)        return pfind->iNum;
  445.  
  446.     pstr = &pfind->pstr[iIndex];
  447.  
  448.             // ストリームデータ情報を暫定的に設定 ------------------
  449.     dwLast    = max(pstr->dwLastMovieNo, pstr->dwLastAudioNo);
  450.     wFps    = _strGetFrameRate(pstr->szFrame,
  451.                 pstr->wMinFrame, pstr->wMaxFrame);
  452.     lpStreamInfo->wTypeFlags    = PSR_STRTYPE_MOVIE;
  453.     lpStreamInfo->wReserved        = 0;
  454.     lpStreamInfo->nBeginSector    = pstr->dwBeginNo;
  455.     lpStreamInfo->nNumSector    = (dwLast - pstr->dwBeginNo) + 1;
  456.     lpStreamInfo->nNumFrame        = pstr->nNumFrame;
  457.     lpStreamInfo->szFrame        = pstr->szFrame;
  458.     lpStreamInfo->wFrameRate    = wFps;
  459.     lpStreamInfo->wFormatTag    = 0;
  460.     lpStreamInfo->wChannels        = 0;
  461.     lpStreamInfo->wBitsPerSample    = 0;
  462.     lpStreamInfo->nSamplesPerSec    = 0;
  463.     lpStreamInfo->nPlayTime        = (pstr->nNumFrame * 10000) /
  464.                         lpStreamInfo->wFrameRate;
  465.     lpStreamInfo->nDataSize        = pstr->dwSize;            // 1.30
  466.  
  467.             // オーディオ情報を設定 --------------------------------
  468.     if(pstr->nNumAudio) {
  469.         nChannels   = (pstr->abAudioSH[3] & 0x01) ? 2 : 1;
  470.         nSampleRate = (pstr->abAudioSH[3] & 0x04) ? 18900 : 37800;
  471.         lpStreamInfo->wTypeFlags    |= PSR_STRTYPE_AUDIO;
  472.         lpStreamInfo->wFormatTag    = WAVE_FORMAT_PCM;
  473.         lpStreamInfo->wBitsPerSample    = 16;
  474.         lpStreamInfo->wChannels        = (WORD)nChannels;
  475.         lpStreamInfo->nSamplesPerSec    = nSampleRate;
  476.  
  477.             // オーディオデータを元にフレームレートを計算 ----------
  478.         nSample    = nChannels * (nSampleRate / 100);
  479.         dwTime    = (pstr->nSyncAudio * 40320) / nSample;
  480.         if(dwTime) wFps = (WORD)((pstr->nSyncFrame * 10000) / dwTime);
  481.  
  482.             // 可変フレームレートの場合… --------------------------
  483.         if(abs((INT)lpStreamInfo->wFrameRate - (INT)wFps) > 20){
  484.             if(pstr->wMaxFrame - pstr->wMinFrame > 3) {
  485.                 lpStreamInfo->wTypeFlags |= PSR_STRTYPE_VFRATE;
  486.                 lpStreamInfo->wFrameRate = _strGetFrameRate(
  487.                                 pstr->szFrame,
  488.                                 pstr->wMinFrame,
  489.                                 pstr->wMinFrame);
  490.             }
  491.  
  492.             // 固定フレームレートの場合 ----------------------------
  493.             else {
  494.                 lpStreamInfo->wFrameRate = ((wFps + 2) / 5) * 5;
  495.             }
  496.         }
  497.         lpStreamInfo->wFrameRate = max(lpStreamInfo->wFrameRate, 50);
  498.  
  499.             // 再生時間の再計算 ------------------------------------
  500.         dwAudio = (pstr->nNumAudio * 40320) / nSample;
  501.         dwMovie = (pstr->nNumFrame * 10000) / lpStreamInfo->wFrameRate;
  502.         lpStreamInfo->nPlayTime    = max(dwAudio, dwMovie);
  503.     }
  504.  
  505.     return pfind->iNum;
  506. }
  507.  
  508. /******************************************************************************/
  509. /*                                          */
  510. /*    PsrGetStrDataInfo() : ストリームデータ情報の取得              */
  511. /*                                          */
  512. /******************************************************************************/
  513.  
  514. CEXPORT    BOOL    PsrGetStrDataInfo(
  515.     INT        iDriveNo,    // ドライブ番号
  516.     DWORD        dwBegin,    // 開始セクタ番号
  517.     DWORD        dwNumSector,    // セクタ数
  518.     LPPSRSTREAMINFO    lpStreamInfo)    // ストリームデータ情報
  519. {
  520.     HANDLE        hCdrom;
  521.     _PTSECTOR    psector;
  522.     SIZE        szFrame;
  523.     DWORD        nNumAudio, nNumMovie, nNumFrame, nTimeAudio;
  524.     DWORD        nSecCount, nMin, nMax, nChannels, nSampleRate;
  525.     WORD        wRate;
  526.     BYTE        bAudioSubH;
  527.  
  528.  
  529.             // 先頭nフレーム分のセクタを読み取って必要な情報を収集 -
  530.     hCdrom = CdReadOpen(iDriveNo, NULL, dwBegin, min(dwNumSector, 300), -1);
  531.     if(!hCdrom)    return FALSE;
  532.  
  533.     nNumAudio = nNumMovie = nNumFrame = 0;
  534.     while(psector = CdReadSector(hCdrom, NULL)) {
  535.         if(psector->abSubHeader[2] == 0x64) {
  536.             nNumAudio ++;
  537.             bAudioSubH = psector->abSubHeader[3];
  538.         }
  539.         else if(psector->usStatus && psector->ulFrameNo > 30) {
  540.             CdUnlockReadBuffer(hCdrom, psector);
  541.             break;
  542.         }
  543.         else {
  544.             nNumMovie ++;
  545.             if(psector->usStatus && psector->usSectorNo == 0) {
  546.                 szFrame.cx = psector->usWidth;
  547.                 szFrame.cy = psector->usHeight;
  548.                 nNumFrame = psector->ulFrameNo;
  549.             }
  550.         }
  551.         CdUnlockReadBuffer(hCdrom, psector);
  552.     }
  553.     CdReadClose(hCdrom);
  554.     if(!nNumMovie)    return FALSE;
  555.  
  556.             // ストリームデータ情報を作成する ----------------------
  557.     nSecCount = nNumAudio + nNumMovie;
  558.     nMin      = nNumMovie / nNumFrame;
  559.     nMax      = (nNumMovie + nNumFrame - 1) / nNumFrame;
  560.     lpStreamInfo->wTypeFlags    = PSR_STRTYPE_MOVIE;
  561.     lpStreamInfo->wReserved        = 0;
  562.     lpStreamInfo->nBeginSector    = dwBegin;
  563.     lpStreamInfo->nNumSector    = dwNumSector;
  564.     lpStreamInfo->nNumFrame        = (dwNumSector * nNumFrame) / nSecCount;
  565.     lpStreamInfo->szFrame        = szFrame;
  566.     lpStreamInfo->wFrameRate    = _strGetFrameRate(szFrame, nMin, nMax);
  567.     lpStreamInfo->wFormatTag    = 0;
  568.     lpStreamInfo->wChannels        = 0;
  569.     lpStreamInfo->wBitsPerSample    = 0;
  570.     lpStreamInfo->nSamplesPerSec    = 0;
  571.  
  572.     if(nNumAudio) {
  573.         nChannels   = (bAudioSubH & 0x01) ? 2 : 1;
  574.         nSampleRate = (bAudioSubH & 0x04) ? 18900 : 37800;
  575.         lpStreamInfo->wTypeFlags    |= PSR_STRTYPE_AUDIO;
  576.         lpStreamInfo->wFormatTag    = WAVE_FORMAT_PCM;
  577.         lpStreamInfo->wBitsPerSample    = 16;
  578.         lpStreamInfo->wChannels        = (WORD)nChannels;
  579.         lpStreamInfo->nSamplesPerSec    = nSampleRate;
  580.  
  581.             // フレームレート補正 ----------------------------------
  582.         nTimeAudio = (nNumAudio * 40320) /
  583.                     (nChannels * (nSampleRate / 100));
  584.         wRate = (WORD)((nNumFrame * 10000) / nTimeAudio);
  585.         if(abs((INT)lpStreamInfo->wFrameRate - (INT)wRate) > 20){
  586.             lpStreamInfo->wFrameRate = ((wRate + 2) / 5) * 5;
  587.         }
  588.     }
  589.     lpStreamInfo->nPlayTime = (lpStreamInfo->nNumFrame * 10000) /
  590.                         lpStreamInfo->wFrameRate;
  591.     return TRUE;
  592. }
  593.  
  594. /******************************************************************************/
  595. /*                                          */
  596. /*    PsrOpenCD() : CDストリームのオープン                      */
  597. /*                                          */
  598. /******************************************************************************/
  599.  
  600. CEXPORT HANDLE    PsrOpenCD(
  601.     INT        iDriveNo,    // ドライブ番号
  602.     LPPSRSTREAMINFO    lpStreamInfo)    // ストリームデータ情報
  603. {
  604.     _PTHANDLE    phandle;
  605.     _PTSECTOR    psector;
  606.     HANDLE        hCdrom;
  607.     DWORD        i, dwSec1, dwSec2;
  608.  
  609.  
  610.             // CD-ROMのオープン ------------------------------------
  611.     hCdrom = CdReadOpen(iDriveNo, NULL,
  612.                 lpStreamInfo->nBeginSector,
  613.                 lpStreamInfo->nNumSector, _SpinSPEED);
  614.     if(!hCdrom)    return NULL;
  615.  
  616.             // ハンドルを作成 --------------------------------------
  617.     if(!(phandle = malloc(sizeof(_THANDLE)))) {
  618.         CdReadClose(hCdrom);
  619.         return NULL;
  620.     }
  621.     phandle->hCdrom    = hCdrom;
  622.     phandle->str    = *lpStreamInfo;
  623.     for(i=0; i<_NumAUDIOBUFF; i++)    phandle->apaudio[i] = NULL;
  624.  
  625.             // オーディオセクタ間隔を求める ------------------------
  626.     dwSec1 = dwSec2 = 0;
  627.     if(lpStreamInfo->wTypeFlags & PSR_STRTYPE_AUDIO) {
  628.         for(i=1; !dwSec1 || !dwSec2; i++) {
  629.             if(!(psector = CdReadSector(hCdrom, NULL)))    break;
  630.             if((psector->abSubHeader[2] & 0x64) == 0x64) {
  631.                 if(!dwSec1)    dwSec1 = i;
  632.                 else        dwSec2 = i;
  633.             }
  634.             CdUnlockReadBuffer(hCdrom, psector);
  635.         }
  636.         CdSetReadPointer(hCdrom, 0, FILE_BEGIN);
  637.     }
  638.     if(dwSec2)    phandle->nStepAudio = dwSec2 - dwSec1;
  639.     else        phandle->nStepAudio = dwSec1;
  640.  
  641.     return phandle;
  642. }
  643.  
  644. /******************************************************************************/
  645. /*                                          */
  646. /*    PsrClose() : ストリームデータのクローズ                      */
  647. /*                                          */
  648. /******************************************************************************/
  649.  
  650. CEXPORT BOOL    PsrClose(
  651.     HANDLE        hStream)    // ストリームハンドル
  652. {
  653.     _PTHANDLE    phandle;
  654.  
  655.  
  656.     phandle = hStream;
  657.     if(phandle->hCdrom)    CdReadClose(phandle->hCdrom);
  658.     free(phandle);
  659.     return TRUE;
  660. }
  661.  
  662. /******************************************************************************/
  663. /*                                          */
  664. /*    PsrRead() : ストリームデータの読み取り                      */
  665. /*                                          */
  666. /******************************************************************************/
  667.  
  668. CEXPORT BOOL    PsrRead(
  669.     HANDLE        hStream,    // ストリームハンドル
  670.     LPPSRREADBUFF    lpBuffer)    // 読み取りバッファ
  671. {
  672.     _PTHANDLE    phandle;
  673.     _PTSECTOR    psector;
  674.     PBYTE        pbBuff;
  675.     INT        iLength, iSize, i, iPos;
  676.     BOOL        fComp;
  677.  
  678.  
  679.     phandle = hStream;
  680.     memset(lpBuffer, 0, sizeof(PSRREADBUFF) - PSR_FRAMEBUFFER);
  681.  
  682.             // 退避オーディオバッファの内容を設定 ------------------
  683.     pbBuff    = lpBuffer->abData;
  684.     for(i=0; i<_NumAUDIOBUFF; i++) {
  685.         if(!phandle->apaudio[i])    break;
  686.         memcpy(pbBuff, &phandle->apaudio[i]->usStatus, 0x900);
  687.         CdUnlockReadBuffer(phandle->hCdrom, phandle->apaudio[i]);
  688.         phandle->apaudio[i] = NULL;
  689.         lpBuffer->nLength += 0x900;
  690.         pbBuff += 0x900;
  691.     }
  692.     if(lpBuffer->nLength)    return TRUE;
  693.  
  694.     iLength = 0;    // CDから読み込んで設定 --------------------------------
  695.     fComp    = FALSE;
  696.     while(!fComp) {
  697.         if(!(psector = CdReadSector(phandle->hCdrom, NULL)))    break;
  698.  
  699.                 // 音声データ - - - - - - - - - - - - - - - - -
  700.         if((psector->abSubHeader[2] & 0x64) == 0x64) {
  701.             if(!lpBuffer->nFrameNo) {
  702.                 lpBuffer->nLength    = 0x900;
  703.                 memcpy(lpBuffer->abData, &psector->usStatus, 0x900);
  704.                 fComp = TRUE;
  705.             }
  706.             else {
  707.                 for(i=0; i<_NumAUDIOBUFF; i++) {
  708.                     if(!phandle->apaudio[i]) {
  709.                         phandle->apaudio[i] = psector;
  710.                         break;
  711.                     }
  712.                 }
  713.                 if(i != _NumAUDIOBUFF)    continue;
  714.             }
  715.         }
  716.  
  717.                 // 映像データ - - - - - - - - - - - - - - - - -
  718.         else if(psector->usStatus && psector->ulFrameNo) {
  719.  
  720.             iPos = 0;    // 先頭セクタ - - - - - - - - - - - - -
  721.             if(!psector->usSectorNo) {
  722.                 lpBuffer->nFrameNo    = psector->ulFrameNo;
  723.                 lpBuffer->szFrame.cx    = psector->usWidth;
  724.                 lpBuffer->szFrame.cy    = psector->usHeight;
  725.                 iLength    = (INT)psector->ulLength;
  726.                 pbBuff    = lpBuffer->abData;
  727.                 for(iPos=0; iPos<_MaxSEARCH; iPos++) {
  728.                     if(psector->ausMovie[iPos+1] == 0x3800)    break;
  729.                 }
  730.             }
  731.  
  732.             if(iLength) {    // イメージデータのコピー - - - - - - -
  733.                 iSize = sizeof(psector->ausMovie) -
  734.                         (sizeof(USHORT) * iPos);
  735.                 iSize = min(iSize, iLength);
  736.                 memcpy(pbBuff, &psector->ausMovie[iPos], iSize);
  737.                 pbBuff    += iSize;
  738.                 iLength    -= iSize;
  739.                 lpBuffer->nLength += iSize;
  740.             }
  741.  
  742.                     // 最終セクタ - - - - - - - - - - - - -
  743.             if(psector->usSectorNo == psector->usNumSector - 1) {
  744.                 if(lpBuffer->nFrameNo) {
  745.                     fComp = TRUE;
  746.                     if(phandle->str.wTypeFlags & PSR_STRTYPE_VFRATE) {
  747.                         lpBuffer->wFrameRate =
  748.                             _strGetFrameRate(
  749.                                 lpBuffer->szFrame,
  750.                                 psector->usNumSector-1,
  751.                                 psector->usNumSector);
  752.                     }
  753.                 }
  754.             }
  755.         }
  756.         CdUnlockReadBuffer(phandle->hCdrom, psector);
  757.     }
  758.     return fComp;
  759. }
  760.  
  761. /******************************************************************************/
  762. /*                                          */
  763. /*    PsrSeek() : 読み取り位置の設定                          */
  764. /*                                          */
  765. /******************************************************************************/
  766.  
  767. CEXPORT BOOL    PsrSeek(
  768.     HANDLE        hStream,    // ストリームハンドル
  769.     DWORD        dwPosition)    // 読み取り位置        1/1000秒単位
  770. {
  771.     _PTHANDLE    phandle;
  772.     DWORD        nFrame, nSector;
  773.     INT        i;
  774.     double        dPos;
  775.  
  776.  
  777.     phandle = hStream;
  778.     for(i=0; i<_NumAUDIOBUFF; i++) {
  779.         if(phandle->apaudio[i]) {
  780.             CdUnlockReadBuffer(phandle->hCdrom, phandle->apaudio[i]);
  781.             phandle->apaudio[i] = NULL;
  782.         }
  783.     }
  784.  
  785.             // 映像データからセクタ位置を算出 ----------------------
  786.     if(!(phandle->str.wTypeFlags & PSR_STRTYPE_AUDIO)) {
  787.         nFrame    = (dwPosition * phandle->str.wFrameRate) / 10000;
  788.         nSector    = (nFrame * phandle->str.nNumSector) / phandle->str.nNumFrame;
  789.     }
  790.  
  791.     else {        // 音声データからセクタ位置を算出 ----------------------
  792.         dPos = (double)(phandle->str.nSamplesPerSec / 100);
  793.         dPos *= (double)(dwPosition * phandle->nStepAudio);
  794.         dPos /= (double)(40320 / (DWORD)phandle->str.wChannels);
  795.         nSector = (DWORD)dPos;
  796.     }
  797.     nSector = min(nSector, phandle->str.nNumSector);
  798.  
  799.     if(CdSetReadPointer(phandle->hCdrom, (LONG)nSector, FILE_BEGIN) == 0xffffffff) {
  800.         return FALSE;
  801.     }
  802.  
  803.     return TRUE;
  804. }
  805.