k-yle / rtsp-relay

📽 View an RTSP stream in your web browser using an express.js server
https://npm.im/rtsp-relay
MIT License
312 stars 58 forks source link

Issue with Loading Multiple Live Streaming Videos Using offline jsmpeg.min.js File #271

Open fullmooooon opened 1 month ago

fullmooooon commented 1 month ago

Hi, first of all, thank you for your module, which has saved me a lot of time.

I noticed that the rtsp-relay repository behaves differently when using the jsmpeg.min.js file from a CDN compared to using it locally. While using the CDN version, it can successfully play multiple live streaming videos (in my case, it's 3 videos),I suspect that each video is using a different JSMpeg object at this time. However, when using the local jsmpeg.min.js file, no video can be loaded. After investigation, I found that this is due to the issue of JSMpeg object reuse when using offline files.

Steps to Reproduce

Use the local jsmpeg.min.js version. Attempt to load multiple live streaming videos. All videos will not play properly, and there will be no error reminders on the console.

Expected Behavior

Expect that when using the local jsmpeg.min.js version, it should be able to successfully load multiple live streaming videos, similar to when using the CDN version.

Actual Behavior

None video is successfully loaded, and all fail to play.

Proposed Solution

I have identified the issue and proposed a solution: this is caused by the reuse of the JSMpeg object. In the proposed solution:

Create a new JSMpeg object when loading each video instead of reusing the existing one. Ensure that each video has its own independent playback instance to avoid issues caused by object reuse.

Additional Information

Version Used: 1.9.0

I will provide my solution in case someone encounters the same problem and doesn't need to waste 6 hours like me

create file src\assets\rtsp-relay-browser.js copy from node_modules\rtsp-relay\browser\index.js Make the following modifications

  const importJSMpeg = () =>
    new Promise((resolve, reject) => {
        resolve();
    });
var JSMpeg=【All text from 'https://cdn.jsdelivr.net/gh/phoboslab/jsmpeg@b5799bf/jsmpeg.min.js'】

           const player = new JSMpeg.Player(url, {
       // const player = new window.JSMpeg.Player(url, {
  // if (typeof module !== 'undefined') {
  //   // being imported
  //   module.exports = { loadPlayer };
  // } else {
  //   // loaded via script tag
  //   window.loadPlayer = loadPlayer;
  // }
  window.loadPlayer = loadPlayer;
k-yle commented 1 month ago

[...] when using the local jsmpeg.min.js file

What do you mean the "local jsmpeg.min.js file"? This library does not bundle JSMpeg, we always load it from the CDN.

Create a new JSMpeg object when loading each video instead of reusing the existing one.

We already do this, when you call loadPlayer, it creates a new instance of the JSMpeg class for each stream:

https://github.com/k-yle/rtsp-relay/blob/e1b91b50d1a5acac0123ab87d741a277508f856a/browser/index.js#L53

We also have end-to-end tests which run in GitHub Actions and confirm that multiple live streams on the same page are already supported. This is the frontend code for that test case:

https://github.com/k-yle/rtsp-relay/blob/e1b91b50d1a5acac0123ab87d741a277508f856a/test/setupTests.js#L77-L89

If this is not working for you, perhaps you could share more information about the browser/platform that your using?

fullmooooon commented 1 month ago

I have an Electron program that needs to run in an environment where CDN access is not possible. I can confirm that when window.JSMpeg exists, the JSMpeg object reuse occurs. Here are the tests I just conducted.

An Electron program that includes the following configurations

      contextIsolation: false,
      nodeIntegration: true,
      webSecurity: false,

index.vue

<template>
    <div>
        <canvas id="canvas2"></canvas>
        <canvas id="canvas3"></canvas>
    </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { loadPlayer } from 'rtsp-relay/browser'
//import 'assets/rtsp-relay-browser.js'

onMounted(() => {
    ;(async () => {
        const express = require('express')
        const app = express()
        const { proxy, scriptUrl } = require('rtsp-relay')(app)
        const handler1 = proxy({
            url: canvasRTSPurl_1,
            transport: 'tcp',
        })
        app.ws('/api/stream1', handler1)

        const handler2 = proxy({
            url: canvasRTSPurl_2,
            transport: 'tcp',
        })
        app.ws('/api/stream2', handler2)

        const handler3 = proxy({
            url: canvasRTSPurl_3,
            transport: 'tcp',
        })
        app.ws('/api/stream3', handler3)
        app.listen(2001)

        let player_1 = loadPlayer({
            url: `ws://localhost:2001/api/stream1`,
            canvas: document.getElementById('canvas1'),
        })
        let player_2 = loadPlayer({
            url: `ws://localhost:2001/api/stream2`,
            canvas: document.getElementById('canvas2'),
        })
        let player_3 = loadPlayer({
            url: `ws://localhost:2001/api/stream3`,
            canvas: document.getElementById('canvas3'),
        })
        console.log(`player_1 `, player_1 )
        console.log(`player_2 `, player_2 )
        console.log(`player_3 `, player_3 )
    })()
})
</script>

When using the offline jsmpeg.min.js file

index.html

    <script src="/jsmpeg.min.js"></script>

test in electron devtools

player_1_PromiseResult.wasmModule.memory == player_2_PromiseResult.wasmModule.memory
true

When not loading jsmpeg.min.js in index.html (Using CDN)

player_1_PromiseResult.wasmModule.memory == player_2_PromiseResult.wasmModule.memory
false

Use the 'rtsp-relay/browser' that I have modified

player_1_PromiseResult.wasmModule.memory == player_2_PromiseResult.wasmModule.memory
false