发现文件格式

在将文件发送到设备之前,应用程序应确定设备是否支持该文件格式。

发现文件格式可能比较复杂。 最简单的方法是创建映射到特定WMDM_FORMATCODE枚举值的文件扩展名列表。 但是,此系统存在一些问题:一是单个格式可以具有多个扩展 (,例如) JPEG 图像的.jpg、.jpe 和 .jpeg。 此外,同一文件扩展名可以由不同的程序用于不同的格式。

为了克服严格映射的限制,应用程序最好验证格式是否与扩展匹配。 DirectShow SDK 提供的工具使应用程序能够发现有关大多数媒体文件类型的有限详细信息集。 Windows Media Format SDK 公开大量详细信息,但仅提供有关 ASF 文件的详细信息。 由于所有文件类型都应尽可能验证其格式代码,因此最好使用 DirectShow 发现或验证基本格式代码,并使用 Windows 媒体格式 SDK 发现所需的有关 ASF 文件的任何其他元数据。 DirectShow 还可用于发现非 ASF 文件的基本元数据。

下面是使用扩展映射和 DirectShow 发现文件格式的一种方法。

首先,将文件扩展名与已知扩展名的列表进行比较。 请务必使比较不区分大小写。 如果未映射扩展,请将格式设置为 WMDM_FORMATCODE_UNDEFINED。

  • 如果 (找不到格式代码,或者想要验证文件是否为媒体文件) ,可以执行以下步骤:
    1. 使用 CoCreateInstance (CLSID_MediaDet) 并检索 IMediaDet 接口创建 DirectShow 媒体检测器对象。
    2. 通过调用 IMediaDet::p ut_Filename 打开文件。 如果文件受保护,此调用将失败。
    3. 通过调用 IMediaDet::get_StreamMediaType 获取默认流的媒体类型,这将返回 AM_MEDIA_TYPE
    4. 通过调用 IMediaDet::get_OutputStreams 获取流数。
      • 如果只有一个流并且它是音频,则文件类型WMDM_FORMATCODE_UNDEFINEDAUDIO
      • 如果只有一个流并且它是视频,则文件类型为WMDM_FORMATCODE_UNDEFINEDVIDEO
      • 如果只有一个流且它是视频流,并且比特率为零,则文件类型WMDM_FORMATCODE_WINDOWSIMAGEFORMAT。

还可以尝试匹配从get_StreamMediaType检索到的 VIDEOINFOHEADERWAVEFORMATEX 成员的音频或 视频编解码器。

以下 C++ 函数演示了文件扩展名匹配并使用 DirectShow 尝试分析未知文件。

// For IMediaDet, you must link to strmiids.lib. Also include the following:
//#include <Qedit.h>  // for IMediaDet declaration.
//#include <Dshow.h>  // for VIDEOINFOHEADER declaration.
WMDM_FORMATCODE CWMDMController::myGetWMDM_FORMATCODE(LPCWSTR pFileName)
{
    HRESULT hr = S_OK;

    // Declare the variable to hold the WMDM format code.
    WMDM_FORMATCODE fmt = WMDM_FORMATCODE_UNDEFINED;
    
    // Get the file extension.
    wstring ext = pFileName;
    ext = ext.substr(ext.find_last_of(L".") + 1);

    // This is not an exhaustive list. 
    // It is also case-sensitive.
    if (ext == L"js" || ext == L"vb")
        fmt = WMDM_FORMATCODE_SCRIPT;
    else if (ext == L".exe")
        fmt = WMDM_FORMATCODE_EXECUTABLE;
    else if (ext == L"txt")
        fmt = WMDM_FORMATCODE_TEXT;
    else if (ext == L"html" || ext == L"htm" || ext == L"shtm")
        fmt = WMDM_FORMATCODE_HTML;
    else if (ext == L"aiff")
        fmt = WMDM_FORMATCODE_AIFF;
    else if (ext == L"wav")
        fmt = WMDM_FORMATCODE_WAVE;
    else if (ext == L"mp3")
        fmt = WMDM_FORMATCODE_MP3;
    else if (ext == L"mpg" || ext == L"mpeg" || ext == L"mp2")
        fmt = WMDM_FORMATCODE_MPEG;
    else if (ext == L"bmp")
        fmt = WMDM_FORMATCODE_IMAGE_BMP;
    else if (ext == L"avi")
        fmt = WMDM_FORMATCODE_AVI;
    else if (ext == L"asf")
        fmt = WMDM_FORMATCODE_ASF;
    else if (ext == L"tif")
        fmt = WMDM_FORMATCODE_IMAGE_TIFF;
    else if (ext == L"gif")
        fmt = WMDM_FORMATCODE_IMAGE_GIF;
    else if (ext == L"pct")
        fmt = WMDM_FORMATCODE_IMAGE_PICT;
    else if (ext == L"png")
        fmt = WMDM_FORMATCODE_IMAGE_PNG;
    else if (ext == L"wma")
        fmt = WMDM_FORMATCODE_WMA;
    else if (ext == L"wpl")
        fmt = WMDM_FORMATCODE_WPLPLAYLIST;
    else if (ext == L"asx")
        fmt = WMDM_FORMATCODE_ASXPLAYLIST;
    else if (ext == L"m3u")
        fmt = WMDM_FORMATCODE_M3UPLAYLIST;
    else if (ext == L"wmv")
        fmt = WMDM_FORMATCODE_WMV;
    else if (ext == L"jpg" || ext == L"jpeg" || ext == L"jpe")
        fmt = WMDM_FORMATCODE_IMAGE_EXIF;
    else if (ext == L"jp2")
        fmt = WMDM_FORMATCODE_IMAGE_JP2;
    else if (ext == L"jpx" || ext == L"jpf")
        fmt = WMDM_FORMATCODE_IMAGE_JPX;

    // If we couldn't get the type from the extension, perhaps DirectShow 
    // can determine the type. You could also modify this to verify that 
    // the major media type matches the file extension (for example, that 
    // a .gif file has a video image stream with a bit rate of zero).
    if (fmt == WMDM_FORMATCODE_UNDEFINED)
    {
        CComPtr<IMediaDet> pIMediaDet;
        hr = pIMediaDet.CoCreateInstance(CLSID_MediaDet, NULL);
        if (hr == S_OK && pIMediaDet != NULL)
        {
            hr = pIMediaDet->put_Filename(BSTR(pFileName));
            if (FAILED(hr)) return WMDM_FORMATCODE_UNDEFINED;

            AM_MEDIA_TYPE mediaType;
            if (hr == S_OK)
            {
                hr = pIMediaDet->get_StreamMediaType(&mediaType);
                CHECK_HR(hr, 
                  "get_StreamMediaType succeeded in myGetWMDM_FORMATCODE.", 
                  "get_StreamMediaType failed in myGetWMDM_FORMATCODE.");
            }

            if (hr == S_OK)
            {
                LONG numStreams = 0;
                hr = pIMediaDet->get_OutputStreams(&numStreams);

                // If there is at least one video stream, the file is video. 
                // If there are only audio streams, it is audio.
                // Loop through all streams or until first video stream is found.
                for (int i = 0; i < numStreams; i++)
                {
                    // Choices are either VIDEOINFOHEADER or WAVEFORMATEX. 
                    // VIDEOINFOHEADER2 is not supported.
                    if (IsEqualGUID(mediaType.formattype, 
                        FORMAT_VideoInfo))
                    {
                        VIDEOINFOHEADER* data = 
                            (VIDEOINFOHEADER*) mediaType.pbFormat;

                        // If only one stream and there was no matching 
                        // extension, it is undefined video. If no 
                        // bit rate, it's a still image.
                        if (data->dwBitRate == 0) fmt = 
                            WMDM_FORMATCODE_WINDOWSIMAGEFORMAT;
                        else fmt = WMDM_FORMATCODE_UNDEFINEDVIDEO;
                        break; // Found video--any additional streams are soundtracks.
                    }
                    if (IsEqualGUID(mediaType.formattype, FORMAT_WaveFormatEx))
                    {
                        // If only one stream and there was no matching 
                        // extension, it is undefined audio. 
                        if (fmt == WMDM_FORMATCODE_UNDEFINED)
                        {
                            fmt = WMDM_FORMATCODE_UNDEFINEDAUDIO;
                        }
                        WAVEFORMATEX* data = 
                            (WAVEFORMATEX*) mediaType.pbFormat;
                    }
                } // Loop through streams.
            }     // Got a stream media type.
        }         // Created a media detector object.
    }
    return fmt;
}

将文件写入设备