使用 DVD 文本字符串

[与此页面关联的功能 DirectShow 是旧版功能。 它已被 MediaPlayerIMFMediaEngineMedia Foundation 中的音频/视频捕获所取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能在 Media Foundation 中使用 MediaPlayerIMFMediaEngine音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]

某些 DVD 光盘(尤其是卡拉OK光盘)可能包含文本字符串列表,以补充视频或音频内容。 这些文本字符串包含有关内容的元数据,例如歌曲标题、艺术家姓名、流派信息等。 文本字符串可以以多种语言提供。 这些字符串是可选的,许多光盘没有这些字符串。

若要从 DVD 检索文本字符串,请使用由 DVD 导航器公开的 IDvdInfo2 接口。 实际上不需要生成 DVD 播放图来检索文本字符串。 只需创建 DVD 导航器、设置 DVD 卷,然后调用相关的文本字符串方法:

方法 说明
IDvdInfo2::GetDVDTextNumberOfLanguages 获取具有文本字符串的语言数。
IDvdInfo2::GetDVDTextLanguageInfo 获取有关一种语言的文本字符串的信息。
IDvdInfo2::GetDVDTextStringAsUnicode 按索引获取指定语言的文本字符串。
IDvdInfo2::GetDVDTextStringAsNative 获取文本字符串作为原始字节数组。 如果文本字符串使用 GetDVDTextStringAsUnicode 不支持的字符编码,请使用此方法。

 

下面是获取文本字符串的基本过程:

  1. 调用 IDvdInfo2::GetDVDTextNumberOfLanguages 查找文本字符串所显示语言的总数。 如果数字为零,则表示 DVD 没有任何文本字符串。 (这也许是最常见的情况,事实上。)
  2. 如果语言数量至少为一种,请调用 IDvdInfo2::GetDVDTextLanguageInfo 以获取有关每种语言的信息。 语言由索引指定。 方法返回该语言的文本字符串总数、语言的区域设置标识符 (LCID) ,以及字符编码 (Unicode 或其他) 。 DVD 文本字符串可以使用多个不同的字符集;这些项列在 DVD_TextCharSet枚举中。
  3. 若要获取文本字符串,请调用 IDvdInfo2::GetDVDTextStringAsUnicodeIDvdInfo2::GetDVDTextStringAsNative。 第一个方法返回宽字符字符串,但不支持每个字符集。 第二个方法返回包含原始文本数据的字节数组。 对于这两种方法,可以使用 NULL 缓冲区指针调用 方法,以查找字符串的大小和文本类型。 然后分配缓冲区并再次调用 方法以获取字符串。

每个文本字符串都有一个关联的标识符代码,该代码指示文本字符串的含义。 标识符作为 DVD_TextStringType 值返回。 标识符有两个类别: 结构标识符内容标识符。 结构标识符在0x00-0x02F范围内具有数字代码。 内容标识符的范围0x30及更高。 (DVD_TextStringType 枚举定义最常见标识符的子集,但 IDvdInfo2 方法可以返回任何标识符代码。) 结构标识符描述 DVD 的逻辑部分,例如卷、游戏或部分游戏 (PTT) 。 内容标识符指示特定文本字符串的含义,例如电影标题、歌曲标题或流派。

结构标识符没有关联的文本字符串。 当结构标识符出现在文本字符串数据中时,它会指示以下文本字符串应用于 DVD 的逻辑部分,直到下一个结构标识符。 结构标识符在文本数据中的位置对应于 DVD 卷的逻辑层次结构。 例如,DVD_Struct_Title标识符的第一个匹配项 (0x02) 表示卷中的第一个标题,下一个匹配项表示第二个标题。

下表显示了如何为具有两个标题的 DVD 定义文本字符串。

DVD_TextStringType 文本字符串 说明
DVD_Struct_Volume (0x01) "" 整个光盘端的结构标识符。
DVD_General_Name (0x30) “DVD 卷” DVD 卷名称。
DVD_Struct_Title (0x02) "" 第一个游戏的结构标识符。
DVD_General_Name (0x30) “标题 1” 第一个游戏的名称。
DVD_Struct_Title (0x02) "" 第二个游戏的结构标识符。
DVD_General_Name (0x30) “标题 2” 第二个标题的名称。

 

GetDVDTextStringAsUnicodeGetDVDTextStringAsNative 方法将结构标识符和内容标识符视为相同。 唯一的区别在于,对于结构标识符,关联的文本缓冲区为空。 由应用程序来跟踪文本字符串与 DVD 逻辑部分之间的关系。

以下示例演示如何从 DVD 获取文本字符串。 此示例忽略实际应用程序需要的某些详细信息。 (例如,它忽略结构标识符。) 该示例仅用于显示正确的调用序列。

#define CHECK_HR(hr) if (FAILED(hr)) { goto done; }
#define SAFE_ARRAY_DELETE(x) { if (x != NULL) { delete [] x; x = NULL; } }

HRESULT GetDVDTextStrings()
{
    HRESULT hr = S_OK;
    ULONG cLangs = 0;       // Number of languages.
    ULONG cStrings = 0;     // Number of text strings.
    ULONG cchBuffer = 0;    // Buffer size.
    ULONG cchActual = 0;    // Actual string size.

    LCID lcid;              // Locale identifier.
    DVD_TextCharSet     characterSet;
    DVD_TextStringType  stringType;

    WCHAR *pszBuffer = NULL;

    CComPtr<IBaseFilter> pFilter;
    CComPtr<IDvdInfo2> pInfo;
    CComPtr<IDvdControl2> pControl;

    // Set up the DVD Navigator.
    CHECK_HR(hr = pFilter.CoCreateInstance(CLSID_DVDNavigator));
    CHECK_HR(hr = pFilter.QueryInterface(&pInfo));
    CHECK_HR(hr = pFilter.QueryInterface(&pControl));
    CHECK_HR(hr = pControl->SetDVDDirectory(NULL));

    // Find the number of text-string languages.
    CHECK_HR(hr = pInfo->GetDVDTextNumberOfLanguages(&cLangs));
    if (cLangs == 0)
    {
        return S_FALSE; // No text strings.
    }

    // Get information about the 0'th language.
    CHECK_HR(hr = pInfo->GetDVDTextLanguageInfo(
        0, &cStrings, &lcid, &characterSet));

    // First check if this character set is compatible with the 
    // GetDVDTextStringAsUnicode method.

    if (characterSet == DVD_CharSet_Unicode || 
        characterSet == DVD_CharSet_ISO646)
    {
        // Loop through all of the strings.
        for (ULONG i = 0; i < cStrings; i++)
        {
            // Get the i'th string for the 0'th language.

            // Find the required buffer size and the string type.
            CHECK_HR(hr = pInfo->GetDVDTextStringAsUnicode(
                0,            // Language index.
                i,            // String index.
                NULL,         // Pass NULL pointer to get the buffer size.
                0,            // Size of the buffer we are passing in.
                &cchBuffer,   // Receives the required buffer size.
                &stringType   // Receives the identifier code.
                ));

            // Skip structure identifiers (0x00 - 0x2F).
            if ((cchBuffer > 0) && (stringType >= 0x30))
            {
                // Allocate a buffer and get the text string.
                pszBuffer = new WCHAR[cchBuffer];
                if (pszBuffer == NULL)
                {
                    CHECK_HR(hr = E_OUTOFMEMORY);
                }

                CHECK_HR(hr = pInfo->GetDVDTextStringAsUnicode(
                    0, i, pszBuffer, cchBuffer, &cchActual, &stringType));

                // TODO: Display the text string.

                SAFE_ARRAY_DELETE(pszBuffer);
            }
        }
    }

done:
    SAFE_ARRAY_DELETE(pszBuffer);
    return hr;
}

有关 DVD 文本字符串的信息,请参阅 DVD 论坛的网站

DVDSample 应用程序中的 CDvdCore::GetDvdText 方法演示枚举和显示 DVD 文本字符串的基本步骤。

DVD 应用程序