第9章 高级功能

在本章中,我们将学习RecordRTC的高级功能,包括实时流处理、多流合并和自定义录制器等。

9.1 实时流处理

使用timeSlice选项实现录制过程中的实时数据处理:

实时流处理

// 实时流处理配置
var options = {
    type: 'video',
    mimeType: 'video/webm',
    timeSlice: 1000, // 每秒触发一次
    
    // 数据可用回调
    ondataavailable: function(blob) {
        console.log('接收到数据块:', blob.size);
        
        // 实时上传数据块
        uploadChunk(blob);
    }
};

// 实时上传函数
function uploadChunk(blob) {
    var formData = new FormData();
    formData.append('chunk', blob);
    formData.append('timestamp', Date.now());
    
    fetch('/upload-chunk', {
        method: 'POST',
        body: formData
    }).then(response => {
        console.log('数据块上传成功');
    }).catch(error => {
        console.error('上传失败:', error);
    });
}

// 初始化录制器
var recorder = RecordRTC(mediaStream, options);
recorder.startRecording();

9.2 多流合并

将多个媒体流合并为一个录制流:

多流合并

// 多流合并录制器
class MultiStreamRecorder {
    constructor() {
        this.recorders = [];
        this.blobs = [];
    }
    
    // 添加流
    addStream(stream, options) {
        const recorder = RecordRTC(stream, options);
        this.recorders.push({
            recorder: recorder,
            stream: stream
        });
    }
    
    // 开始录制所有流
    startAll() {
        this.recorders.forEach(item => {
            item.recorder.startRecording();
        });
    }
    
    // 停止录制所有流
    stopAll(callback) {
        let completed = 0;
        const total = this.recorders.length;
        
        this.recorders.forEach((item, index) => {
            item.recorder.stopRecording(() => {
                this.blobs[index] = item.recorder.getBlob();
                completed++;
                
                if (completed === total) {
                    callback(this.blobs);
                }
            });
        });
    }
    
    // 合并录制结果
    mergeBlobs(blobs, callback) {
        // 创建一个新的Blob包含所有数据
        const mergedBlob = new Blob(blobs, { type: blobs[0].type });
        callback(mergedBlob);
    }
}

// 使用示例
const multiRecorder = new MultiStreamRecorder();

// 添加摄像头流
navigator.mediaDevices.getUserMedia({ video: true, audio: true })
    .then(stream => {
        multiRecorder.addStream(stream, {
            type: 'video',
            mimeType: 'video/webm'
        });
    });

// 添加屏幕流
navigator.mediaDevices.getDisplayMedia({ video: true })
    .then(stream => {
        multiRecorder.addStream(stream, {
            type: 'video',
            mimeType: 'video/webm'
        });
    });

// 开始录制
// multiRecorder.startAll();

9.3 自定义录制器

创建自定义录制器以满足特殊需求:

自定义录制器

// 自定义录制器示例
function CustomRecorder(mediaStream, config) {
    // 继承RecordRTC的基本功能
    const recorder = RecordRTC(mediaStream, config);
    
    // 添加自定义方法
    recorder.customMethod = function() {
        console.log('自定义方法被调用');
    };
    
    // 重写开始录制方法
    const originalStart = recorder.startRecording;
    recorder.startRecording = function() {
        console.log('自定义开始录制逻辑');
        // 执行原始方法
        originalStart.call(this);
    };
    
    // 重写停止录制方法
    const originalStop = recorder.stopRecording;
    recorder.stopRecording = function(callback) {
        console.log('自定义停止录制逻辑');
        // 执行原始方法
        originalStop.call(this, callback);
    };
    
    return recorder;
}

// 使用自定义录制器
var customRecorder = CustomRecorder(mediaStream, {
    type: 'video'
});

customRecorder.startRecording();

9.4 录制状态管理

管理录制过程中的各种状态:

录制状态管理

// 录制状态管理器
class RecordingStateManager {
    constructor() {
        this.state = 'idle'; // idle, recording, paused, stopped
        this.recorder = null;
        this.startTime = null;
        this.pausedTime = null;
        this.totalPausedTime = 0;
    }
    
    // 开始录制
    startRecording(stream, options) {
        if (this.state !== 'idle') {
            console.warn('录制器不在空闲状态');
            return;
        }
        
        this.recorder = RecordRTC(stream, options);
        this.recorder.startRecording();
        this.state = 'recording';
        this.startTime = Date.now();
        console.log('开始录制');
    }
    
    // 暂停录制
    pauseRecording() {
        if (this.state !== 'recording') {
            console.warn('录制器不在录制状态');
            return;
        }
        
        this.recorder.pauseRecording();
        this.state = 'paused';
        this.pausedTime = Date.now();
        console.log('录制已暂停');
    }
    
    // 恢复录制
    resumeRecording() {
        if (this.state !== 'paused') {
            console.warn('录制器不在暂停状态');
            return;
        }
        
        this.recorder.resumeRecording();
        this.state = 'recording';
        this.totalPausedTime += Date.now() - this.pausedTime;
        this.pausedTime = null;
        console.log('录制已恢复');
    }
    
    // 停止录制
    stopRecording(callback) {
        if (this.state === 'idle') {
            console.warn('录制器处于空闲状态');
            return;
        }
        
        this.recorder.stopRecording(() => {
            const blob = this.recorder.getBlob();
            this.state = 'stopped';
            
            // 计算实际录制时间
            const totalTime = Date.now() - this.startTime;
            const actualRecordingTime = totalTime - this.totalPausedTime;
            
            console.log('录制已停止');
            console.log('总时间:', totalTime + 'ms');
            console.log('实际录制时间:', actualRecordingTime + 'ms');
            
            if (callback) callback(blob);
        });
    }
    
    // 获取当前状态
    getState() {
        return this.state;
    }
}

9.5 录制数据处理

对录制的数据进行后处理:

录制数据处理

// 录制数据处理器
class RecordingDataProcessor {
    // 压缩录制数据
    static compressBlob(blob, quality = 0.8) {
        return new Promise((resolve, reject) => {
            if (blob.type.startsWith('video/')) {
                // 视频压缩处理
                this.compressVideo(blob, quality, resolve, reject);
            } else if (blob.type.startsWith('audio/')) {
                // 音频压缩处理
                this.compressAudio(blob, quality, resolve, reject);
            } else {
                resolve(blob);
            }
        });
    }
    
    // 视频压缩
    static compressVideo(blob, quality, resolve, reject) {
        // 创建视频元素
        const video = document.createElement('video');
        video.src = URL.createObjectURL(blob);
        
        video.addEventListener('loadedmetadata', () => {
            // 创建canvas
            const canvas = document.createElement('canvas');
            canvas.width = video.videoWidth * quality;
            canvas.height = video.videoHeight * quality;
            
            const ctx = canvas.getContext('2d');
            
            // 绘制压缩后的视频帧
            video.addEventListener('timeupdate', () => {
                ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
                
                // 转换为blob
                canvas.toBlob((compressedBlob) => {
                    resolve(compressedBlob);
                }, 'video/webm', quality);
            });
            
            video.play();
        });
        
        video.addEventListener('error', reject);
    }
    
    // 音频压缩
    static compressAudio(blob, quality, resolve, reject) {
        // 音频压缩逻辑
        // 这里简化处理,实际项目中可能需要使用Web Audio API
        const reader = new FileReader();
        reader.onload = function(e) {
            // 模拟压缩处理
            const compressedData = e.target.result;
            const compressedBlob = new Blob([compressedData], { type: blob.type });
            resolve(compressedBlob);
        };
        reader.onerror = reject;
        reader.readAsArrayBuffer(blob);
    }
    
    // 转换格式
    static convertFormat(blob, targetFormat) {
        // 格式转换逻辑
        console.log('转换格式:', blob.type, '->', targetFormat);
        return Promise.resolve(blob);
    }
}

// 使用示例
// RecordingDataProcessor.compressBlob(recordedBlob, 0.7)
//     .then(compressedBlob => {
//         console.log('压缩完成:', compressedBlob.size);
//     });