ビデオをキャプチャしてiPhoneカメラからリアルタイムフレームを取得するために使用AVCaptureSession
していますが、フレームとサウンドを多重化してサーバーに送信する方法と、ffmpegを使用してこのタスクを完了する方法を教えてください。ここで共有します。
3 に答える
私がやっている方法は、すべてのフレームで実行されるコールバックを持つデリゲートを持つ AVCaptureSession を実装することです。そのコールバックは、ネットワークを介して各フレームをサーバーに送信します。サーバーには、それを受信するためのカスタム設定があります。
フローは次のとおりです。
そして、ここにいくつかのコードがあります:
// make input device
NSError *deviceError;
AVCaptureDevice *cameraDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *inputDevice = [AVCaptureDeviceInput deviceInputWithDevice:cameraDevice error:&deviceError];
// make output device
AVCaptureVideoDataOutput *outputDevice = [[AVCaptureVideoDataOutput alloc] init];
[outputDevice setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
// initialize capture session
AVCaptureSession *captureSession = [[[AVCaptureSession alloc] init] autorelease];
[captureSession addInput:inputDevice];
[captureSession addOutput:outputDevice];
// make preview layer and add so that camera's view is displayed on screen
AVCaptureVideoPreviewLayer *previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:captureSession];
previewLayer.frame = view.bounds;
[view.layer addSublayer:previewLayer];
// go!
[captureSession startRunning];
次に、出力デバイスのデリゲート (ここでは自己) がコールバックを実装する必要があります。
-(void) captureOutput:(AVCaptureOutput*)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection*)connection
{
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer( sampleBuffer );
CGSize imageSize = CVImageBufferGetEncodedSize( imageBuffer );
// also in the 'mediaSpecific' dict of the sampleBuffer
NSLog( @"frame captured at %.fx%.f", imageSize.width, imageSize.height );
}
生のフレームまたは個々の画像を送信しても、十分に機能することはありません (データ量とフレーム数のため)。また、電話から合理的にサービスを提供することもできません (WWAN ネットワークにはあらゆる種類のファイアウォールがあります)。ビデオをエンコードし、サーバーにストリーミングする必要があります。ほとんどの場合、標準のストリーミング形式 (RTSP、RTMP) を使用します。iPhone >= 3GS には H.264 エンコーダ チップがあります。問題は、ストリーム指向ではないことです。つまり、ビデオを最後に解析するために必要なメタデータを出力します。これにより、いくつかのオプションが残ります。
1) 生データを取得し、FFmpeg を使用して電話でエンコードします (大量の CPU とバッテリーを使用します)。
2) H.264/AAC 出力用の独自のパーサーを作成します (非常に難しい)。
3) チャンクで記録および処理します (チャンクの長さに等しいレイテンシーが追加され、セッションを開始および停止すると、各チャンク間で約 1/4 秒のビデオがドロップされます)。
それには長い話と短い話があります。
これは短いものです: https://github.com/OpenWatch/H264-RTSP-Server-iOSを見てください。
これが出発点です。
あなたはそれを手に入れて、彼がどのようにフレームを抽出するかを見ることができます. これは小さくて単純なプロジェクトです。
次に、特定の関数「encodedFrame」を持つキックフリップを確認できます。これは一度コールバックされ、エンコードされたフレームがこの時点から到着し、Websocket 経由で送信することができます。mpeg アトムを読み取ることができる非常にハードなコードがたくさんあります
AV Foundation フレームワークを使用してビデオをキャプチャしてみてください。HTTP ストリーミングでサーバーにアップロードします。
以下のスタック別のスタックオーバーフローの投稿もチェックしてください
あなたはおそらくすでに知っているでしょう....
1) How to get compressed frames and audio from iPhone's camera?
これはできません。AVFoundation API は、これをあらゆる角度から防止してきました。名前付きパイプや、その他の卑劣な UNIX foo も試しました。そのような幸運はありません。ファイルに書き込むしかありません。リンクされた投稿では、エンコードされたフレームを配信するようにコールバックを設定することをユーザーが提案しています。私の知る限り、これは H.264 ストリームでは不可能です。キャプチャ デリゲートは、特定のピクセル形式でエンコードされた画像を配信します。エンコードを行うのは Movie Writer と AVAssetWriter です。
2) Encoding uncompressed frames with ffmpeg's API is fast enough for
real-time streaming?
はい、そうです。ただし、GPL の領域に入る libx264 を使用する必要があります。それはアプリストアと完全に互換性がありません。
効率的な理由から、AVFoundation と AVAssetWriter を使用することをお勧めします。