Order Now AdSolution Sign Up | Login » Bits on the Run Sign Up | Login »

Forums

/

Precision srubbing and playlist start-time

15 replies [Last post]

see http://www.longtailvideo.com/support/forum/Bug-Reports/14493/Scrub-bar-is-in-accurate for background.

I'm migrating a system from RealPlayer that relies on precise (sub-second) start times in playlists.

While a video stream can only be played back starting at keyframes, it seems arbitrary start times could be be implemented behind the scenes by doing the following:

- accept a requested start time.
- start reading the video stream at the first keyframe preceeding the requested time (it appears this is how it works today) but do not display it.
- wait until the playhead reaches the requested start time.
- start rendering video to the screen.

If a file has very few keyframes this would cause a delay between seeking and playback, so perhaps it would be an optional feature enabled by preciseseek=true?

Flash will do this by default.

If you use a serverside means to seek to an arbitrary point in a video file, the player will start loading the video file, but will not start displaying the video until it hits a keyframe and can begin to re-assemble video frames based upon the keyframe+change data.

I have a sort-of-demo using ffmpeg to supply the video, if you would like to see how this works. Since the requests for video data have to supplied from the server, instead from local cache, there may be a slight delay before the video starts in addition to the delay before Flash hits the keyframe. Audio playback starts immediately.

Interesting. Does xmoov.php count as a serverside means for seeking in this instance? That's what I'm using now, and I'm pretty sure it's starting at the preceding keyframe.
In http://www.counterbalance.net/flashtest/lefty.html The first clip is supposed to start at 25 seconds, but starts at 24. Only when I change the start time in the playlist to >=27 does it change where the video starts playing. This is conistent with the file having keyframes every 90 frames.

When accessing a video file through xmoov, the player looks up the nearest previous keyframe in the metadata array of time/byte-position and sends the byte position of the keyframe to the script. That guarantees that the video file received from the xmoov script starts on a keyframe.

Using ffmpeg, you can request any arbitrary time to start and stop. ffmpeg then adds the FLV header and serves the chunk without regard to keyframes. The player receives the file but doesn't display the video until it receives a keyframe.

I'll send a link to the demo to your email address. But first I'll add a form box to it where you can input any arbitrary start and stop times and have that chunk of the video file served by ffmpeg.

only first video is loaded and displayed.
but from the second one , video is loading but not displaying ....

plz help me..

this is my code:

videos.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Simple Play On Schedule - JWMP v4.4.x - swfobject v2.2</title>
<script type="text/javascript">
var params=window.location.search.substring(1);
var jvalue=0;
var getjvalue=new Array();
ps = params.split("&");
for(i=0;i<ps.length;i++){
getjvalue = ps[i].split("=");
if(getjvalue[0]=='jval'){jvalue=getjvalue[1];}
}
</script>
<!--<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/swfobject/2.1/swfobject.js"></script>-->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/swfobject/2.1/swfobject.js"></script>
<script type="text/javascript">
var flashvars =
{ 'displayclick': 'play',
'file': 'videos_details.xml',
'playlist': 'right',
'playlistsize': '350',
'repeat': 'true',
'shuffle': 'false',
'skin': 'bright',
'frontcolor': 'ffffff', // text & icons (green)
'backcolor': '000000', // playlist background (blue)
'lightcolor': 'C286BA', // selected text/track highlight (red)
'screencolor': '000000', // screen background (white)
'id': 'playerId1',
};
var params =
{
'allowfullscreen': 'true',
'allowscriptaccess': 'always',
'bgcolor': '#000000'
};
var attributes =
{
'name': 'playerId1',
'id': 'playerId1'
};

swfobject.embedSWF('player-viral.swf', 'player1', '780', '314', '9.0.124', false, flashvars, params, attributes);
</script>
<script type="text/javascript">
var player = null;
var playlist = null;

function playerReady(obj)
{
player = gid(obj.id);
startTime();
}

function startTime()
{
playlist = player.getPlaylist();
if((playlist !== null) && (playlist !== undefined))
{
var currentTime = new Date();

var hours = ""+currentTime.getHours();
if(hours.length<2) hours = "0"+hours;
var minutes = ""+currentTime.getMinutes();
if(minutes.length<2) minutes = "0"+minutes;
var seconds = ""+currentTime.getSeconds();
if(seconds.length<2) seconds = "0"+minutes;
var tm = hours+":"+minutes;//+":"+seconds;

var itemNo=0,count=0,refreshTime=0;
var endTime="";
var j=jvalue;
for(j in playlist)
{ itemNo++;

var aaa = playlist[j].starttime;
var h = aaa.substr(0,aaa.indexOf(':'));
var m = aaa.substr(3,aaa.indexOf(':',1));
var s = aaa.substr(6,aaa.indexOf(':',3));
var t = h+":"+m;//+":"+s;

var duration=0;

if(playlist[j].starttime == tm)
{ //alert("jvalue********************"+jvalue);
//alert(tm+","+playlist[j].starttime);
duration = playlist[j].duration;
player.sendEvent('ITEM', j);
player.sendEvent("PLAY","true");
gid('start').innerHTML = 'START TIME = ' + playlist[j].starttime+":00" + '<br>CURRENT TIME = ' + tm + ":00" + '<br>ITEM: ' + itemNo + '<BR>DURATION IN SECONDS=' + duration;
break;
}
}
//if(duration!=0)setTimeout("location.reload(true);",duration*1000);
if(duration!=0){setTimeout("window.location.replace('videos.html?jval="+itemNo+"')",duration*1000);}
else setTimeout("location.reload(true);",5000);
}
}
function gid(name)
{
return document.getElementById(name);
}
</script>
</head>
<body>
<div id="playercontainer1" class="playercontainer"><a id="player1" class="player1" href="http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash">Get the Adobe Flash Player to see this video.</a></div>
<div id="start" style="font-family:arial;"></div>
</body>
</html>

and videos_details.xml

<?xml version="1.0" encoding="UTF-8"?><playlist version="1" xmlns="http://xspf.org/ns/0/"><trackList>
<track><title>World's costliest Ad</title><location>admin_videos/world's_costliest_Ad.flv</location><meta rel='starttime'>10:15</meta><meta rel='duration'>120</meta><meta rel='description'>This is the world's costliest Ad ! Watch itl</meta><image>admin_video_thumbnails/world's_costliest_Ad.jpg</image></track>
<track><title>Cars crash</title><location>admin_videos/toycom13.flv</location><meta rel='starttime'>10:16</meta><meta rel='duration'>30</meta><meta rel='description'>Watch the video of the cars</meta><image>admin_video_thumbnails/toycom13.jpg</image></track>
<track><title>2012 Calendar</title><location>admin_videos/2012_Calendar.flv</location><meta rel='starttime'>10:17</meta><meta rel='duration'>399</meta><meta rel='description'>This is 2012 calendar's description</meta><image>admin_video_thumbnails/2012_Calendar.jpg</image></track>
<track><title>Flash Example</title><location>admin_videos/video1.flv</location><meta rel='starttime'>10:18</meta><meta rel='duration'>6</meta><meta rel='description'>Ths is some flash video file example</meta><image>admin_video_thumbnails/video1.jpg</image></track>
</trackList></playlist>

Thanks

can anybody help me please............................

Can you provide a link?

 
Here's your page in a functional state.

Since you didn't explain what you are trying to do with the re-loading by item number, you may have to adjust things a wee bit.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html lang="en">

<!-- From:  http://www.longtailvideo.com/support/forum/Feature-Suggestions/16218/Precision-srubbing-and-playlist-start-time -->

  <head>

    <title>Simple Play On Schedule - JWMP v5.1.x - swfobject v2.2</title>

    <script src="http://www.google.com/jsapi"></script>

    <script type="text/javascript">google.load('swfobject', '2.2');</script>

    <script type="text/javascript">
      var flashvars =
      {
        'file':                        'videos_details.xml',
        'playlist':                    'right',
        'playlistsize':                '350',
        'repeat':                      'true',
        'shuffle':                     'false',
        'skin':                        'bright.swf',
        'frontcolor':                  'FFFFFF', // text & icons                  (white)
        'backcolor':                   '000000', // playlist background           (black)
        'lightcolor':                  'C286BA', // selected text/track highlight (magenta)
        'screencolor':                 '000000', // screen background             (black)
        'id':                          'playerID'
      };

      var params =
      {
        'allowscriptaccess':           'always',
        'allowfullscreen':             'true',
        'bgcolor':                     '#000000'
      };

      var attributes =
      {
        'name':                        'playerID',
        'id':                          'playerID'
      };

      swfobject.embedSWF('player-5.1.805.swf', 'player', '780', '314', '9.0.124', false, flashvars, params, attributes);
    </script>

    <script type="text/javascript">
      var player    =  null;
      var playlist  =  null;

      function playerReady(obj)
      {
        player = gid(obj.id);
        startTime();
      };

      function startTime()
      {
        playlist = player.getPlaylist();

        if(playlist.length > 0)
        {
          var currentTime = new Date();
          var hours = '' + currentTime.getHours();
          if(hours.length < 2) hours = '0' + hours;
          var minutes = '' + currentTime.getMinutes();
          if(minutes.length < 2) minutes = '0' + minutes;
          var seconds = '' + currentTime.getSeconds();
          if(seconds.length < 2) seconds = '0' + minutes;
          var tm = hours + ':' + minutes; // + ':' + seconds;

          var duration    =       0;
          var refreshTime =       0;
          var endTime     =      '';
          var j           =  jvalue;

          for(j in playlist)
          {
            var aaa  = playlist[j].starttime;
            var h    = aaa.substr(0, aaa.indexOf(':'));
            var m    = aaa.substr(3, aaa.indexOf(':', 1));
            var s    = aaa.substr(6, aaa.indexOf(':', 3));
            var t    = h + ':' + m; // + ':' + s;

alert('Current Time: ' + tm + '\nStart Time: ' + playlist[j].starttime + '\nt: ' + t);

            if(playlist[j].starttime > tm)
            {
              duration = playlist[j - 1].duration;
              player.sendEvent('ITEM', (j - 1));
              player.sendEvent('PLAY', 'true');
              gid('start').innerHTML = 'START TIME: ' + playlist[j - 1].starttime + ':00' + '<br />CURRENT TIME: ' + tm + ':00' + '<br />ITEM: ' + (j - 1) + '<br />DURATION: ' + duration;
              break;
            }
          }

alert('duration: ' + duration);
        //if(duration != 0) setTimeout("location.reload(true);", (duration * 1000));
          if(duration != 0)
          {
            //setTimeout("window.location.replace('videos.html?jval=" + (j - 1) + "')", (duration * 1000));
setTimeout("window.location.replace('saharha.html?jval=" + (j - 1) + "')", (duration * 1000));
          }
          else
          {
            setTimeout("location.reload(true);", 5000);
          }
        }
      };

      function gid(name)
      {
        return document.getElementById(name);
      };
    </script>

    <script type="text/javascript">
      var params     =  window.location.search.substring(1);
      var jvalue     =                                    0;
      var getjvalue  =                                   [];
      var ps         =                    params.split('&');
alert('ps: ' + ps + '\nps.length: ' + ps.length);

      if(ps)
      {
        for(i = 0; i < ps.length; i++)
        {
          getjvalue = ps[i].split('=');

          if(getjvalue[0] == 'jval')
          {
            jvalue = getjvalue[1];
          }
        }
      }
    </script>

  </head>

  <body>

    <div id="playercontainer" class="playercontainer"><a id="player" class="player" href="http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash">Get the Adobe Flash Player to see this video.</a></div>
    <div id="start" style="font-family:arial;"></div>

  </body>

</html>

really thankful for ur reply.

I want to create the live tv.
i already stored the videos in some folder, and details in the database.
details:

video_id,video_file_name,video_title,video_description, video_display_date,video_starttime and duration.

i want to populate the playlist with videos according to date and scheduled time(start time).

those videos shud get displayed compared to the current time. that is if(playlist[i].starttime==current_time) .....

kindly reply soon .......

and why iam reloading the page using id means,

by passing the currently displayed video id, i can start the loop from that passed id so that loop need not start from the first.

urgent....
please help waiting for the reply.

 
You can't use [i]if(playlist[i].starttime==current_time)[/i] because you won't get a perfect match.

You have to look through the playlist looking for a starttime that is greater that the current time, then use the previous track. And that's what I changed your code to do.

many thanks for ur reply.

ok I wil change that code(playlist[j].starttime > tm).

the first video is working fine (buffered , played and also displaying in player) but from second onwards is not displaying. it is buffered, played but not displaying in the player.

plz help me.

can anyone help me please....

 
Please post a link to your Test Page so someone can help you further.

please change ur system time to 10:15 AM and check this

http://www.evoltree.com/videoUpload/videos.html

regards
sahasra.

Has anyone followed up on this. I too would like to make a playlist that plays from various points within a video or subsequent videos according to the date and time. In otherwordds, an playlist that plays as if it is a real-time television broadcast, but using fixed archived files.

It seems Noodle and Sahasra were heading in this direction.