基于iOS的网络音视频实时传输系统(二)- 捕获音视频数据
下载
GitHub:
client 端:https://github.com/AmoAmoAmo/Smart_Device_Client
server端:https://github.com/AmoAmoAmo/Smart_Device_Server
另还写了一份macOS版的server,但是目前还有一些问题,有兴趣的去看看吧:https://github.com/AmoAmoAmo/Server_Mac
获取音视频数据,这里使用的是AVCaptureSession,可以方便地自定义相机界面,看起来大概是这样的:
关于AVCaptureSession的使用步骤这里不赘述,网上一搜一大把,无非就是设置输入输出对象,设置代理、预览层之类。
这里直接上代码了,具体注释都有哦。
过程
初始化session
self.avSession = [[AVCaptureSession alloc] init];
self.avSession.sessionPreset = AVCaptureSessionPreset640x480;
// 设备对象 (audio)
AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
// 输入流
AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:nil];
// 输出流
AVCaptureAudioDataOutput *audioOutput = [[AVCaptureAudioDataOutput alloc] init];
[audioOutput setSampleBufferDelegate:self queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
// 添加输入输出流
if ([_avSession canAddInput:audioInput]) {
[_avSession addInput:audioInput];
}
if ([_avSession canAddOutput:audioOutput]) {
[_avSession addOutput:audioOutput];
}
// 设备对象 (video)
AVCaptureDevice *inputCamera = nil;
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
for (AVCaptureDevice *device in devices)
{
if ([device position] == AVCaptureDevicePositionBack)
{
inputCamera = device;
}
}
AVCaptureDeviceInput *videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:inputCamera error:nil];
if ([self.avSession canAddInput:videoInput]) {
[self.avSession addInput:videoInput];
}
self.videoOutput = [[AVCaptureVideoDataOutput alloc] init];
[self.videoOutput setAlwaysDiscardsLateVideoFrames:NO]; // 是否抛弃延迟的帧:NO
[self.videoOutput setVideoSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange] forKey:(id)kCVPixelBufferPixelFormatTypeKey]];
[self.videoOutput setSampleBufferDelegate:self queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
if ([self.avSession canAddOutput:self.videoOutput]) {
[self.avSession addOutput:self.videoOutput];
}
AVCaptureConnection *connection = [self.videoOutput connectionWithMediaType:AVMediaTypeVideo];
[connection setVideoOrientation:AVCaptureVideoOrientationLandscapeRight]; // 因为要横屏,所以让输出视频图像旋转90°
self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.avSession];
[self.previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[[self.previewLayer connection] setVideoOrientation:AVCaptureVideoOrientationLandscapeRight];// 预览层也让它右转90°
[self.previewLayer setFrame:self.captureView.bounds];
[self.captureView.layer insertSublayer:self.previewLayer above:0];
AVCapture输出流代理
设备捕获到的音视频数据都在这里取得,然后进行编码等操作。
// 默认情况下,为30 fps,意味着该函数每秒调用30次
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
// 获取输入设备数据,有可能是音频有可能是视频
if (captureOutput == self.videoOutput) {
// 收到数据,开始编码
[self.videoEncoder startH264EncodeWithSampleBuffer:sampleBuffer andReturnData:^(NSData *data) {
// 当TCP需要开始传输数据时,开始传编码后的数据
if (self.isReadyToEncode) {
// 返回一个编码后的数据 data,传给TCP 开始发送给client
[self.tcpServer sendVideoDataToClientWithData:data];
}
}];
}
else
{
// 音频
dispatch_sync(mEncodeQueue, ^{
// block回调 返回编码后的音频数据
// printf("----- audio -------\n");
[self.audioEncoder encodeSampleBuffer:sampleBuffer completionBlock:^(NSData *encodedData, NSError *error) {
printf("----- Audio encodedData length = %d ----- \n", (int)[encodedData length]);
// 写入socket
if (self.isReadyToEncode) {
[self.tcpServer sendAudioDataToClientWithData:encodedData];
}
}];
});
}
}
问题记录
server端使用VideoToolbox进行视频编码时,发现在client端解析出来的视频画面方向发生了旋转,client端如下所示:
首先排除了client端接收数据或硬解码的过程中的问题,因为把server端编码后的数据使用NSFileHandle写入文件,用VLC播放的情况与上图所示一致。
首先,判断源及目标图像是否翻转:
打印结果如下:BOOL isFlipped = CVImageBufferIsFlipped(pixelBuffer); NSLog(@"pixelBuffer is %s", isFlipped ? "flipped" : "not flipped");
发现在原始数据中,图像都是翻转的pixelBuffer is flipped
找了好久,最后发现在server端设置捕获视频的output的地方把它旋转(左右横屏):
AVCaptureConnection *connection = [self.videoOutput connectionWithMediaType:AVMediaTypeVideo]; [connection setVideoOrientation:AVCaptureVideoOrientationLandscapeRight]; // 因为要横屏,所以让输出视频图像旋转90°
运行一下:
问题就这么解决啦
相关文章
基于iOS的网络音视频实时传输系统(三)- VideoToolbox编码音视频数据为H264、AAC
基于iOS的网络音视频实时传输系统(四)- 自定义socket协议(TCP、UDP)
基于iOS的网络音视频实时传输系统(五)- 使用VideoToolbox硬解码H264
基于iOS的网络音视频实时传输系统(六)- AudioQueue播放音频,OpenGL渲染显示图像
上一篇: Debian9 安装Mysql的过程