Использование индексатора для поиска в ASF-файле
Индексатор ASF — это компонент уровня WMContainer, который используется для чтения или записи объектов индекса в файле ASF. В этом разделе содержатся сведения об использовании индексатора ASF для поиска в ASF-файле.
Сведения о структуре ASF-файла см. в разделе Структура файлов ASF.
Инициализация индексатора для поиска
Чтобы инициализировать индексатор ASF для поиска, выполните следующие действия.
- Вызовите MFCreateASFIndexer , чтобы создать новый экземпляр индексатора ASF.
- Вызовите IMFASFIndexer::Initialize , чтобы инициализировать индексатор. Этот метод получает сведения из заголовка ASF, чтобы определить, какие потоки ASF индексируются. По умолчанию объект индексатора настроен для поиска.
- Вызовите IMFASFIndexer::GetIndexPosition , чтобы найти смещение индекса в ASF-файле.
- Вызовите функцию MFCreateASFIndexerByteStream , чтобы создать поток байтов для чтения индекса. Входными данными для этой функции является указатель на поток байтов, содержащий ASF-файл, и смещение индекса (из предыдущего шага).
- Вызовите IMFASFIndexer::SetIndexByteStreams , чтобы задать индексный поток байтов в индексаторе.
Следующий код показывает эти действия.
HRESULT CreateASFIndexer(
IMFByteStream *pContentByteStream, // Pointer to the content byte stream
IMFASFContentInfo *pContentInfo,
IMFASFIndexer **ppIndexer
)
{
IMFASFIndexer *pIndexer = NULL;
IMFByteStream *pIndexerByteStream = NULL;
QWORD qwLength = 0, qwIndexOffset = 0, qwBytestreamLength = 0;
// Create the indexer.
HRESULT hr = MFCreateASFIndexer(&pIndexer);
if (FAILED(hr))
{
goto done;
}
//Initialize the indexer to work with this ASF library
hr = pIndexer->Initialize(pContentInfo);
if (FAILED(hr))
{
goto done;
}
//Check if the index exists. You can only do this after creating the indexer
//Get byte stream length
hr = pContentByteStream->GetLength(&qwLength);
if (FAILED(hr))
{
goto done;
}
//Get index offset
hr = pIndexer->GetIndexPosition(pContentInfo, &qwIndexOffset);
if (FAILED(hr))
{
goto done;
}
if ( qwIndexOffset >= qwLength)
{
//index object does not exist, release the indexer
goto done;
}
else
{
// initialize the indexer
// Create a byte stream that the Indexer will use to read in
// and parse the indexers.
hr = MFCreateASFIndexerByteStream(
pContentByteStream,
qwIndexOffset,
&pIndexerByteStream
);
if (FAILED(hr))
{
goto done;
}
}
hr = pIndexer->SetIndexByteStreams(&pIndexerByteStream, 1);
if (FAILED(hr))
{
goto done;
}
// Return the pointer to the caller.
*ppIndexer = pIndexer;
(*ppIndexer)->AddRef();
done:
SafeRelease(&pIndexer);
SafeRelease(&pIndexerByteStream);
return hr;
}
Получение позиции поиска.
- Чтобы узнать, индексируется ли определенный поток, вызовите IMFASFIndexer::GetIndexStatus. Если поток индексируется, параметр pfIsIndexed получает значение TRUE; в противном случае он получает значение FALSE.
- По умолчанию индексатор использует поиск вперед. Для обратного поиска (т. е. поиска в конце файла) вызовите IMFASFIndexer::SetFlags и установите флаг MFASF_INDEXER_READ_FOR_REVERSEPLAYBACK . В противном случае пропустите этот шаг.
- Если поток индексирован, получите позицию поиска для указанного времени презентации, вызвав IMFASFIndexer::GetSeekPositionForValue. Этот метод считывает индекс ASF и находит запись индекса, которая ближе всего к требуемому времени. Метод возвращает смещение в байтах пакета данных, указанного в записи индекса. Смещение в байтах относительно начала объекта данных ASF.
Метод GetSeekPositionForValue принимает указатель на структуру ASF_INDEX_IDENTIFIER . Эта структура задает тип индекса и идентификатор потока. В настоящее время тип индекса должен быть GUID_NULL, что указывает индексирование на основе времени.
Следующий код получает позицию поиска с учетом идентификатора потока и целевого времени презентации. Если вызов выполнен успешно, он возвращает смещение данных в параметре pcbDataOffset и приблизительное фактическое время поиска в phnsApproxSeekTime.
HRESULT GetSeekPositionWithIndexer(
IMFASFIndexer *pIndexer,
WORD wStreamNumber,
MFTIME hnsSeekTime, // Desired seek time, in 100-nsec.
BOOL bReverse,
QWORD *pcbDataOffset, // Receives the offset in bytes.
MFTIME *phnsApproxSeekTime // Receives the approximate seek time.
)
{
// Query whether the stream is indexed.
ASF_INDEX_IDENTIFIER IndexIdentifier = { GUID_NULL, wStreamNumber };
BOOL fIsIndexed = FALSE;
ASF_INDEX_DESCRIPTOR descriptor;
DWORD cbIndexDescriptor = sizeof(descriptor);
HRESULT hr = pIndexer->GetIndexStatus(
&IndexIdentifier,
&fIsIndexed,
(BYTE*)&descriptor,
&cbIndexDescriptor
);
if (hr == MF_E_BUFFERTOOSMALL)
{
hr = S_OK;
}
else if (FAILED(hr))
{
goto done;
}
if (!fIsIndexed)
{
hr = MF_E_ASF_NOINDEX;
goto done;
}
if (bReverse)
{
hr = pIndexer->SetFlags(MFASF_INDEXER_READ_FOR_REVERSEPLAYBACK);
if (FAILED(hr))
{
goto done;
}
}
// Get the offset from the indexer.
PROPVARIANT var;
var.vt = VT_I8;
var.hVal.QuadPart = hnsSeekTime;
hr = pIndexer->GetSeekPositionForValue(
&var,
&IndexIdentifier,
pcbDataOffset,
phnsApproxSeekTime,
0
);
done:
return hr;
}
Связанные темы