在不解压缩数据的情况下复制流

将流从一个文件复制到另一个文件的最简单和最常见的方法是检索处于压缩状态的样本,然后将其写入新文件,而无需解压缩和重新压缩它们。 从处于压缩状态的文件获取的样本称为流样本,因为它们在流中的表示形式是不变的。 建议始终使用流示例来复制流,因为解压缩和重新压缩数字媒体数据会降低质量。 如果必须从解压缩的数据复制流,请参阅 使用解压缩的示例复制流

可以使用压缩样本将两个或多个流连接到单个流,但前提是比特率相同。 此过程与下面所述的步骤基本相同,只不过必须读取多个原始文件才能获取所需的所有内容。 但是,如果 WM_MEDIA_TYPE结构 ( 包括所有压缩流的所有 pbFormat 结构成员) 相同,则只能将压缩样本从多个文件写入单个流。 若要合并来自不同格式的多个流的数据,必须解压缩内容并将其重新压缩到目标流中。 此外,将两个或多个流中的数据合并到单个流中时,必须将所有流的缓冲区窗口值一起添加,以获取新流的缓冲区窗口。 这是因为无法确定在一个流的末尾和另一个流的开头占用多少缓冲区。

可以使用 IWMReaderAdvanced::SetReceiveStreamSamples 通过异步读取器检索流示例。 流示例将传送到 IWMReaderCallbackAdvanced::OnStreamSample,而不是 IWMReaderCallback::OnSample。 如果要读取文件并检索一些压缩的流和一些解压缩的流,则必须实现这两种回调方法。

同步读取器为检索样本提供了更大的灵活性。 可以在播放期间使用 IWMSyncReader::SetReadStreamSamples 在压缩和解压缩样本之间自由切换。

若要将整个流从一个 ASF 文件复制到新的 ASF 文件,请执行以下步骤。 这些步骤使用同步读取器,因为它用于此类操作要简单得多。

  1. 通过调用 WMCreateSyncReader 函数创建同步读取器对象。
  2. 通过调用 IWMSyncReader::Open 打开读取器中的文件。
  3. 通过调用 IWMSyncReader::QueryInterface 获取指向同步读取器对象的 IWMProfile 接口的指针。
  4. 通过调用 IWMProfile::GetStreamByNumber 检索所需流的属性。 这将检索指向所需流的流配置对象的 IWMStreamConfig 接口的指针。
  5. 获取流的 WM_MEDIA_TYPE 结构的副本。 对 IWMMediaProps::GetMediaType 进行两次调用:第一次调用获取结构的大小,第二次调用获取结构本身。
  6. 通过调用 WMCreateProfileManager 函数创建配置文件管理器对象。
  7. 调用 IWMProfileManager::CreateEmptyProfile 以 (创建新的配置文件,或打开要将流添加到) 的现有配置文件。 在新配置文件上调用 IWMProfile::AddStream ,以从现有文件添加流。 添加流时,请使用步骤 4 中获取的 IWMStreamConfig 指针。
  8. 使用对 WMCreateWriter 函数的调用创建编写器对象。 通过调用 IWMWriter::SetProfile,将新创建的配置文件设置为编写器中的活动配置文件。 通过调用 IWMWriter::SetOutputFilename 创建用于输出的文件。
  9. 对于与要复制的一个或多个流关联的每个输入,调用 IWMWriter::SetInputProps,为 IWMInputMediaProps 接口传递 NULL。 这会通知编写器对象,它不需要验证你传递的数据。 在调用 beginWriting (步骤 14) 之前,必须进行此调用,否则读取对象可能无法解码内容。
  10. 通过将 fCompressed 参数设置为 True 的 iWMSyncReadReader::SetReadStreamSamples,将同步读取器设置为为所选流提供压缩流样本。
  11. 获取要复制的每个流的编解码器信息,并在写入之前将编解码器信息添加到 标头。 若要获取编解码器信息,请调用 IWMHeaderInfo2::GetCodecInfoCountIWMHeaderInfo2::GetCodecInfo 以枚举与读取器中的文件关联的编解码器。 选择与流配置匹配的编解码器信息。 然后,通过调用 IWMHeaderInfo3::AddCodecInfo 并传递从读取器获取的信息,在编写器中设置编解码器信息。
  12. 通过调用 IWMWriter::QueryInterface 获取指向 IWMWriterAdvanced 接口的指针。
  13. 通过调用 IWMWriter::BeginWriting 将编写器设置为写入模式。
  14. 重复调用 IWMSyncReader::GetNextSample,指定所需的流编号。 收到示例后,通过调用 IWMWriterAdvanced::WriteStreamSample 将它们传递给编写器。 对于视频流,如果编写器在每次调用 GetNextSample 时设置任何) ,则应检查标志 (。 如果设置了WM_SF_CLEANPOINT,还必须在调用 WriteStreamSample 时对其进行设置。
  15. 读取完成后,调用 IWMWriter::EndWriting。 应传输流。

注意

无法使用流示例将图像流从一个文件复制到另一个文件。 若要复制图像流数据,请检索未压缩的样本,然后像平时一样通过编写器处理它们。

 

将数据从一个文件复制到另一个文件

使用解压缩的示例复制流