lobsterseeds
Posts: 4
Joined: Tue Nov 13, 2012 2:03 pm

Rpi Video Wall

Tue Nov 13, 2012 2:31 pm

Hi, everyone!

I'm trying to do simple video wall using raspberry.
The idea is to run 6 videos on 6 RPi with syncronisation to show 1 big image on 6 screens.

I'm novice in linux and i never used it before.
I thought that i'll use puredata for this - but it's not work on raspberry (

I found a solution with mplayer.
I use 1 RPi as master and send clock using -udp-master command to another 5 rasperries connected as -udp-slave.

BUT!
Video works too slow, because it's no possible to use mplayer for video (of course if it not 320x240) (

As anybody knows how to use omxplayer in the same way ?
Or how to work with omx-h264 codec but with the mplayer ?
Or how to accelerate video using video core and mplayer ?

Now i'm in a trouble - because i should finish this project until sunday (((

I have mpeg2 licence - but it not work with mplayer.
The video size is 960x600 h.264 codec.

Sorry for my English.

Thank you!

Alex.

jole
Posts: 4
Joined: Thu Jun 14, 2012 8:17 am
Location: Edmonton, AB
Contact: Website

Re: Rpi Video Wall

Wed Nov 14, 2012 7:11 am

Hi Alex,

I'm interested in the same sort of project, however I've been encountering similar roadblocks.
I use 1 RPi as master and send clock using -udp-master command to another 5 rasperries connected as -udp-slave.
I was hoping to use a similar approach, however projects like mplayer and VLC require at the very least an X11 that is accelerated in some way. Performance is not useable right now.
As anybody knows how to use omxplayer in the same way ?
Since omxplayer is fairly simplistic, it does not have the same udp-master/udp-slave functions.
Or how to accelerate video using video core and mplayer ?
I look forward to the day this may happen, but doesn't look possible right now.

There was a post about controlling the clock of omxplayer a while back, but there wasn't a whole lot of information about it, and it involved a fair bit of hacking of the omxplayer itself.

Edit: http://www.raspberrypi.org/phpBB3/viewt ... 33&t=10476 here's the post in question!

Good luck!
-Joel

GeorgeIoak
Posts: 50
Joined: Thu Aug 30, 2012 1:50 am

Re: Rpi Video Wall

Thu Nov 15, 2012 4:31 pm

Have you tried using the hello_video program? I find that it starts up videos very quickly. You could then run a program on all the boards that starts the video when a level changes on a GPIO pin. You can tie all the GPIO pins together and then use a button to change the level. If all the RPi are configured the same you might get could results.

User avatar
RaTTuS
Posts: 10539
Joined: Tue Nov 29, 2011 11:12 am
Location: North West UK
Contact: Twitter YouTube

Re: Rpi Video Wall

Thu Nov 15, 2012 4:35 pm

omxplayer -o hdmi video.file.name
How To ask Questions :- http://www.catb.org/esr/faqs/smart-questions.html
WARNING - some parts of this post may be erroneous YMMV

1QC43qbL5FySu2Pi51vGqKqxy3UiJgukSX
Covfefe

ghans
Posts: 7882
Joined: Mon Dec 12, 2011 8:30 pm
Location: Germany

Re: Rpi Video Wall

Thu Nov 15, 2012 5:58 pm

It's not impossible - you'll have to learn to code with OpenMAX though.


ghans
• Don't like the board ? Missing features ? Change to the prosilver theme ! You can find it in your settings.
• Don't like to search the forum BEFORE posting 'cos it's useless ? Try googling : yoursearchtermshere site:raspberrypi.org

lobsterseeds
Posts: 4
Joined: Tue Nov 13, 2012 2:03 pm

Re: Rpi Video Wall

Thu Nov 15, 2012 7:23 pm

Thank you for your responces!

Actually my first idea was to rewind video using GPIO, like GeorgeIoak wrote.
But i tried it with mplayer - and it was very slow, because endless loop in python use a lot of memory.

Can someone write a code how send a rewind button to omxplayer using python ?


In future i'll learn openmax, but now i don't have a time for it (
Deadline for me is sunday.

So the question is: how to "clear" the screen on omxplayer when i use it at full screen mode.
and second how to rewind the omx player to begining at the end?

Sorry for this primitive questions - but i don't have a time to googling and trying my code.
I'll work with my pi only tommorow!

Thank you one more time and sorry for my english!

ps. I've found this topic http://www.raspberrypi.org/phpBB3/viewt ... 2&p=161169
Maybe it's possible to do similar thing ?

But i don't know what i should write there (

And my video also should start on boot.

lobsterseeds
Posts: 4
Joined: Tue Nov 13, 2012 2:03 pm

Re: Rpi Video Wall

Fri Nov 16, 2012 5:29 pm

upd.

I continue my work with the hello_video example

I have added wiripingPi library (thanks for Gordon!) to the code.
Also i make loop.

And now i can send video to beggining.

But now - it's a new problem.
As anybody knows how to send video directly to the begging ? In what place of the code I should check button status ? Because now it's take a time.

Maybe i need to use button as volatile ?
But i don't know how to work with volatile OR check the button status in parallel.

here is my code

Code: Select all

// Video deocode demo using OpenMAX IL though the ilcient helper library

#include <wiringPi.h>
#include <stdint.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "bcm_host.h"
#include "ilclient.h"

#define pin 15

  int bright = 0 ;
  int prev = 0;

static int video_decode_test(char *filename)
{
   OMX_VIDEO_PARAM_PORTFORMATTYPE format;
   OMX_TIME_CONFIG_CLOCKSTATETYPE cstate;
   COMPONENT_T *video_decode = NULL, *video_scheduler = NULL, *video_render = NULL, *clock = NULL;
   COMPONENT_T *list[5];
   TUNNEL_T tunnel[4];
   ILCLIENT_T *client;
   FILE *in;
   int status = 0;
   unsigned char *data = NULL;
   unsigned int data_len = 0;
   int find_start_codes = 0;
   int packet_size = 16<<10;   

   memset(list, 0, sizeof(list));
   memset(tunnel, 0, sizeof(tunnel));

   if((in = fopen(filename, "rb")) == NULL)
      return -2;

   if((client = ilclient_init()) == NULL)
   {
      fclose(in);
      return -3;
   }

   if(OMX_Init() != OMX_ErrorNone)
   {
      ilclient_destroy(client);
      fclose(in);
      return -4;
   }

   if(find_start_codes && (data = malloc(packet_size+4)) == NULL)
   {
      status = -16;
      if(OMX_Deinit() != OMX_ErrorNone)
         status = -17;
      ilclient_destroy(client);
      fclose(in);
      return status;
   }
   // create video_decode
   if(ilclient_create_component(client, &video_decode, "video_decode", ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS) != 0)
      status = -14;
   list[0] = video_decode;

   // create video_render
   if(status == 0 && ilclient_create_component(client, &video_render, "video_render", ILCLIENT_DISABLE_ALL_PORTS) != 0)
      status = -14;
   list[1] = video_render;

   // create clock
   if(status == 0 && ilclient_create_component(client, &clock, "clock", ILCLIENT_DISABLE_ALL_PORTS) != 0)
      status = -14;
   list[2] = clock;

   memset(&cstate, 0, sizeof(cstate));
   cstate.nSize = sizeof(cstate);
   cstate.nVersion.nVersion = OMX_VERSION;
   cstate.eState = OMX_TIME_ClockStateWaitingForStartTime;
   cstate.nWaitMask = 1;
   if(clock != NULL && OMX_SetParameter(ILC_GET_HANDLE(clock), OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone)
      status = -13;

   // create video_scheduler
   if(status == 0 && ilclient_create_component(client, &video_scheduler, "video_scheduler", ILCLIENT_DISABLE_ALL_PORTS) != 0)
      status = -14;
   list[3] = video_scheduler;

   set_tunnel(tunnel, video_decode, 131, video_scheduler, 10);
   set_tunnel(tunnel+1, video_scheduler, 11, video_render, 90);
   set_tunnel(tunnel+2, clock, 80, video_scheduler, 12);

   // setup clock tunnel first
   if(status == 0 && ilclient_setup_tunnel(tunnel+2, 0, 0) != 0)
      status = -15;
   else
      ilclient_change_component_state(clock, OMX_StateExecuting);

   if(status == 0)
      ilclient_change_component_state(video_decode, OMX_StateIdle);

   memset(&format, 0, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
   format.nSize = sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE);
   format.nVersion.nVersion = OMX_VERSION;
   format.nPortIndex = 130;
   format.eCompressionFormat = OMX_VIDEO_CodingAVC;

   if(status == 0 &&
      OMX_SetParameter(ILC_GET_HANDLE(video_decode), OMX_IndexParamVideoPortFormat, &format) == OMX_ErrorNone &&
      ilclient_enable_port_buffers(video_decode, 130, NULL, NULL, NULL) == 0)
   {
      OMX_BUFFERHEADERTYPE *buf;
      int port_settings_changed = 0;
      int first_packet = 1;

      ilclient_change_component_state(video_decode, OMX_StateExecuting);

      while(( buf = ilclient_get_input_buffer(video_decode, 130, 1)) != NULL)
      {
	bright = digitalRead (pin);
             if (bright == 0 && prev == 0) { fseek(in, 0, SEEK_SET); prev = 1; }
             else if (bright == 1 && prev == 1) { prev = 0; }
         
         // feed data and wait until we get port settings changed
         unsigned char *dest = find_start_codes ? data + data_len : buf->pBuffer;

         data_len += fread(dest, 1, packet_size+(find_start_codes*4)-data_len, in);

         if(port_settings_changed == 0 &&
            ((data_len > 0 && ilclient_remove_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1) == 0) ||
             (data_len == 0 && ilclient_wait_for_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1,
                                                       ILCLIENT_EVENT_ERROR | ILCLIENT_PARAMETER_CHANGED, 10000) == 0)))
         {
            port_settings_changed = 1;

            if(ilclient_setup_tunnel(tunnel, 0, 0) != 0)
            {
               status = -7;
               break;
            }

            ilclient_change_component_state(video_scheduler, OMX_StateExecuting);

            // now setup tunnel to video_render
            if(ilclient_setup_tunnel(tunnel+1, 0, 1000) != 0)
            {
               status = -12;
               break;
            }
            
            ilclient_change_component_state(video_render, OMX_StateExecuting);
         }
         if(!data_len)
            fseek(in, 0, SEEK_SET);

         if(find_start_codes)
         {
            int i, start = -1, len = 0;
            int max_len = data_len > packet_size ? packet_size : data_len;
            for(i=2; i<max_len; i++)
            {
               if(data[i-2] == 0 && data[i-1] == 0 && data[i] == 1)
               {
                  len = 3;
                  start = i-2;

                  // check for 4 byte start code
                  if(i > 2 && data[i-3] == 0)
                  {
                     len++;
                     start--;
                  }

                  break;
               }
            }

            if(start == 0)
            {
               // start code is next, so just send that
               buf->nFilledLen = len;
            }
            else if(start == -1)
            {
               // no start codes seen, send the first block
               buf->nFilledLen = max_len;
            }
            else
            {
               // start code in the middle of the buffer, send up to the code
               buf->nFilledLen = start;
            }

            memcpy(buf->pBuffer, data, buf->nFilledLen);
            memmove(data, data + buf->nFilledLen, data_len - buf->nFilledLen);
            data_len -= buf->nFilledLen;
         }
         else
         {
            buf->nFilledLen = data_len;
            data_len = 0;
         }

         buf->nOffset = 0;
         if(first_packet)
         {
            buf->nFlags = OMX_BUFFERFLAG_STARTTIME;
            first_packet = 0;
         }
         else
            buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN;

         if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone)
         {
            status = -6;
            break;
         }
         
      }

      buf->nFilledLen = 0;
      buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN | OMX_BUFFERFLAG_EOS;
      
      if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone)
         status = -20;
      
      // wait for EOS from render
      ilclient_wait_for_event(video_render, OMX_EventBufferFlag, 90, 0, OMX_BUFFERFLAG_EOS, 0,
                              ILCLIENT_BUFFER_FLAG_EOS, 10000);
      
      // need to flush the renderer to allow video_decode to disable its input port
      ilclient_flush_tunnels(tunnel, 0);

      ilclient_disable_port_buffers(video_decode, 130, NULL, NULL, NULL);
   }

   fclose(in);

   ilclient_disable_tunnel(tunnel);
   ilclient_disable_tunnel(tunnel+1);
   ilclient_disable_tunnel(tunnel+2);
   ilclient_teardown_tunnels(tunnel);

   ilclient_state_transition(list, OMX_StateIdle);
   ilclient_state_transition(list, OMX_StateLoaded);

   ilclient_cleanup_components(list);

   OMX_Deinit();

   ilclient_destroy(client);
   return status;
}

int main (int argc, char **argv)
{
   if (argc < 2) {
      printf("Usage: %s <filename>\n", argv[0]);
      exit(1);
   }
   
  if (wiringPiSetup () == -1)
    exit (1) ;

  pinMode (pin, INPUT) ;
  pullUpDnControl (pin, PUD_UP) ;

   bcm_host_init();
   return video_decode_test(argv[1]);
}


as you can see i just add

Code: Select all

if (wiringPiSetup () == -1)
    exit (1) ;

  pinMode (pin, INPUT) ;
  pullUpDnControl (pin, PUD_UP) ;
in a main code
and

Code: Select all

bright = digitalRead (pin);
    if (bright == 0 && prev == 0) { fseek(in, 0, SEEK_SET); prev = 1; }
    else if (bright == 1 && prev == 1) { prev = 0; }
after while statement.
It's the best that i can do (

fisejs
Posts: 2
Joined: Mon Mar 04, 2013 10:29 am

Re: Rpi Video Wall

Sun Mar 10, 2013 12:33 pm

Hello Lobster,
its great you already work on this. I want to build similar video wall and from different sollution I end up with raspberry and omxplayer. I can write just simple scripts in bash, so I am going to find some programmer to help me.

Could you write a bit more how to build the wall? What code do you run on master pi and what on slaves? Does your code-sollution realy work (all frames go synchro)?

Thans for any help, Jakub

Sogorman
Posts: 1
Joined: Sun Mar 10, 2013 10:57 pm

Re: Rpi Video Wall

Sun Mar 10, 2013 11:01 pm

I too am looking at using 9 RPIs in a 3x3 video wall configuration. Would be interested in seeing what everyone comes up with for a master / slave configuration.

Thanks much!

Sean

fisejs
Posts: 2
Joined: Mon Mar 04, 2013 10:29 am

Re: Rpi Video Wall

Wed Mar 13, 2013 8:24 pm

I haven´t tried it yet, but this looks very promising:
https://github.com/turingmachine/omxpla ... layer-sync

Neil_pdj
Posts: 1
Joined: Thu Aug 29, 2013 11:24 pm

Re: Rpi Video Wall

Thu Aug 29, 2013 11:26 pm

Hi. I'm really keen to learn more about doing this. Did anyone ever get a working solution?
Thanks.

karlkiste
Posts: 189
Joined: Tue Jan 22, 2013 8:50 am
Location: berlin, germany

Re: Rpi Video Wall

Sat Aug 31, 2013 4:14 pm

I've done something similar, but not quite the same.

I've modified omxplayer, so it won't start until a certain GPIO has a "high" level. This check is done after all the initializations, right before the first video frame is displayed. It is checked in a fast spinning loop to get a quick startup.

The "master" is a microcontroller, but it could also be an extra pi which does not act as a video player. The master switches the GPIO line, and all the player start at the same time, give or take a few microseconds.

The real trick is - the videos are no longer than three minutes or so. Within that short period, the players stay in sync, at least to the human eye.

I doubt it would work for feature-length movies without online syncing, however.

For the other solutions: I doubt that omxplayer will ever get such a sync-feature. And I presume it will take another couple of years for mplayer (of a fork thereof) to support openmax. I would, however, greatly welcome both ;-)

Greets,
Kiste

powertieke
Posts: 4
Joined: Tue Sep 10, 2013 10:21 am

Re: Rpi Video Wall

Tue Sep 10, 2013 3:10 pm

Currently building something similar. It's first incarnation will be for a trade show stand, using 17 screens which will need to play animations in sync as well as loop presentations / movies when not synced.

I'm running as many pi's as I have screens, as well as one extra for controlling them.

Syncing is done by ethernet. The controller shoots out it's position (using UDP), and if one of the screens is too far off, if will correct itself by pausing or accelerating the omxplayer subprocess.

Gave up trying to get the movies to stop/start seamlessly. Instead I'm looking into pi3d for displaying an image in between stop/starts.

Ideally, the controller will host a site which someone using an iphone or android connected to the network can access to start/stop individual screens or initiate synced play.

What I have working so far:
http://www.youtube.com/watch?v=Bn2c5kdZY58

You can check out the terrible terrible code at the github repository

User avatar
paddyg
Posts: 2501
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: Rpi Video Wall

Tue Sep 10, 2013 4:44 pm

@powertieke I was just wondering about using pi3d split over several screens. leconeur is doing some shader development and starting to play with pi3d, presumably he could benefit from a wall of screens system. Interesting to see how you get on.

Your code looks fine but a complete absence of comments makes it all a bit mind-boggling!
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

powertieke
Posts: 4
Joined: Tue Sep 10, 2013 10:21 am

Re: Rpi Video Wall

Tue Sep 10, 2013 7:58 pm

That's something I have to work on. I'm affraid the comments will make matters worse.

I have to admit that this is my first programming project beyond 'single file/couple of lines' scripts and some light web development. I'm having a blast though.

Not doing anything fancy (like splitting video streams) yet. All of the screens get their own pre-rendered portions of the big animation.

User avatar
paddyg
Posts: 2501
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: Rpi Video Wall

Tue Sep 10, 2013 9:03 pm

The issue of video splitting also seemed like it would be a problem to me so I thought that, as pi3d has a camera object with direction vectors but also field of view angle, It should be possible to render the same objects the the same virtual x,y,z location on each pi but 'point the camera' in a different direction so as the objects, pictures etc move out of one screen they appear on another. Keeping the frame count synchronised between the python programs shouldn't be too hard. (Did I really say that? Obviously there's a lot of work to do but I can imagine a way of doing it!)

Comments seem to be a real bother when you first start programming but the first time you go back to something you did two month's ago, or attempt to figure out someone else's code you will start adding them willingly.
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

ghans
Posts: 7882
Joined: Mon Dec 12, 2011 8:30 pm
Location: Germany

Re: Rpi Video Wall

Fri Sep 13, 2013 11:05 am

This might be useful for anybody following this thread :

http://www.ccfe.ac.uk/computing_projects.aspx

I have no idea if they already are distributing the software yet.


ghans
• Don't like the board ? Missing features ? Change to the prosilver theme ! You can find it in your settings.
• Don't like to search the forum BEFORE posting 'cos it's useless ? Try googling : yoursearchtermshere site:raspberrypi.org

denjell
Posts: 25
Joined: Sun Feb 10, 2013 4:00 pm

Re: Rpi Video Wall

Sun Sep 15, 2013 11:11 am

Here is the download & instructions:

http://www.piwall.co.uk/information/10- ... vie-piwall

ghans
Posts: 7882
Joined: Mon Dec 12, 2011 8:30 pm
Location: Germany

Re: Rpi Video Wall

Tue Sep 17, 2013 10:23 am

Nice !

ghans
• Don't like the board ? Missing features ? Change to the prosilver theme ! You can find it in your settings.
• Don't like to search the forum BEFORE posting 'cos it's useless ? Try googling : yoursearchtermshere site:raspberrypi.org

Return to “Graphics, sound and multimedia”