CSDN博客

img kathywp

DVD的界解码

发表于2002/11/4 13:03:00  2106人阅读

分类: DirectX

 

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

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

 

 

 

 

0 0

相关博文

我的热门文章

img
取 消
img