Condividi tramite


Generazione di esempi di flusso da un oggetto dati ASF esistente

L'oggetto splitter ASF è un componente livello WMContainer che analizza l'oggetto dati ASF di un file ASF (Advanced Systems Format).

Prima di passare pacchetti di dati al splitter, l'applicazione deve inizializzare, configurare e selezionare i flussi nel splitter per prepararlo per il processo di analisi. Per informazioni, vedere Creazione dell'oggetto Splitter ASF e Configurazione dell'oggetto Splitter ASF.

I metodi necessari per l'analisi dell'oggetto dati ASF sono:

Individuazione dell'offset dei dati

Prima di avviare il processo di analisi, l'applicazione deve individuare l'oggetto dati all'interno del file ASF. Esistono due modi per ottenere l'offset dell'oggetto dati dall'inizio del file:

  • Prima di aver inizializzato l'oggetto ContentInfo, è possibile chiamare il metodo IMFASFContentInfo::GetHeaderSize . Questo metodo richiede un buffer contenente i primi 30 byte dell'intestazione ASF. Restituisce le dimensioni dell'intera intestazione che indica l'offset al primo pacchetto di dati. Questo valore include anche le dimensioni dell'intestazione oggetto dati di 50 byte.

  • Dopo aver inizializzato l'oggetto ContentInfo, è possibile ottenere il descrittore di presentazione chiamando FMASFContentInfo::GeneratePresentationDescriptor e quindi eseguendo una query sul descrittore di presentazione per l'attributo MF_PD_ASF_DATA_START_OFFSET . Il valore di questo attributo è la dimensione dell'intestazione.

    Nota

    L'attributo MF_PD_ASF_DATA_LENGTH nel descrittore di presentazione specifica la lunghezza dell'oggetto dati ASF.

     

In entrambi i casi, il valore restituito è la dimensione dell'oggetto Intestazione e le dimensioni della sezione intestazione dell'oggetto dati. Pertanto, il valore risultante è l'offset all'inizio dei pacchetti di dati nell'oggetto dati ASF. Quando si inizia a inviare dati al splitter, i dati devono iniziare a partire dall'inizio del file ASF.

Il valore di offset viene passato come parametro a ParseData che avvia il processo di analisi.

L'oggetto dati è diviso in pacchetti di dati. Ogni pacchetto di dati contiene un'intestazione del pacchetto di dati che fornisce informazioni sull'analisi dei pacchetti e i dati del payload, ovvero i dati multimediali digitali effettivi. In uno scenario di ricerca, l'applicazione potrebbe voler avviare l'analisi in un determinato pacchetto di dati. A tale scopo, è possibile usare l'indicizzatore ASF per recuperare l'offset. L'indicizzatore restituisce un valore di offset che inizia al limite del pacchetto. Se non si usa l'indicizzatore, assicurarsi che l'offset inizi all'inizio dell'intestazione del pacchetto di dati. Se un offset non valido viene passato al splitter, ad esempio il valore non punta al limite del pacchetto, Le chiamate ParseHeader e GetNextSample hanno esito positivo, ma GetNextSample non recupera esempi e NULL viene ricevuto nel parametro pSample .

Se il splitter è configurato per l'analisi nella direzione inversa, il splitter avvia sempre l'analisi alla fine del buffer multimediale passato a ParseData. Pertanto, per l'analisi inversa nella chiamata a ParseData, passare l'offset nel parametro cbLength , che specifica la lunghezza dei dati e impostare cbBufferOffset su zero.

Generazione di esempi per pacchetti di dati ASF

Un'applicazione avvia il processo di analisi passando i pacchetti di dati al splitter. L'input del splitter è una serie di buffer multimediali che contengono l'intero o i frammenti dell'oggetto dati. L'output del splitter è una serie di esempi multimediali che contengono i dati del pacchetto.

Per passare i dati di input al splitter, creare un buffer multimediale e riempirlo con dati dalla sezione Oggetto dati del file ASF. Per altre informazioni sui buffer multimediali, vedere Buffer multimediali. Passare quindi il buffer multimediale al metodo IMFASFSplitter::P arseData . È inoltre possibile specificare:

  • Offset nel buffer in cui deve iniziare l'analisi del splitter. Se l'offset è zero, l'analisi inizia all'inizio del buffer. Per informazioni sull'impostazione dell'offset dei dati, vedere la sezione "Ricerca dell'offset dati" in questo argomento.
  • Quantità di dati da analizzare. Se questo valore è zero, il splitter analizza finché non raggiunge la fine del buffer, come specificato dal metodo FMMediaBuffer::GetCurrentLength .

Il splitter genera esempi multimediali facendo riferimento ai dati nei buffer multimediali. Il client può recuperare gli esempi di output chiamando FMASFSplitter::GetNextSample in un ciclo finché non sono presenti altri dati da analizzare. Se GetNextSample restituisce il flag di ASF_STATUSFLAGS_INCOMPLETE nel parametro pdwStatusFlags , significa che sono disponibili altri esempi da recuperare e l'applicazione può chiamare di nuovo GetNextSample . In caso contrario, chiamare ParseData per passare più dati al splitter. Per gli esempi generati, il splitter imposta le informazioni seguenti:

  • Il splitter imposta un timestamp su tutti gli esempi generati. L'ora di esempio rappresenta l'ora di presentazione e non include l'ora di preroll. L'applicazione può chiamare FMSample::GetSampleTime per ottenere il tempo di presentazione in 100-nanosecondi.
  • Se si verifica un'interruzione durante la generazione di esempio, il splitter imposta l'attributo MFSampleExtension_Discontinuity nel primo esempio dopo la discontinuità. Le interruzioni sono in genere causate da pacchetti eliminati in una connessione di rete, dati di file danneggiati o il cambio di divisione da un flusso di origine a un altro.
  • Per il video, il splitter verifica se l'esempio contiene un fotogramma chiave. In caso contrario, il splitter imposta l'attributo MFSampleExtension_CleanPoint nell'esempio.

Se il splitter analizza i pacchetti di dati ricevuti da un server multimediale, è possibile che la lunghezza del pacchetto sia variabile. In questo caso, il client deve chiamare ParseData per ogni pacchetto e impostare l'attributo MFASFSPLITTER_PACKET_BOUNDARY su ogni buffer inviato al splitter. Questo attributo indica al splitter se il buffer multimediale contiene l'inizio di un pacchetto ASF. Impostare l'attributo su TRUE se il buffer contiene l'inizio di un nuovo pacchetto. Se il buffer contiene una continuazione del pacchetto precedente, impostare l'attributo su FALSE. I buffer non possono estendersi su più pacchetti.

Prima di passare nuovi buffer multimediali al splitter, l'applicazione deve chiamare FMASFSplitter::Flush. Questo metodo reimposta lo splitter e cancella qualsiasi frame parziale in attesa di completamento. Questo è utile in uno scenario di ricerca in cui l'offset si trova in una posizione diversa.

Esempio

Nell'esempio di codice seguente viene illustrato come analizzare i pacchetti di dati. In questo esempio viene analizzato dall'inizio dell'oggetto dati alla fine del flusso e vengono visualizzate informazioni sugli esempi che contengono fotogrammi chiave. Per un esempio completo che usa questo codice, vedere Esercitazione: Lettura di un file 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;
}

ASF Splitter