MagicMirror Forum
    • Recent
    • Tags
    • Unsolved
    • Solved
    • MagicMirror² Repository
    • Documentation
    • 3rd-Party-Modules
    • Donate
    • Discord
    • Register
    • Login
    A New Chapter for MagicMirror: The Community Takes the Lead
    Read the statement by Michael Teeuw here.

    MMM-MPlayer

    Scheduled Pinned Locked Moved Utilities
    44 Posts 10 Posters 14.0k Views 10 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • M Offline
      myfingersarecold
      last edited by

      I couldnt get the EXT-FreeboxTV module to work on my magic mirror so i gave up, and used chatgpt to help me write a module.

      Its called MMM-MPlayer, and using MPlayer it will open either 1 or 2 Mplayer windows and play whatever files or rtsp streams you like. If you define multiple it will cycle through them, determined by the streamInterval. I am using it to stream 3 Unifi Cameras so that i can keep an eye on the front yard in one window, and an eye on my kids via the cameras we use as nanny cams while they nap/sleep, cycling through those two rooms every 30 seconds.

      Reasons for using MPlayer over something else is that the version of raspbian that I am running on my pi3 has a broken version of VLC, which doesnt respond to command line position arguments, and also cant run OMXplayer. Its the most recent distro, i dont remember the name for it. mplayer works well, and plays on my pi3 just fine, along with all the other stuff i have running.

      Obviously your use case could be for anything, cameras around your house, livestreams you like to watch. Essentially anything that mplayer can play. The module natively responds to the MMM-Pir notification so that it kills and restarts the streams when the PIR module tells the screen to turn off and on, so that the screen acts as it should.

      I don’t feel like actually uploading it to github, but here is the source code, and an example config.

      --------------- CONFIG.js

      {
      	module: 'MMM-MPlayer',  // Update the module name here
      	position: 'top_left',  // Magic Mirror position
      	config: {
      	  useTwoWindows: true, // Use two windows
      	  layout: 'row',  // Can be 'row' or 'column'
      	  windowSize: { width: 525, height: 295 },  // Window size for both windows
      	  windowPosition: { x: 12, y: 575 },  // Position of the first window (window1) [window2 is either 5px below or to the right of this window, depending on layout]
      	  streamInterval: 30000,
      	  streams: {
      		window1: [
      		  'somthing_else.mp4',
      		  'something.mp4'
      		],
      		window2: [
      		  'rtsp://foo',
      		  'rtsp://bar',
      		]
      	  }
      	}
      },
      

      ---------------MMM-MPlayer.js

      /* MagicMirror Module: MMM-MPlayer.js
       * This script communicates with the backend (node_helper.js) to control mplayer window streaming
       * It starts the stream cycle process only after the DOM is fully loaded.
       */
      
      Module.register('MMM-MPlayer', {
          // Define the module's defaults
          defaults: {
            useTwoWindows: true,
            layout: 'column',  // Can be 'row' or 'column'
            windowSize: { width: 640, height: 480 },
            windowPosition: { x: 0, y: 0 },  // Position of the first window
            streamInterval:30000,
            streams: {
              window1: [
                'http://stream1.example.com/video1',
                'http://stream2.example.com/video1'
              ],
              window2: [
                'http://stream1.example.com/video2',
                'http://stream2.example.com/video2'
              ]
            }
          },
        
          // Start the module
          start: function() {
            console.log('MMM-MPlayer module starting...');
            
            // Send the configuration to the backend
            this.sendSocketNotification('SET_CONFIG', this.config);
        
            // Notify the backend to start the stream cycle (backend will handle stream cycling)
            //this.sendSocketNotification('START_STREAM_CYCLE');
          },
        
          // Define socket notification handlers
          socketNotificationReceived: function(notification, payload) {
            switch(notification)
            {
              case 'STREAM_CYCLE_STARTED':
                console.log('Stream cycle process started.');
                break;
            }
          },
        
          // This function listens to the DOM_CREATED event and starts the stream cycle process
          notificationReceived: function(notification, payload, sender) {
            switch(notification) {
              case 'DOM_OBJECTS_CREATED':
                console.log('DOM created. Starting the stream cycle process...');
                
                // Send the notification to the backend to initiate the stream cycle
                this.sendSocketNotification('START_STREAM_CYCLE');
                break;
              case 'MMM_PIR-SCREEN_POWERSTATUS':
                console.log(`Received PIR Screen Show Notification ${payload}`);
                if (payload == true) {
                  this.sendSocketNotification('START_STREAM_CYCLE');
                }
                else {
                  this.sendSocketNotification('STOP_STREAM_CYCLE');
                }
                break;
            }
          },
      
          getDom: function() {
              var wrapper = document.createElement("div");
              wrapper.innerHTML = '';
              return wrapper;
          }
        });
      

      ------------------ NODE HELPER

      const NodeHelper = require('node_helper');
      const { spawn } = require('child_process');
      const { os } = require('os');
      const Log = require('logger');  // Import the Log module from MagicMirror
      
      module.exports = NodeHelper.create({
        start: function() {
          Log.info('Starting MMM-MPlayer module...');
          this.streams = {};
          this.currentStreamIndex = { window1: -1, window2: -1 };
          this.mplayerProcesses = { window1: null, window2: null }; // Track mplayer processes for each window
          this.streamInterval = 30000;
          this.streamSwitcher = null;
        },
      
        // Handle socket notifications from the frontend
        socketNotificationReceived: function(notification, payload) {
          switch(notification) {
            case 'SET_CONFIG':
              Log.info('Received configuration for MMM-MPlayer module');
      
              // Save the configuration
              this.config = payload;
      
              // Adjust layout and start the stream cycle
              this.adjustLayout();
              break;
            case 'START_STREAM_CYCLE':
              Log.info('Stream cycle process started.');
              this.cycleStreams(); // Start the stream cycle after receiving the notification
              break;
            case 'STOP_STREAM_CYCLE':
              Log.info('Stream cycle process stopped.');
              this.stopStreams();
          }
        },
      
        // Start or refresh the streams
        cycleStreams: function() {
          //fire up the streams immediately
          this.switchStream('window1');
          this.switchStream('window2');
          if (this.streamSwitcher == null) {
            this.streamSwitcher = setInterval(() => {
              this.switchStream('window1');
              this.switchStream('window2');
            }, this.config.streamInterval);  // cycle based on the config
      
            this.sendSocketNotification('STREAM_CYCLE_STARTED');
          }
        },
      
        stopStreams: function() {
          if (this.streamSwitcher != null) {
            clearInterval(this.streamSwitcher);
            this.killMPlayer('window1');
            this.killMPlayer('window2');
            this.streamSwitcher = null;
            this.currentStreamIndex = { window1: -1, window2: -1 };
          }
        },
      
        // Switch the stream for the given window
        switchStream: function(window) {
          const windowStreams = this.config.streams[window];
          Log.info(`Switching stream for ${window}`);
          const currentIndex = this.currentStreamIndex[window];
          const nextIndex = (currentIndex + 1) % windowStreams.length;
      
          // Update stream index
          this.currentStreamIndex[window] = nextIndex;
      
          if (currentIndex != nextIndex) {
              // Kill the old mplayer process for the window using SIGTERM
              this.killMPlayer(window);
      
              // Launch new mplayer process for the window
              this.launchMPlayer(windowStreams[nextIndex], window);
          }
        },
      
        // Kill any existing mplayer process for a window using SIGTERM
        killMPlayer: function(window) {
          const mplayerProcess = this.mplayerProcesses[window];
          if (mplayerProcess) {
            Log.info(`Killing mplayer process for ${window}...${mplayerProcess.pid}`);
            const killer = spawn(`kill`, [`${mplayerProcess.pid}`]);
      
            // Handle standard output and error
            killer.stdout.on('data', (data) => {
              Log.debug(`killer [${window}] stdout: ${data}`);
            });
      
            killer.stderr.on('data', (data) => {
              Log.error(`killer [${window}] stderr: ${data}`);
            });
      
            killer.on('close', (code) => {
              Log.info(`killer process for ${window} exited with code ${code}`);
            });
          }
        },
      
        // Launch a new mplayer process for the window using spawn
        launchMPlayer: function(stream, window) {
          const size = this.config.windowSize;
          const position = this.config[`${window}Position`] || this.config.windowPosition; // Use specific or general window position
      
          // Spawn a new mplayer process
          const env = { ...process.env, DISPLAY: ':0' };
          const mplayerProcess = spawn(`mplayer`, ['-noborder', '-geometry', `${position.x}:${position.y}`, `-xy`, `${size.width}`, `${size.height}`, `${stream}`], {env: env}); //C, 
      
          Log.info(`Launched mplayer process for ${window} with PID ${mplayerProcess.pid}`);
      
          // Track the process for future termination
          this.mplayerProcesses[window] = mplayerProcess;
      
          // Handle standard output and error
          mplayerProcess.stdout.on('data', (data) => {
            Log.debug(`mplayer [${window}] stdout: ${data}`);
          });
      
          mplayerProcess.stderr.on('data', (data) => {
            //Log.error(`mplayer [${window}] stderr: ${data}`);
          });
      
          mplayerProcess.on('close', (code) => {
            Log.info(`mplayer process for ${window} exited with code ${code}`);
          });
        },
      
        // Adjust stream positions and size based on layout
        adjustLayout: function() {
          const windowPosition = this.config.windowPosition; // General window position for window1
          const windowSize = this.config.windowSize;
          const layout = this.config.layout;
      
          // Calculate position for second window automatically based on layout
          if (layout === 'column') {
            // If layout is column, position window 2 below window 1
            this.config.window2Position = {
              x: windowPosition.x,  // Same x position
              y: windowPosition.y + windowSize.height + 5 // y position of window2 is below window1
            };
          } else if (layout === 'row') {
            // If layout is row, position window 2 to the right of window 1
            this.config.window2Position = {
              x: windowPosition.x + windowSize.width + 5, // x position of window2 is to the right of window1
              y: windowPosition.y  // Same y position
            };
          }
        }
      });
      
      evroomE KristjanESPERANTOK Cr4z33C 4 Replies Last reply Reply Quote 3
      • evroomE Offline
        evroom @myfingersarecold
        last edited by

        @myfingersarecold

        Hi there !

        This is most probably the module I was most anticipating for and that will enable me to finally go from ‘buster’ to ‘bookworm’.
        Finally a worthy and easy follow-up for OMXPlayer.

        I am still testing, but it looks very promising.

        Thanks a lot !

        E.J.

        PS I will have a few question later on.

        MagicMirror version: 2.33.0
        Raspberry Pi 4 Model B Rev 1.5 (8 GB RAM)
        Raspbian GNU/Linux 12 (bookworm)

        Test environment:
        MagicMirror version: v2.33.0
        Raspberry Pi 3 Model B Plus Rev 1.3 (1 GB RAM)
        Raspbian GNU/Linux 12 (bookworm)

        evroomE 1 Reply Last reply Reply Quote 0
        • evroomE Offline
          evroom @evroom
          last edited by

          @myfingersarecold

          Here two questions:

          1/ What does streamInterval do ?

          2/ Is it possible to rotate the output ?
          I am using my screen in portrait mode and therefore need my RTSP stream to be rotated by 90 degrees.

          Thanks in advance.

          MagicMirror version: 2.33.0
          Raspberry Pi 4 Model B Rev 1.5 (8 GB RAM)
          Raspbian GNU/Linux 12 (bookworm)

          Test environment:
          MagicMirror version: v2.33.0
          Raspberry Pi 3 Model B Plus Rev 1.3 (1 GB RAM)
          Raspbian GNU/Linux 12 (bookworm)

          evroomE 1 Reply Last reply Reply Quote 0
          • KristjanESPERANTOK Offline
            KristjanESPERANTO Module Developer @myfingersarecold
            last edited by

            @myfingersarecold Nice! It would be cool if you maybe reconsidered and uploaded it to GitHub 👩‍💻

            evroomE 1 Reply Last reply Reply Quote 0
            • evroomE Offline
              evroom @KristjanESPERANTO
              last edited by evroom

              @myfingersarecold Nice! It would be cool if you maybe reconsidered and uploaded it to GitHub 👩‍💻

              In order to encourage and to help you a bit, here a README.md:

              # MMM-MPlayer
              A MagicMirror module that uses MPlayer to display rtsp streams
              
              ## Project Status
              This module is working, but still under development.
              
              ## Installation of mplayer
              ### Verify if mplayer is already installed
              ```shell
              $ which mplayer
              /usr/bin/mplayer
              

              Install mplayer (when not installed yet)

              $ sudo apt install -y mplayer
              

              Installation of the MM module

              1. In your terminal, change to your Magic Mirror module directory cd ~/MagicMirror/modules

              2. Clone this repository git clone https://github.com/myfingersarecold/MMM-MPlayer

              3. Make changes to your config.js file.

              Config Example

              Edit the file ~/MagicMirror/config/config.js to add or modify the module.

              {
              	module: 'MMM-MPlayer',
                      disabled: false,
                      position: "top_left",
                      header: "MPlayer",
              	config: {
              	  useTwoWindows: true,
              	  layout: 'row',
              	  windowSize: { width: 525, height: 295 },
              	  windowPosition: { x: 12, y: 575 },
              	  streamInterval: 30000,
              	  streams: {
              		window1: [
              		  'something_else.mp4',
              		  'something.mp4'
              		],
              		window2: [
              		  'rtsp://foo',
              		  'rtsp://bar',
              		]
              	  }
              	}
              },
              

              Configuration Options

              Option Description Default
              useTwoWindows Use two windows true
              layout Can be ‘row’ or ‘column’ row
              windowSize Window size for both windows { width: 525, height: 295 }
              windowPosition Position of the first window (window1)
              [window2 is either 5px below or to the right of this window, depending on layout]
              { x: 12, y: 575 }
              streamInterval 30000
              streams window1 and / or window2 streams [ mp4 , rtsp ]

              Test environment

              This procedure has been tested on:

              • Raspberry Pi 4 Model B Rev 1.5
              • Debian GNU/Linux 12 (bookworm)
              • Magic Mirror version: 2.30.0

              Contributions

              Code provided by user ‘myfingersarecold’.

              https://forum.magicmirror.builders/user/myfingersarecold

              MagicMirror version: 2.33.0
              Raspberry Pi 4 Model B Rev 1.5 (8 GB RAM)
              Raspbian GNU/Linux 12 (bookworm)

              Test environment:
              MagicMirror version: v2.33.0
              Raspberry Pi 3 Model B Plus Rev 1.3 (1 GB RAM)
              Raspbian GNU/Linux 12 (bookworm)

              1 Reply Last reply Reply Quote 0
              • evroomE Offline
                evroom @evroom
                last edited by

                @evroom said in MMM-MPlayer:

                @myfingersarecold

                Here two questions:

                1/ What does streamInterval do ?

                2/ Is it possible to rotate the output ?
                I am using my screen in portrait mode and therefore need my RTSP stream to be rotated by 90 degrees.

                To answer my own questions:

                1/ Cycles the streams defined in window1 and/or window2 after the provided interval (in milliseconds).
                Where applicable, the streams will start from the beginning again (for example for mp4 videos).

                2/ Yes, this is possible using the -vf rotate=[0-3] option and adjusting the windowPosition values.

                MagicMirror version: 2.33.0
                Raspberry Pi 4 Model B Rev 1.5 (8 GB RAM)
                Raspbian GNU/Linux 12 (bookworm)

                Test environment:
                MagicMirror version: v2.33.0
                Raspberry Pi 3 Model B Plus Rev 1.3 (1 GB RAM)
                Raspbian GNU/Linux 12 (bookworm)

                M 1 Reply Last reply Reply Quote 0
                • evroomE Offline
                  evroom @myfingersarecold
                  last edited by

                  @myfingersarecold said in MMM-MPlayer:

                  I don’t feel like actually uploading it to github, but here is the source code, and an example config.

                  I took the liberty to take the provided code, make changes to it and make it available as a public repository:

                  https://github.com/evroom/MMM-MPlayer

                  My own main purpose for using it, is to setup a new Raspberry Pi (Raspberry Pi 4 Model B), with Debian 12 (bookworm) and the latest MM version (2.30.0).
                  Replacing a Pi 3b 32-bit Debian 10 buster setup where OMXPlayer is still working.
                  I will be using a single window with a single RTSP stream (for an Axis Network Camera).
                  Nothing fancy.

                  Best regards,

                  E.J.

                  MagicMirror version: 2.33.0
                  Raspberry Pi 4 Model B Rev 1.5 (8 GB RAM)
                  Raspbian GNU/Linux 12 (bookworm)

                  Test environment:
                  MagicMirror version: v2.33.0
                  Raspberry Pi 3 Model B Plus Rev 1.3 (1 GB RAM)
                  Raspbian GNU/Linux 12 (bookworm)

                  KristjanESPERANTOK M 2 Replies Last reply Reply Quote 2
                  • KristjanESPERANTOK Offline
                    KristjanESPERANTO Module Developer @evroom
                    last edited by

                    @evroom Nice! 🚀 Please add it to the module list 🙂

                    evroomE 1 Reply Last reply Reply Quote 0
                    • evroomE Offline
                      evroom @KristjanESPERANTO
                      last edited by

                      @KristjanESPERANTO said in MMM-MPlayer:

                      @evroom Nice! 🚀 Please add it to the module list 🙂

                      Done.

                      MagicMirror version: 2.33.0
                      Raspberry Pi 4 Model B Rev 1.5 (8 GB RAM)
                      Raspbian GNU/Linux 12 (bookworm)

                      Test environment:
                      MagicMirror version: v2.33.0
                      Raspberry Pi 3 Model B Plus Rev 1.3 (1 GB RAM)
                      Raspbian GNU/Linux 12 (bookworm)

                      1 Reply Last reply Reply Quote 2
                      • M Offline
                        myfingersarecold @evroom
                        last edited by

                        @evroom you are 100% correct regarding item #1, the streamInterval is for when multiple streams are defined, it will switch between the available streams.

                        regarding #2 on my pi i didnt have to rotate the mplayer orientation, but i adjusted the output of my pi to portrait and everything behaved but ymmv depending on how it’s setup.

                        evroomE 1 Reply Last reply Reply Quote 0
                        • M Offline
                          myfingersarecold @evroom
                          last edited by

                          @evroom thanks for that. glad its of use to someone 😊

                          1 Reply Last reply Reply Quote 0
                          • Cr4z33C Offline
                            Cr4z33 @myfingersarecold
                            last edited by

                            @myfingersarecold said in MMM-MPlayer:

                            I couldnt get the EXT-FreeboxTV module to work on my magic mirror

                            Out of curiosity what was the issue with it?

                            I use that module all the time to watch the TV channels of my Enigma2 decoder.

                            M 1 Reply Last reply Reply Quote 0
                            • evroomE Offline
                              evroom @myfingersarecold
                              last edited by

                              @myfingersarecold said in MMM-MPlayer:

                              regarding #2 on my pi i didnt have to rotate the mplayer orientation, but i adjusted the output of my pi to portrait and everything behaved but ymmv depending on how it’s setup.

                              Could you please tell me how you do the general rotation to portrait ?

                              I use the custom.css to get it rotated clockwise.
                              As MPlayer is an overlay, like OMXPlayer, it is not affected by this.

                              body {
                              :
                              :
                                transform: rotate(-90deg);
                                transform-origin: top left;
                                width: 100vh;
                                height: 100vw;
                              :
                              :
                               }
                              

                              But of course there are more, potential better, ways of getting it rotated.

                              MagicMirror version: 2.33.0
                              Raspberry Pi 4 Model B Rev 1.5 (8 GB RAM)
                              Raspbian GNU/Linux 12 (bookworm)

                              Test environment:
                              MagicMirror version: v2.33.0
                              Raspberry Pi 3 Model B Plus Rev 1.3 (1 GB RAM)
                              Raspbian GNU/Linux 12 (bookworm)

                              M 1 Reply Last reply Reply Quote 0
                              • M Offline
                                myfingersarecold @evroom
                                last edited by

                                @evroom

                                i didnt use this guide to do it, but this is how i rotated my screen.

                                https://www.makeuseof.com/how-to-rotate-your-raspberry-pi-screen-without-moving-the-display/

                                I am running the latest version of raspbian on my pi3

                                this results in my magicmirror instance loading in portrait mode, and my 16x9 streams loading properly where i want them without having to do any CSS rotation.

                                1 Reply Last reply Reply Quote 0
                                • M Offline
                                  myfingersarecold @Cr4z33
                                  last edited by

                                  @Cr4z33 no idea but couldn’t get RTSP streams to work.

                                  1 Reply Last reply Reply Quote 0
                                  • G Offline
                                    Guku
                                    last edited by

                                    HI, im running my MM on on Proxmox VM and pointing my display to IP on VM, when i try to run Mplayer it just displays black box but no feed, i doo see the feed on the server VM. any ideas how to get this playing on my remote display?

                                    S 1 Reply Last reply Reply Quote 0
                                    • S Do not disturb
                                      sdetweil @Guku
                                      last edited by

                                      @Guku did you expose that port on the vm to another connecting host?
                                      maybe a firewall filter?

                                      I don’t use proxmox, but I see this on windows VM’s all the time

                                      Sam

                                      How to add modules

                                      learning how to use browser developers window for css changes

                                      G 1 Reply Last reply Reply Quote 0
                                      • G Offline
                                        Guku @sdetweil
                                        last edited by

                                        @sdetweil

                                        thanks for checking in with me, i gave up on the player since even when i ran it localy on my VM the camera feed was delayed by about 5sec which defeted the pourpose. thanks anyways!

                                        1 Reply Last reply Reply Quote 0
                                        • C Offline
                                          clakkentt
                                          last edited by

                                          Just a comment

                                          I am using MagicMirror on a pi using bullseye 32bit.

                                          When using a rpi4 everything works fine. When I transfer the sd card to a rpi3 every time the MPlayer shows a live feed the desktop taskbar shows up, when MPlayer is switching between feeds the taskbar is not visible.

                                          This is probably due to my specific choice of settings but just thought it might help someone.

                                          S 1 Reply Last reply Reply Quote 0
                                          • S Do not disturb
                                            sdetweil @clakkentt
                                            last edited by

                                            @clakkentt if you use my backup/restore to capture your MM config
                                            and build a new card ON the pi3, and install MM and restore the config
                                            do you see the same problem?

                                            backup/restore here https://github.com/sdetweil/MagicMirror-backup-restore

                                            install/upgrade here https://github.com/sdetweil/MagicMirror_scripts

                                            Sam

                                            How to add modules

                                            learning how to use browser developers window for css changes

                                            C 1 Reply Last reply Reply Quote 0

                                            Hello! It looks like you're interested in this conversation, but you don't have an account yet.

                                            Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

                                            With your input, this post could be even better 💗

                                            Register Login
                                            • 1
                                            • 2
                                            • 3
                                            • 1 / 3
                                            • First post
                                              Last post
                                            Enjoying MagicMirror? Please consider a donation!
                                            MagicMirror created by Michael Teeuw.
                                            Forum managed by Sam, technical setup by Karsten.
                                            This forum is using NodeBB as its core | Contributors
                                            Contact | Privacy Policy