阿里云RTC为您提供了输入外部音视频流的功能。通过阅读本文,您可以了解输入外部音视频流的方法。
输入外部视频流
说明 SDK允许先推流然后开启外部视频输入,但这种情况下,默认开始推流时,先推送出的是本地原始采集源(摄像头或屏幕捕获)的视频数据,直到启用外部输入。
- 调用setExternalVideoSource打开外部视频输入开关。
int ret = [self.engine setExternalVideoSource:YES useTexture:NO sourceType:AliRtcVideosourceCameraLargeType renderMode:AliRtcRenderModeAuto];
- 调用pushExternalVideoFrame输入视频数据。说明
- 此处需要重新开启线程调用pushExternalVideoFrame。
- 视频流类型仅支持AliRtcVideosourceCameraLargeType(大分辨率视频流)。
float pcmHzFloat; int yuvDataWidth; int yuvDataHeight; NSThread * yuvInputThread; FILE * yuvInputFile; - (void)inputYUVRun { int width = yuvDataWidth; int height = yuvDataHeight; int dataSize = width*height*3/2; char *yuv_read_data = (char *)malloc(dataSize); while (true) { if ([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); NSLog(@"input yuv reset head!"); if (yuvInputThread) { continue; } else { break; } } bool push_error = false; while (true) { if (![yuvInputThread isExecuting]) { push_error = YES; break; } AliRtcVideoDataSample *dataSample = [[AliRtcVideoDataSample alloc] init]; dataSample.dataPtr = (long)yuv_read_data; dataSample.format = AliRtcVideoFormat_I420; dataSample.width = width; dataSample.height = height; dataSample.strideY = width; dataSample.strideU = width/2; dataSample.strideV = width/2; dataSample.dataLength = dataSample.strideY * dataSample.height * 3/2; //加判断是否开启输入屏幕共享 int ret = 0; if (yuvShareState != YES) { } else { ret = [self.engine pushExternalVideoFrame:dataSample sourceType:AliRtcVideosourceScreenShareType]; } if (ret == AliRtcErrAudioBufferFull && [yuvInputThread isCancelled] == NO) { } else { if (ret < 0) { push_error = true ; } } //加判断频率, 默认为60hz(30毫秒) if (pcmHzFloat > 0) { float hz = 1.0/pcmHzFloat; [NSThread sleepForTimeInterval:hz]; // 指定频率 } else { [NSThread sleepForTimeInterval:0.03]; // 默认30毫秒 (加延迟操作播放出流畅的画面) } break; } if (push_error) { break ; } } free(yuv_read_data); fclose(yuvInputFile); yuvInputFile = NULL ; }
输入外部音频流
- 调用setExternalAudioSource启用外部音频输入,并调用setMixedWithMic设置外部音频输入是否与麦克风混合。
int ret = [self.engine setExternalAudioSource:YES withSampleRate:pcmSampleRate channelsPerFrame:pcmChannels]; // 完全替代麦克风采集 [self.engine setMixedWithMic:NO];
- 调用pushExternalAudioFrameRawData输入音频数据。说明 如果返回值为AliRtcErrAudioBufferFull,表示当前buffer队列饱和,建议您等待20ms,再继续输送数据。
int pcmSampleRate; int pcmChannels; NSThread * pcmInputThread; FILE * pcmInputFile; - (void)inputPCMRun { // 40ms int readbufSize = (pcmSampleRate/100)*4*sizeof(int16_t)*pcmChannels ; while (true) { if ([pcmInputThread isCancelled]) { break; } size_t read = fread(pcmData, 1, readbufSize, pcmInputFile) ; if (read > readbufSize) { break; } if (read == 0) { fseek(pcmInputFile, 0, SEEK_SET) ; NSLog(@"input pcm reset head!"); if (pcmInputThread) { continue; } else { break; } } bool push_error = false; while (true) { if (![pcmInputThread isExecuting]) { push_error = YES; break; } int rc = [self.engine pushExternalAudioFrameRawData:pcmData samples:read timestamp:0]; if ( rc == AliRtcErrAudioBufferFull && [pcmInputThread isCancelled ] == NO ) { [NSThread sleepForTimeInterval:0.08] ; } else { if (rc < 0) { push_error = true ; } break; } } if (push_error) { break; } } fclose(pcmInputFile); pcmInputFile = NULL ; }