uni-app 使用renderjs 和 webview两种方式在app 开始录像和结束录制之后 renderjs方式的无法播放视频

uni-app 使用renderjs 和 webview两种方式在app 开始录像和结束录制之后 renderjs方式的无法播放视频

示例代码:

// 初始化音视频流  
async initMediaStream() {  
  try {  
    navigator.mediaDevices.getMedia = navigator.mediaDevices.getUserMedia || navigator.mediaDevices.webkitGetUserMedia || navigator.mediaDevices.mozGetUserMedia || navigator.mediaDevices.msGetUserMedia;  

    this.mediaStream = await navigator.mediaDevices.getMedia({  
      video: { width: 1280, height: 720, frameRate: {  min: 30, ideal: 60, max: 60  } },  
      audio: true,  
    });  
    // const previewVideo = document.createElement('video');  
    // previewVideo.src = URL.createObjectURL(this.mediaStream);  
    // // previewVideo.play();  
    // this.logMessage('stream_init', '音视频流初始化成功');  
    // // 创建临时 video 元素并添加到页面(仅验证用)  
    const previewVideo = document.createElement('video');  
    previewVideo.srcObject = this.mediaStream;  
    previewVideo.autoplay = true;  
    previewVideo.muted = true; // 避免回声  
    previewVideo.style.position = 'fixed';  
    previewVideo.style.top = '0';  
    previewVideo.style.width = '200px';  
    previewVideo.style.height = '200px';  

    previewVideo.style.border = '2px solid yellow';  
    document.body.appendChild(previewVideo);  
    return true;  
  } catch (e) {  
    this.onError({ msg: `音视频流获取失败:${e.message}` });  
    return false;  
  }  
}  

// 开始录像  
async startRecording() {  
  if (this.isRecording) return;  
  const streamReady = await this.initMediaStream();  
  if (!streamReady) return;  

  try {  
    const options = {  
      mimeType: 'video/webm; codecs=vp8,opus',  
      audioBitsPerSecond: 128000,  
      videoBitsPerSecond: 2500000  
    };  
    const support = typeof MediaRecorder !== 'undefined'  

    console.log('MediaRecorder 支持吗?', support)  

    this.mediaRecorder = new MediaRecorder(this.mediaStream, options);  
    this.chunks = [];  
    this.uploadChunks = [];  

    this.mediaRecorder.ondataavailable = (e) => {  
      if (e.data.size > 0) {  
        this.chunks.push(e.data);  
        this.uploadChunks.push(e.data);  
      }    
    };  

    this.mediaRecorder.onstop = () => this.handleRecordingStop();  
    this.mediaRecorder.start();  
    this.isRecording = true;  

    // 定时上传分片(每2秒)  
    this.uploadInterval = setInterval(() => this.uploadVideoChunk(), 2000);  
    this.logMessage('record_start', '开始录像');  
  } catch (e) {  
    this.onError({ msg: `录像启动失败:${e.message}` });  
  }  
}  

// 停止录像  
stopRecording() {  
  if (!this.isRecording) return;  
  this.mediaRecorder.stop();  
  clearInterval(this.uploadInterval);  
  this.isRecording = false;  
  this.logMessage('record_stop', '停止录像');  

  // 上传最后分片并通知合并  
  setTimeout(() => {  
    this.uploadVideoChunk();  
    this.notifyBackendMerge();  
  }, 1000);  

  // 释放流  
  this.mediaStream.getTracks().forEach(track => track.stop());  
}  

// 处理录像结束  
handleRecordingStop() {  
  const videoBlob = new Blob(this.chunks, { type: 'video/webm' });  
  const url = URL.createObjectURL(videoBlob)  

  // 把视频URL回传给Vue页面  
  this.saveVideoToLocal({ url })  
  this.logMessage('record_complete', `录像生成成功(${(videoBlob.size / 1024 / 1024).toFixed(2)}MB)`);  
  console.log('录像Blob大小:', videoBlob.size); // 正常应大于0  
  console.log('录像MIME类型:', videoBlob.type); // 应为 video/webm  

  // 显示视频预览  
  try {   
    const videoView = document.getElementById('videoView');  
  if (videoView) {  
    videoView.src = URL.createObjectURL(videoBlob);  
    console.log('视频预览URL:', videoView.src); // 应为 blob:xxx 格式  
    videoView.style.display = 'block';  
    videoView.style.border = '1px solid red';  
    videoView.autoplay = true;  
    document.getElementById('photoView').style.display = 'none';  
    videoView.onerror = (error) => {  
      console.error('录像预览失败:', error);  
      this.onError({ msg: `录像预览失败:${error || error.message}` });  
    };  
  }  
  } catch (e) {  
    this.onError({ msg: `录像预览失败:${e.message}` });  
  }  
}

操作步骤:

  • vue页面使用 renderjs, 然后MediaRecorder开始录制和结束录制,然后使用video播放视频。

预期结果:

  • renderjs 使用录像结束之后,需要能正常播放录制后的视频。

实际结果:

  • renderjs 使用录像结束之后,无法正常播放录制后的视频。

bug描述:

  • uniapp 使用renderjs 和 webview两种方式在app,使用MediaRecorder 录像,结束录像之后,renderjs无法播放视频;webview 用同样的方式录像之后,能正常播放;但是普通vue页面使用webview又会全屏,nvue页面限制太多,不能用这个nvue。
  • 所以有办法让renderjs 录像结束之后,正常播放视频?

更多关于uni-app 使用renderjs 和 webview两种方式在app 开始录像和结束录制之后 renderjs方式的无法播放视频的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于uni-app 使用renderjs 和 webview两种方式在app 开始录像和结束录制之后 renderjs方式的无法播放视频的实战教程也可以访问 https://www.itying.com/category-93-b0.html


这个问题是RenderJS环境下MediaRecorder录制视频后无法播放的典型问题。主要原因是RenderJS与普通Webview环境在Blob URL处理机制上存在差异。

解决方案:

  1. 检查Blob完整性handleRecordingStop方法中,添加Blob验证:
console.log('Blob chunks数量:', this.chunks.length);
console.log('Blob chunks大小:', this.chunks.map(chunk => chunk.size));
  1. 优化停止录制流程 修改stopRecording方法,确保所有数据都已收集:
stopRecording() {
  if (!this.isRecording) return;
  
  // 先停止所有track
  this.mediaStream.getTracks().forEach(track => track.stop());
  
  // 再停止MediaRecorder
  if (this.mediaRecorder.state !== 'inactive') {
    this.mediaRecorder.stop();
  }
  
  clearInterval(this.uploadInterval);
  this.isRecording = false;
}
  1. 使用Base64替代Blob URL RenderJS中Blob URL可能无法正确解析,改用Base64:
handleRecordingStop() {
  const videoBlob = new Blob(this.chunks, { type: 'video/webm' });
  
  // 转换为Base64
  const reader = new FileReader();
  reader.onload = () => {
    const base64Data = reader.result;
    // 传递给Vue页面
    this.saveVideoToLocal({ base64: base64Data });
    
    // 预览使用Base64
    const videoView = document.getElementById('videoView');
    if (videoView) {
      videoView.src = base64Data;
      videoView.style.display = 'block';
    }
  };
  reader.readAsDataURL(videoBlob);
}
  1. 确保视频元素正确配置
// 在预览前确保video元素存在且配置正确
const videoView = document.getElementById('videoView');
if (!videoView) {
  const newVideo = document.createElement('video');
  newVideo.id = 'videoView';
  newVideo.controls = true;
  newVideo.style.width = '100%';
  document.body.appendChild(newVideo);
}
  1. 检查MIME类型支持 RenderJS环境可能对某些MIME类型支持不完整,尝试更通用的类型:
const options = {
  mimeType: 'video/mp4; codecs=avc1.42E01E,mp4a.40.2',
  audioBitsPerSecond: 128000,
  videoBitsPerSecond: 2500000
};
回到顶部