DVD的界解码

    技术2022-05-11  101

     

    这是很久以前的东西,如果有不准确的地方还请见谅

    DVD的解码

    本节主要包括DirectShow属性设置和特定DVD及扩展解码所用的接口描述,此外还有支持通用 DirectShow 过滤器接口的解码器及其管脚属性描述。

    本节主要包含以下主题:

    l         解码器音量控制

    l         Windows 支持的DVD区码变换

    以及:

    l         DVD Karaoke 属性设置

    l         DVD 复制保护属性设置

    l         DVD 子图属性设置

    l         管脚属性设置

    l         IKsPropertySet 接口

    l         IVideoFrameStep 接口(硬件解码器专用)

    l         IVPConfig 接口(硬件解码器专用)

    1、音量控制

    应用程序通过iBasicAudio接口管理音量控制,而iBasicAudio接口是由KSProxy进行管理,所以为了使解码器处理这些命令,就必须在KSPPROPSETID_Wave属性设置中增加一些注册键。下来我们就来创建这些新的驱动注册键:

    HKLM/SYSTEM/     CurrentControlSet/Control       DeviceClasses         (decoder guid, eg 2721AE....)           (Pnp id, eg ##?#VDGENDEV#...)             #GLOBAL               Device Parameters                 CLSID     REG_SZ  {17CCA...}                   FriendlyName REG_SZ  WDM DVD Driver                     Interfaces <--- create this key                     {b9f8ac3e-0f71-11d2-b72c-00c04fb6bd3d} <-- also create this key, it is not a value)       MediaInterfaces         {b9f8ac3e-0f71-11d2-b72c-00c04fb6bd3d} <-- create this key           (default)       REG_SZ  'KsProxy IBasicAudio handler' <-- set this value           IID REG_SZ  56 a8 68 b3 0a d4 11 ce b0 3a 00 20 af 0b a7 70 <-- create this string value

    实现音量控制,驱动程序必需支持KSPROPSETID_WaveKsProperty.IdKSPROPERTY_WAVE_VOLUME。该属性是驱动程序通过IksPropertySet::GetIksPropertySet::Set方法进行控制的。左、右音频控制的音量大小是0x00000xffff的线性值

    2DVD的区码变换

     本段解释windows9xwindows2000下选择DVD区码的工作过程。首先描述三种DVD区码信息的来源,随后描述PC厂商如何设置系统进行DVD区码初始化,接着解释DVD导航怎样通过驱动、解码器和碟片来决定区码的匹配,最后揭示应用程序和解码器开发者怎样才能实现正确的DVD区码选择。

    2.1DVD区码信息的来源

    DVD区码信息有三种来源,这些来源一起就决定了windowsDVD播放器区码。

    DVD标题大部分DVD标题被标记为特定区码。有些标题只能在某个区域播放,但另一些却可以在很多区域播放,还有的可以全区域播放。DVD-ROM驱动器有两种DVD-ROM驱动器:RPC 1RPC 2RPC 1驱动器没有内置硬件支持的区码管理,所以对于这些驱动器来说,需要由Windows来管理区码改变次数信息,且只能改变一次;而RPC 2驱动器将这些管理放到了硬件里,因此这些驱动器的区码可以被改变5次。DVD解码器一些DVD解码器,无论硬件或者软件,都被设置为特定区码服务。通常情况下,用户不能改变解码器本身设置的区码。

    2.2、如何在Windows98Windows 2000中设置初始化区码

    此问题主要是DVD驱动器生产商的责任,他们会在DVD驱动器出厂之前选择一个合适的区码。在Windows98中,生产商可以通过设定注册键值HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/Current/Version/Default DVD的区码(二进制)来确定DVD驱动器默认区码。该值决定WindowsDVD解码的首选解码器,如果此值在系统DVD播放之前被设定,那么Windows组件会自动选择该解码器进行DVD播放。

    如果生产商在注册表中设定了默认的区码,然后却播放不同区码的碟片(包括默认区码DVD驱动器),用户将会被提示需要改变所要求的区码。如果厂商没有指定默认的区码,那么Windows将选择一个基于操作系统的本地区码、时区和其它因素。如果第一张碟片是多区码碟片,那么Windows将还将寻找相匹配的最小区码数。如果找不到相匹配的区码,则选择的区码就是最小区码数最小的那个区码。

    如果生产商没有设置区码,则第一次启动Windows 98操作系统基本组件时,将选择基于操作系统的语言、时区并设置驱动器为此种区码。生产厂家设置区码为“全部适应”,如果厂家没有成这些处理完,则最好选择推荐区码。

    Windows 2000下,默认DVD区码选择基于机器的设定。如果有碟片在驱动器中,Windows 2000通常使用默认和碟片相同的区码为DVD驱动器设置初始化区码,因此在Windows 2000 DVD驱动器生产商可以不为初始化DVD驱动器做任何事情。

    对于Rpc1的驱动器,如果Windows启动时驱动器中没有DVD碟片,那么将会基于本地机器创建默认区码;如果有碟片在驱动器中,那么将选择驱动器的区码为默认区码,即驱动器中的碟片的区码,否则碟片的最低区码将被用来初始化驱动器的区码。万一默认值不正确,那么用户也有一次改变区码的权利。

    对于Rpc2驱动器,如果在处理设置的时,没有对驱动器进行任何区码设置,将会试图按照以上的方法进行选择区码,但是要求驱动器中有碟片。(Rpc1可以选择区码而不要求碟片放在驱动器中。)一旦Rpc2驱动器的区码被设置,那么就无法通过重装windows或者卸载操作系统来自动改变区码了。

    3、微软的DVD导航

    pc上播放DVD碟片时,微软的DVD导航使用以下方法来决定区码匹配:DVD导航获取碟片的区码、驱动器区码和解码器的区码。如果碟片区码是全区域的,则DVD导航将进行无条件播放;如果碟片不是全区域区码,DVD导航会检测解码器是否有预先设定区码;如果解码器包含的区码与碟片区码不匹配,则DVD导航会返回错误信息,以表明不能用当前DVD配置播放碟片;如果解码器区码与碟片区码相同,则DVD导航会继续检测驱动器区码是否与碟片区码相同,若相同,则DVD导航播放碟片。不同,则DVD导航调用代码来改变驱动器的区码;若允许改变区码的次数被用尽,则改变区码被视为失败,将不能进行播放。

    4DVD区码改变的发展

    Windows 9x系统中,当DVD导航检测到驱动器必要的区码改变时,使用DVDrgn.exe请求驱动器进行区码的改变。应用程序和操作系统的其它组件被分别安装到目标系统。示范方法如下:

    Windows 2000中,DVD导航调用设备管理中DVD-ROM驱动器设备的属性页。当区码需要被改变的时候,该属性页由DVDplay.exe应用程序产生。此属性页的用户界面非常类似DVDrgn.exe的,可被操作系统识别。

    对于Rpc1驱动器,由Windows操作系统部件管理区码的改变;而Rpc2驱动器在其硬件中维持区码设置,在Rpc2驱动器中,当用尽允许改变的次数时,驱动器调用区码改变就会失败,操作系统的区码改变组件将会给用户这些情况和结果的说明。

    5、安装支持Windows改变区码的部件

    应用程序开发者可以利用DVD区码改变支持,在DVD应用程序中进行区码的改变。这里提供处理此问题的两种不同方法。

    5.1Windows 9x

    Windows 9x 平台下,区码改变应用程序DVDrgn.exe,只有安装硬件解码和wdmmini驱动后才被安装,且使用标准的inf文件。

    对于软件解码器,可在inf文件中插入以下几行。(这是已安装程序加载DVDrgn.exe到目标系统的方法)

    [Version]

    Signature=$CHICAGO$

    LayoutFile=layout.inf

     

    [DestinationDirs]

    DVDRgnCopy=25       ; Windows

    DefaultDestDir=25   ; Windows

     

    [DefaultInstall]

    CopyFiles=DVDRgnCopy

     

    [DVDRgnCopy]

    DVDrgn.exe

    5.2Windows 2000

    Windows 2000 系统下,组件在Windows目录下的system32下的storprop.dll文件中提供了DVD区码改变的支持。此dll是通过默认方式安装的,没有额外的步骤来确认它的有效性。

    6、在应用程序中加入整合区码改变支持

    下面的代码为软件开发者提供了在DVD应用程序中加入DVD区码变化的代码:

    /

    // ChangeDVDRegion :  Function to change the DVD drive region.

    //

    // Parameters:

    //  In:  hWnd - window handle of the application

    //              that calls this function

    //  Out: none.

    //

    // Returns:

    //    TRUE: if the drive region change is successful

    //    FALSE: if drive region change fails (probably because

    //           no drive was found with a valid DVD-V disc).

    /

    BOOL ChangeDVDRegion(HWND hWnd)

    {

      typedef BOOL (APIENTRY *DVDPPLAUNCHER) (HWND hWnd, CHAR DriveLetter);

      BOOL   bRegionChanged = FALSE;

      TCHAR   szCmdLine[MAX_PATH];

     

      // First find out which drive is a DVD drive with a valid DVD-V disc.

     

      TCHAR     szDVDDrive[4];

      if (! GetDriveLetter (szDVDDrive) )

      {

        MessageBox(hWnd,

        TEXT("No DVD drive was found with DVD-V disc.")

        TEXT("/nCannot change DVD region of the drive."),

        TEXT("Error"), MB_OK | MB_INFORMATION) ;

        return FALSE;

      }

     

      // Detect which OS we are running on. For Windows NT, use the storprop.dll,

      // while for Windows 9x use the DVDRgn.exe application to change the region.

     

      OSVERSIONINFO   ver;

      ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

      GetVersionEx(&ver);

      if (VER_PLATFORM_WIN32_NT  == ver.dwPlatformId)

      {

        // Windows NT platform

        HINSTANCE       hInstDLL;

        DVDPPLAUNCHER    DVDPPLauncher;

        CHAR         szDVDDriveA[4];

     

      #ifdef UNICODE

        WideCharToMultiByte(0, 0, szDVDDrive, -1,

                  szDVDDriveA, sizeof(szDVDDriveA),

                  NULL, NULL );

      #else

        strcpy(szDVDDriveA, szDVDDrive);

      #endif  // UNICODE

     

        GetSystemDirectory(szCmdLine, MAX_PATH);

        lstrcat(szCmdLine, TEXT("//storprop.dll"));

       

        hInstDLL = LoadLibrary (szCmdLine);

        if (hInstDLL)

        {

          DVDPPLauncher = (DVDPPLAUNCHER) GetProcAddress(hInstDLL,

                                                "DVDLauncher");

          if (DVDPPLauncher)

          {

            bRegionChanged = DVDPPLauncher(hWnd, szDVDDriveA[0]);

          }

          FreeLibrary(hInstDLL);

        }

      }  // end of region change code for Windows NT platform

      else   // Windows 9x platform

      {

        // Get path of /windows/DVDrgn.exe for command line string

        GetWindowsDirectory(szCmdLine, MAX_PATH);

        lstrcat(szCmdLine, TEXT("//DVDRgn.exe "));

     

        // Add only the drive letter as command line parameter

        lstrncat(szCmdLine, szDVDDrive, 1);

       

        // Prepare to execute DVDRgn.exe

        STARTUPINFO               StartupInfo;

        PROCESS_INFORMATION       ProcessInfo;

        StartupInfo.cb            = sizeof(StartupInfo);

        StartupInfo.dwFlags       = STARTF_USESHOWWINDOW;

        StartupInfo.wShowWindow   = SW_SHOWNORMAL;

        StartupInfo.lpReserved    = NULL;

        StartupInfo.lpDesktop     = NULL;

        StartupInfo.lpTitle       = NULL;

        StartupInfo.cbReserved2   = 0;

        StartupInfo.lpReserved2   = NULL;

        if (CreateProcess(csModuleName, szCmdLine,

                        NULL, NULL, TRUE,

                        NORMAL_PRIORITY_CLASS,

                        NULL, NULL, &StartupInfo, &ProcessInfo) )

        {

          // Wait until DVDRgn.exe finishes

          WaitForSingleObject(ProcessInfo.hProcess, INFINITE);

          DWORD dwRet = 1;

          BOOL bRet = GetExitCodeProcess(ProcessInfo.hProcess,

                               &dwRet);

          // If the user changed the drive region

          // successfully, the exit code of DVDRgn.exe is 0.

          if (bRet && 0 == dwRet) 

          {

            bRegionChanged = TRUE;

          }

        }

      }  // end of region change code for Windows 9x platform

     

      if (bRegionChanged)   // if region changed successfully

      {

        // Delete old filter graph and create new filter graph

        // via IDVDGraphBuilder::RenderDVDVideoVolume().

      }

      else   // DVD region didn't happen

      {

        MessageBox(hWnd,

        TEXT("DVD drive region could not be changed.")

        TEXT("Error"), MB_OK | MB_INFORMATION) ;

      }

    } //End function ChangeDVDRegion

     

    /

    // GetDriveLetter :  Function to get the drive letter of the currently

    //           active DVD drive

    // Parameters:

    //  In:    pDVDC - pointer to IDVDControl interface of

    //                DVDNavigator filter..

    //  Out:   pszDrive - the first DVD drive that is found

    //                   to have a valid DVD-V disc.

    //

    // Returns:

    //     TRUE:   if a DVD drive is found (with valid disc)

    //    FALSE:   if no DVD drive was found with valid DVD-V disc.

    /

    BOOL GetDriveLetter(IDVDControl *pDVDC, TCHAR *pszDrive)

    {

      CHAR   szPathA[MAX_PATH];

      TCHAR   szPath[MAX_PATH];

      ULONG   ulActualSize;

      pszDrive[0] = pszDrive[3] = 0;

     

      // Get the current root directory

      if (pDVDC ->GetRoot(szPathA, MAX_PATH, &ulActualSize))

      {

        #ifdef UNICODE

          MultiByteToWideChar(CP_ACP, 0, szPathA, 0, szPath, MAX_PATH);

        #else

          lstrcpy(szPath, szPathA);

        #endif  // UNICODE

        lstrcpyn(pszDrive, szPath, 3);

        if (DRIVE_CDROM == GetDriveType(pszDrive)) // could be a DVD drive

          return TRUE;

      }

     

      // Now loop through all the valid drives to detect which one

      // is a DVD drive with a valid DVD-V disc in it.

     

      // Get all valid drives

      DWORD dwLeng = GetLogicalDriveStrings(MAX_PATH, szPath);

      TCHAR  *pszTemp = szPath;

      // Try all drives one by one

      for (DWORD dw = 0; dw < dwLeng; dw += 4)

      {

        // Look only for CD-ROM drives that has a disc with required (.ifo) files

        if (DRIVE_CDROM  == GetDriveType(pszTemp))

          {

            TCHAR   szDVDPath1[MAX_PATH]

            TCHAR   szDVDPath2[MAX_PATH];

            lstrcpyn(szDVDPath1, pszTemp, 4);

            lstrcpyn(szDVDPath 2, pszTemp, 4);

            lstrcat(szDVDPath1, TEXT("Video_ts//Video_ts.ifo"));

            lstrcat(szDVDPath2, TEXT("Video_ts//Vts_01_0.ifo"));

     

            // If the .ifo files exist on this drive then it has a valid DVD-V disc

            if (DoesFileExist(achDVDPath1) && DoesFileExist(achDVDPath2))   

            {

              lstrcpyn(pszDrive, pszTemp, 3);

              return TRUE;   // return the first drive that has a valid DVD-V disc

            }

          }

        pszTemp += 4;

      }

     

      return FALSE ;   // didn't find any DVD drive (with DVD-V content)

    } //End function GetDriveLetter

     

    /

    // DoesFileExist : Function to determine if the given filename is an existing file.

    //

    // Parameters:

    //  In:    pszFile - filename string to check for existence.

    //  Out:   none.

    //

    // Returns:

    //     TRUE:   if the specified file is found.

    //      FALSE:   if the specified file is not found.

    /

    BOOL DoesFileExist(LPTSTR pszFile)

    {

      HANDLE    hFile = NULL ;

      // We don't want any error message box to pop up when we try to test

      // if the required file is available to open for read.

     

      UINT uErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS |

      SEM_NOOPENFILEERRORBOX);

      hFile = CreateFile(pszFile, GENERIC_READ,

                        FILE_SHARE_READ, NULL,

                        OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN,

                        NULL);

      SetErrorMode(uErrorMode);  // restore error mode

      If (INVALID_HANDLE_VALUE  == hFile)

        return FALSE ;   

     

      CloseHandle(hFile);

      return TRUE;

    } //End function DoesFileExist

     

     

    <script language=JavaScript> function SetGlossary(){;}; function Glossary(oObj){;}; </script>

     

     


    最新回复(0)