ios - 通过 NSInputStream 和 NSOutputStream 的视频流

标签 ios video-streaming multipeer-connectivity nsinputstream

现在我正在研究通过 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 进行视频流传输?我只是没有找到太多关于这项技术的信息,我找到的只是一些我已经知道的简单的东西。

最佳答案

这是我编写的一个应用程序,向您展示了如何:

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 用于视频流……从来没有。由于一个原因,它非常复杂。

流式传输视频的方式有很多种(而且更好);我不会走这条路。我只是接受了它,因为没有其他人能够成功地做到这一点。

关于ios - 通过 NSInputStream 和 NSOutputStream 的视频流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42369838/

相关文章:

c# - Kindle Fire 视频流式传输崩溃

Android 无法实例化编解码器 'video/avc'

ios - 为什么 Multipeer Connectivity 这么慢?

ios - iOS 中的 GCD 总是创建新线程

java - MjpegView 与其他 XML 布局

iphone - 尝试将完成按钮添加到数字键盘

ios - MCSession 需要很长时间才能释放

ios - 使用 Multipeer Connectivity 发送图像

iOS 动画 : Slide a large UiImageView from Behind a small UIImageView

ios - 当提示打开另一个应用程序时,如何处理用户单击取消