Comment libérer correctement un AVCaptureSession
Je suis à l'aide de l'AV Foundation classes de capturer le flux vidéo en direct de la caméra et de traiter la vidéo échantillons. Cela fonctionne très bien. Cependant, j'ai des problèmes correctement libérant de l'AV de la fondation des instances (session de capture, l'aperçu de la couche d'entrée et de sortie) une fois que je suis fait.
Quand je n'ai plus besoin de la séance et tous les objets associés, j'ai arrêter la session de capture et de le relâcher. Cela fonctionne la plupart du temps. Cependant, parfois, l'application se bloque avec un EXEC_BAD_ACCESS signal soulevées dans le deuxième thread a été créé par l'envoi de la file d'attente (et où la vidéo échantillons sont traités). Le crash est dû principalement à ma propre instance de classe, qui sert de tampon d'échantillon délégué et est libéré après j'ai arrêter la session de capture.
La documentation d'Apple mentionne le problème: l'Arrêt de la session de capture est une opération asynchrone. C'est: il ne se produit pas immédiatement. En particulier, le deuxième thread continue à traiter les échantillons vidéo et d'accéder aux différentes instances de la session de capture ou l'entrée et la sortie des appareils.
Alors, comment puis-je libérer correctement la AVCaptureSession et de toutes les instances? Est-il une notification fiable me dit que le AVCaptureSession a fini?
Voici mon code:
Déclarations:
AVCaptureSession* session;
AVCaptureVideoPreviewLayer* previewLayer;
UIView* view;
Configuration d'instances:
AVCaptureDevice* camera = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
session = [[AVCaptureSession alloc] init];
AVCaptureDeviceInput* input = [AVCaptureDeviceInput deviceInputWithDevice: camera error: &error];
[session addInput: input];
AVCaptureVideoDataOutput* output = [[[AVCaptureVideoDataOutput alloc] init] autorelease];
[session addOutput: output];
dispatch_queue_t queue = dispatch_queue_create("augm_reality", NULL);
[output setSampleBufferDelegate: self queue: queue];
dispatch_release(queue);
previewLayer = [[AVCaptureVideoPreviewLayer layerWithSession: session] retain];
previewLayer.frame = view.bounds;
[view.layer addSublayer: previewLayer];
[session startRunning];
De nettoyage:
[previewLayer removeFromSuperlayer];
[previewLayer release];
[session stopRunning];
[session release];
Vous devez vous connecter pour publier un commentaire.
Voici la meilleure solution que j'ai trouvé jusqu'à présent. L'idée de base est d'utiliser l'outil de finalisation de l'envoi de la file d'attente. Lors de l'envoi de la file d'attente se ferme, on peut être sûr qu'il n'y aura plus d'action dans le deuxième thread où l'échantillon tampons sont traitées.
Malheureusement, j'ai maintenant explicitement arrêter la capture. Sinon, libérant mon exemple ne sera pas libre parce que le deuxième thread maintenant incrémente et décrémente le compteur ainsi.
Un autre problème est que ma classe est maintenant libéré de deux threads différents. Est-ce fiable ou est-ce un autre problème provoquant des plantages?
J'ai posté une question très semblable dans l'Apple Developer Forum et a obtenu une réponse d'un employé d'Apple. Il dit que c'est un problème connu:
Il/elle propose le code suivant:
J'aime toujours l'approche avec l'envoi de la file d'attente finaliseur mieux parce que ce code que conjectures, quand le deuxième thread avez terminé.
Comme par apple docs(Un)
[AVCaptureSession stopRunning]
est une opération synchrone qui bloque jusqu'à ce que le récepteur a complètement cessé de fonctionner. Donc, toutes ces questions ne devrait pas se produire plus.Résolu!
C'est peut-être la séquence de acions sur l'initialisation de la session. Celui-ci fonctionne pour moi:
Btw cette séquence semble résoudre le synchrone notifications de problème 🙂
Avec la file d'attente finaliseurs, vous pouvez utiliser un dispatch_semaphore pour chaque file d'attente, puis continuer avec votre routine de nettoyage une fois votre fait.
N'oubliez pas que vous devez définir votre AVCaptureVideoDataOutput/AVCaptureAudioDataOutput objets de tampon d'échantillon délégués à néant, ou qu'ils ne seront jamais à la libération de leurs associés les files d'attente et donc de ne jamais faire appel à leur finaliseurs lorsque vous relâchez votre AVCaptureSession.
j'ai appelé cette fonction avant de sauter et pousser tout autre point de vue. Il a résolu mon problème d'avertissement de mémoire faible.
Après AVCaptureSession allocation, vous pouvez utiliser:
Ces sont de retour d'appel les méthodes pertinentes lors de la session.stopRunning, de la session.startRunning etc.
Là, vous devriez également mettre en œuvre certaines des sans-papiers de nettoyage du bloc:
Ce que j'ai trouvé déroutant, c'est que lors de l'appel de seesion.stopRunning, onVideoStop: est appelée de manière synchrone! en dépit d'Apple asynchrone hypothèse sur le cas.
Son travail mais s'il vous plaît laissez-moi savoir dans le cas où vous voyez un truc. Je préfère travailler avec elle de manière asynchrone.
Grâce