目前我正在研究通过MultipeerConnectivity框架实现视频流的可能性。为此,我正在使用NSInputStream和NSOutputStream。
问题是:到目前为止我无法收到任何图片。现在我正试图通过简单的图片并在接收器上显示它。这是我的代码的一小部分:
通过NSOutputStream发送图片:
- (void)sendMessageToStream
{
NSData *imgData = UIImagePNGRepresentation(_testImage);
int img_length = (int)[imgData length];
NSMutableData *msgData = [[NSMutableData alloc] initWithBytes:&img_length length:sizeof(img_length)];
[msgData appendData:imgData];
int msg_length = (int)[msgData length];
uint8_t *readBytes = (uint8_t *)[msgData bytes];
uint8_t buf[msg_length];
(void)memcpy(buf, readBytes, msg_length);
int stream_len = [_stream writeData:(uint8_t*)buf maxLength:msg_length];
//int stream_len = [_stream writeData:(uint8_t *)buf maxLength:data_length];
//NSLog(@"stream_len = %d", stream_len);
_tmpCounter++;
dispatch_async(dispatch_get_main_queue(), ^{
_lblOperationsCounter.text = [NSString stringWithFormat:@"Sent: %ld", (long)_tmpCounter];
});
}
上面的代码完全正常。写入后的stream_len参数等于29627字节,这是预期值,因为图像的大小约为25-26 kb。
通过NSinputStream接收图片:
- (void)readDataFromStream
{
UInt32 length;
if (_currentFrameSize == 0) {
uint8_t frameSize[4];
length = [_stream readData:frameSize maxLength:sizeof(int)];
unsigned int b = frameSize[3];
b <<= 8;
b |= frameSize[2];
b <<= 8;
b |= frameSize[1];
b <<= 8;
b |= frameSize[0];
_currentFrameSize = b;
}
uint8_t bytes[1024];
length = [_stream readData:bytes maxLength:1024];
[_frameData appendBytes:bytes length:length];
if ([_frameData length] >= _currentFrameSize) {
UIImage *img = [UIImage imageWithData:_frameData];
NSLog(@"SETUP IMAGE!");
_imgView.image = img;
_currentFrameSize = 0;
[_frameData setLength:0];
}
_tmpCounter++;
dispatch_async(dispatch_get_main_queue(), ^{
_lblOperationsCounter.text = [NSString stringWithFormat:@"Received: %ld", (long)_tmpCounter];
});
}
正如你所看到的,我试图通过几个步骤接收图片,这就是原因。当我尝试从流中读取数据时,无论我在maxLength:
参数中放入什么数字,它总是读取最大1095个字节。但是当我在第一段代码中发送图片时,它发送的绝对正常(29627字节。顺便说一句,图像的大小约为29 kb。
这就是我的问题出现的地方 - 为什么会这样?为什么通过NSOutputStream发送29 kb在接收导致问题时完全正常?有没有一种可靠的方法让视频流通过NSInputStream和NSOutputStream工作?我只是没有找到关于这项技术的更多信息,我发现的只是一些我已经知道的简单事情。
答案 0 :(得分:1)
这是我写的一个应用程序,向您展示如何:
https://app.box.com/s/94dcm9qjk8giuar08305qspdbe0pc784
使用Xcode 9构建项目并在两台iOS 11设备上运行应用程序。
要播放实时视频,请触摸两个设备之一上的“相机”图标。
如果您没有两台设备,可以在模拟器中运行一个应用程序;但是,您只能在真实设备上使用相机(模拟器将显示播放的视频)。
您也知道:这不是在设备之间传输实时视频的理想方式(它应该是您的最后选择)。数据包(与流式传输)相比,效率更高,速度更快。
无论如何,我对你的NSInputStream相关代码感到困惑。我认为,这是一些更有意义的事情:
case NSStreamEventHasBytesAvailable: {
// len is a global variable set to a non-zero value;
// mdata is a NSMutableData object that is reset when a new input
// stream is created.
// displayImage is a block that accepts the image data and a reference
// to the layer on which the image will be rendered
uint8_t * buf[len];
len = [aStream read:(uint8_t *)buf maxLength:len];
if (len > 0) {
[mdata appendBytes:(const void *)buf length:len];
} else {
displayImage(mdata, wLayer);
}
break;
}
输出流代码应如下所示:
// data is an NSData object that contains the image data from the video
// camera;
// len is a global variable set to a non-zero value
// byteIndex is a global variable set to zero each time a new output
// stream is created
if (data.length > 0 && len >= 0 && (byteIndex <= data.length)) {
len = (data.length - byteIndex) < DATA_LENGTH ? (data.length - byteIndex) : DATA_LENGTH;
uint8_t * bytes[len];
[data getBytes:&bytes range:NSMakeRange(byteIndex, len)];
byteIndex += [oStream write:(const uint8_t *)bytes maxLength:len];
}
流媒体视频比正确设置NSStream类还要多得多。您在我的应用程序中注意到,我为输入和输出流创建了一个缓存。这解决了你可能遇到的无数问题,如果你不这样做的话。
我从未见过有人成功使用NSStreams进行视频流播放......由于某种原因,它非常复杂。
有许多不同(和更好)的视频流方式;我不会走这条路。我只是接受了它,因为没有其他人能够成功地完成它。
答案 1 :(得分:0)
我认为问题在于您假设所有数据在您阅读时始终在NSInputStream
中可用。 NSInputStream
对象生成的NSURL
具有异步性质,应使用NSStreamDelegate
进行相应访问。您可以在POSInputStreamLibrary的自述文件中查看示例。