iOS 基于实时音视频 SDK 实现屏幕共享功能——2

/uploads/files_user1/article/5fc8bd1c34156270201.png

iOS 基于实时音视频 SDK 实现屏幕共享功能——1

iOS 基于实时音视频 SDK 实现屏幕共享功能——2

iOS 基于实时音视频 SDK 实现屏幕共享功能——3

iOS 基于实时音视频 SDK 实现屏幕共享功能——4



这里的核心思想是拿到屏幕共享的数据之后,先进行压缩,当压缩完成后会通过回调上报给当前类。既而通过 clientSend 方法,发给主 App。发给主 App 的数据中自定义了一个头部,头部添加了一个前缀和一个每次发送字节的长度,当接收端收到数据包后解析即可。

- (void)clientSend:(NSData *)data {
    //data length
    NSUInteger dataLength = data.length;
    // data header struct
    DataHeader dataH;
    memset((void *)&dataH, 0, sizeof(dataH));
    // pre
    PreHeader preH;
    memset((void *)&preH, 0, sizeof(preH));
    preH.pre[0] = '&';
    preH.dataLength = dataLength;
    dataH.preH = preH;
    // buffer
    int headerlength = sizeof(dataH);
    int totalLength = dataLength + headerlength;
    // srcbuffer
    Byte *src = (Byte *)[data bytes];
    // send buffer
    char *buffer = (char *)malloc(totalLength * sizeof(char));
    memcpy(buffer, &dataH, headerlength);
    memcpy(buffer + headerlength, src, dataLength);
    // to send
    [self sendBytes:buffer length:totalLength];
    free(buffer);
}

1.4 接收屏幕共享数据

//
//  RongRTCServerSocket.m
//  SealRTC
//
//  Created by Sun on 2020/5/7.
//  Copyright © 2020 RongCloud. All rights reserved.
//
#import "RongRTCServerSocket.h"
#import <arpa/inet.h>
#import <netdb.h>
#import <sys/types.h>
#import <sys/socket.h>
#import <ifaddrs.h>
#import <UIKit/UIKit.h>
#import "RongRTCThread.h"
#import "RongRTCSocketHeader.h"
#import "RongRTCVideoDecoder.h"
@interface RongRTCServerSocket() <RongRTCCodecProtocol>
{
    pthread_mutex_t lock;
    int _frameTime;
    CMTime _lastPresentationTime;
    Float64 _currentMediaTime;
    Float64 _currentVideoTime;
    dispatch_queue_t _frameQueue;
}
@property (nonatomic, assign) int acceptSocket;
/**
 data length
 */
@property (nonatomic, assign) NSUInteger dataLength;
/**
 timeData
 */
@property (nonatomic, strong) NSData *timeData;
/**
 decoder queue
 */
@property (nonatomic, strong) dispatch_queue_t decoderQueue;
/**
 decoder
 */
@property (nonatomic, strong) RongRTCVideoDecoder *decoder;
@end
@implementation RongRTCServerSocket
- (BOOL)createServerSocket {
    if ([self createSocket] == -1) {
        return NO;
    }
    [self setReceiveBuffer];
    [self setReceiveTimeout];
    BOOL isB = [self bind];
    BOOL isL = [self listen];
    if (isB && isL) {
        _decoderQueue = dispatch_queue_create("cn.rongcloud.decoderQueue", NULL);
        _frameTime = 0;
        [self createDecoder];
        [self receive];
        return YES;
    } else {
        return NO;
    }
}
- (void)createDecoder {
    self.decoder = [[RongRTCVideoDecoder alloc] init];
    self.decoder.delegate = self;
    RongRTCVideoEncoderSettings *settings = [[RongRTCVideoEncoderSettings alloc] init];
    settings.width = 720;
    settings.height = 1280;
    settings.startBitrate = 300;
    settings.maxFramerate = 30;
    settings.minBitrate = 1000;
    [self.decoder configWithSettings:settings onQueue:_decoderQueue];
}
- (void)receiveData {
    struct sockaddr_in rest;
    socklen_t rest_size = sizeof(struct sockaddr_in);
    self.acceptSocket = accept(self.socket, (struct sockaddr *) &rest, &rest_size);
    while (self.acceptSocket != -1) {
        DataHeader dataH;
        memset(&dataH, 0, sizeof(dataH));
        if (![self receiveData:(char *)&dataH length:sizeof(dataH)]) {
            continue;
        }
        PreHeader preH = dataH.preH;
        char pre = preH.pre[0];
        if (pre == '&') {
            // rongcloud socket
            NSUInteger dataLenght = preH.dataLength;
            char *buff = (char *)malloc(sizeof(char) * dataLenght);
            if ([self receiveData:(char *)buff length:dataLenght]) {
                NSData *data = [NSData dataWithBytes:buff length:dataLenght];
                [self.decoder decode:data];
                free(buff);
            }
        } else {
            NSLog(@"pre is not &");
            return;
        }
    }
}
- (BOOL)receiveData:(char *)data length:(NSUInteger)length {
    LOCK(lock);
    int receiveLength = 0;
    while (receiveLength < length) {
        ssize_t res = recv(self.acceptSocket, data, length - receiveLength, 0);
        if (res == -1 || res == 0) {
            UNLOCK(lock);
            NSLog(@"receive data error");
            break;
        }
        receiveLength += res;
        data += res;
    }
    UNLOCK(lock);
    return YES;
}
- (void)didGetDecodeBuffer:(CVPixelBufferRef)pixelBuffer {
    _frameTime += 1000;
    CMTime pts = CMTimeMake(_frameTime, 1000);
    CMSampleBufferRef sampleBuffer = [RongRTCBufferUtil sampleBufferFromPixbuffer:pixelBuffer time:pts];
    // Check to see if there is a problem with the decoded data. If the image appears, you are right.
    UIImage *image = [RongRTCBufferUtil imageFromBuffer:sampleBuffer];
    [self.delegate didProcessSampleBuffer:sampleBuffer];
    CFRelease(sampleBuffer);
}
- (void)close {
    int res = close(self.acceptSocket);
    self.acceptSocket = -1;
    NSLog(@"shut down server: %d", res);
    [super close];
}
- (void)dealloc {
    NSLog(@"dealoc server socket");
}
@end

主 App 通过 Socket 会持续收到数据包,再将数据包进行解码,将解码后的数据通过代理 didGetDecodeBuffer 代理方法回调给 App 层。App 层就可以通过融云 RongRTCLib 的发送自定义流方法将视频数据发送到对端。



0 个评论

要回复文章请先登录注册