Eğitim: Tek Geçişli Windows Media Kodlama

Kodlama, dijital medyayı bir biçimden diğerine dönüştürme işlemini ifade eder. Örneğin, MP3 sesini Gelişmiş Sistemler Biçimi (ASF) belirtimi tarafından tanımlandığı şekilde Windows Media Audio biçimine dönüştürme.

Not ASF belirtimi, çıktı dosyası (.wma veya .wmv) için herhangi bir biçimde, sıkıştırılmış veya sıkıştırılmamış medya verileri içerebilen bir kapsayıcı türü tanımlar. Örneğin, .wma dosyası gibi bir ASF kapsayıcısı MP3 biçiminde medya verileri içerebilir. Kodlama işlemi, dosyanın içinde yer alan verilerin gerçek biçimini dönüştürür.

Bu öğreticide, Temiz içerik (DRM korumalı olmayan) giriş kaynağını Windows Media içeriğine kodlama ve İşlem Hattı Katmanı ASF Bileşenleri kullanılarak verileri yeni bir ASF dosyasında (.wm*) yazma işlemi gösterilmektedir. Bu bileşenler, Medya Oturumu örneği tarafından denetlenecek kısmi kodlama topolojisi oluşturmak için kullanılır.

Bu öğreticide, girdi ve çıkış dosya adlarını ve kodlama modunu bağımsız değişken olarak alan bir konsol uygulaması oluşturacaksınız. Giriş dosyası sıkıştırılmış veya sıkıştırılmamış bir medya biçiminde olabilir. Geçerli kodlama modları "CBR" (sabit bit hızı) veya "VBR" (değişken bit hızı) şeklindedir. Uygulama, giriş dosya adı tarafından belirtilen kaynağı temsil eden bir medya kaynağı ve kaynak dosyanın kodlanmış içeriğini ASF dosyasında arşivlemesi için ASF dosya havuzu oluşturur. Senaryonun uygulanmasını basit tutmak için çıkış dosyasında yalnızca bir ses akışı ve bir video akışı olur. Uygulama, ses akışı biçimi dönüştürme için Windows Media Audio 9.1 Professional codec bileşenini ve video akışı için Windows Media Video 9 codec bileşenini ekler.

Sabit bit hızı kodlaması için kodlama oturumu başlamadan önce kodlayıcının ulaşması gereken hedef bit hızını bilmesi gerekir. Bu öğreticide, "CBR" modu için uygulama, hedef bit hızı olarak medya türü anlaşması sırasında kodlayıcıdan alınan ilk çıkış medya türüyle kullanılabilir bit hızını kullanır. Değişken bit hızı kodlaması için bu öğreticide kalite düzeyi ayarlayarak değişken bit hızı ile kodlama gösterilmektedir. Ses akışları 98 kalite düzeyinde, video akışları ise 95 kalite düzeyinde kodlanır.

Aşağıdaki yordam, 1 geçişli kodlama modu kullanarak ASF kapsayıcısında Windows Media içeriğini kodlama adımlarını özetler.

  1. Kaynak çözümleyiciyi kullanarak belirtilen için bir medya kaynağı oluşturun.
  2. Medya kaynağındaki akışları numaralandırın.
  3. ASF medya havuzu oluşturun ve kodlanması gereken medya kaynağındaki akışlara bağlı olarak akış havuzları ekleyin.
  4. Medya havuzunu gerekli kodlama özellikleriyle yapılandırın.
  5. Çıkış dosyasındaki akışlar için Windows Media kodlayıcılarını oluşturun.
  6. Kodlayıcıları medya havuzu üzerinde ayarlanan özelliklerle yapılandırın.
  7. Kısmi kodlama topolojisi oluşturun.
  8. Medya Oturumu örneği açın ve Medya Oturumu'nda topolojiyi ayarlayın.
  9. Medya Oturumunu denetleyerek ve Medya Oturumu'ndan ilgili tüm olayları alarak kodlama oturumunu başlatın.
  10. VBR kodlaması için kodlayıcıdan kodlama özelliği değerlerini alın ve bunları medya alıcısına ayarlayın.
  11. Kodlama oturumunu kapatın ve sonlandırın.

Bu öğretici aşağıdaki bölümleri içerir:

Önkoşullar

Bu öğreticide aşağıdakiler varsayılır:

Projeyi ayarlama

  1. Kaynak dosyanıza aşağıdaki üst bilgileri ekleyin:

    #include <new>
    #include <mfidl.h>            // Media Foundation interfaces
    #include <mfapi.h>            // Media Foundation platform APIs
    #include <mferror.h>        // Media Foundation error codes
    #include <wmcontainer.h>    // ASF-specific components
    #include <wmcodecdsp.h>        // Windows Media DSP interfaces
    #include <Dmo.h>            // DMO objects
    #include <uuids.h>            // Definition for FORMAT_VideoInfo
    #include <propvarutil.h>
    
    
  2. Aşağıdaki kitaplık dosyalarına bağlantı:

    // The required link libraries 
    #pragma comment(lib, "mfplat")
    #pragma comment(lib, "mf")
    #pragma comment(lib, "mfuuid")
    #pragma comment(lib, "msdmo")
    #pragma comment(lib, "strmiids")
    #pragma comment(lib, "propsys")
    
    
  3. SafeRelease işlevini bildirin.

    template <class T> void SafeRelease(T **ppT)
    {
        if (*ppT)
        {
            (*ppT)->Release();
            *ppT = NULL;
        }
    }
    
  4. CBR ve VBR kodlama türlerini tanımlamak için ENCODING_MODE numaralandırmasını bildirin.

    // Encoding mode
    typedef enum ENCODING_MODE {
      NONE  = 0x00000000,
      CBR   = 0x00000001,
      VBR   = 0x00000002,
    } ;
    
    
  5. Video akışı için arabellek penceresi için sabit tanımlayın.

    // Video buffer window
    const INT32 VIDEO_WINDOW_MSEC = 3000;
    
    

Medya Kaynağı Oluşturma

Giriş kaynağı için bir medya kaynağı oluşturun. Media Foundation, çeşitli medya biçimleri için yerleşik medya kaynakları sağlar: MP3, MP4/3GP, AVI/WAVE. Media Foundation tarafından desteklenen biçimler hakkında bilgi için bkz. Media Foundation'da Desteklenen Medya Biçimleri .

Medya kaynağını oluşturmak için Kaynak Çözümleyicisikullanın. Bu nesne, kaynak dosya için belirtilen URL'yi analiz eder ve uygun medya kaynağını oluşturur.

Aşağıdaki çağrıları yapın:

Aşağıdaki kod örneği, belirtilen dosya için bir medya kaynağı oluşturan CreateMediaSource işlevini gösterir.

//  Create a media source from a URL.
HRESULT CreateMediaSource(PCWSTR sURL, IMFMediaSource **ppSource)
{
    MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID;

    IMFSourceResolver* pSourceResolver = NULL;
    IUnknown* pSource = NULL;

    // Create the source resolver.
    HRESULT hr = MFCreateSourceResolver(&pSourceResolver);
    if (FAILED(hr))
    {
        goto done;
    }

    // Use the source resolver to create the media source.

    // Note: For simplicity this sample uses the synchronous method to create 
    // the media source. However, creating a media source can take a noticeable
    // amount of time, especially for a network source. For a more responsive 
    // UI, use the asynchronous BeginCreateObjectFromURL method.

    hr = pSourceResolver->CreateObjectFromURL(
        sURL,                       // URL of the source.
        MF_RESOLUTION_MEDIASOURCE,  // Create a source object.
        NULL,                       // Optional property store.
        &ObjectType,        // Receives the created object type. 
        &pSource            // Receives a pointer to the media source.
        );
    if (FAILED(hr))
    {
        goto done;
    }

    // Get the IMFMediaSource interface from the media source.
    hr = pSource->QueryInterface(IID_PPV_ARGS(ppSource));

done:
    SafeRelease(&pSourceResolver);
    SafeRelease(&pSource);
    return hr;
}

ASF Dosya Havuzu Oluşturma

Kodlama oturumunun sonunda kodlanmış medya verilerini bir ASF dosyasına arşivleyecek ASF dosya havuzu örneğini oluşturun.

Bu öğreticide ASF dosya havuzu için bir etkinleştirme nesnesi oluşturacaksınız. Gerekli akış havuzlarını oluşturmak için dosya havuzu aşağıdaki bilgilere ihtiyaç duyar.

  • Kodlanacak ve son dosyaya yazılacak akışlar.
  • Kodlama türü, kodlama geçişi sayısı ve ilgili özellikler gibi medya içeriğini kodlamak için kullanılan kodlama özellikleri.
  • Medya alıcısının, sızdıran kova parametrelerini (bit hızı ve arabellek boyutu) otomatik olarak ayarlayıp ayarlamayacağını belirleyen genel dosya özellikleri.

Akış bilgileri ASF Profili nesnesinde yapılandırılır ve kodlama ve genel özellikler ASF ContentInfo Nesnesi tarafından yönetilen bir özellik deposunda ayarlanır.

ASF dosya havuzuna genel bakış için bkz. ASF Medya Havuzları.

ASF Profil Nesnesini Oluştur

ASF dosya havuzu bir ASF dosyasına kodlanmış medya verileri yazabilmesi için havuzun akış sayısını ve akış havuzlarının oluşturulacağı akış türünü bilmesi gerekir. Bu öğreticide, bu bilgileri medya kaynağından ayıklayacak ve karşılık gelen çıkış akışlarını oluşturacaksınız. Çıkış akışlarınızı bir ses akışı ve bir video akışıyla kısıtlayın. Kaynaktaki seçili her akış için bir hedef akış oluşturun ve bunu profile ekleyin.

Bu adımı uygulamak için aşağıdaki nesnelere ihtiyacınız vardır.

  • ASF Profili
  • Medya kaynağı için Sunu Tanımlayıcısı
  • Medya kaynağında seçili akışlar için akış tanımlayıcıları.
  • Seçili akışlar için Medya Türleri.

Aşağıdaki adımlarda ASF profilini ve hedef akışlarını oluşturma işlemi açıklanmaktadır.

ASF profili oluşturmak için

  1. Boş bir profil nesnesi oluşturmak için MFCreateASFProfileçağrısı yapın.

  2. Bu öğreticinin "Medya Kaynağını Oluşturma" bölümünde açıklanan adımda oluşturulan medya kaynağının sunu tanımlayıcısını oluşturmak için IMFMediaSource::CreatePresentationDescriptor çağrısı yapın.

  3. Medya kaynağındaki akış sayısını almak için IMFPresentationDescriptor::GetStreamDescriptorCount çağırın.

  4. Medya kaynağındaki her akış için IMFPresentationDescriptor::GetStreamDescriptorByIndex çağırın, akışın akış tanımlayıcısını alın.

  5. IMFStreamDescriptor::GetMediaTypeHandler ve ardından IMFMediaTypeHandler::GetMediaTypeByIndex çağırın ve akış için ilk medya türünü alın.

    Not Karmaşık çağrıları önlemek için akış başına yalnızca bir medya türü olduğunu varsayalım ve akışın ilk medya türünü seçin. Karmaşık akışlar için, medya türü işleyicisinden her medya türünü listelemeniz ve kodlamak istediğiniz medya türünü seçmeniz gerekir.

  6. IIMFMediaType::GetMajorType çağırarak akışın ses veya video içerip içermediğini belirlemek için akışın ana türünü alın.

  7. Akışın ana türüne bağlı olarak hedef medya türleri oluşturun. Bu medya türleri, kodlayıcının kodlama oturumu sırasında kullanacağı biçim bilgilerini tutar. Bu öğreticinin aşağıdaki bölümlerinde hedef medya türlerini oluşturma işlemi açıklanmaktadır.

    • Sıkıştırılmış Ses Medya Türü Oluşturma
    • Sıkıştırılmış Video Medya Türü Oluşturma
  8. Hedef medya türüne göre bir akış oluşturun, akışı uygulamanın gereksinimlerine göre yapılandırın ve akışı profile ekleyin. Daha fazla bilgi için bkz. ASF Dosya Havuzuna Akış Bilgileri Ekleme.

    1. Çıktı akışını oluşturmak için IMFASFProfile::CreateStream çağırın ve hedef medya türünü geçirin. yöntemi, akış nesnesinin IMFASFStreamConfig arabirimini alır.
    2. Akışı yapılandırın.
      • Akışa numara atamak için IMFASFStreamConfig::SetStreamNumberçağırın. Bu ayar zorunludur.
      • İsteğe bağlı olarak, IMFASFStreamConfig yöntemlerini ve ilgili akış yapılandırma özniteliklerini çağırarak her akış için sızdıran demet parametrelerini, yük genişletmesini ve karşılıklı dışlamayı yapılandırın.
    3. ASF ContentInfo nesnesini kullanarak akış düzeyi kodlama özelliklerini ekleyin. Bu adım hakkında daha fazla bilgi için bu öğreticideki "ASF ContentInfo Nesnesi Oluşturma" bölümüne bakın.
    4. Akışı profile eklemek için IMFASFProfile::SetStream çağırın.

    Aşağıdaki kod örneği bir çıkış ses akışı oluşturur.

    //-------------------------------------------------------------------
    //  CreateAudioStream
    //  Create an audio stream and add it to the profile.
    //
    //  pProfile: A pointer to the ASF profile.
    //  wStreamNumber: Stream number to assign for the new stream.
    //-------------------------------------------------------------------
    
    HRESULT CreateAudioStream(IMFASFProfile* pProfile, WORD wStreamNumber)
    {
        if (!pProfile)
        {
            return E_INVALIDARG;
        }
        if (wStreamNumber < 1 || wStreamNumber > 127 )
        {
            return MF_E_INVALIDSTREAMNUMBER;
        }
    
        IMFMediaType* pAudioType = NULL;
        IMFASFStreamConfig* pAudioStream = NULL;
    
        //Create an output type from the encoder
        HRESULT hr = GetOutputTypeFromWMAEncoder(&pAudioType);
        if (FAILED(hr))
        {
            goto done;
        }
    
        //Create a new stream with the audio type
        hr = pProfile->CreateStream(pAudioType, &pAudioStream);
        if (FAILED(hr))
        {
            goto done;
        }
    
        //Set stream number
        hr = pAudioStream->SetStreamNumber(wStreamNumber);
        if (FAILED(hr))
        {
            goto done;
        }
    
        //Add the stream to the profile
        hr = pProfile->SetStream(pAudioStream);
        if (FAILED(hr))
        {
            goto done;
        }
    
        wprintf_s(L"Audio Stream created. Stream Number: %d.\n", wStreamNumber);
    
    done:
        SafeRelease(&pAudioStream);
        SafeRelease(&pAudioType);
        return hr;
    }
    

    Aşağıdaki kod örneği bir çıkış video akışı oluşturur.

    //-------------------------------------------------------------------
    //  CreateVideoStream
    //  Create an video stream and add it to the profile.
    //
    //  pProfile: A pointer to the ASF profile.
    //  wStreamNumber: Stream number to assign for the new stream.
    //    pType: A pointer to the source's video media type.
    //-------------------------------------------------------------------
    
    HRESULT CreateVideoStream(IMFASFProfile* pProfile, WORD wStreamNumber, IMFMediaType* pType)
    {
        if (!pProfile)
        {
            return E_INVALIDARG;
        }
        if (wStreamNumber < 1 || wStreamNumber > 127 )
        {
            return MF_E_INVALIDSTREAMNUMBER;
        }
    
        HRESULT hr = S_OK;
    
    
        IMFMediaType* pVideoType = NULL;
        IMFASFStreamConfig* pVideoStream = NULL;
    
        UINT32 dwBitRate = 0;
    
        //Create a new video type from the source type
        hr = CreateCompressedVideoType(pType, &pVideoType);
        if (FAILED(hr))
        {
            goto done;
        }
    
        //Create a new stream with the video type
        hr = pProfile->CreateStream(pVideoType, &pVideoStream);
        if (FAILED(hr))
        {
            goto done;
        }
    
    
        //Set a valid stream number
        hr = pVideoStream->SetStreamNumber(wStreamNumber);
        if (FAILED(hr))
        {
            goto done;
        }
    
        //Add the stream to the profile
        hr = pProfile->SetStream(pVideoStream);
        if (FAILED(hr))
        {
            goto done;
        }
    
        wprintf_s(L"Video Stream created. Stream Number: %d .\n", wStreamNumber);
    
    done:
    
        SafeRelease(&pVideoStream);
        SafeRelease(&pVideoType);
    
        return hr;
    }
    

Aşağıdaki kod örneği, kaynaktaki akışlara bağlı olarak çıkış akışları oluşturur.

    //For each stream in the source, add target stream information in the profile
    for (DWORD iStream = 0; iStream < dwSrcStream; iStream++)
    {
        hr = pPD->GetStreamDescriptorByIndex(
            iStream, &fSelected, &pStreamDesc);
        if (FAILED(hr))
        {
            goto done;
        }

        if (!fSelected)
        {
            continue;
        }

        //Get the media type handler
        hr = pStreamDesc->GetMediaTypeHandler(&pHandler);
        if (FAILED(hr))
        {
            goto done;
        }

        //Get the first media type 
        hr = pHandler->GetMediaTypeByIndex(0, &pMediaType);
        if (FAILED(hr))
        {
            goto done;
        }

        //Get the major type
        hr = pMediaType->GetMajorType(&guidMajor);
        if (FAILED(hr))
        {
            goto done;
        }

        // If this is a video stream, create the target video stream
        if (guidMajor == MFMediaType_Video)
        {
            //The stream level encoding properties will be set in this call
            hr = CreateVideoStream(pProfile, wStreamID, pMediaType);

            if (FAILED(hr))
            {
                goto done;
            }
        }
        
        // If this is an audio stream, create the target audio stream
        if (guidMajor == MFMediaType_Audio)
        {
            //The stream level encoding properties will be set in this call
            hr = CreateAudioStream(pProfile, wStreamID);

            if (FAILED(hr))
            {
                goto done;
            }
        }

        //Get stream's encoding property
        hr = pContentInfo->GetEncodingConfigurationPropertyStore(wStreamID, &pContentInfoProps);
        if (FAILED(hr))
        {
            goto done;
        }

        //Set the stream-level encoding properties
        hr = SetEncodingProperties(guidMajor, pContentInfoProps);       
        if (FAILED(hr))
        {
            goto done;
        }


        SafeRelease(&pMediaType);
        SafeRelease(&pStreamDesc);
        SafeRelease(&pContentInfoProps);
        wStreamID++;
    }

Sıkıştırılmış Ses Medya Türü Oluşturma

Çıkış dosyasına bir ses akışı eklemek istiyorsanız, gerekli öznitelikleri ayarlayarak kodlanmış türün özelliklerini belirterek bir ses türü oluşturun. Ses türünün Windows Media ses kodlayıcıyla uyumlu olduğundan emin olmak için, kodlayıcı MFT'sini başlatın, kodlama özelliklerini ayarlayın ve IMFTransform::GetOutputAvailableTypeçağırarak bir medya türü alın. Tüm kullanılabilir türler arasında döngü yaparak, her medya türünün özniteliklerini alarak ve gereksinimlerinize en yakın türü seçerek gerekli çıkış türünü alın. Bu öğreticide, kodlayıcı tarafından desteklenen çıkış medya türleri listesinden ilk kullanılabilir türü edinin.

Not Windows 7 için Media Foundation, uyumlu ses türlerinin listesini alan MFTranscodeGetAudioOutputAvailableTypesyeni bir işlev sağlar. Bu işlev yalnızca CBR kodlaması için medya türlerini alır.

Tam bir ses türü aşağıdaki özniteliklere sahip olmalıdır:

Aşağıdaki kod örneği, Windows Media Audio kodlayıcısından uyumlu bir tür alarak sıkıştırılmış bir ses türü oluşturur. SetEncodingProperties uygulaması, bu öğreticinin "ASF ContentInfo Nesnesi Oluşturma" bölümünde gösterilir.

//-------------------------------------------------------------------
//  GetOutputTypeFromWMAEncoder
//  Gets a compatible output type from the Windows Media audio encoder.
//
//  ppAudioType: Receives a pointer to the media type.
//-------------------------------------------------------------------

HRESULT GetOutputTypeFromWMAEncoder(IMFMediaType** ppAudioType)
{
    if (!ppAudioType)
    {
        return E_POINTER;
    }

    IMFTransform* pMFT = NULL;
    IMFMediaType* pType = NULL;
    IPropertyStore* pProps = NULL;

    //We need to find a suitable output media type
    //We need to create the encoder to get the available output types
    //and discard the instance.

    CLSID *pMFTCLSIDs = NULL;   // Pointer to an array of CLISDs. 
    UINT32 cCLSID = 0;            // Size of the array.

    MFT_REGISTER_TYPE_INFO tinfo;
    
    tinfo.guidMajorType = MFMediaType_Audio;
    tinfo.guidSubtype = MFAudioFormat_WMAudioV9;

    // Look for an encoder.
    HRESULT hr = MFTEnum(
        MFT_CATEGORY_AUDIO_ENCODER,
        0,                  // Reserved
        NULL,                // Input type to match. None.
        &tinfo,             // WMV encoded type.
        NULL,               // Attributes to match. (None.)
        &pMFTCLSIDs,        // Receives a pointer to an array of CLSIDs.
        &cCLSID             // Receives the size of the array.
        );
    if (FAILED(hr))
    {
        goto done;
    }

    // MFTEnum can return zero matches.
    if (cCLSID == 0)
    {
        hr = MF_E_TOPO_CODEC_NOT_FOUND;
        goto done;
    }
    else
    {
        // Create the MFT decoder
        hr = CoCreateInstance(pMFTCLSIDs[0], NULL,
            CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pMFT));

        if (FAILED(hr))
        {
            goto done;
        }

    }

    // Get the encoder's property store

    hr = pMFT->QueryInterface(IID_PPV_ARGS(&pProps));
    if (FAILED(hr))
    {
        goto done;
    }
    
    //Set encoding properties
    hr = SetEncodingProperties(MFMediaType_Audio, pProps);
    if (FAILED(hr))
    {
        goto done;
    }

    //Get the first output type
    //You can loop through the available output types to choose 
    //the one that meets your target requirements
    hr = pMFT->GetOutputAvailableType(0, 0, &pType);
    if (FAILED(hr))
    {
        goto done;
    }

    //Return to the caller
    *ppAudioType = pType;
    (*ppAudioType)->AddRef();
    
done:
    SafeRelease(&pProps);
    SafeRelease(&pType);
    SafeRelease(&pMFT);
    CoTaskMemFree(pMFTCLSIDs);
    return hr;
}

Sıkıştırılmış Video Medya Türü Oluşturma

Çıkış dosyasına bir video akışı eklemek istiyorsanız, tam kodlanmış bir video türü oluşturun. Tam medya türü istenen bit hızını ve codec özel verilerini içermelidir.

Eksiksiz bir video medya türü oluşturmanın iki yolu vardır.

  • Boş bir medya türü oluşturun, kaynak video türünden medya türü özniteliklerini kopyalayın ve GUID sabiti MFVideoFormat_WMV3 MF_MT_SUBTYPE özniteliğinin üzerine yazın.

    Tam bir video türünde aşağıdaki öznitelikler ayarlanmalıdır:

    • MF_MT_MAJOR_TYPE
    • MF_MT_SUBTYPE
    • MF_MT_FRAME_RATE
    • MF_MT_KARE_BOYUTU
    • MF_MT_Ara Çizim Modu
    • MF_MT_PIXEL_ASPECT_RATIO
    • MF_MT_AVG_BITRATE
    • MF_MT_KULLANICI_VERİSİ

    Aşağıdaki kod örneği, kaynağın video türünden sıkıştırılmış bir video türü oluşturur.

    //-------------------------------------------------------------------
    //  CreateCompressedVideoType
    //  Creates an output type from source's video media type.
    //
    //    pType: A pointer to the source's video media type.
    //  ppVideoType: Receives a pointer to the media type.
    //-------------------------------------------------------------------
    
    HRESULT CreateCompressedVideoType(
            IMFMediaType* pType, 
            IMFMediaType** ppVideoType)
    {
        if (!pType)
        {
            return E_INVALIDARG;
        }
        if (!ppVideoType)
        {
            return E_POINTER;
        }
    
        HRESULT hr = S_OK;
        MFRatio fps = { 0 };
        MFRatio par = { 0 };
        UINT32 width = 0, height = 0;
        UINT32 interlace = MFVideoInterlace_Unknown;
        UINT32 fSamplesIndependent = 0;
        UINT32 cBitrate = 0;
    
        IMFMediaType* pMediaType = NULL;
    
        GUID guidMajor = GUID_NULL;
    
        hr = pType->GetMajorType(&guidMajor);
        if (FAILED(hr))
        {
            goto done;
        }
    
        if (guidMajor != MFMediaType_Video )
        {
            hr = MF_E_INVALID_FORMAT;
            goto done;
        }
    
        hr = MFCreateMediaType(&pMediaType);
        if (FAILED(hr))
        {
            goto done;
        }
    
        hr = pType->CopyAllItems(pMediaType);
        if (FAILED(hr))
        {
            goto done;
        }
    
        //Fill the missing attributes
        //1. Frame rate
        hr = MFGetAttributeRatio(pMediaType, MF_MT_FRAME_RATE, (UINT32*)&fps.Numerator, (UINT32*)&fps.Denominator);
        if (hr == MF_E_ATTRIBUTENOTFOUND)
        {
            fps.Numerator = 30000;
            fps.Denominator = 1001;
    
            hr = MFSetAttributeRatio(pMediaType, MF_MT_FRAME_RATE, fps.Numerator, fps.Denominator);
            if (FAILED(hr))
            {
                goto done;
            }
        }
    
        ////2. Frame size
        hr = MFGetAttributeSize(pMediaType, MF_MT_FRAME_SIZE, &width, &height);
        if (hr == MF_E_ATTRIBUTENOTFOUND)
        {
            width = 1280;
            height = 720;
    
            hr = MFSetAttributeSize(pMediaType, MF_MT_FRAME_SIZE, width, height);
            if (FAILED(hr))
            {
                goto done;
            }
        }
    
        ////3. Interlace mode
    
        if (FAILED(pMediaType->GetUINT32(MF_MT_INTERLACE_MODE, &interlace)))
        {
            hr = pMediaType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
            if (FAILED(hr))
            {
                goto done;
            }
    
        }
    
        ////4. Pixel aspect Ratio
        hr = MFGetAttributeRatio(pMediaType, MF_MT_PIXEL_ASPECT_RATIO, (UINT32*)&par.Numerator, (UINT32*)&par.Denominator);
        if (hr == MF_E_ATTRIBUTENOTFOUND)
        {
            par.Numerator = par.Denominator = 1;
            hr = MFSetAttributeRatio(pMediaType, MF_MT_PIXEL_ASPECT_RATIO, (UINT32)par.Numerator, (UINT32)par.Denominator);
            if (FAILED(hr))
            {
                goto done;
            }
    
        }
    
        //6. bit rate
        if (FAILED(pMediaType->GetUINT32(MF_MT_AVG_BITRATE, &cBitrate)))
        {
            hr = pMediaType->SetUINT32(MF_MT_AVG_BITRATE, 1000000);
            if (FAILED(hr))
            {
                goto done;
            }
    
        }
    
        hr = pMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_WMV3);
        if (FAILED(hr))
        {
            goto done;
        }
    
        // Return the pointer to the caller.
        *ppVideoType = pMediaType;
        (*ppVideoType)->AddRef();
    
    
    done:
        SafeRelease(&pMediaType);
        return hr;
    }
    
    
  • Kodlama özelliklerini ayarlayarak ve ardından IMFTransform::GetOutputAvailableTypeçağırarak Windows Media video kodlayıcısından uyumlu bir medya türü alın. Bu yöntem kısmi türü döndürür. Aşağıdaki bilgileri ekleyerek kısmi türü tam bir türe dönüştürdüğünüzden emin olun:

    • MF_MT_AVG_BITRATE özniteliğinde video bit hızını ayarlayın.
    • MF_MT_USER_DATA özniteliğini ayarlayarak codec özel verileri ekleyin. Ayrıntılı yönergeler için bkz. WMV Kodlayıcısını Yapılandırma "Özel Codec Verileri".

    IWMCodecPrivateData::GetPrivateData codec özel verilerini döndürmeden önce bit hızını denetlediğinden, codec özel verilerini almadan önce bit hızını ayarladığınızdan emin olun.

    Aşağıdaki kod örneği, Windows Media Video kodlayıcısından uyumlu bir tür alarak sıkıştırılmış bir video türü oluşturur. Ayrıca sıkıştırılmamış bir video türü oluşturur ve kodlayıcının girişi olarak ayarlar. Bu, CreateUncompressedVideoType yardımcı işlevinde uygulanır. GetOutputTypeFromWMVEncoder, codec özel verileri ekleyerek döndürülen kısmi türü tam bir türe dönüştürür. SetEncodingProperties uygulaması, bu öğreticinin "ASF ContentInfo Nesnesi Oluşturma" bölümünde gösterilir.

    //-------------------------------------------------------------------
    //  GetOutputTypeFromWMVEncoder
    //  Gets a compatible output type from the Windows Media video encoder.
    //
    //  pType: A pointer to the source video stream's media type.
    //  ppVideoType: Receives a pointer to the media type.
    //-------------------------------------------------------------------
    
    HRESULT GetOutputTypeFromWMVEncoder(IMFMediaType* pType, IMFMediaType** ppVideoType)
    {
        if (!ppVideoType)
        {
            return E_POINTER;
        }
    
        IMFTransform* pMFT = NULL;
        IPropertyStore* pProps = NULL;
        IMFMediaType* pInputType = NULL;
        IMFMediaType* pOutputType = NULL;
    
        UINT32 cBitrate = 0;
    
        //We need to find a suitable output media type
        //We need to create the encoder to get the available output types
        //and discard the instance.
    
        CLSID *pMFTCLSIDs = NULL;   // Pointer to an array of CLISDs. 
        UINT32 cCLSID = 0;          // Size of the array.
    
        MFT_REGISTER_TYPE_INFO tinfo;
    
        tinfo.guidMajorType = MFMediaType_Video;
        tinfo.guidSubtype = MFVideoFormat_WMV3;
    
        // Look for an encoder.
        HRESULT hr = MFTEnum(
            MFT_CATEGORY_VIDEO_ENCODER,
            0,                  // Reserved
            NULL,               // Input type to match. None.
            &tinfo,             // WMV encoded type.
            NULL,               // Attributes to match. (None.)
            &pMFTCLSIDs,        // Receives a pointer to an array of CLSIDs.
            &cCLSID             // Receives the size of the array.
            );
        if (FAILED(hr))
        {
            goto done;
        }
    
        // MFTEnum can return zero matches.
        if (cCLSID == 0)
        {
            hr = MF_E_TOPO_CODEC_NOT_FOUND;
            goto done;
        }
        else
        {
            //Create the MFT decoder
            hr = CoCreateInstance(pMFTCLSIDs[0], NULL,
                CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pMFT));
            if (FAILED(hr))
            {
                goto done;
            }
    
        }
    
        //Get the video encoder property store
        hr = pMFT->QueryInterface(IID_PPV_ARGS(&pProps));
        if (FAILED(hr))
        {
            goto done;
        }
    
        //Set encoding properties
        hr = SetEncodingProperties(MFMediaType_Video, pProps);
        if (FAILED(hr))
        {
            goto done;
        }
    
        hr = CreateUncompressedVideoType(pType, &pInputType);
        if (FAILED(hr))
        {
            goto done;
        }
    
        hr = pMFT->SetInputType(0, pInputType, 0);
    
        //Get the first output type
        //You can loop through the available output types to choose 
        //the one that meets your target requirements
        hr =  pMFT->GetOutputAvailableType(0, 0, &pOutputType);
        if (FAILED(hr))
        {
            goto done;
        }
    
        hr = pType->GetUINT32(MF_MT_AVG_BITRATE, &cBitrate);
        if (FAILED(hr))
        {
            goto done;
        }
    
        //Now set the bit rate
        hr = pOutputType->SetUINT32(MF_MT_AVG_BITRATE, cBitrate);
        if (FAILED(hr))
        {
            goto done;
        }
    
        hr = AddPrivateData(pMFT, pOutputType);
        if (FAILED(hr))
        {
            goto done;
        }
    
        //Return to the caller
        *ppVideoType = pOutputType;
        (*ppVideoType)->AddRef();
    
    done:
        SafeRelease(&pProps);
        SafeRelease(&pOutputType);
        SafeRelease(&pInputType);
        SafeRelease(&pMFT);
        CoTaskMemFree(pMFTCLSIDs);
        return hr;
    }
    

    Aşağıdaki kod örneği sıkıştırılmamış bir video türü oluşturur.

    //-------------------------------------------------------------------
    //  CreateUncompressedVideoType
    //  Creates an uncompressed video type.
    //
    //    pType: A pointer to the source's video media type.
    //  ppVideoType: Receives a pointer to the media type.
    //-------------------------------------------------------------------
    
    HRESULT CreateUncompressedVideoType(IMFMediaType* pType, IMFMediaType** ppMediaType)
    {
        if (!pType)
        {
            return E_INVALIDARG;
        }
        if (!ppMediaType)
        {
            return E_POINTER;
        }
    
        MFRatio fps = { 0 };
        MFRatio par = { 0 };
        UINT32 width = 0, height = 0;
        UINT32 interlace = MFVideoInterlace_Unknown;
        UINT32 cBitrate = 0;
    
        IMFMediaType* pMediaType = NULL;
    
        GUID guidMajor = GUID_NULL;
    
        HRESULT hr = pType->GetMajorType(&guidMajor);
        if (FAILED(hr))
        {
            goto done;
        }
    
        if (guidMajor != MFMediaType_Video )
        {
            hr = MF_E_INVALID_FORMAT;
            goto done;
        }
    
        hr = MFGetAttributeRatio(pType, MF_MT_FRAME_RATE, (UINT32*)&fps.Numerator, (UINT32*)&fps.Denominator);
        if (hr == MF_E_ATTRIBUTENOTFOUND)
        {
            fps.Numerator = 30000;
            fps.Denominator = 1001;
    
        }
        hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height);
        if (hr == MF_E_ATTRIBUTENOTFOUND)
        {
            width = 1280;
            height = 720;
    
        }
    
        interlace = MFGetAttributeUINT32(pType, MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
    
        hr = MFGetAttributeRatio(pType, MF_MT_PIXEL_ASPECT_RATIO, (UINT32*)&par.Numerator, (UINT32*)&par.Denominator);
        if (FAILED(hr))
        {
            par.Numerator = par.Denominator = 1;
        }
    
        cBitrate = MFGetAttributeUINT32(pType, MF_MT_AVG_BITRATE, 1000000);
    
        hr = MFCreateMediaType(&pMediaType);
        if (FAILED(hr))
        {
            goto done;
        }
        hr = pMediaType->SetGUID(MF_MT_MAJOR_TYPE, guidMajor);
        if (FAILED(hr))
        {
            goto done;
        }
        hr = pMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32);
        if (FAILED(hr))
        {
            goto done;
        }
        hr = MFSetAttributeRatio(pMediaType, MF_MT_FRAME_RATE, fps.Numerator, fps.Denominator);
        if (FAILED(hr))
        {
            goto done;
        }
        hr = MFSetAttributeSize(pMediaType, MF_MT_FRAME_SIZE, width, height);
        if (FAILED(hr))
        {
            goto done;
        }
        hr = pMediaType->SetUINT32(MF_MT_INTERLACE_MODE, 2);
        if (FAILED(hr))
        {
            goto done;
        }
    
        hr = pMediaType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
        if (FAILED(hr))
        {
            goto done;
        }
    
        hr = pMediaType->SetUINT32(MF_MT_AVG_BITRATE, cBitrate);
        if (FAILED(hr))
        {
            goto done;
        }
    
        // Return the pointer to the caller.
        *ppMediaType = pMediaType;
        (*ppMediaType)->AddRef();
    
    
    done:
        SafeRelease(&pMediaType);
        return hr;
    }
    

    Aşağıdaki kod örneği, belirtilen video medya türüne codec özel verileri ekler.

    //
    // AddPrivateData
    // Appends the private codec data to a media type.
    //
    // pMFT: The video encoder
    // pTypeOut: A video type from the encoder's type list.
    //
    // The function modifies pTypeOut by adding the codec data.
    //
    
    HRESULT AddPrivateData(IMFTransform *pMFT, IMFMediaType *pTypeOut)
    {
        HRESULT hr = S_OK;
        ULONG cbData = 0;
        BYTE *pData = NULL;
    
        IWMCodecPrivateData *pPrivData = NULL;
    
        DMO_MEDIA_TYPE mtOut = { 0 };
    
        // Convert the type to a DMO type.
        hr = MFInitAMMediaTypeFromMFMediaType(
            pTypeOut, 
            FORMAT_VideoInfo, 
            (AM_MEDIA_TYPE*)&mtOut
            );
    
        if (SUCCEEDED(hr))
        {
            hr = pMFT->QueryInterface(IID_PPV_ARGS(&pPrivData));
        }
    
        if (SUCCEEDED(hr))
        {
            hr = pPrivData->SetPartialOutputType(&mtOut);
        }
    
        //
        // Get the private codec data
        //
    
        // First get the buffer size.
        if (SUCCEEDED(hr))
        {
            hr = pPrivData->GetPrivateData(NULL, &cbData);
        }
    
        if (SUCCEEDED(hr))
        {
            pData = new BYTE[cbData];
    
            if (pData == NULL)
            {
                hr = E_OUTOFMEMORY;
            }
        }
    
        // Now get the data.
        if (SUCCEEDED(hr))
        {
            hr = pPrivData->GetPrivateData(pData, &cbData);
        }
    
        // Add the data to the media type.
        if (SUCCEEDED(hr))
        {
            hr = pTypeOut->SetBlob(MF_MT_USER_DATA, pData, cbData);
        }
    
        delete [] pData;
        MoFreeMediaType(&mtOut);
        SafeRelease(&pPrivData);
        return hr;
    }
    

ASF ContentInfo Nesnesi Oluşturma

ASF ContentInfo nesnesi, asf üst bilgi nesnesi bilgilerini depolamak için tasarlanmış bir WMContainer düzeyi bileşenidir. ASF dosya havuzu, kodlanmış dosyanın ASF Üst Bilgi Nesnesi yazmak için kullanılacak bilgileri (özellik deposunda) depolamak için ContentInfo nesnesini uygular. Bunu yapmak için, kodlama oturumunu başlatmadan önce ContentInfo nesnesinde aşağıdaki bilgi kümesini oluşturmanız ve yapılandırmanız gerekir.

  1. Boş bir ContentInfo nesnesi oluşturmak için MFCreateASFContentInfoçağrısı yapın.

    Aşağıdaki kod örneği boş bir ContentInfo nesnesi oluşturur.

        // Create an empty ContentInfo object
        hr = MFCreateASFContentInfo(&pContentInfo);
        if (FAILED(hr))
        {
            goto done;
        }
    
    
  2. Dosya havuzu akış düzeyi özellik deposunu almak için IMFASFContentInfo::GetEncodingConfigurationPropertyStore çağırın. Bu çağrıda, ASF profilini oluştururken akışa atadığınız akış numarasını geçirmeniz gerekiyor.

  3. Dosya havuzunun akış özelliği deposunda akış düzeyi Kodlama Özellikleri'i ayarlayın. Daha fazla bilgi için, Dosya Çıkışı altında yer alanÖzellikleri Ayarlama bölümündeki "Akış Kodlama Özellikleri" kısmına bakın.

    Aşağıdaki kod örneği, dosya havuzunun özellik deposundaki akış düzeyi özelliklerini ayarlar.

            //Get stream's encoding property
            hr = pContentInfo->GetEncodingConfigurationPropertyStore(wStreamID, &pContentInfoProps);
            if (FAILED(hr))
            {
                goto done;
            }
    
            //Set the stream-level encoding properties
            hr = SetEncodingProperties(guidMajor, pContentInfoProps);       
            if (FAILED(hr))
            {
                goto done;
            }
    
    
    

    Aşağıdaki kod örneği SetEncodingProperties uygulamasını gösterir. Bu işlev CBR ve VBR için akış düzeyi kodlama özelliklerini ayarlar.

    //-------------------------------------------------------------------
    //  SetEncodingProperties
    //  Create a media source from a URL.
    //
    //  guidMT:  Major type of the stream, audio or video
    //  pProps:  A pointer to the property store in which 
    //           to set the required encoding properties.
    //-------------------------------------------------------------------
    
    HRESULT SetEncodingProperties (const GUID guidMT, IPropertyStore* pProps)
    {
        if (!pProps)
        {
            return E_INVALIDARG;
        }
    
        if (EncodingMode == NONE)
        {
            return MF_E_NOT_INITIALIZED;
        }
    
        HRESULT hr = S_OK;
    
        PROPVARIANT var;
    
        switch (EncodingMode)
        {
            case CBR:
                // Set VBR to false.
                hr = InitPropVariantFromBoolean(FALSE, &var);
                if (FAILED(hr))
                {
                    goto done;
                }
    
                hr = pProps->SetValue(MFPKEY_VBRENABLED, var);
                if (FAILED(hr))
                {
                    goto done;
                }
    
                // Set the video buffer window.
                if (guidMT == MFMediaType_Video)
                {
                    hr = InitPropVariantFromInt32(VIDEO_WINDOW_MSEC, &var);
                    if (FAILED(hr))
                    {
                        goto done;
                    }
    
                    hr = pProps->SetValue(MFPKEY_VIDEOWINDOW, var);    
                    if (FAILED(hr))
                    {
                        goto done;
                    }
                }
                break;
    
            case VBR:
                //Set VBR to true.
                hr = InitPropVariantFromBoolean(TRUE, &var);
                if (FAILED(hr))
                {
                    goto done;
                }
    
                hr = pProps->SetValue(MFPKEY_VBRENABLED, var);
                if (FAILED(hr))
                {
                    goto done;
                }
    
                // Number of encoding passes is 1.
    
                hr = InitPropVariantFromInt32(1, &var);
                if (FAILED(hr))
                {
                    goto done;
                }
    
                hr = pProps->SetValue(MFPKEY_PASSESUSED, var);
                if (FAILED(hr))
                {
                    goto done;
                }
    
                // Set the quality level.
    
                if (guidMT == MFMediaType_Audio)
                {
                    hr = InitPropVariantFromUInt32(98, &var);
                    if (FAILED(hr))
                    {
                        goto done;
                    }
    
                    hr = pProps->SetValue(MFPKEY_DESIRED_VBRQUALITY, var);    
                    if (FAILED(hr))
                    {
                        goto done;
                    }
                }
                else if (guidMT == MFMediaType_Video)
                {
                    hr = InitPropVariantFromUInt32(95, &var);
                    if (FAILED(hr))
                    {
                        goto done;
                    }
    
                    hr = pProps->SetValue(MFPKEY_VBRQUALITY, var);    
                    if (FAILED(hr))
                    {
                        goto done;
                    }
                }
                break;
    
            default:
                hr = E_UNEXPECTED;
                break;
        }    
    
    done:
        PropVariantClear(&var);
        return hr;
    }
    
  4. Dosya havuzu genel özellik deposunu almak için IMFASFContentInfo::GetEncodingConfigurationPropertyStore çağırın. Bu çağrıda, ilk parametrede 0 geçirmeniz gerekir. Daha fazla bilgi için, dosya havuzu Özellikleri Ayarlama bölümünde yer alan "Genel Dosya Havuzu Özellikleri" bölümüne bakın.

  5. ASF çoğullayıcıdaki sızdıran demet değerlerinin düzgün ayarlandığından emin olmak için MFPKEY_ASFMEDIASINK_AUTOADJUST_BITRATE VARIANT_TRUE olarak ayarlayın. Bu özellik hakkında bilgi için, Multiplexer Nesnesi Oluşturmaiçindeki "Çoklayıcı Başlatma ve Sızıntılı Kova Ayarları" bölümüne bakın.

    Aşağıdaki kod örneği, dosya havuzunun özellik deposundaki akış düzeyi özelliklerini ayarlar.

        //Now we need to set global properties that will be set on the media sink
        hr = pContentInfo->GetEncodingConfigurationPropertyStore(0, &pContentInfoProps);
        if (FAILED(hr))
        {
            goto done;
        }
    
        //Auto adjust Bitrate
        var.vt = VT_BOOL;
        var.boolVal = VARIANT_TRUE;
    
        hr = pContentInfoProps->SetValue(MFPKEY_ASFMEDIASINK_AUTOADJUST_BITRATE, var);
    
        //Initialize with the profile
        hr = pContentInfo->SetProfile(pProfile);
        if (FAILED(hr))
        {
            goto done;
        }
    

    Dikkat

    Dosya havuzu için genel düzeyde ayarlayabileceğiniz başka özellikler de vardır. Daha fazla bilgi için contentinfo nesnesi Özellikleri Ayarlama makalesindeki "ContentInfo Nesnesini Kodlayıcı Ayarlarıyla Yapılandırma" bölümüne bakın.

     

ASF dosya havuzu için bir etkinleştirme nesnesi oluşturmak için yapılandırılan ASF ContentInfo kullanacaksınız (sonraki bölümde açıklanmıştır).

İşlem dışı bir dosya veri havuzu (MFCreateASFMediaSinkActivate) oluşturuyorsanız, yani bir etkinleştirme nesnesi kullanıyorsanız, yapılandırılmış ContentInfo nesnesini kullanarak ASF medya havuzunu örneklendirebilirsiniz (bir sonraki bölümde açıklanmıştır). 1. adımda açıklandığı gibi boş ContentInfo nesnesini oluşturmak yerine işlem içi bir dosya havuzu (MFCreateASFMediaSink) oluşturuyorsanız, dosya havuzundaki IMFMediaSink::QueryInterface çağırarak IMFASFContentInfo arabirimine bir başvuru alın. Daha sonra ContentInfo nesnesini bu bölümde açıklandığı gibi yapılandırmanız gerekir.

ASF Dosya Havuzu Oluşturma

Öğreticinin bu adımında, önceki adımda oluşturduğunuz yapılandırılmış ASF ContentInfo'yu kullanarak, MFCreateASFMediaSinkActivate işlevini çağırarak ASF dosya çukuru için bir etkinleştirme nesnesi oluşturacaksınız. Daha fazla bilgi için bkz. asf dosya havuzu oluşturma .

Aşağıdaki kod örneği, dosya havuzu için etkinleştirme nesnesini oluşturur.

    //Create the activation object for the  file sink
    hr = MFCreateASFMediaSinkActivate(sURL, pContentInfo, &pActivate);
    if (FAILED(hr))
    {
        goto done;
    }

Kısmi Kodlama Topolojisi Oluşturma

Ardından, medya kaynağı, gerekli Windows Media kodlayıcıları ve ASF dosya havuzu için topoloji düğümleri oluşturarak kısmi kodlama topolojisi oluşturacaksınız. Topoloji düğümlerini ekledikten sonra kaynağı, dönüşümü ve havuz düğümlerini bağlayacaksınız. Topoloji düğümlerini eklemeden önce MFCreateTopologyçağırarak boş bir topoloji nesnesi oluşturmanız gerekir.

Medya Kaynağı için Kaynak Topoloji Düğümü Oluşturma

Bu adımda, medya kaynağı için kaynak topoloji düğümünü oluşturacaksınız.

Bu düğümü oluşturmak için aşağıdaki başvurulara ihtiyacınız vardır:

  • Bu öğreticinin "Medya Kaynağını Oluşturma" bölümünde açıklanan adımda oluşturduğunuz medya kaynağının işaretçisi.
  • Medya kaynağı için sunu tanımlayıcısına yönelik bir işaretçi. IMFMediaSource::CreatePresentationDescriptorçağırarak medya kaynağı IMFPresentationDescriptor arabirimine bir referans alabilirsiniz.
  • Bu öğreticinin "ASF Profil Nesnesi Oluşturma" bölümünde açıklanan adımda hedef akış oluşturduğunuz medya kaynağındaki her akış için akış tanımlayıcısına yönelik bir işaretçi.

Kaynak düğümleri oluşturma ve kod örneği hakkında daha fazla bilgi için bkz. kaynak düğüm oluşturma .

Aşağıdaki kod örneği, kaynak düğümü ve gerekli dönüştürme düğümlerini ekleyerek kısmi bir topoloji oluşturur. Bu kod AddSourceNode ve AddTransformOutputNodes yardımcı işlevlerini çağırır. Bu işlevler bu eğitimin ilerleyen bölümlerinde yer alır.

//-------------------------------------------------------------------
//  BuildPartialTopology
//  Create a partial encoding topology by adding the source and the sink.
//
//  pSource:  A pointer to the media source to enumerate the source streams.
//  pSinkActivate: A pointer to the activation object for ASF file sink.
//  ppTopology:  Receives a pointer to the topology.
//-------------------------------------------------------------------

HRESULT BuildPartialTopology(
       IMFMediaSource *pSource, 
       IMFActivate* pSinkActivate,
       IMFTopology** ppTopology)
{
    if (!pSource || !pSinkActivate)
    {
        return E_INVALIDARG;
    }
    if (!ppTopology)
    {
        return E_POINTER;
    }

    HRESULT hr = S_OK;

    IMFPresentationDescriptor* pPD = NULL;
    IMFStreamDescriptor *pStreamDesc = NULL;
    IMFMediaTypeHandler* pMediaTypeHandler = NULL;
    IMFMediaType* pSrcType = NULL;

    IMFTopology* pTopology = NULL;
    IMFTopologyNode* pSrcNode = NULL;
    IMFTopologyNode* pEncoderNode = NULL;
    IMFTopologyNode* pOutputNode = NULL;


    DWORD cElems = 0;
    DWORD dwSrcStream = 0;
    DWORD StreamID = 0;
    GUID guidMajor = GUID_NULL;
    BOOL fSelected = FALSE;


    //Create the topology that represents the encoding pipeline
    hr = MFCreateTopology (&pTopology);
    if (FAILED(hr))
    {
        goto done;
    }

        
    hr = pSource->CreatePresentationDescriptor(&pPD);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pPD->GetStreamDescriptorCount(&dwSrcStream);
    if (FAILED(hr))
    {
        goto done;
    }

    for (DWORD iStream = 0; iStream < dwSrcStream; iStream++)
    {
        hr = pPD->GetStreamDescriptorByIndex(
            iStream, &fSelected, &pStreamDesc);
        if (FAILED(hr))
        {
            goto done;
        }

        if (!fSelected)
        {
            continue;
        }

        hr = AddSourceNode(pTopology, pSource, pPD, pStreamDesc, &pSrcNode);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pStreamDesc->GetMediaTypeHandler (&pMediaTypeHandler);
        if (FAILED(hr))
        {
            goto done;
        }
        
        hr = pStreamDesc->GetStreamIdentifier(&StreamID);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pMediaTypeHandler->GetMediaTypeByIndex(0, &pSrcType);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pSrcType->GetMajorType(&guidMajor);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = AddTransformOutputNodes(pTopology, pSinkActivate, pSrcType, &pEncoderNode);
        if (FAILED(hr))
        {
            goto done;
        }

        //now we have the transform node, connect it to the source node
        hr = pSrcNode->ConnectOutput(0, pEncoderNode, 0);
        if (FAILED(hr))
        {
            goto done;
        }
                

        SafeRelease(&pStreamDesc);
        SafeRelease(&pMediaTypeHandler);
        SafeRelease(&pSrcType);
        SafeRelease(&pEncoderNode);
        SafeRelease(&pOutputNode);
        guidMajor = GUID_NULL;
    }

    *ppTopology = pTopology;
   (*ppTopology)->AddRef();


    wprintf_s(L"Partial Topology Built.\n");

done:
    SafeRelease(&pStreamDesc);
    SafeRelease(&pMediaTypeHandler);
    SafeRelease(&pSrcType);
    SafeRelease(&pEncoderNode);
    SafeRelease(&pOutputNode);
    SafeRelease(&pTopology);

    return hr;
}

Aşağıdaki kod örneği, kaynak topoloji düğümünü oluşturur ve kodlama topolojisine ekler. Daha önceki bir topoloji nesnesine, kaynak akışları listelemek için medya kaynağına, medya kaynağının sunum tanımlayıcısına ve medya kaynağının akış tanımlayıcısına işaretçileri alır. Çağıran, kaynak topoloji düğümü için bir işaretçi alır.

// Add a source node to a topology.
HRESULT AddSourceNode(
    IMFTopology *pTopology,           // Topology.
    IMFMediaSource *pSource,          // Media source.
    IMFPresentationDescriptor *pPD,   // Presentation descriptor.
    IMFStreamDescriptor *pSD,         // Stream descriptor.
    IMFTopologyNode **ppNode)         // Receives the node pointer.
{
    IMFTopologyNode *pNode = NULL;

    // Create the node.
    HRESULT hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &pNode);
    if (FAILED(hr))
    {
        goto done;
    }

    // Set the attributes.
    hr = pNode->SetUnknown(MF_TOPONODE_SOURCE, pSource);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pNode->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, pPD);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pNode->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pSD);
    if (FAILED(hr))
    {
        goto done;
    }
    
    // Add the node to the topology.
    hr = pTopology->AddNode(pNode);
    if (FAILED(hr))
    {
        goto done;
    }

    // Return the pointer to the caller.
    *ppNode = pNode;
    (*ppNode)->AddRef();

done:
    SafeRelease(&pNode);
    return hr;
}

Gerekli Kodlayıcıların Örneğini Oluşturma ve Dönüştürme Düğümleri Oluşturma

Media Foundation işlem hattı, kodlaması gereken akışlar için gerekli Windows Media kodlayıcılarını otomatik olarak eklemez. Uygulamanın kodlayıcıları el ile eklemesi gerekir. Bunu yapmak için, bu öğreticinin "ASF Profil Nesnesi Oluşturma" bölümünde açıklanan adımda oluşturduğunuz ASF profilindeki akışları numaralandırın. Kaynaktaki ve profildeki ilgili her bir akış için gerekli kodlayıcıları oluşturun. Bu adım için, bu öğreticinin "ASF Dosya Havuzu Oluşturma" bölümünde açıklanan adımda oluşturduğunuz dosya havuzu için etkinleştirme nesnesine yönelik bir işaretçi gerekir.

Etkinleştirme nesneleri aracılığıyla kodlayıcı oluşturmaya genel bakış için bkz. Kodlayıcının Etkinleştirme Nesnelerini Kullanma.

Aşağıdaki yordamda, gerekli kodlayıcıların örneğini oluştururken gereken adımlar açıklanmaktadır.

  1. dosya alıcısının ContentInfo nesnesine bir başvuru almak için, önce dosya alıcısını etkinleştirerek IMFActivate::ActivateObject çağırın ve ardından QueryInterfacekullanarak dosya alıcısından IMFASFContentInfo sorgulayın.

  2. IMFASFContentInfo::GetProfileçağırarak ContentInfo nesnesiyle ilişkili ASF profilini alın.

  3. Profildeki akışları numaralandırın. Bunun için akış sayısına ve her akışın IMFASFStreamConfig arabirimine bir başvuru gerekir.

    Aşağıdaki yöntemleri çağırın:

  4. Her akış için ContentInfo nesnesinden ana türü ve akışın kodlama özelliklerini alın.

    Aşağıdaki yöntemleri çağırın:

  5. Akış, ses veya video türüne bağlı olarak, MFCreateWMAEncoderActivateveya MFCreateWMVEncoderActivateçağırarak kodlayıcı için etkinleştirme nesnesinin örneğini oluşturun.

    Bu işlevleri çağırmak için aşağıdaki başvurulara ihtiyacınız vardır:

  6. Ses akışı için leaky bucket parametresini güncelleyin.

    MFCreateWMAEncoderActivate, Windows Media ses codec'i için altta yatan kodlayıcı MFT üzerinde çıkış türünü ayarlar. Çıkış medya türü ayarlandıktan sonra kodlayıcı, çıktı medya türünden ortalama bit hızını alır, arabellek pencere bit hızını hesaplar ve kodlama oturumu sırasında kullanılacak leaky bucket değerlerini ayarlar. Kodlayıcıyı sorgulayarak veya özel değerler ayarlayarak dosya havuzundaki bu değerleri güncelleştirebilirsiniz. Değerleri güncelleştirmek için aşağıdaki bilgi kümesine ihtiyacınız vardır:

    Bir DWORD dizisi oluşturun ve ses akışı havuzundaki MFPKEY_ASFSTREAMSINK_CORRECTED_LEAKYBUCKET özelliğindeki değeri ayarlayın. Güncelleştirilmiş değerleri sağlamazsanız, Medya Oturumu bunları uygun şekilde ayarlar.

    Daha fazla bilgi için bkz. Sızdıran Demet Arabellek Modeli.

5. adımda oluşturulan etkinleştirme nesnelerinin topolojiye dönüşüm topolojisi düğümleri olarak eklenmesi gerekir. Daha fazla bilgi ve kod örneği için dönüştürme düğümleri oluşturma 'de "Etkinleştirme Nesnesinden Dönüşüm Düğümü Oluşturma" bölümüne bakın.

Aşağıdaki kod örneği gerekli kodlayıcı etkinleştirmelerini oluşturur ve ekler. Daha önce oluşturulmuş bir topoloji nesnesine, dosya havuzuna ait etkinleştirme nesnesine ve kaynak akışın medya türüne işaretçiler alır. Ayrıca, havuz düğümünü oluşturan ve kodlama topolojisine ekleyen AddOutputNode 'ı (sonraki kod örneğine bakın) çağırır. Çağıran, kaynak topoloji düğümüne bir işaretçi alır.

//-------------------------------------------------------------------
//  AddTransformOutputNodes
//  Creates and adds the sink node to the encoding topology.
//  Creates and adds the required encoder activates.

//  pTopology:  A pointer to the topology.
//  pSinkActivate:  A pointer to the file sink's activation object.
//  pSourceType: A pointer to the source stream's media type.
//  ppNode:  Receives a pointer to the topology node.
//-------------------------------------------------------------------

HRESULT AddTransformOutputNodes(
    IMFTopology* pTopology,
    IMFActivate* pSinkActivate,
    IMFMediaType* pSourceType,
    IMFTopologyNode **ppNode    // Receives the node pointer.
    )
{
    if (!pTopology || !pSinkActivate || !pSourceType)
    {
        return E_INVALIDARG;
    }

    IMFTopologyNode* pEncNode = NULL;
    IMFTopologyNode* pOutputNode = NULL;
    IMFASFContentInfo* pContentInfo = NULL;
    IMFASFProfile* pProfile = NULL;
    IMFASFStreamConfig* pStream = NULL;
    IMFMediaType* pMediaType = NULL;
    IPropertyStore* pProps = NULL;
    IMFActivate *pEncoderActivate = NULL;
    IMFMediaSink *pSink = NULL; 

    GUID guidMT = GUID_NULL;
    GUID guidMajor = GUID_NULL;

    DWORD cStreams = 0;
    WORD wStreamNumber = 0;

    HRESULT hr = S_OK;
        
    hr = pSourceType->GetMajorType(&guidMajor);
    if (FAILED(hr))
    {
        goto done;
    }

    // Create the node.
    hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &pEncNode);
    if (FAILED(hr))
    {
        goto done;
    }
    
    //Activate the sink
    hr = pSinkActivate->ActivateObject(__uuidof(IMFMediaSink), (void**)&pSink);
    if (FAILED(hr))
    {
        goto done;
    }
    //find the media type in the sink
    //Get content info from the sink
    hr = pSink->QueryInterface(__uuidof(IMFASFContentInfo), (void**)&pContentInfo);
    if (FAILED(hr))
    {
        goto done;
    }
    

    hr = pContentInfo->GetProfile(&pProfile);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pProfile->GetStreamCount(&cStreams);
    if (FAILED(hr))
    {
        goto done;
    }

    for(DWORD index = 0; index < cStreams ; index++)
    {
        hr = pProfile->GetStream(index, &wStreamNumber, &pStream);
        if (FAILED(hr))
        {
            goto done;
        }
        hr = pStream->GetMediaType(&pMediaType);
        if (FAILED(hr))
        {
            goto done;
        }
        hr = pMediaType->GetMajorType(&guidMT);
        if (FAILED(hr))
        {
            goto done;
        }
        if (guidMT!=guidMajor)
        {
            SafeRelease(&pStream);
            SafeRelease(&pMediaType);
            guidMT = GUID_NULL;

            continue;
        }
        //We need to activate the encoder
        hr = pContentInfo->GetEncodingConfigurationPropertyStore(wStreamNumber, &pProps);
        if (FAILED(hr))
        {
            goto done;
        }

        if (guidMT == MFMediaType_Audio)
        {
             hr = MFCreateWMAEncoderActivate(pMediaType, pProps, &pEncoderActivate);
            if (FAILED(hr))
            {
                goto done;
            }
            wprintf_s(L"Audio Encoder created. Stream Number: %d .\n", wStreamNumber);

            break;
        }
        if (guidMT == MFMediaType_Video)
        {
            hr = MFCreateWMVEncoderActivate(pMediaType, pProps, &pEncoderActivate);
            if (FAILED(hr))
            {
                goto done;
            }
            wprintf_s(L"Video Encoder created. Stream Number: %d .\n", wStreamNumber);

            break;
        }
    }

    // Set the object pointer.
    hr = pEncNode->SetObject(pEncoderActivate);
    if (FAILED(hr))
    {
        goto done;
    }

    // Add the node to the topology.
    hr = pTopology->AddNode(pEncNode);
    if (FAILED(hr))
    {
        goto done;
    }

    //Add the output node to this node.
    hr = AddOutputNode(pTopology, pSinkActivate, wStreamNumber, &pOutputNode);
    if (FAILED(hr))
    {
        goto done;
    }

    //now we have the output node, connect it to the transform node
    hr = pEncNode->ConnectOutput(0, pOutputNode, 0);
    if (FAILED(hr))
    {
        goto done;
    }

   // Return the pointer to the caller.
    *ppNode = pEncNode;
    (*ppNode)->AddRef();


done:
    SafeRelease(&pEncNode);
    SafeRelease(&pOutputNode);
    SafeRelease(&pEncoderActivate);
    SafeRelease(&pMediaType);
    SafeRelease(&pProps);
    SafeRelease(&pStream);
    SafeRelease(&pProfile);
    SafeRelease(&pContentInfo);
    SafeRelease(&pSink);
    return hr;
}

Dosya Havuzu için Çıkış TopolojiSi Düğümleri Oluşturma

Bu adımda ASF dosya havuzu için çıkış topolojisi düğümünü oluşturacaksınız.

Bu düğümü oluşturmak için aşağıdaki başvurulara ihtiyacınız vardır:

  • Bu öğreticinin "ASF Dosya Havuzu Oluşturma" bölümünde açıklanan adımda oluşturduğunuz etkinleştirme nesnesinin işaretçisi.
  • Dosya havuzuna eklenen akış havuzlarını tanımlamak için akış numaraları. Akış numaraları, akış oluşturma sırasında ayarlanan akışın kimliğiyle eşleşmektedir.

Çıkış düğümleri ve kod örneği oluşturma hakkında daha fazla bilgi için, Çıkış Düğümleri Oluşturma'deki "Etkinleştirme Nesnesinden Çıkış Düğümü Oluşturma" bölümüne bakın.

Dosya havuzu için etkinleştirme nesnesi kullanmıyorsanız, ASF dosya havuzundaki akış havuzlarını listelemeli ve her akış havuzunu topolojide çıkış düğümü olarak ayarlamalısınız. Akış havuzu numaralandırması hakkında daha fazla bilgi için asf dosya havuzuna akış bilgileri ekleme "Akış Havuzlarını Numaralandırma" bölümüne bakın.

Aşağıdaki kod örneği havuz düğümünü oluşturur ve kodlama topolojisine ekler. Daha önce oluşturulmuş bir topoloji nesnesine, dosya havuzu etkinleştirme nesnesine ve akışın kimlik numarasına işaretçiler alır. Çağrıcı, kaynak topoloji düğümüne bir işaretçi alır.

// Add an output node to a topology.
HRESULT AddOutputNode(
    IMFTopology *pTopology,     // Topology.
    IMFActivate *pActivate,     // Media sink activation object.
    DWORD dwId,                 // Identifier of the stream sink.
    IMFTopologyNode **ppNode)   // Receives the node pointer.
{
    IMFTopologyNode *pNode = NULL;

    // Create the node.
    HRESULT hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &pNode);
    if (FAILED(hr))
    {
        goto done;
    }

    // Set the object pointer.
    hr = pNode->SetObject(pActivate);
    if (FAILED(hr))
    {
        goto done;
    }

    // Set the stream sink ID attribute.
    hr = pNode->SetUINT32(MF_TOPONODE_STREAMID, dwId);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pNode->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
    if (FAILED(hr))
    {
        goto done;
    }

    // Add the node to the topology.
    hr = pTopology->AddNode(pNode);
    if (FAILED(hr))
    {
        goto done;
    }

    // Return the pointer to the caller.
    *ppNode = pNode;
    (*ppNode)->AddRef();

done:
    SafeRelease(&pNode);
    return hr;
}

Aşağıdaki kod örneği, belirli bir medya havuzu için akış havuzlarını numaralandırır.

//-------------------------------------------------------------------
//  EnumerateStreamSinks
//  Enumerates the stream sinks within the specified media sink.
//
//  pSink:  A pointer to the media sink.
//-------------------------------------------------------------------
HRESULT EnumerateStreamSinks (IMFMediaSink* pSink)
{
    if (!pSink)
    {
        return E_INVALIDARG;
    }
    
    IMFStreamSink* pStreamSink = NULL;
    DWORD cStreamSinks = 0;

    HRESULT hr = pSink->GetStreamSinkCount(&cStreamSinks);
    if (FAILED(hr))
    {
        goto done;
    }

    for(DWORD index = 0; index < cStreamSinks; index++)
    {
        hr = pSink->GetStreamSinkByIndex (index, &pStreamSink);
        if (FAILED(hr))
        {
            goto done;
        }

        //Use the stream sink
        //Not shown.
    }
done:
    SafeRelease(&pStreamSink);

    return hr;
}

Kaynak, Dönüşüm ve Havuz Düğümlerini Bağlama

Bu adımda, bu öğreticinin "Gerekli Kodlayıcıları Oluşturma ve Dönüştürme Düğümlerini Oluşturma" bölümünde açıklanan adımda oluşturduğunuz kodlama etkinleştirmelerine başvuran dönüştürme düğümüne kaynak düğümü bağlayacaksınız. Dönüştürme düğümü, dosya havuzu için etkinleştirme nesnesini içeren çıkış düğümüne bağlanır.

Kodlama Oturumunu İşleme

Bu adımda aşağıdaki adımları gerçekleştirebilirsiniz:

  1. Kodlama oturumu oluşturmak için MFCreateMediaSession çağırın.

  2. Oturumdaki kodlama topolojisini ayarlamak için IMFMediaSession::SetTopology çağrısı. Çağrı tamamlanırsa, Medya Oturumu topoloji düğümlerini değerlendirir ve kodlayıcıya giriş olarak beslemek üzere belirtilen sıkıştırılmış kaynağı sıkıştırılmamış örneklere dönüştüren kod çözücü gibi ek dönüştürme nesneleri ekler.

  3. Medya Oturumu tarafından oluşturulan olayları istemek için IMFMediaSession::GetEvent arayın.

    Olay döngüsünde, Medya Oturumu tarafından tetiklenen olaylara bağlı olarak kodlama oturumunu başlatacak ve kapatacaksınız. IMFMediaSession::SetTopology çağrısı, Medya Oturumunda MESessionTopologyStatus olayını MF_TOPOSTATUS_READY bayrağı ayarlanmış olarak tetikler. Tüm olaylar zaman uyumsuz olarak oluşturulur ve bir uygulama bu olayları zaman uyumlu veya zaman uyumsuz olarak alabilir. Bu öğreticideki uygulama bir konsol uygulaması olduğundan ve kullanıcı arabirimi iş parçacıklarının engellenmesi önemli olmadığından, olayları Medya Oturumu'ndan zaman uyumlu bir şekilde alacağız.

    Olayları zaman uyumsuz olarak almak için uygulamanızın IMFAsyncCallback arabirimini uygulaması gerekir. Daha fazla bilgi edinmek ve bu arabirimin örnek bir uygulaması için media foundation ile Medya Dosyalarını Yürütme"Oturum Olaylarını İşleme" bölümüne bakın.

Medya Oturumu olaylarını almak için olay döngüsünde, IMFMediaSession::SetTopology tamamlandığında ve topoloji çözümlendiğinde oluşturulan MESessionTopologyStatus olayını bekleyin. MESessionTopologyStatus olayını aldıktan sonra, IMFMediaSession::Startçağırarak kodlama oturumunu başlatın. Medya Oturumu, tüm kodlama işlemleri tamamlandığında MEEndOfPresentation olayını oluşturur. Bu olayın VBR kodlaması için ele alınması gerekmektedir ve bu öğreticide "VBR Kodlaması için Dosya Havuzundaki Kodlama Özelliklerini Güncelleştirme" bölümünde açıklanmıştır.

Medya Oturumu ASF Üst Bilgi Nesnesi oluşturur ve kodlama oturumu tamamlandığında dosyayı son haline dönüştürür ve ardından MESessionClosed olayını başlatır. Bu olay, Medya Oturumu'nda düzgün kapatma işlemleri gerçekleştirilerek işlenmelidir. Kapatma işlemlerini başlatmak için IMFMediaSession::Shutdownçağrısında bulunur. Kodlama oturumu kapatıldıktan sonra, aynı Medya Oturumu örneğinde kodlama için başka bir topoloji ayarlayamazsınız. Başka bir dosyayı kodlamak için geçerli Medya Oturumu kapatılıp serbest bırakılmalı ve yeni topoloji yeni oluşturulan bir Medya Oturumunda ayarlanmalıdır. Aşağıdaki kod örneği Medya Oturumu'nu oluşturur, kodlama topolojisini ayarlar ve Medya Oturumu olaylarını işler.

Aşağıdaki kod örneği Medya Oturumu'nu oluşturur, kodlama topolojisini ayarlar ve Medya Oturumu'ndan olayları işleyerek kodlama oturumunu denetler.

//-------------------------------------------------------------------
//  Encode
//  Controls the encoding session and handles events from the media session.
//
//  pTopology:  A pointer to the encoding topology.
//-------------------------------------------------------------------

HRESULT Encode(IMFTopology *pTopology)
{
    if (!pTopology)
    {
        return E_INVALIDARG;
    }
    
    IMFMediaSession *pSession = NULL;
    IMFMediaEvent* pEvent = NULL;
    IMFTopology* pFullTopology = NULL;
    IUnknown* pTopoUnk = NULL;


    MediaEventType meType = MEUnknown;  // Event type

    HRESULT hr = S_OK;
    HRESULT hrStatus = S_OK;            // Event status
                
    MF_TOPOSTATUS TopoStatus = MF_TOPOSTATUS_INVALID; // Used with MESessionTopologyStatus event.    
        

    hr = MFCreateMediaSession(NULL, &pSession);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pSession->SetTopology(MFSESSION_SETTOPOLOGY_IMMEDIATE, pTopology);
    if (FAILED(hr))
    {
        goto done;
    }

    //Get media session events synchronously
    while (1)
    {
        hr = pSession->GetEvent(0, &pEvent);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pEvent->GetType(&meType);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pEvent->GetStatus(&hrStatus);
        if (FAILED(hr))
        {
            goto done;
        }
        if (FAILED(hrStatus))
        {
            hr = hrStatus;
            goto done;
        }

       switch(meType)
        {
            case MESessionTopologyStatus:
                {
                    // Get the status code.
                    MF_TOPOSTATUS status = (MF_TOPOSTATUS)MFGetAttributeUINT32(
                                             pEvent, MF_EVENT_TOPOLOGY_STATUS, MF_TOPOSTATUS_INVALID);

                    if (status == MF_TOPOSTATUS_READY)
                    {
                        PROPVARIANT var;
                        PropVariantInit(&var);
                        wprintf_s(L"Topology resolved and set on the media session.\n");

                        hr = pSession->Start(NULL, &var);
                        if (FAILED(hr))
                        {
                            goto done;
                        }

                    }
                    if (status == MF_TOPOSTATUS_STARTED_SOURCE)
                    {
                        wprintf_s(L"Encoding started.\n");
                        break;
                    }
                    if (status == MF_TOPOSTATUS_ENDED)
                    {
                        wprintf_s(L"Encoding complete.\n");
                        hr = pSession->Close();
                        if (FAILED(hr))
                        {
                            goto done;
                        }

                        break;
                    }
                }
                break;


            case MESessionEnded:
                wprintf_s(L"Encoding complete.\n");
                hr = pSession->Close();
                if (FAILED(hr))
                {
                    goto done;
                }
                break;

            case MEEndOfPresentation:
                {
                    if (EncodingMode == VBR)
                    {
                        hr = pSession->GetFullTopology(MFSESSION_GETFULLTOPOLOGY_CURRENT, 0, &pFullTopology);
                        if (FAILED(hr))
                        {
                            goto done;
                        }
                        hr = PostEncodingUpdate(pFullTopology);
                        if (FAILED(hr))
                        {
                            goto done;
                        }
                        wprintf_s(L"Updated sinks for VBR. \n");
                    }
                }
                break;

            case MESessionClosed:
                wprintf_s(L"Encoding session closed.\n");

                hr = pSession->Shutdown();
                goto done;
        }
        if (FAILED(hr))
        {
            goto done;
        }

        SafeRelease(&pEvent);

    }
done:
    SafeRelease(&pEvent);
    SafeRelease(&pSession);
    SafeRelease(&pFullTopology);
    SafeRelease(&pTopoUnk);
    return hr;
}

Dosya Havuzundaki Kodlama Özelliklerini Güncelleştirme

Kodlama bit hızı ve doğru sızdıran demet değerleri gibi belirli kodlama özellikleri, özellikle VBR kodlaması için kodlama tamamlanana kadar bilinmez. Doğru değerleri almak için uygulamanın kodlama oturumunun tamamlandığını belirten meendofpresentation olayını beklemesi gerekir. Sızdıran kova değerleri, ASF Üst Bilgisi Nesnesinin doğru değerleri yansıtabilmesi için alıcıda güncellenmelidir.

Aşağıdaki yordamda, dosya havuzu düğümünü almak ve gerekli sızdıran demet özelliklerini ayarlamak için kodlama topolojisindeki düğümler arasında geçiş yapmak için gereken adımlar açıklanmaktadır.

ASF dosya havuzundaki kodlama sonrası özellik değerlerini güncelleştirmek için

  1. Çıkış düğümü koleksiyonunu kodlama topolojisinden almak için IMFTopology::GetOutputNodeCollection çağırın.
  2. Her düğüm için, IMFTopologyNode::GetObjectçağırarak düğümdeki akış havuzuna bir işaretçi alın. IMFTopologyNode::GetObjecttarafından döndürülen IUnknown işaretçisinde IMFStreamSink arabirimini sorgula.
  3. Her akış havuzu için IMFTopologyNode::GetInputçağırarak aşağı akış düğümünü (kodlayıcı) alın.
  4. Düğümü sorgula ve kodlayıcı düğümünden IMFTransform işaretçisini al.
  5. Kodlayıcıdan kodlama özelliği deposunu almak için IPropertyStore işaretçisini sorgulayın.
  6. Akış alıcısının özellik deposunu almak için IPropertyStore işaretçisini almak amacıyla akış alıcısını sorgulayın.
  7. Kodlayıcının özellik deposundan gerekli özellik değerlerini almak için IPropertyStore::GetValueçağırın ve IPropertyStore::SetValueçağırarak bunları akış havuzu özellik deposuna kopyalayın.

Aşağıdaki tabloda, video akışı için akış havuzu üzerinde ayarlanması gereken kodlama sonrası özellik değerleri gösterilmektedir.

Kodlama türü Özellik adı (GetValue) Özellik adı (SetValue)
Sabit Bit Hızı Kodlama MFPKEY_BAVG
MFPKEY_RAVG
MFPKEY_STAT_BAVG
MFPKEY_STAT_RAVG
Değişken Bit Hızı Kodlama Quality-Based MFPKEY_BAVG
MFPKEY_RAVG
MFPKEY_BMAX
MFPKEY_RMAX
MFPKEY_STAT_BAVG
MFPKEY_STAT_RAVG
MFPKEY_STAT_BMAX
MFPKEY_STAT_RMAX

 

Aşağıdaki kod örneği, kodlama sonrası özellik değerlerini ayarlar.

//-------------------------------------------------------------------
//  PostEncodingUpdate
//  Updates the file sink with encoding properties set on the encoder
//  during the encoding session.
    //1. Get the output nodes
    //2. For each node, get the downstream node
    //3. For the downstream node, get the MFT
    //4. Get the property store
    //5. Get the required values
    //6. Set them on the stream sink
//
//  pTopology: A pointer to the full topology retrieved from the media session.
//-------------------------------------------------------------------

HRESULT PostEncodingUpdate(IMFTopology *pTopology)
{
    if (!pTopology)
    {
        return E_INVALIDARG;
    }

    HRESULT hr = S_OK;

    IMFCollection* pOutputColl = NULL;
    IUnknown* pNodeUnk = NULL;
    IMFMediaType* pType = NULL;
    IMFTopologyNode* pNode = NULL;
    IUnknown* pSinkUnk = NULL;
    IMFStreamSink* pStreamSink = NULL;
    IMFTopologyNode* pEncoderNode = NULL;
    IUnknown* pEncoderUnk = NULL;
    IMFTransform* pEncoder = NULL;
    IPropertyStore* pStreamSinkProps = NULL;
    IPropertyStore* pEncoderProps = NULL;

    GUID guidMajorType = GUID_NULL;

    PROPVARIANT var;
    PropVariantInit( &var );

    DWORD cElements = 0;

    hr = pTopology->GetOutputNodeCollection( &pOutputColl);
    if (FAILED(hr))
    {
        goto done;
    }


    hr = pOutputColl->GetElementCount(&cElements);
    if (FAILED(hr))
    {
        goto done;
    }


    for(DWORD index = 0; index < cElements; index++)
    {
        hr = pOutputColl->GetElement(index, &pNodeUnk);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pNodeUnk->QueryInterface(IID_IMFTopologyNode, (void**)&pNode);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pNode->GetInputPrefType(0, &pType);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pType->GetMajorType( &guidMajorType );
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pNode->GetObject(&pSinkUnk);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pSinkUnk->QueryInterface(IID_IMFStreamSink, (void**)&pStreamSink);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pNode->GetInput( 0, &pEncoderNode, NULL );
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pEncoderNode->GetObject(&pEncoderUnk);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pEncoderUnk->QueryInterface(IID_IMFTransform, (void**)&pEncoder);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pStreamSink->QueryInterface(IID_IPropertyStore, (void**)&pStreamSinkProps);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pEncoder->QueryInterface(IID_IPropertyStore, (void**)&pEncoderProps);
        if (FAILED(hr))
        {
            goto done;
        }

        if( guidMajorType == MFMediaType_Video )
        {            
            hr = pEncoderProps->GetValue( MFPKEY_BAVG, &var );
            if (FAILED(hr))
            {
                goto done;
            }
            hr = pStreamSinkProps->SetValue( MFPKEY_STAT_BAVG, var );
            if (FAILED(hr))
            {
                goto done;
            }

            PropVariantClear( &var );
            hr = pEncoderProps->GetValue( MFPKEY_RAVG, &var );
            if (FAILED(hr))
            {
                goto done;
            }
            hr = pStreamSinkProps->SetValue( MFPKEY_STAT_RAVG, var);
            if (FAILED(hr))
            {
                goto done;
            }

            PropVariantClear( &var );
            hr = pEncoderProps->GetValue( MFPKEY_BMAX, &var );
            if (FAILED(hr))
            {
                goto done;
            }
            hr = pStreamSinkProps->SetValue( MFPKEY_STAT_BMAX, var);
            if (FAILED(hr))
            {
                goto done;
            }

            PropVariantClear( &var );
            hr = pEncoderProps->GetValue( MFPKEY_RMAX, &var );
            if (FAILED(hr))
            {
                goto done;
            }
            hr = pStreamSinkProps->SetValue( MFPKEY_STAT_RMAX, var);
            if (FAILED(hr))
            {
                goto done;
            }
        }
        else if( guidMajorType == MFMediaType_Audio )
        {      
            hr = pEncoderProps->GetValue( MFPKEY_STAT_BAVG, &var );
            if (FAILED(hr))
            {
                goto done;
            }
            hr = pStreamSinkProps->SetValue( MFPKEY_STAT_BAVG, var );
            if (FAILED(hr))
            {
                goto done;
            }
            
            PropVariantClear( &var );
            hr = pEncoderProps->GetValue( MFPKEY_STAT_RAVG, &var );
            if (FAILED(hr))
            {
                goto done;
            }
            hr = pStreamSinkProps->SetValue( MFPKEY_STAT_RAVG, var );
            if (FAILED(hr))
            {
                goto done;
            }
            
            PropVariantClear( &var );
            hr = pEncoderProps->GetValue( MFPKEY_STAT_BMAX, &var);
            if (FAILED(hr))
            {
                goto done;
            }
            hr = pStreamSinkProps->SetValue( MFPKEY_STAT_BMAX, var);
            if (FAILED(hr))
            {
                goto done;
            }

            PropVariantClear( &var );
            hr = pEncoderProps->GetValue( MFPKEY_STAT_RMAX, &var );
            if (FAILED(hr))
            {
                goto done;
            }
            hr = pStreamSinkProps->SetValue( MFPKEY_STAT_RMAX, var );         
            if (FAILED(hr))
            {
                goto done;
            }

            PropVariantClear( &var );
            hr = pEncoderProps->GetValue( MFPKEY_WMAENC_AVGBYTESPERSEC, &var );
            if (FAILED(hr))
            {
                goto done;
            }
            hr = pStreamSinkProps->SetValue( MFPKEY_WMAENC_AVGBYTESPERSEC, var );         
            if (FAILED(hr))
            {
                goto done;
            }
        } 
        PropVariantClear( &var ); 
   }
done:
    SafeRelease (&pOutputColl);
    SafeRelease (&pNodeUnk);
    SafeRelease (&pType);
    SafeRelease (&pNode);
    SafeRelease (&pSinkUnk);
    SafeRelease (&pStreamSink);
    SafeRelease (&pEncoderNode);
    SafeRelease (&pEncoderUnk);
    SafeRelease (&pEncoder);
    SafeRelease (&pStreamSinkProps);
    SafeRelease (&pEncoderProps);

    return hr;
   
}

Ana İşlevi Uygula

Aşağıdaki kod örneği konsol uygulamanızın ana işlevini gösterir.

int wmain(int argc, wchar_t* argv[])
{
    HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);

    if (argc != 4)
    {
        wprintf_s(L"Usage: %s inputaudio.mp3, %s output.wm*, %Encoding Type: CBR, VBR\n");
        return 0;
    }


    HRESULT             hr = S_OK;

    IMFMediaSource* pSource = NULL;
    IMFTopology* pTopology = NULL;
    IMFActivate* pFileSinkActivate = NULL;

    hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
    if (FAILED(hr))
    {
        goto done;
    }

    //Set the requested encoding mode
    if (wcscmp(argv[3], L"CBR")==0)
    {
        EncodingMode = CBR;
    }
    else if (wcscmp(argv[3], L"VBR")==0)
    {
        EncodingMode = VBR;
    }
    else
    {
        EncodingMode = CBR;
    }

    // Start up Media Foundation platform.
    hr = MFStartup(MF_VERSION);
    if (FAILED(hr))
    {
        goto done;
    }

    //Create the media source
    hr = CreateMediaSource(argv[1], &pSource);
    if (FAILED(hr))
    {
        goto done;
    }

    //Create the file sink activate
    hr = CreateMediaSink(argv[2], pSource, &pFileSinkActivate);
    if (FAILED(hr))
    {
        goto done;
    }

    //Build the encoding topology.
    hr = BuildPartialTopology(pSource, pFileSinkActivate, &pTopology);
    if (FAILED(hr))
    {
        goto done;
    }

    //Instantiate the media session and start encoding
    hr = Encode(pTopology);
    if (FAILED(hr))
    {
        goto done;
    }


done:
    // Clean up.
    SafeRelease(&pSource);
    SafeRelease(&pTopology);
    SafeRelease(&pFileSinkActivate);

    MFShutdown();
    CoUninitialize();

    if (FAILED(hr))
    {
        wprintf_s(L"Could not create the output file due to 0x%X\n", hr);
    }
    return 0;
}

Çıktı Dosyasını Test Edin

Aşağıdaki listede, kodlanmış dosyayı test etmek için bir denetim listesi açıklanmaktadır. Bu değerler, kodlanmış dosyaya sağ tıklayıp bağlam menüsünden Özellikler seçilerek görüntüleyebileceğiniz dosya özellikleri iletişim kutusunda denetlenebilir.

  • Kodlanmış dosyanın yolu doğru.
  • Dosyanın boyutu sıfır KB'tan fazladır ve yürütme süresi kaynak dosyanın süresiyle eşleşir.
  • Video akışı için çerçeve genişliğini ve yüksekliğini, kare hızını denetleyin. Bu değerler, "ASF Profil Nesnesi Oluşturma" bölümünde açıklanan adımda oluşturduğunuz ASF profilinde belirttiğiniz değerlerle eşleşmelidir.
  • Ses akışı için bit hızı hedef medya türünde belirttiğiniz değere yakın olmalıdır.
  • Dosyayı Windows Media Player'da açın ve kodlamanın kalitesini denetleyin.
  • ASF dosyasının yapısını görmek için ASFViewer'da ASF dosyasını açın. Bu araç bu Microsoft web sitesindenindirilebilir.

Yaygın Hata Kodları ve Hata Ayıklama İpuçları

Aşağıdaki listede, alabileceğiniz yaygın hata kodları ve hata ayıklama ipuçları açıklanmaktadır.

  • IMFSourceResolver::CreateObjectFromURL çağrısı uygulamayı geciktirir.

    MFStartupçağırarak Media Foundation platformunu başlatdığınızdan emin olun. Bu işlev, IMFSourceResolver::CreateObjectFromURLgibi zaman uyumsuz işlemleri başlatan tüm yöntemler tarafından kullanılan zaman uyumsuz platformu dahili olarak ayarlar.

  • IMFSourceResolver::CreateObjectFromURL HRESULT döndürür 0x80070002 "Sistem belirtilen dosyayı bulamıyor.

    İlk bağımsız değişkende kullanıcı tarafından belirtilen giriş dosyası adının var olduğundan emin olun.

  • HRESULT 0x80070020 "Başka bir işlem tarafından kullanıldığından işlem dosyaya erişemiyor. "

    Giriş ve çıkış dosyalarının şu anda sistemdeki başka bir kaynak tarafından kullanılmadığından emin olun.

  • IMFTransform yöntemlerine yapılan çağrılar MF_E_INVALIDMEDIATYPE döndürür.

    Aşağıdaki koşulların doğru olduğundan emin olun:

    • Belirttiğiniz giriş türü veya çıkış türü, kodlayıcının desteklediği medya türleriyle uyumludur.
    • Belirttiğiniz medya türleri tamamlandı. Medya türlerinin tamamlanması için bu öğreticinin "Sıkıştırılmış Ses Medya Türü Oluşturma" ve "Sıkıştırılmış Video Medya Türü Oluşturma" bölümlerindeki gerekli özniteliklere bakın.
    • Codec özel verilerini eklediğiniz kısmi medya türünde hedef bit hızını ayarladığınızdan emin olun.
  • Medya Oturumu, olay durumunda MF_E_UNSUPPORTED_D3D_TYPE döndürür.

    Bu hata, kaynağın medya türü Windows Media Video kodlayıcı tarafından desteklenmeyen karma bir interlace modunu gösterdiğinde döndürülür. Sıkıştırılmış video medya türünüz aşamalı modu kullanacak şekilde ayarlandıysa, işlem hattının bir geçişsizleştirme dönüştürmesi kullanması gerekir. İşlem hattı bir eşleşme bulamadığından (bu hata koduyla belirtilir), kod çözücü ve kodlayıcı düğümleri arasına el ile bir de-interlacer (çözme ve kodlama video işlemcisi) eklemeniz gerekir.

  • Medya Oturumu, olay durumunda E_INVALIDARG döndürür.

    Kaynağın medya türü öznitelikleri Windows Media kodlayıcıda ayarlanan çıkış medya türü öznitelikleriyle uyumlu olmadığında bu hata döndürülür.

  • IWMCodecPrivateData::GetPrivateDataHRESULT 0x80040203 "Sorgu dizesi değerlendirilmeye çalışılırken söz dizimi hatası oluştu" sonucunu verir

    Giriş türünün kodlayıcı MFT'sinde ayarlandığından emin olun.

Pipeline Katmanı ASF Bileşenleri