Создание примеров потоков из существующего объекта данных ASF
Объект разделителя ASF — это компонент слоя WMContainer, который анализирует объект данных ASF файла Advanced Systems Format (ASF).
Перед передачей пакетов данных в разделитель приложение должно инициализировать, настроить и выбрать потоки в разделитель, чтобы подготовить его к процессу синтаксического анализа. Дополнительные сведения см. в разделах Создание объекта разделитировщика ASF и Настройка объекта разделитировщика ASF.
Для анализа объекта данных ASF требуются следующие методы:
- IMFASFSplitter::P arseData , который запускает процесс синтаксического анализа путем отправки буфера, содержащего пакеты данных, в разделитель.
- IMFASFSplitter::GetNextSample , который собирает образцы потоков, созданные из буфера, переданного в разделитель.
Поиск смещения данных
Перед запуском процесса синтаксического анализа приложение должно найти объект данных в ASF-файле. Существует два способа получить смещение объекта данных от начала файла.
Перед инициализацией объекта ContentInfo можно вызвать метод IMFASFContentInfo::GetHeaderSize . Для этого метода требуется буфер, содержащий первые 30 байт заголовка ASF. Он возвращает размер всего заголовка, который указывает смещение к первому пакету данных. Это значение также включает размер заголовка Data Object 50 байт.
После инициализации объекта ContentInfo можно получить дескриптор презентации, вызвав IMFASFContentInfo::GeneratePresentationDescriptor, а затем запросив дескриптор презентации для атрибута MF_PD_ASF_DATA_START_OFFSET . Значение этого атрибута — размер заголовка.
Примечание
Атрибут MF_PD_ASF_DATA_LENGTH в дескрипторе представления указывает длину объекта данных ASF.
В обоих случаях возвращаемое значение — это размер объекта заголовка плюс размер раздела заголовка объекта данных. Таким образом, результирующее значение представляет собой смещение к началу пакетов данных в объекте данных ASF. Когда вы начинаете отправлять данные в разделитель, данные должны начинаться с этого смещения от начала ASF-файла.
Значение смещения передается в качестве параметра в ParseData , который запускает процесс синтаксического анализа.
Объект данных делится на пакеты данных. Каждый пакет данных содержит заголовок пакета данных, который предоставляет сведения о анализе пакетов и полезные данные — фактические цифровые данные мультимедиа. В сценарии поиска приложению может потребоваться, чтобы разделитель начал синтаксический анализ определенного пакета данных. Для этого можно использовать индексатор ASF, используемый для получения смещения. Индексатор возвращает значение смещения, которое начинается с границы пакета. Если индексатор не используется, убедитесь, что смещение начинается с начала заголовка пакета данных. Если в разделитель передается недопустимое смещение, например значение не указывает на границу пакета, вызовы ParseHeader и GetNextSample завершаются успешно, но GetNextSample не получает примеры и в параметре pSample получается значение NULL.
Если разделитель настроен для анализа в обратном направлении, то разделитель всегда начинает анализ в конце буфера мультимедиа, передаваемого в ParseData. Поэтому для обратного анализа в вызове ParseData передайте смещение в параметре cbLength , который указывает длину данных и задайте для параметра cbBufferOffset нулевое значение.
Создание примеров для пакетов данных ASF
Приложение запускает процесс синтаксического анализа, передав пакеты данных в разделитель. Входные данные в разделитель — это ряд буферов мультимедиа, содержащих весь объект или фрагменты объекта данных. Выходные данные разбиения — это серия примеров мультимедиа, содержащих данные пакета.
Чтобы передать входные данные в разделитель, создайте буфер мультимедиа и заполните его данными из раздела Объект данных ASF-файла. (Дополнительные сведения о буферах мультимедиа см. в разделе Буферы мультимедиа.) Затем передайте буфер мультимедиа в метод IMFASFSplitter::P arseData . Также можно указать:
- Смещение в буфере, где разделитель должен начать синтаксический анализ. Если смещение равно нулю, синтаксический анализ начинается с начала буфера. Сведения о настройке смещения данных см. в разделе "Поиск смещения данных" этой статьи.
- Объем данных для анализа. Если это значение равно нулю, разделитель анализирует, пока не достигнет конца буфера, как указано в методе IMFMediaBuffer::GetCurrentLength .
Разделитель создает примеры мультимедиа, ссылаясь на данные в буферах мультимедиа. Клиент может получить выходные образцы, вызывая IMFASFSplitter::GetNextSample в цикле, пока не будет больше данных для анализа. Если GetNextSample возвращает флаг ASF_STATUSFLAGS_INCOMPLETE в параметре pdwStatusFlags , это означает, что есть дополнительные примеры для извлечения, и приложение может снова вызвать GetNextSample . В противном случае вызовите ParseData , чтобы передать дополнительные данные в разделитель. Для созданных примеров разделитель задает следующие сведения:
- Разделитель устанавливает метку времени для всех создаваемых выборок. Выборка времени представляет время презентации и не включает время предварительной подготовки. Приложение может вызвать IMFSample::GetSampleTime , чтобы получить время презентации в 100-наносекундных единицах.
- Если разрыв происходит во время создания образца, разделитель устанавливает атрибут MFSampleExtension_Discontinuity в первом образце после разрыва. Разрывы обычно вызваны удаленными пакетами в сетевом подключении, повреждением файловых данных или переключением сплиттера из одного исходного потока в другой.
- Для видео разделитель проверяет, содержит ли образец ключевой кадр. Если это так, разделитель задает атрибут MFSampleExtension_CleanPoint в примере.
Если разделитель анализирует пакеты данных, полученные с сервера мультимедиа, возможно, длина пакета является переменной. В этом случае клиент должен вызывать ParseData для каждого пакета и задавать атрибут MFASFSPLITTER_PACKET_BOUNDARY для каждого буфера, отправляемого в разделитель. Этот атрибут указывает сплиттеру, содержит ли буфер мультимедиа начало пакета ASF. Задайте для атрибута значение TRUE , если буфер содержит начало нового пакета. Если буфер содержит продолжение предыдущего пакета, задайте для атрибута значение FALSE. Буферы не могут охватывать несколько пакетов.
Перед передачей новых буферов мультимедиа в разделитель приложение должно вызвать IMFASFSplitter::Flush. Этот метод сбрасывает разделитель и очищает все частичные кадры, ожидающие завершения. Это полезно в сценарии поиска, где смещение находится в другом расположении.
Пример
В следующем примере кода показано, как анализировать пакеты данных. В этом примере выполняется анализ от начала объекта данных до конца потока и отображаются сведения о примерах, содержащих ключевые кадры. Полный пример использования этого кода см. в разделе Учебник. Чтение ASF-файла.
// Parse the video stream and display information about the video samples.
//
// The current read position of the byte stream must be at the start of the ASF
// Data Object.
HRESULT DisplayKeyFrames(IMFByteStream *pStream, IMFASFSplitter *pSplitter)
{
const DWORD cbReadSize = 2048; // Read size (arbitrary value)
IMFMediaBuffer *pBuffer = NULL;
IMFSample *pSample = NULL;
HRESULT hr = S_OK;
while (SUCCEEDED(hr))
{
// The parser must get a newly allocated buffer each time.
hr = MFCreateMemoryBuffer(cbReadSize, &pBuffer);
if (FAILED(hr))
{
break;
}
// Read data into the buffer.
hr = ReadFromByteStream(pStream, pBuffer, cbReadSize);
if (FAILED(hr))
{
break;
}
// Get the amound of data that was read.
DWORD cbData;
hr = pBuffer->GetCurrentLength(&cbData);
if (FAILED(hr))
{
break;
}
if (cbData == 0)
{
break; // End of file.
}
// Send the data to the ASF splitter.
hr = pSplitter->ParseData(pBuffer, 0, 0);
SafeRelease(&pBuffer);
if (FAILED(hr))
{
break;
}
// Pull samples from the splitter.
DWORD parsingStatus = 0;
do
{
WORD streamID;
hr = pSplitter->GetNextSample(&parsingStatus, &streamID, &pSample);
if (FAILED(hr))
{
break;
}
if (pSample == NULL)
{
// No samples yet. Parse more data.
break;
}
if (IsRandomAccessPoint(pSample))
{
DisplayKeyFrame(pSample);
}
SafeRelease(&pSample);
} while (parsingStatus & ASF_STATUSFLAGS_INCOMPLETE);
}
SafeRelease(&pSample);
SafeRelease(&pBuffer);
return hr;
}
Связанные темы