Watching a remotely stored video

by Theo Verelst

Maybe a bit of a specialistic page, but fun.

I tried using tcl to set up a connection to a remote machine, over a simple ethernet connection, where a video file would be transfered with two short tcl scripts.

The one machine, with the video file on it, would run this script:

 set ss [socket -server servvid 1234]

 proc servvid {s i p} {
   global argv
   puts "connection from $i"
   flush stdout
 #   set f [open h:/dinsd2b.wmv r]
   set f [open [lindex $argv 0] r]
   fconfigure $s -translation binary
   fconfigure $f -translation binary
   fileevent $s readable "puts \"read: \[gets $s\]\" ; flush stdout
      if \[eof $s\] { 
      close $s 
      close $f 
      puts {End of file.}} "
   after 2000
   fileevent $s writable "fcopy $f $s -size 1024
      if \[eof $s\] { 
      close $s 
      close $f 
      puts {End of file.}} "
 }

 vwait forever

called like this (I used cygwin):

 tclsh servvid.tcl i:/Videos/Thunderbold\ and\ Lightfoot.mpg

where the mpeg file is a large file (the example is about 7 Gigabytes), which is the reason it's not simply copied to the other machine. It may not have enough free disc space, and even over 100baseT ethernet it would take some time to copy.

On the other machine, I used another small tcl script to take data from the above dedicated server script, and copy it to stdout:

 set s [socket 192.168.0.1 1234]
 fconfigure $s -translation binary
 fconfigure stdout -translation binary
 fileevent $s readable "puts -nonewline stdout \[read $s 1024\]; flush stdout"

 vwait forever

this script is called like this to pipe it's output to mplayer a linux/windows video player of good visual quality:

 tclsh socktostdout.tcl | mplayer -

With a from-tv recorded movie in (D1) DVD quality, on 'consumer' machines (not too slow) this works neat, except one cannot wind through the video, it starts and then runs, and can be paused (press p in mplayer) but always runs from the beginning.

Remarkably enough, with this 6Mb/s movie material, there are no glitches or hickups, display is nice and smooth.

File sharing of some kind would be possible as alternative, of course, instead of the socket connection, but the machine I used as server has an internet connection, and I don't want to take the risk of anything shared on it. The above script allows serving of only a specific file and nothing else, so can be considered safe, just like that I use pcom with local-only connections to start xterms.

Using Dune

Setup diagram (using BWise)

Image Bwise servvid.jpg

Dune [L1 ] is a set of programs to under linux (at least) control a Pinnacle compatible USB TV mpeg encoder, for a few hundred $s it works fine.

Install dune and on can pipe the output of dunerec to for instance mplayer.

I have this on a machine near a cable/sattelite connection, and can watch dvd quality encoded TV over a network with mplayer using the following tcl scripts.

On the pinnacle side this script should be run, after duneinit has been run (possibly twice) to make the usb connection feed the video box with the right usb driver.

 set ss [socket -server servvid 1234]

 proc servvid {s i p} {
   global argv
   puts "connection from $i"
   flush stdout
   # set f [open h:/dinsd2b.wmv r]
   # set f [open [lindex $argv 0] r]
   fconfigure $s -translation binary
    set f [ open "| dunerec -a [lindex $argv 0] -t dvd -i 0 -R -" r]
 # alternatively this enables the front side composite video/audio inputs
 #  set f [ open "| dunerec -a [lindex $argv 0] -i 2 -R -" r] 
   fconfigure $f -translation binary
   fileevent $s readable "puts \"read: \[gets $s\]\" ; flush stdout
      if \[eof $s\] {
      close $s
      close $f
      puts {End of file.}} "
   after 2000
   fileevent $s writable "fcopy $f $s -size 1024
      if \[eof $s\] {
      close $s
      close $f
      puts {End of file.}} "
 }

like this froma command line:

    tclsh servvid.tcl 544250

Where the latter is the frequency of the channel.

The receiving PC runs this script:

 set s [socket 192.168.1.33 1234]
 fconfigure $s -translation binary -buffering full
 fconfigure stdout -translation binary -buffering full
 fileevent $s readable "puts -nonewline stdout \[read $s 10240\]; flush stdout"

 vwait forever

like this:

  tclsh socktostdout2.tcl | mplayer -cache 4096 -

Image quality is great, and can be varied, recording is also possible (a tee ?) the tcl scripts don't take much processing time, the linux encoder is hardly noticable. It waits for a connection which when it is made over the socket keeps dunerec running. After mplayer has been killed, it possibly has to be killed by control-c from the commandline, too. After that it can be started again indefinitely, and the serverside dunerec will only work during actual connections.


tb 20090205 - For those like me, who use a different DVB-Recevier with Linux, the server side part can use tzap and ts2ps to substitute the dune suite of programs.

 # Configure here
 set TZAP /usr/bin/tzap 
 set TS2PS /usr/bin/ts2ps
 
 # Kill previous instance of "tzap"
 catch {exec killall -KILL tzap; sleep 1}
 # Call tzap to zap to $1 and wait 2 secs for sync
 exec $TZAP -r [lindex $argv 0] >/dev/null 2>/dev/null &
 exec sleep 2
 puts "Awaiting connection..."
 flush stdout
 
 set ss [socket -server servvid 8111]
 
 proc servvid {s i p} {
   global argv
   puts "\nconnection from $i"
   flush stdout
   set f [open "|$TS2PS /dev/dvb/adapter0/dvr0 0 0" r]
   fconfigure $f -translation binary
   flush stdout
   fconfigure $s -translation binary
   fileevent $s readable "puts \"read: \[gets $s\]\" ; flush stdout
      if \[eof $s\] {
      close $s
      close $f
      puts {End of file.}} "
   after 2000
   fileevent $s writable "fcopy $f $s -size 128
      if \[eof $s\] {
      close $s
      close $f
      puts {End of file.}} "
 }
 
 vwait forever

tb 20090205 - This is really interesting :) - Here's another one which scales and encodes from DVB to MPEG4 using mencoder. It is tweaked to serv over a DSL :) - I had best results on the client side using xine instead of mplayer.

 puts "Awaiting connection..."
 flush stdout
 
 set ss [socket -server servvid 8111]
 
 proc servvid {s i p} {
    global argv
    puts "\nconnection from $i"
    flush stdout

    # the following strings are setting
    # encoding parameters for serving one
    # client over DSL (60Kb upstream)
    set scale "-vf scale -zoom -xy 280 -ofps 15"
    set vcodec "-ovc lavc -lavcopts vcodec=msmpeg4:vbitrate=384:vhq"
    set acodec "-oac mp3lame"

    set ch [open "|mencoder dvb://[lindex $argv 0] -really-quiet -msglevel all=-1 $scale $vcodec $acodec -o -" r]
    puts ""
    flush stdout
    fconfigure $ch -translation binary
    fconfigure $s -translation binary
    fileevent $s readable "puts \"read: \[gets $s\]\" ; flush stdout
      if \[eof $s\] {
      close $s 
      close $ch
      puts {End of file.}} "
    after 2000
    fileevent $s writable "fcopy $ch $s -size 128
      if \[eof $s\] {
      close $s 
      close $ch
      puts {End of file.}} "
 }
 
 vwait forever

See also: