2017-03-05 67 views
5

Używam WebRTC do zbudowania czatu wideo między dwoma użytkownikami. Chcę zrobić migawkę widoku localView, który pokazuje jedną z osób.Robienie migawki widoku AVCaptureVideoPreviewLayer

To moja klasa z metodą configureLocalPreview który łączy strumienie wideo z UIViews:

@IBOutlet var remoteView: RTCEAGLVideoView! 
@IBOutlet var localView: UIView! 

var captureSession: AVCaptureSession? 
var videoSource: RTCAVFoundationVideoSource? 
var videoTrack: RTCVideoTrack? 

func configureLocalPreview() { 
    self.videoTrack = self.signaling.localMediaStream.self.videoTracks.first as! RTCVideoTrack? 
    self.videoSource = (self.videoTrack?.source as? RTCAVFoundationVideoSource) 
    self.captureSession = self.videoSource?.self.captureSession 

    self.previewLayer = AVCaptureVideoPreviewLayer.init(session: self.captureSession) 
    self.previewLayer.frame = self.localView.bounds 
    self.localView.layer.addSublayer(self.previewLayer) 
    self.localView.isUserInteractionEnabled = true 
    //self.localView.layer.position = CGPointMake(100, 100); 
} 

w miejscu chcę otworzyć migawkę, wzywam:

self.localView.pb_takeSnapshot() 

pb_takeSnapshot przychodzi z rozszerzenia UIView, które znalazłem w innym poście. Jest zdefiniowany następująco:

extension UIView { 
    func pb_takeSnapshot() -> UIImage { 
    UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.main.scale) 

    drawHierarchy(in: self.bounds, afterScreenUpdates: true) 

    let image = UIGraphicsGetImageFromCurrentImageContext()! 
    UIGraphicsEndImageContext() 
    return image 
    } 
} 

Kiedy spojrzeć na obraz w debugera Xcode, wygląda zupełnie zielony, a osoba, której mogę zobaczyć na ekranie iPhone (wewnątrz tego poglądu), nie jest tam:

screenshot of the snapshot

Co może dlatego, że dana osoba nie jest widoczny? Czy nie jest możliwe zrobienie migawki strumienia? Dziękujemy za obejrzenie!

Odpowiedz

2

Ponieważ AVCaptureVideoPreviewLayer jest zaimplementowana jako warstwa OpenGL, nie można używać zwykłego kontekstu CoreGraphic. Mogę zasugerować próbę uzyskania dostępu do nieprzetworzonych danych.

Dodaj AVCaptureVideoDataOutput z delegatem:

previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) 

let captureVideoOutput = AVCaptureVideoDataOutput() 
captureVideoOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main) 
captureSession?.addOutput(captureVideoOutput) 

previewLayer.frame = localView.bounds 

Zgodne kontroler (lub cokolwiek) do AVCaptureVideoDataOutputSampleBufferDelegate.

Zadeklaruj shouldCaptureFrame zmienną i ustaw ją w dowolnym momencie, aby zrobić zdjęcie.

var shouldCaptureFrame: Bool = false 
... 
func takeSnapshot() { 
    shouldCaptureFrame = true 
} 

i wdrożenie didOutputSampleBuffer od delegata:

func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) { 
    if !shouldCaptureFrame { 
    return 
    } 

    let image = UIImage.from(sampleBuffer: sampleBuffer) 
    shouldCaptureFrame = false 
} 

Wreszcie rozszerzenie z from(sampleBuffer:) funkcji:

extension UIImage { 

    static func from(sampleBuffer: CMSampleBuffer) -> UIImage? { 
     guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { 
      return nil 
     } 
     CVPixelBufferLockBaseAddress(imageBuffer, CVPixelBufferLockFlags(rawValue: 0)) 
     let baseAddresses = CVPixelBufferGetBaseAddress(imageBuffer) 
     let colorSpace = CGColorSpaceCreateDeviceRGB() 
     let context = CGContext(
      data: baseAddresses, 
      width: CVPixelBufferGetWidth(imageBuffer), 
      height: CVPixelBufferGetHeight(imageBuffer), 
      bitsPerComponent: 8, 
      bytesPerRow: CVPixelBufferGetBytesPerRow(imageBuffer), 
      space: colorSpace, 
      bitmapInfo: CGBitmapInfo.byteOrder32Little.rawValue 
     ) 
     let quartzImage = context?.makeImage() 
     CVPixelBufferUnlockBaseAddress(imageBuffer, CVPixelBufferLockFlags(rawValue: 0)) 

     if let quartzImage = quartzImage { 
      let image = UIImage(cgImage: quartzImage) 
      return image 
     } 

     return nil 
    } 

} 
3

Należy stworzyć localView używając RTCEAGLVideoView zamiast UIView. Używam tego samego dla mojego localView i mogę zrobić migawkę za pomocą tego samego fragmentu kodu, jak wspomniano w twoim poście.

Poniżej znajduje się przykładowy kod, który rozpocznie swój aparat i pokazać podgląd lokalny:

class ViewController: UIViewController,RTCEAGLVideoViewDelegate { 

var captureSession: AVCaptureSession? 
var previewLayer :AVCaptureVideoPreviewLayer? 
var peerConnectionFactory: RTCPeerConnectionFactory! 
var videoSource:RTCAVFoundationVideoSource! 
var localTrack :RTCVideoTrack! 

@IBOutlet var myView: UIView! 
override func viewDidLoad() { 
    super.viewDidLoad() 
    /*myView = UIView(frame: CGRect(x: 0, 
           y: 0, 
           width: UIScreen.main.bounds.size.width, 
           height: UIScreen.main.bounds.size.height))*/ 
    startCamera() 
    // Do any additional setup after loading the view, typically from a nib. 
} 

fileprivate func startCamera() { 

    peerConnectionFactory = RTCPeerConnectionFactory() 
    RTCInitializeSSL(); 
    RTCSetupInternalTracer(); 
    RTCSetMinDebugLogLevel(RTCLoggingSeverity.info) 

    videoSource = peerConnectionFactory.avFoundationVideoSource(with: nil); 


    localTrack = peerConnectionFactory.videoTrack(with: videoSource, trackId: "ARDAMSv0") 



    let localScaleX = CGFloat(1.0) 
    let localView : RTCEAGLVideoView = RTCEAGLVideoView(frame: self.view.bounds) 
    self.view.insertSubview(localView, at: 1) 
    localView.frame = self.view.bounds; 
    localView.transform = CGAffineTransform(scaleX: localScaleX, y: 1) 

    localTrack.add(localView) 
} 


override func didReceiveMemoryWarning() { 
    super.didReceiveMemoryWarning() 
    // Dispose of any resources that can be recreated. 
} 

override func viewDidAppear(_ animated: Bool) { 
    //previewLayer?.frame.size = myView.frame.size 
} 

func videoView(_ videoView: RTCEAGLVideoView, didChangeVideoSize size: CGSize) { 
    print("Inside didChangeVideoSize") 
} 

} 
+0

Dziękuję za odpowiedź, jestem nieco zdezorientowany, jak wyglądałby rzeczywisty kod, chociaż próbowałem tak wielu różnych kodów wersje. – Linus

+0

@Linus Zaktualizowałem post z przykładowym fragmentem kodu, za pomocą którego można uruchomić kamerę i zobaczyć podgląd lokalny. –

1

Dla warstwy wideo WebRTC należy użyć RTCEAGLVideoView dla widoków. Aby uzyskać więcej informacji, zapoznaj się z przykładową aplikacją WebRTC, która jest tutaj: AppRTC App