Copying Streams Without Decompressing the 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.]
The simplest and most common way to copy a stream from one file to another is to retrieve the samples in their compressed state and then write them to the new file without decompressing and recompressing them. Samples obtained from a file in their compressed state are called stream samples, because they are unaltered from their representation in the stream. It is recommended that you always use stream samples to copy streams, because decompressing and recompressing digital media data degrades quality. If you must copy a stream from decompressed data, see Copying Streams Using Decompressed Samples.
It is possible to concatenate two or more streams into a single stream using compressed samples, but only if the bit rates are identical. The process is essentially the same as the steps described below, except that you must read multiple original files to get all of the content you need. However, you can only write compressed samples from multiple files to a single stream if the WM_MEDIA_TYPE structures (including all the pbFormat structure members) of all the compressed streams are identical. To combine data from multiple streams that are not of the same format, you must decompress the content and recompress it into the destination stream. Additionally, when you combine data from two or more streams into a single stream, you must add the buffer window values for all of the streams together to get the buffer window for the new stream. This is because it is impossible to determine how much of the buffer is taken up at the end of one stream and at the beginning of another.
You can retrieve stream samples with the asynchronous reader using IWMReaderAdvanced::SetReceiveStreamSamples. Stream samples are delivered to IWMReaderCallbackAdvanced::OnStreamSample, not to IWMReaderCallback::OnSample. If you are reading a file and retrieving some streams compressed and some decompressed, you must implement both callback methods.
The synchronous reader provides more flexibility for retrieving samples. You can switch between compressed and decompressed samples freely during playback using IWMSyncReader::SetReadStreamSamples.
To copy an entire stream from one ASF file to a new ASF file, perform the following steps. These steps use the synchronous reader because it is much simpler to use for this kind of operation.
- Create a synchronous reader object by calling the WMCreateSyncReader function.
- Open a file in the reader with a call to IWMSyncReader::Open.
- Get a pointer to the IWMProfile interface of the synchronous reader object by calling IWMSyncReader::QueryInterface.
- Retrieve the properties of the desired stream by calling IWMProfile::GetStreamByNumber. This will retrieve a pointer to the IWMStreamConfig interface of the stream configuration object for the stream you want.
- Get a copy of the WM_MEDIA_TYPE structure for the stream. Make two calls to IWMMediaProps::GetMediaType: the first to get the size of the structure, the second to get the structure itself.
- Create a profile manager object by calling the WMCreateProfileManager function.
- Call IWMProfileManager::CreateEmptyProfile to create a new profile (or open an existing profile to which you want to add the stream). Call IWMProfile::AddStream on the new profile to add the stream from the existing file. When adding the stream, use the IWMStreamConfig pointer obtained in step 4.
- Create a writer object with a call to the WMCreateWriter function. Set the newly created profile as the active profile in the writer by calling IWMWriter::SetProfile. Create a file for output by calling IWMWriter::SetOutputFilename.
- For each input associated with the stream or streams you are copying, call IWMWriter::SetInputProps, passing NULL for the IWMInputMediaProps interface. This informs the writer object that it does not need to validate the data you are passing. You must make this call before calling BeginWriting (step 14), otherwise a reading object may not be able to decode the content.
- Set the synchronous reader to deliver compressed stream samples for the selected stream by calling IWMSyncReader::SetReadStreamSamples with the fCompressed parameter set to True.
- Obtain codec information for every stream being copied and add the codec information to the header before writing. 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.
- Obtain a pointer to the IWMWriterAdvanced interface by calling IWMWriter::QueryInterface.
- Set the writer to writing mode by calling IWMWriter::BeginWriting.
- Make repeated calls to IWMSyncReader::GetNextSample, specifying the desired stream number. When samples are received, pass them to the writer with calls to IWMWriterAdvanced::WriteStreamSample. For video streams, you should check the flags (if any) set by the writer on each call to GetNextSample. If WM_SF_CLEANPOINT is set, you must also set it on your call to WriteStreamSample.
- When reading is complete, call IWMWriter::EndWriting. The stream should be transferred.
Note
Image streams cannot be copied from one file to another using stream samples. To copy image stream data, retrieve the samples uncompressed and then process them through the writer as you normally would.
Related topics