Копирование потоков без распаковки данных

Самый простой и распространенный способ копирования потока из одного файла в другой — получить примеры в сжатом состоянии, а затем записать их в новый файл без распаковки и повторного сжатия. Примеры, полученные из файла в сжатом состоянии, называются примерами потока, так как они не отличаются от их представления в потоке. Рекомендуется всегда использовать примеры потоков для копирования потоков, так как распаковка и повторное сжатие цифровых мультимедийных данных ухудшает качество. Если необходимо скопировать поток из распакованных данных, см. раздел Копирование потоков с помощью распакованных примеров.

Можно сцепить два или более потоков в один поток с помощью сжатых выборок, но только в том случае, если скорость передачи данных идентична. Процесс по сути совпадает с описанными ниже шагами, за исключением того, что необходимо прочитать несколько исходных файлов, чтобы получить все необходимое содержимое. Однако сжатые примеры из нескольких файлов можно записывать в один поток, только если структуры WM_MEDIA_TYPE (включая все элементы структуры pbFormat ) всех сжатых потоков идентичны. Чтобы объединить данные из нескольких потоков, которые имеют разный формат, необходимо распаковать содержимое и повторно спаковать его в целевой поток. Кроме того, при объединении данных из двух или более потоков в один поток необходимо добавить значения окна буфера для всех потоков вместе, чтобы получить окно буфера для нового потока. Это связано с тем, что невозможно определить, какая часть буфера занята в конце одного потока и в начале другого.

Примеры потоков можно получить с помощью асинхронного средства чтения с помощью IWMReaderAdvanced::SetReceiveStreamSamples. Примеры потоков доставляются в IWMReaderCallbackAdvanced::OnStreamSample, а не в IWMReaderCallback::OnSample. Если вы считываете файл и извлекаете некоторые потоки, сжатые и распакованные, необходимо реализовать оба метода обратного вызова.

Синхронное средство чтения обеспечивает большую гибкость при извлечении примеров. Вы можете свободно переключаться между сжатыми и распакованными примерами во время воспроизведения с помощью IWMSyncReader::SetReadStreamSamples.

Чтобы скопировать весь поток из одного ASF-файла в новый ASF-файл, выполните следующие действия. В этих шагах используется синхронное средство чтения, так как его гораздо проще использовать для такого рода операций.

  1. Создайте синхронный объект чтения, вызвав функцию WMCreateSyncReader .
  2. Откройте файл в средстве чтения с помощью вызова IWMSyncReader::Open.
  3. Получите указатель на интерфейс IWMProfile синхронного объекта средства чтения, вызвав метод IWMSyncReader::QueryInterface.
  4. Получите свойства требуемого потока, вызвав IWMProfile::GetStreamByNumber. При этом будет получен указатель на интерфейс IWMStreamConfig объекта конфигурации потока для нужного потока.
  5. Получите копию структуры WM_MEDIA_TYPE для потока. Выполните два вызова IWMMediaProps::GetMediaType: первый для получения размера структуры, второй — для получения самой структуры.
  6. Создайте объект диспетчера профилей, вызвав функцию WMCreateProfileManager .
  7. Вызовите IWMProfileManager::CreateEmptyProfile , чтобы создать новый профиль (или открыть существующий профиль, в который вы хотите добавить поток). Вызовите IWMProfile::AddStream в новом профиле, чтобы добавить поток из существующего файла. При добавлении потока используйте указатель IWMStreamConfig , полученный на шаге 4.
  8. Создайте объект записи с помощью вызова функции WMCreateWriter . Задайте созданный профиль в качестве активного профиля в записи, вызвав IWMWriter::SetProfile. Создайте файл для выходных данных, вызвав IWMWriter::SetOutputFilename.
  9. Для каждого входа, связанного с копируемым потоком или потоками, вызовите IWMWriter::SetInputProps, передав значение NULL для интерфейса IWMInputMediaProps . Это информирует объект модуля записи о том, что ему не нужно проверять передаваемые данные. Этот вызов необходимо выполнить перед вызовом BeginWriting (шаг 14), в противном случае объект чтения не сможет декодировать содержимое.
  10. Задайте синхронное средство чтения для доставки сжатых примеров потока для выбранного потока, вызвав IWMSyncReader::SetReadStreamSamples с параметром fCompressed , равным True.
  11. Получение сведений о кодека для каждого копируемого потока и добавление сведений о кодека в заголовок перед записью. Чтобы получить сведения о кодеке, вызовите IWMHeaderInfo2::GetCodecInfoCount и IWMHeaderInfo2::GetCodecInfo для перечисления кодеков, связанных с файлом в средстве чтения. Выберите сведения кодека, соответствующие конфигурации потока. Затем задайте сведения кодека в средстве записи, вызвав метод IWMHeaderInfo3::AddCodecInfo, передав сведения, полученные от средства чтения.
  12. Получите указатель на интерфейс IWMWriterAdvanced , вызвав IWMWriter::QueryInterface.
  13. Переведите модуль записи в режим записи, вызвав IWMWriter::BeginWriting.
  14. Повторяйте вызовы IWMSyncReader::GetNextSample, указывая нужный номер потока. При получении примеров передайте их в модуль записи с вызовами IWMWriterAdvanced::WriteStreamSample. Для видеопотоков следует проверка флаги (при наличии), установленные модулем записи при каждом вызове GetNextSample. Если WM_SF_CLEANPOINT задано, необходимо также задать для вызова writeStreamSample.
  15. По завершении чтения вызовите IWMWriter::EndWriting. Поток должен быть передан.

Примечание

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

 

Копирование данных из одного файла в другой

Копирование потоков с помощью распакованных примеров