J'ai travaillé sur la lecture d'un asset audio en utilisant AVAssetReader pour que je puisse plus tard lire l'audio avec un AUGraph avec un rappel AudioUnit. J'ai le rappel AUGraph et AudioUnit fonctionnant mais il lit des dossiers du disque et si le dossier est trop grand cela prendrait trop de mémoire et écraserait l'application. Donc, je lis plutôt l'actif directement et seulement une taille limitée. Je vais ensuite le gérer comme un double tampon et obtenir le AUGraph ce dont il a besoin quand il en a besoin.Comment vous ajoutez à un AudioBufferList avec un AVAssetReader?
(Note: J'aimerais savoir si je peux utiliser les services de file d'attente audio et utilisez toujours un AUGraph avec rappel AudioUnit si la mémoire me est gérée par les cadres iOS.)
Mon problème est que je n'ai pas une bonne compréhension des tableaux, des structures et des pointeurs en C. La partie où j'ai besoin d'aide prend l'AudioBufferList individuel qui tient sur un seul AudioBuffer et ajoute ces données à une autre AudioBufferList qui conserve toutes les données à utiliser plus tard. Je crois que j'ai besoin d'utiliser memcpy mais il n'est pas clair comment l'utiliser ou même initialiser un AudioBufferList à mes fins. J'utilise MixerHost pour référence qui est le projet exemple d'Apple qui lit dans le fichier à partir du disque.
J'ai téléchargé mon travail en cours si vous souhaitez le charger dans Xcode. J'ai trouvé la plupart de ce dont j'ai besoin pour faire cela et une fois que j'ai les données recueillies en un seul endroit, je devrais être bon à faire.
Exemple de projet: MyAssetReader.zip
Dans l'en-tête, vous pouvez voir que je déclare la bufferList comme un pointeur vers la struct.
@interface MyAssetReader : NSObject {
BOOL reading;
signed long sampleTotal;
Float64 totalDuration;
AudioBufferList *bufferList; // How should this be handled?
}
J'allouent bufferList cette façon, en grande partie empruntant MixerHost ...
UInt32 channelCount = [asset.tracks count];
if (channelCount > 1) {
NSLog(@"We have more than 1 channel!");
}
bufferList = (AudioBufferList *) malloc (
sizeof (AudioBufferList) + sizeof (AudioBuffer) * (channelCount - 1)
);
if (NULL == bufferList) {NSLog (@"*** malloc failure for allocating bufferList memory"); return;}
// initialize the mNumberBuffers member
bufferList->mNumberBuffers = channelCount;
// initialize the mBuffers member to 0
AudioBuffer emptyBuffer = {0};
size_t arrayIndex;
for (arrayIndex = 0; arrayIndex < channelCount; arrayIndex++) {
// set up the AudioBuffer structs in the buffer list
bufferList->mBuffers[arrayIndex] = emptyBuffer;
bufferList->mBuffers[arrayIndex].mNumberChannels = 1;
// How should mData be initialized???
bufferList->mBuffers[arrayIndex].mData = malloc(sizeof(AudioUnitSampleType));
}
Enfin, je boucle à travers les lectures.
int frameCount = 0;
CMSampleBufferRef nextBuffer;
while (assetReader.status == AVAssetReaderStatusReading) {
nextBuffer = [assetReaderOutput copyNextSampleBuffer];
AudioBufferList localBufferList;
CMBlockBufferRef blockBuffer;
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(nextBuffer, NULL, &localBufferList, sizeof(localBufferList), NULL, NULL,
kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, &blockBuffer);
// increase the number of total bites
bufferList->mBuffers[0].mDataByteSize += localBufferList.mBuffers[0].mDataByteSize;
// carefully copy the data into the buffer list
memcpy(bufferList->mBuffers[0].mData + frameCount, localBufferList.mBuffers[0].mData, sizeof(AudioUnitSampleType));
// get information about duration and position
//CMSampleBufferGet
CMItemCount sampleCount = CMSampleBufferGetNumSamples(nextBuffer);
Float64 duration = CMTimeGetSeconds(CMSampleBufferGetDuration(nextBuffer));
Float64 presTime = CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(nextBuffer));
if (isnan(duration)) duration = 0.0;
if (isnan(presTime)) presTime = 0.0;
//NSLog(@"sampleCount: %ld", sampleCount);
//NSLog(@"duration: %f", duration);
//NSLog(@"presTime: %f", presTime);
self.sampleTotal += sampleCount;
self.totalDuration += duration;
frameCount++;
free(nextBuffer);
}
Je ne suis pas sûr de la ce que je manipule mDataByteSize et MDATA, en particulier avec memcpy. Puisque mData est un pointeur vide, c'est une zone compliquée.
memcpy(bufferList->mBuffers[0].mData + frameCount, localBufferList.mBuffers[0].mData, sizeof(AudioUnitSampleType));
Dans cette ligne, je pense qu'il devrait être copier la valeur à partir des données localBufferList à la position dans le bufferList plus le nombre de cadres pour positionner le pointeur où il doit écrire les données. J'ai quelques idées sur ce que je dois changer pour que cela fonctionne.
- Comme un pointeur vide est juste 1 et non la taille du pointeur pour un AudioUnitSampleType je peux avoir besoin de multiplier aussi par sizeof (AudioUnitSampleType) pour obtenir le memcpy dans la bonne position
- Je ne peux pas être en utilisant malloc correctement pour préparer MDATA mais comme je ne suis pas sûr du nombre de cadres, il y aura je ne suis pas sûr de ce qu'il faut faire pour l'initialiser
Actuellement quand je lance cette application, il termine cette fonction avec un pointeur non valide pour bufferList .
J'apprécie votre aide pour me permettre de mieux comprendre comment gérer une AudioBufferList.
J'ai appris plus sur les pointeurs void et comment utiliser malloc et memcpy qui semblent être un élément clé de la compréhension de la structure AudioBufferList. J'aurai besoin de savoir comment conserver les valeurs dans un tableau dynamique en C. Je lis des fonctions comme celles-ci qui ont été ajoutées avec C99. Je continue à lire à ce sujet. – Brennan
Je pense que je vais accumuler les valeurs de AudioBuffer à un tableau qui est développé avec ralloc mais je peux le faire avec des blocs de 100 afin que realloc ne soit pas appelé à chaque itération. Ensuite, je peux créer un tableau de taille dynamique après la boucle, utiliser memcpy pour remplir ce tableau avec les valeurs accumulées, puis définir mData sur le tampon avec ce tableau. – Brennan