您的位置:首页 > 理论基础 > 计算机网络

[置顶] 基于iOS的网络音视频实时传输系统(二)- 捕获音视频数据

2017-09-25 20:41 661 查看


下载

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的网络音视频实时传输系统(一)- 前言

基于iOS的网络音视频实时传输系统(二)- 捕获音视频数据

基于iOS的网络音视频实时传输系统(三)- VideoToolbox编码音视频数据为H264、AAC

基于iOS的网络音视频实时传输系统(四)- 自定义socket协议(TCP、UDP)

基于iOS的网络音视频实时传输系统(五)- 使用VideoToolbox硬解码H264

基于iOS的网络音视频实时传输系统(六)- AudioQueue播放音频,OpenGL渲染显示图像
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: