You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ionic 3中播放黑盒相机MJPEG流失败,寻求可行解决方案

解决Ionic 3中MJPEG流播放及控制的可行方案

我之前在Ionic 3项目里处理过类似的MJPEG流播放需求,结合你的场景,给你两个经过验证的可行路径,同时满足停止、重新加载和截图的功能需求:

方案一:利用<img>标签自动渲染MJPEG流

MJPEG流本质是连续推送的JPEG图片序列,大多数浏览器的<img>标签可以直接识别并自动刷新显示这个流,这是最简单的实现方式。

实现代码

页面HTML (mjpeg-viewer.html)

<ion-header>
  <ion-toolbar>
    <ion-title>MJPEG Stream Viewer</ion-title>
    <ion-buttons end>
      <button ion-button (click)="toggleStream()">
        {{ isStreaming ? '停止' : '重新加载' }}
      </button>
      <button ion-button (click)="takeScreenshot()" [disabled]="!isStreaming">
        截图
      </button>
    </ion-buttons>
  </ion-toolbar>
</ion-header>

<ion-content padding>
  <img #streamImage [src]="streamUrl" *ngIf="isStreaming" alt="MJPEG Stream">
  <div *ngIf="!isStreaming" class="stream-stopped">
    流已停止,点击重新加载恢复
  </div>
</ion-content>

组件TS (mjpeg-viewer.ts)

import { Component, ViewChild, ElementRef } from '@angular/core';
import { NavController } from 'ionic-angular';

@Component({
  selector: 'page-mjpeg-viewer',
  templateUrl: 'mjpeg-viewer.html'
})
export class MjpegViewerPage {
  @ViewChild('streamImage') streamImage: ElementRef;
  streamUrl = 'http://192.168.10.123:7060';
  isStreaming = true;
  originalSrc: string;

  constructor(public navCtrl: NavController) {
    this.originalSrc = this.streamUrl;
  }

  toggleStream() {
    this.isStreaming = !this.isStreaming;
    if (this.isStreaming) {
      // 重新加载流:通过修改src触发刷新,避免缓存问题
      this.streamUrl = `${this.originalSrc}?t=${new Date().getTime()}`;
    }
  }

  takeScreenshot() {
    if (!this.isStreaming) return;
    const imgElement = this.streamImage.nativeElement;
    // 创建canvas用于截图
    const canvas = document.createElement('canvas');
    canvas.width = imgElement.width;
    canvas.height = imgElement.height;
    const ctx = canvas.getContext('2d');
    ctx.drawImage(imgElement, 0, 0);
    
    // 将canvas转为图片并保存(这里可以用cordova-plugin-screenshot插件实现保存到相册)
    const imageData = canvas.toDataURL('image/png');
    // 示例:调用cordova截图插件保存
    // (window as any).plugins.screenshot.save((error, res) => {
    //   if (error) console.error(error);
    //   else alert('截图已保存到相册');
    // }, 'png', 100);
    console.log('截图数据:', imageData);
  }
}

注意事项

  • 为了避免浏览器缓存导致重新加载不生效,重新加载时给URL添加时间戳参数
  • 截图功能可以配合cordova-plugin-screenshot插件实现保存到手机相册,需要先安装该插件:ionic cordova plugin add cordova-plugin-screenshot

方案二:使用Canvas手动绘制MJPEG帧

如果需要更精细的控制(比如自定义帧率、帧处理),可以通过HTTP请求逐帧获取JPEG数据,然后绘制到Canvas上,这种方式灵活性更高。

实现代码

组件TS核心逻辑

import { Component, ViewChild, ElementRef } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'page-mjpeg-canvas',
  templateUrl: 'mjpeg-canvas.html'
})
export class MjpegCanvasPage {
  @ViewChild('streamCanvas') streamCanvas: ElementRef;
  streamUrl = 'http://192.168.10.123:7060';
  isStreaming = false;
  frameInterval: any;
  canvasCtx: CanvasRenderingContext2D;

  constructor(private http: HttpClient) {}

  ionViewDidLoad() {
    const canvas = this.streamCanvas.nativeElement;
    this.canvasCtx = canvas.getContext('2d');
  }

  startStream() {
    this.isStreaming = true;
    // 每100ms获取一帧(可根据流的实际帧率调整)
    this.frameInterval = setInterval(() => this.loadFrame(), 100);
  }

  stopStream() {
    this.isStreaming = false;
    clearInterval(this.frameInterval);
    this.canvasCtx.clearRect(0, 0, this.streamCanvas.nativeElement.width, this.streamCanvas.nativeElement.height);
  }

  loadFrame() {
    const url = `${this.streamUrl}?t=${new Date().getTime()}`;
    // 获取帧数据并绘制到Canvas
    this.http.get(url, { responseType: 'blob' }).subscribe(blob => {
      const img = new Image();
      img.onload = () => {
        if (this.isStreaming) {
          this.canvasCtx.drawImage(img, 0, 0, this.streamCanvas.nativeElement.width, this.streamCanvas.nativeElement.height);
        }
        URL.revokeObjectURL(img.src); // 释放资源
      };
      img.src = URL.createObjectURL(blob);
    }, error => {
      console.error('加载帧失败:', error);
      this.stopStream();
    });
  }

  takeScreenshot() {
    if (!this.isStreaming) return;
    const canvas = this.streamCanvas.nativeElement;
    const imageData = canvas.toDataURL('image/png');
    // 同样可以用cordova-plugin-screenshot保存,或者直接处理imageData
    console.log('Canvas截图数据:', imageData);
  }
}

页面HTML

<ion-content padding>
  <canvas #streamCanvas width="320" height="240"></canvas>
  <button ion-button (click)="isStreaming ? stopStream() : startStream()">
    {{ isStreaming ? '停止' : '开始播放' }}
  </button>
  <button ion-button (click)="takeScreenshot()" [disabled]="!isStreaming">截图</button>
</ion-content>

为什么之前的方案失败?

HTML5的<video>标签和cordova-plugin-streaming-media主要支持标准的视频格式(如MP4、HLS),而MJPEG是基于图片序列的流格式,不属于标准视频容器,因此无法直接被这些组件解析播放,必须通过上述两种方式手动处理。

内容的提问来源于stack exchange,提问作者operator

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:20:24