Génération d’exemples de flux à partir d’un objet de données ASF existant
L’objet de fractionnement ASF est un composant de couche WMContainer qui analyse l’objet de données ASF d’un fichier ASF (Advanced Systems Format).
Avant de transmettre des paquets de données au fractionnement, l’application doit initialiser, configurer et sélectionner des flux sur le séparateur afin de le préparer pour le processus d’analyse. Pour plus d’informations, consultez Création de l’objet splitter ASF et configuration de l’objet splitter ASF.
Les méthodes requises pour analyser l’objet de données ASF sont les suivantes :
- IMFASFSplitter::P arseData qui démarre le processus d’analyse en envoyant la mémoire tampon contenant des paquets de données au séparateur.
- IMFASFSplitter::GetNextSample qui collecte des échantillons de flux générés à partir de la mémoire tampon passée au séparateur.
Recherche du décalage de données
Avant de démarrer le processus d’analyse, l’application doit localiser l’objet de données dans le fichier ASF. Il existe deux façons d’obtenir le décalage de l’objet de données à partir du début du fichier :
Avant d’avoir initialisé l’objet ContentInfo, vous pouvez appeler la méthode IMFASFContentInfo::GetHeaderSize . Cette méthode nécessite une mémoire tampon qui contient les 30 premiers octets de l’en-tête ASF. Elle retourne la taille de l’en-tête entier qui indique le décalage vers le premier paquet de données. Cette valeur inclut également la taille d’en-tête de l’objet de données de 50 octets.
Après avoir initialisé l’objet ContentInfo, vous pouvez obtenir le descripteur de présentation en appelant IMFASFContentInfo::GeneratePresentationDescriptor, puis en interrogeant le descripteur de présentation pour l’attribut MF_PD_ASF_DATA_START_OFFSET . La valeur de cet attribut est la taille d’en-tête.
Notes
L’attribut MF_PD_ASF_DATA_LENGTH sur le descripteur de présentation spécifie la longueur de l’objet de données ASF.
Dans les deux cas, la valeur retournée est la taille de l’objet Header et la taille de la section d’en-tête de l’objet de données. Par conséquent, la valeur résultante est le décalage vers le début des paquets de données dans l’objet de données ASF. Lorsque vous commencez à envoyer des données au séparateur, les données doivent commencer à ce décalage à partir du début du fichier ASF.
La valeur de décalage est passée en tant que paramètre à ParseData qui démarre le processus d’analyse.
L’objet de données est divisé en paquets de données. Chaque paquet de données contient un en-tête de paquet de données qui fournit des informations d’analyse de paquets et les données de charge utile , les données multimédias numériques réelles. Dans un scénario de recherche, l’application peut souhaiter que le séparateur commence à analyser un paquet de données particulier. Pour ce faire, vous pouvez utiliser l’indexeur ASF pour récupérer le décalage. L’indexeur retourne une valeur de décalage qui commence à la limite du paquet. Si vous n’utilisez pas l’indexeur, assurez-vous que le décalage commence au début de l’en-tête de paquet de données. Si un décalage non valide est passé au séparateur, comme la valeur ne pointe pas vers la limite du paquet, les appels ParseHeader et GetNextSample réussissent, mais GetNextSample ne récupère aucun échantillon et NULL est reçu dans le paramètre pSample .
Si le séparateur est configuré pour analyser dans la direction inverse, le séparateur démarre toujours l’analyse à la fin de la mémoire tampon multimédia transmise à ParseData. Par conséquent, pour l’analyse inversée dans l’appel à ParseData, transmettez le décalage dans le paramètre cbLength , qui spécifie la longueur des données et définit cbBufferOffset sur zéro.
Génération d’exemples pour les paquets de données ASF
Une application démarre le processus d’analyse en passant les paquets de données au fractionnement. L’entrée du séparateur est une série de mémoires tampons multimédias qui contiennent l’intégralité ou les fragments de l’objet de données. La sortie du séparateur est une série d’exemples multimédias qui contiennent les données de paquet.
Pour transmettre des données d’entrée au fractionnement, créez une mémoire tampon multimédia et remplissez-la avec les données de la section Objet de données du fichier ASF. (Pour plus d’informations sur les mémoires tampons multimédias, consultez Mémoires tampons multimédias.) Ensuite, transmettez la mémoire tampon multimédia à la méthode IMFASFSplitter::P arseData . Vous pouvez également spécifier :
- Décalage dans la mémoire tampon où le séparateur doit démarrer l’analyse. Si le décalage est égal à zéro, l’analyse commence au début de la mémoire tampon. Pour plus d’informations sur la définition du décalage de données, consultez la section « Recherche du décalage de données » dans cette rubrique.
- Quantité de données à analyser. Si cette valeur est égale à zéro, le séparateur analyse jusqu’à ce qu’il atteigne la fin de la mémoire tampon, comme spécifié par la méthode IMFMediaBuffer::GetCurrentLength .
Le séparateur génère des exemples multimédias en référençant les données dans les mémoires tampons multimédias. Le client peut récupérer les échantillons de sortie en appelant IMFASFSplitter::GetNextSample dans une boucle jusqu’à ce qu’il n’y ait plus de données à analyser. Si GetNextSample retourne l’indicateur ASF_STATUSFLAGS_INCOMPLETE dans le paramètre pdwStatusFlags , cela signifie qu’il existe davantage d’exemples à récupérer et que l’application peut appeler à nouveau GetNextSample . Sinon, appelez ParseData pour passer plus de données au séparateur. Pour les exemples générés, le séparateur définit les informations suivantes :
- Le séparateur définit un horodatage sur tous les exemples qu’il génère. L’exemple d’heure représente l’heure de présentation et n’inclut pas l’heure de préroll. L’application peut appeler IMFSample::GetSampleTime pour obtenir l’heure de présentation, en unités de 100 nanosecondes.
- Si un saut se produit pendant la génération de l’exemple, le séparateur définit l’attribut MFSampleExtension_Discontinuity sur le premier échantillon après la discontinuité. Les discontinuités sont généralement causées par des paquets supprimés sur une connexion réseau, des données de fichier endommagées ou le basculement d’un flux source vers un autre.
- Pour la vidéo, le séparateur vérifie si l’exemple contient une image clé. Si c’est le cas, le séparateur définit l’attribut MFSampleExtension_CleanPoint sur l’exemple.
Si le séparateur analyse les paquets de données reçus d’un serveur multimédia, il est possible que la longueur du paquet soit variable. Dans ce cas, le client doit appeler ParseData pour chaque paquet et définir l’attribut MFASFSPLITTER_PACKET_BOUNDARY sur chaque mémoire tampon envoyée au séparateur. Cet attribut indique au fractionnement si la mémoire tampon multimédia contient le début d’un paquet ASF. Définissez l’attribut sur TRUE si la mémoire tampon contient le début d’un nouveau paquet. Si la mémoire tampon contient une continuation du paquet précédent, définissez l’attribut sur FALSE. Les mémoires tampons ne peuvent pas s’étendre sur plusieurs paquets.
Avant de passer de nouvelles mémoires tampons multimédias au séparateur, l’application doit appeler IMFASFSplitter::Flush. Cette méthode réinitialise le séparateur et efface toute trame partielle en attente d’achèvement. Cela est utile dans un scénario de recherche où le décalage se trouve à un autre emplacement.
Exemple
L’exemple de code suivant montre comment analyser les paquets de données. Cet exemple analyse du début de l’objet de données à la fin du flux et affiche des informations sur les exemples qui contiennent des images clés. Pour obtenir un exemple complet qui utilise ce code, consultez Tutoriel : Lecture d’un fichier 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;
}
Rubriques connexes