Поделиться через


Обнаружение формата файла

Перед отправкой файла на устройство приложение должно определить, поддерживает ли устройство этот формат.

Обнаружение формата файла может быть сложным. Самый простой способ — создать список расширений файлов, сопоставленных с определенными значениями перечисления WMDM_FORMATCODE. Однако существует несколько проблем с этой системой: один формат может иметь несколько расширений (например, .jpg, .jpe и .jpeg для изображений JPEG). Кроме того, одно и то же расширение файла можно использовать различными программами для разных форматов.

Чтобы преодолеть ограничения строгого сопоставления, лучше всего проверить, что формат соответствует расширению. Пакет SDK DirectShow предоставляет средства, позволяющие приложению обнаруживать ограниченный набор сведений о большинстве типов файлов мультимедиа. Пакет SDK для формата Windows Media предоставляет большое количество сведений, но только о файлах ASF. Так как все типы файлов должны проверять код формата, если это возможно, рекомендуется использовать DirectShow для обнаружения или проверки базового кода формата, а также использовать пакет SDK формата Windows Media для обнаружения дополнительных метаданных, необходимых для файлов ASF. DirectShow также можно использовать для обнаружения базовых метаданных для файлов, отличных от ASF.

Ниже приведен один из способов обнаружения формата файла с помощью сопоставления расширений и DirectShow.

Сначала сравните расширение имени файла со списком известных расширений. Не забудьте сделать сравнение нечувствительным к регистру. Если расширение не сопоставлено, задайте формат WMDM_FORMATCODE_UNDEFINED.

  • Если код формата не найден (или вы хотите убедиться, что файл является файлом мультимедиа), можно выполнить следующие действия:
    1. Создайте объект DirectShow Media Detector с помощью CoCreateInstance(CLSID_MediaDet), получив интерфейс IMediaDet.
    2. Откройте файл, вызвав IMediaDet::put_Filename. Этот вызов завершится ошибкой, если файл защищен.
    3. Получите тип носителя потока по умолчанию, вызвав IMediaDet::get_StreamMediaType, который возвращает AM_MEDIA_TYPE.
    4. Получение количества потоков путем вызова IMediaDet::get_OutputStreams.
      • Если есть только один поток и он является аудио, тип файла WMDM_FORMATCODE_UNDEFINEDAUDIO
      • Если имеется только один поток и это видео, тип файла WMDM_FORMATCODE_UNDEFINEDVIDEO
      • Если существует только один поток и это видео, и битрейт равен нулю, тогда тип файла WMDM_FORMATCODE_WINDOWSIMAGEFORMAT.

Вы также можете попробовать сопоставить звуковые или видеокодеки из VIDEOINFOHEADER или WAVEFORMATEX, полученные из get_StreamMediaType.

Следующая функция 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;
}

запись файлов на устройство