通过阅读本文,您可以了解 iOS 输入外部音视频流的方法。
输入外部视频流
说明
SDK允许先推流然后开启外部视频输入,但这种情况下,默认开始推流时,先推送出的是本地原始采集源(摄像头或屏幕捕获)的视频数据,直到启用外部输入。
1. 调用 setExternalVideoSource 打开外部视频输入开关。
int ret = [DingRtcClient.instance.rtcEngine setExternalVideoSource:YES track:DingRtcVideoTrackCamera];
2. 调用 pushExternalVideoFrame 输入视频数据。
说明
此处需要重新开启线程调用 pushExternalVideoFrame。
FILE * _yuvInputFile;
@property (strong, nonatomic) NSThread *yuvInputThread;
@property (assign, nonatomic) int yuvDataWidth;
@property (assign, nonatomic) int yuvDataHeight;
- (void)runInputYUV {
int width = self.yuvDataWidth;
int height = self.yuvDataHeight;
int dataSize = width * height * 3 / 2;
char *yuv_read_data = (char *)malloc(dataSize);
while (true) {
if ([self.yuvInputThread isCancelled]) {
break;
}
size_t read = fread(yuv_read_data, dataSize, 1, _yuvInputFile);
if (read > dataSize) {
break;
}
if (read == 0) {
fseek(_yuvInputFile, 0, SEEK_SET);
if (self.yuvInputThread) {
continue;
} else {
break;
}
}
BOOL push_error = NO;
if (![self.yuvInputThread isExecuting]) {
push_error = YES;
break;
}
DingRtcVideoFrame *frame = [[DingRtcVideoFrame alloc] init];
frame.frameType = DingRtcVideoFrameRaw;
frame.timestamp = [[NSDate date] timeIntervalSince1970] * 1000;
frame.width = width;
frame.height = height;
frame.rotation = 0;
frame.count = 3;
frame.data = (void *)yuv_read_data;
frame.offset = @[@(0), @(width * height), @(width * height * 5 / 4)];
frame.stride = @[@(width), @(width/2), @(width/2)];
frame.pixelFormat = DingRtcVideoI420;
int ret = [DingRtcClient.instance.rtcEngine pushExternalVideoFrame:frame track:DingRtcVideoTrackCamera];
if (ret != 0) {
push_error = YES;
}
//请根据实际情况控制帧率
[NSThread sleepForTimeInterval:0.03];
if (push_error) {
break;
}
}
free(yuv_read_data);
fclose(_yuvInputFile);
_yuvInputFile = NULL;
}
输入外部音频流
1. 调用 setExternalAudioSource 启用外部音频输入。
//采样率
@property (assign, nonatomic) int sampleRate;
//声道数
@property (assign, nonatomic) int channels;
int ret = [DingRtcClient.instance.rtcEngine setExternalAudioSource:YES withSampleRate:self.sampleRate channelsPerFrame:self.channels];
2. 调用 pushExternalAudioFrame 输入音频数据。
FILE * _inputFile;
@property (strong, nonatomic) NSThread *inputThread;
//每个音频采样字节数, 通常是16bit(即2字节) */
@property (assign, nonatomic) int bytesPerSample;
//采样率
@property (assign, nonatomic) int sampleRate;
//声道数
@property (assign, nonatomic) int channels;
- (void)runInputPCM {
int freq = 40; // audio duration (ms) each time push
float samplesToRead = self.sampleRate / (1000.0 / freq);
int bufferSize = samplesToRead * self.channels * self.bytesPerSample;
char *buffer = (char *)malloc(bufferSize);
DingRtcAudioDataSample *frame = [[DingRtcAudioDataSample alloc] init];
frame.data = (void *)buffer;
frame.bytesPerSample = self.bytesPerSample;
frame.numOfChannels = self.channels;
frame.sampleRate = self.sampleRate;
while (true) {
if ([self.inputThread isCancelled]) {
break;
}
size_t readBytes = fread(buffer, 1, bufferSize, _inputFile);
if (readBytes == 0) {
fseek(_inputFile, 0, SEEK_SET);
if (self.inputThread) {
continue;
} else {
break;
}
}
BOOL push_error = NO;
if (![self.inputThread isExecuting]) {
push_error = YES;
break;
}
frame.numOfSamples = (int)(readBytes / self.bytesPerSample / selfchannels);
int ret = [DingRtcClient.instance.rtcEngine pushExternalAudioFrame:frame];
if (ret != 0) {
push_error = YES;
}
//请根据实际情况控制帧率
[NSThread sleepForTimeInterval:freq/1000.0];
if (push_error) {
break;
}
}
free(buffer);
fclose(_inputFile);
_inputFile = NULL;
}
文档内容是否对您有帮助?