Broadcasting ASF Data

[The feature associated with this page, Windows Media Format 11 SDK, is a legacy feature. It has been superseded by Source Reader and Sink Writer. Source Reader and Sink Writer have been optimized for Windows 10 and Windows 11. Microsoft strongly recommends that new code use Source Reader and Sink Writer instead of Windows Media Format 11 SDK, when possible. Microsoft suggests that existing code that uses the legacy APIs be rewritten to use the new APIs if possible.]

This topic describes how to send ASF data across a network using the HTTP protocol. Sending files over a network requires the use of the writer object, so you should have a general understanding of this object before reading this topic. For more information, see Writing ASF Files.

If you are starting with uncompressed data, do the following:

  1. Create the writer object by calling the WMCreateWriter function. This function returns an IWMWriter pointer.

    IWMWriter *pWriter;
    hr = WMCreateWriter(NULL, &pWriter);
    
  2. Create the network sink object by calling the WMCreateWriterNetworkSink function, which returns an IWMWriterNetworkSink pointer.

    IWMWriterNetworkSink *pNetSink;
    hr = WMCreateWriterNetworkSink(&pNetSink);
    
  3. Call IWMWriterNetworkSink::Open on the network sink and specify the port number to open; for example, 8080. Optionally, call IWMWriterNetworkSink::GetHostURL to get the URL of the host. Clients will access the content from this URL. You can also call IWMWriterNetworkSink::SetMaximumClients to restrict the number of clients.

    DWORD dwPortNum = 8080;
    hr = pNetSink->Open( &dwPortNum)
    
  4. Attach the network sink to the writer by calling IWMWriterAdvanced::AddSink on the writer, with a pointer to the network sink's IWMWriterNetworkSink interface.

    IWMWriterAdvanced *pWriterAdvanced;
    hr = pWriter->QueryInterface(IID_IWMWriterAdvanced, ( void** ) pWriterAdvanced );
    if (SUCCEEDED(hr))
    {
        pWriterAdvanced->AddSink(pNetSink);
    }
    
  5. Set the ASF profile by calling the IWMWriter::SetProfile method on the writer object, with an IWMProfile pointer. For information about creating a profile, see Working with Profiles.

  6. Optionally, specify metadata using the IWMHeaderInfo interface on the writer.

  7. Call IWMWriter::BeginWriting on the writer.

    hr = pWriter->BeginWriting();
    
  8. For each sample, call the IWMWriter::WriteSample method. Specify the stream number, the presentation time, the duration of the sample, and a pointer to the sample buffer. The WriteSample method compresses the samples.

  9. When you are done, call IWMWriter::EndWriting on the writer.

    hr = pWriter->EndWriting();
    
  10. Call IWMWriterAdvanced::RemoveSink on the writer to detach the network sink object.

    hr = pWriterAdvanced->RemoveSink(pNetSink);
    
  11. Call IWMWriterNetworkSink::Close on the network sink to release the port.

    hr = pNetSink->Close();
    

Another way to stream ASF content over a network is to read it from an existing ASF file. The WMVNetWrite sample provided in the SDK demonstrates this approach. In addition to the steps listed previously, do the following:

  1. Create a reader object and call the Open method with the name of the file.

  2. Call IWMReaderAdvanced::SetManualStreamSelection on the reader object, with the value TRUE. This enables the application to read every stream in the file, including streams with mutual exclusion.

  3. Query the reader for the IWMProfile interface. Use this pointer when you call IWMWriter::SetProfile on the writer object (step 5 in the previous procedure).

  4. For every stream defined in the profile, call IWMProfile::GetStream to get the stream number. Pass this stream number to the reader's IWMReaderAdvanced::SetReceiveStreamSamples method. This method informs the reader to deliver compressed samples, rather than decoding them. The samples will be delivered to the application through the application's IWMReaderCallbackAdvanced::OnStreamSample callback method.

    You must obtain codec information for every stream that you read uncompressed and add it to the header before broadcast. To obtain the codec information, call IWMHeaderInfo2::GetCodecInfoCount and IWMHeaderInfo2::GetCodecInfo to enumerate the codecs associated with the file in the reader. Select the codec information that matches the stream configuration. Then set the codec information in the writer by calling IWMHeaderInfo3::AddCodecInfo, passing the information obtained from the reader.

  5. After you set the profile on the writer, call IWMWriter::GetInputCount on the writer to get the number of inputs. For each input, call IWMWriter::SetInputProps with the value NULL. This indicates to the writer object that the application will deliver compressed samples, so the writer does not have to use any codecs to compress the data. Make sure to call SetInputProps before calling BeginWriting.

  6. Optionally, copy the metadata attributes from the reader to the writer

  7. Because the samples from the reader are already compressed, use the IWMWriterAdvanced::WriteStreamSample method to write the samples, instead of the WriteSample method. The WriteStreamSample method bypasses the writer object's usual compression procedures.

  8. When the reader reaches the end of the file, it sends a WMT_EOF notification to the application.

In addition, the application should drive the clock on the reader object, so that the reader pulls data from the file as quickly as possible. To do this, call the IWMReaderAdvanced::SetUserProvidedClock method on the reader, with the value TRUE. After the reader sends the WMT_STARTED notification, call IWMReaderAdvanced::DeliverTime and specify the time interval that the reader should deliver. After the reader is done reading this time interval, it calls the application's IWMReaderCallbackAdvanced::OnTime callback method. The application should call DeliverTime again to read the next time interval. For example, to read from the file in one-second intervals:

// Initial call to DeliverTime.
QWORD m_qwTime = 10000000; // 1 second.
hr = m_pReaderAdvanced->DeliverTime(m_qwTime);

// In the callback:
HRESULT CNetWrite::OnTime(QWORD cnsCurrentTime, void *pvContext)
{
    HRESULT hr = S_OK;
    // Continue calling DeliverTime until the end of the file.
    if(!m_bEOF)
    {
        m_qwTime += 10000000; // 1 second.
        hr = m_pReaderAdvanced->DeliverTime(m_qwTime);
    }
    return S_OK;
}

Sending ASF Data Over a Network

Working with Writer Sinks