ASF 분할자 개체는 ASF(Advanced Systems Format) 파일의 ASF 데이터 개체를 구문 분석하는 WMContainer의 계층적 구성 요소입니다.
데이터 패킷을 분할자로 전달하기 전에 애플리케이션은 구문 분석 프로세스를 준비하기 위해 분할자에서 스트림을 초기화, 구성 및 선택해야 합니다. 자세한 내용은 ASF Splitter 개체 만들기 및 ASF Splitter 개체 구성참조하세요.
ASF 데이터 개체를 구문 분석하는 데 필요한 메서드는 다음과 같습니다.
- IMFASFSplitter::ParseData 데이터 패킷이 포함된 버퍼를 스플리터에 푸시하여 구문 분석 프로세스를 시작합니다.
- IMFASFSplitter::GetNextSample 분할자에 전달된 버퍼에서 생성된 스트림 샘플을 수집합니다.
데이터 오프셋 찾기
구문 분석 프로세스를 시작하기 전에 애플리케이션은 ASF 파일 내에서 데이터 개체를 찾아야 합니다. 파일의 시작 부분부터 Data Object의 오프셋을 가져오는 방법에는 두 가지가 있습니다.
ContentInfo 개체를 초기화하기 전에 IMFASFContentInfo::GetHeaderSize 메서드를 호출할 수 있습니다. 이 메서드에는 ASF 헤더의 처음 30바이트를 포함하는 버퍼가 필요합니다. 첫 번째 데이터 패킷에 대한 오프셋을 나타내는 전체 헤더의 크기를 반환합니다. 이 값에는 50바이트의 데이터 개체 헤더 크기도 포함됩니다.
ContentInfo 개체를 초기화한 후 IMFASFContentInfo::GeneratePresentationDescriptor호출한 다음 MF_PD_ASF_DATA_START_OFFSET 특성에 대한 프레젠테이션 설명자를 쿼리하여 프레젠테이션 설명자를 가져올 수 있습니다. 이 특성의 값은 헤더 크기입니다.
메모
프레젠테이션 설명자의 MF_PD_ASF_DATA_LENGTH 특성은 ASF 데이터 개체의 길이를 지정합니다.
두 경우 모두 반환되는 값은 Header 개체의 크기와 데이터 개체의 헤더 섹션 크기입니다. 따라서 결과 값은 ASF 데이터 개체에서 데이터 패킷의 시작 부분까지의 오프셋입니다. 분할기로 데이터를 보내기 시작하면 데이터는 ASF 파일의 시작 부분에서 해당 오프셋에서 시작해야 합니다.
오프셋 값은 구문 분석 프로세스를 시작하는 parseData 매개 변수로 전달됩니다.
데이터 개체는 데이터 패킷으로 나뉩니다. 각 데이터 패킷에는 패킷 구문 분석 정보 및 페이로드 데이터(실제 디지털 미디어 데이터)를 제공하는 데이터 패킷 헤더가 포함되어 있습니다. 검색 시나리오에서 애플리케이션은 분할기가 특정 데이터 패킷에서 구문 분석을 시작하도록 요청할 수 있습니다. 이렇게 하려면 ASF 인덱서가 오프셋을 검색하는 데 사용되는 것을 사용할 수 있습니다. 인덱서는 패킷 경계에서 시작하는 오프셋 값을 반환합니다. 인덱서가 사용되지 않는 경우 데이터 패킷 헤더 시작 시 오프셋이 시작되었는지 확인합니다. 값이 패킷 경계를 가리키지 않는 것과 같이 잘못된 오프셋이 분할자에 전달되면 ParseHeader 및 getNextSample 호출이 성공하지만 GetNextSample 샘플을 검색하지 않고 NULLpSample 매개 변수에서 수신됩니다.
분할기가 역방향 구문 분석으로 설정된 경우, 항상 미디어 버퍼의 끝에서 구문 분석을 시작하여 ParseData에 전달합니다. 따라서 ParseData호출에서 역방향 구문 분석의 경우 데이터의 길이를 지정하고 cbBufferOffset 0으로 설정하는 cbLength 매개 변수에 오프셋을 전달합니다.
ASF 데이터 패킷에 대한 샘플 생성
애플리케이션은 데이터 패킷을 분할자로 전달하여 구문 분석 프로세스를 시작합니다. 분할자 입력은 데이터 개체의 전체 또는 조각을 포함하는 일련의 미디어 버퍼입니다. 분할자의 출력은 패킷 데이터를 포함하는 일련의 미디어 샘플입니다.
입력 데이터를 분할자로 전달하려면 미디어 버퍼를 만들고 ASF 파일의 데이터 개체 섹션에 있는 데이터로 채웁니다. (미디어 버퍼에 대한 자세한 내용은 미디어 버퍼참조하세요.) 그런 다음 미디어 버퍼를 IMFASFSplitter::P arseData 메서드에 전달합니다. 다음을 지정할 수도 있습니다.
- 구문 분석을 시작해야 하는 버퍼의 오프셋은 스플리터에 있습니다. 오프셋 값이 0이면, 버퍼의 시작부터 구문 분석이 시작됩니다. 데이터 오프셋 설정에 대한 자세한 내용은 이 항목의 "데이터 오프셋 찾기" 섹션을 참조하세요.
- 구문 분석할 데이터의 양입니다. 이 값이 0이면 분리기는 IMFMediaBuffer::GetCurrentLength 메서드에 지정된 대로 버퍼의 끝에 도달할 때까지 구문 분석합니다.
분할은 미디어 버퍼의 데이터를 참조하여 미디어 샘플을 생성합니다. 클라이언트는 더 이상 구문 분석할 데이터가 없을 때까지 IMFASFSplitter::GetNextSample 호출하여 출력 샘플을 검색할 수 있습니다. GetNextSample 함수가 pdwStatusFlags 매개 변수에 ASF_STATUSFLAGS_INCOMPLETE 플래그를 반환하는 경우, 이는 검색할 샘플이 더 있다는 것을 의미하며, 애플리케이션에서 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;
}
관련 항목