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

Forums

/

Movie and a slideshow

92 replies [Last post]

Hello all!

I'm using the mediaplayer here: http://www.tui.edu/JimTest/testing-vid/
and here's my situation.

In the lower left box, I'd like to have a synchronized powerpoint type slideshow. The issues involved are:

1)When you select a course, you get an xml loaded playlist - each item/class on the playlist would have its own slideshow, so the playlist entry needs to not only load the particular video into the player, but also the slideshow into the seperate swf in the corner

2) The slideshow needs to be synchronized with the video lecture, either through careful timing, through play/stop commands sent from the video, or through xml like the closed captioning (or some other method I don't know of)

3) If it's synchronized through timing, then it needs to also be controlled by the mediaplayer's pause/play buttons so that if a student pauses the video, the slideshow doesn't keep going, getting out of synch.

So what do you think - is this actually do-able?

yes, quite doable!

the [url=http://home5.inet.tele.dk/nyboe/flash/mediaplayer/controller.htm]controller[/url] demo on the [url=http://home5.inet.tele.dk/nyboe/flash/mediaplayer/]demopage[/url] does just this (a mediaplayer controls an imagerotator)

for the playlist selection you combine it with one of the multiple playlist demos:
[url=http://home5.inet.tele.dk/nyboe/flash/mediaplayer/playlistlinks.htm]playlistlinks[/url] or [url=http://home5.inet.tele.dk/nyboe/flash/mediaplayer/multipleplaylists.htm]multipleplaylists[/url] and you have exactly what you describe...

Is there an outline of the process somewhere, or is it pretty clear how it's done just by taking a look at the source code on the page?

the latter (but i cant tell if you will find it clear, ofcourse ;)

give it a good try, and tell if it goes wrong (or good) and people here will try and help out if needed...

you might want to have a look at the [url=http://home5.inet.tele.dk/nyboe/flash/mediaplayer/panorama.htm]panorama[/url] demo on the [url=http://home5.inet.tele.dk/nyboe/flash/mediaplayer/]demopage[/url] too- it works quite differently
(no imagerotator, just an iframe, but it could have video as well, instead of just mp3)

note that the [url=http://www.jeroenwijering.com/extras/javascript.html]javascript api[/url] only works online...

okay - diving in now, we'll see what kind of damage I can do! :d

I can't seem to get the imagerotator to actually do anything... :(

http://www.tui.edu/JimTest/testing-vid/videoplayer.html

What am I messing up?

probably the paths - try using absolute paths (at least until it works)
i see you got the paths working now...

yes and no :)

Images showing up, but not working the way I need it to. Rather than having a random image show up when landing on the page, I need *no slideshow at all* until someone selects a class from the playlist - and then it should load both the video, and then a specific slideshow playlist as well.

And I need the images in the slideshow to advance/stop/pause, etc. all in time with the specific video lecture associated with it.

Am I just out of luck, or...?

no, it should be just a matter of tweaking the settings - give me a few minutes i have to read the script again...

Okay - I think I may be in over my head with this project, because I'm not sure I know what to do with your suggestions :)

The slidechange must be triggered by player events, to make sure that the right slide appears at the right time during the lecture.

I'll see what I can do about implementing your suggestions!

you said:

first, you have a:
function sendEvent(typ,prm) {
...
};

too many, you need to rename one of them (in the call too)!

Unfortunately I don't know what this means, or what to do with it... I'm stuck :(

then you need to set s.addVariable("autostart","false"); in the rotator...

Now *this* one I can do! :)

these are the lines invoked by the player to select a specific slide:
function getUpdate(typ,pr1,pr2,pid) {
if(pid != "null") {
if((pid=="thePlayerId")&&(typ == "item")) {
currentItem = pr1;
sendEvent('playitem', currentItem); //this line
}
}
};

that needs to be changed to a call to createRotator(someplaylist) with the correct playlist...

And again - I'm lost. I'm afraid I've only been able to get as far as I have with this by finding specific examples of what I need and copying/pasting them in place.

And yes, the slidechange must be triggered by player events, to make sure that the right slide appears at the right time during the lecture.

ok -

first, you have a:

function sendEvent(typ,prm) {
...
};

too many, you need to rename one of them (in the call too)!

then you need to set s.addVariable("autostart","false"); in the rotator...

these are the lines invoked by the player to select a specific slide:

function getUpdate(typ,pr1,pr2,pid) {
if(pid != "null") {
if((pid=="thePlayerId")&&(typ == "item")) {
currentItem = pr1;
sendEvent('playitem', currentItem); //this line
}
}
};

that needs to be changed to a call to createRotator(someplaylist) with the correct playlist...

then there is the question; if the rotator can be freerunning while the player plays, or if the slidechange must be triggered by player events.
its easy to stop and start the rotator, when the player does (see the [url=http://home5.inet.tele.dk/nyboe/flash/mediaplayer/IDcontrol.htm]IDcontrol[/url] demo on the [url=http://home5.inet.tele.dk/nyboe/flash/mediaplayer/]demopage[/url])
but it takes some sort of extra means to trigger something while playing (what is the event and how do we catch it)...

-----
just saw your response - ok, if the slidechanges are to be at irregular intervals during the video -then it will take more than this...

i think maybe streaming would be the solution to this, but that is not my field im afraid - i know that Will have come up with all sorts of wonderful PHP solutions in this respect around in the forum - do you have the possibility of using PHP?

I do indeed have the possibility of using PHP!

Unfortunately for me

first, you have a:
function sendEvent(typ,prm) {
...
};

too many, you need to rename one of them (in the call too)!

these are the lines invoked by the player to select a specific slide:
function getUpdate(typ,pr1,pr2,pid) {
if(pid != "null") {
if((pid=="thePlayerId")&&(typ == "item")) {
currentItem = pr1;
sendEvent('playitem', currentItem); //this line
}
}
};

that needs to be changed to a call to createRotator(someplaylist) with the correct playlist...

might as well be written in greek

Can you show me an example of what you're talking about? Is there another site out there doing this, or...?

we have to hope that Will comes by soon - he is usually the one that gives the advice in PHP matters - you can find his postings many places in the fora - not the least in the [url=http://www.jeroenwijering.com/?forum=Serverside_modules]Serverside_modules[/url] which is what i think you would need to change the slides while the video plays...

i dont know if you want to persue a solution to the above script questions - when we already know that it cant do what you really want?

Will's busy doing a Brain Dump™ on some other stuff, but if you give him a few days to finish that and get a handle on this, he MAY have a solution.

Okay - how about this - the process will still work without having the video advance/control the slideshow. I can add something like (next slide) in the cc/transcipt and the student can advance the slideshow to the next slide themselves.

So now all I'd really need to do is have the appropriate slideshow load when the student clicked on an item in the playlist... which is what I think you were trying to help me accomplish, yes?

@James,

What I need to know, in plain English, is how you want this system to work. Forget about the code, that comes much later.

How are the video and slide show going to be coordinated?
Will the slide change every, say 30 seconds of the video?

Where will the playlist for the slide show come from? Do you need a PHP script to generate the playlist? Where will the actual list of slides come from? A list that you make; reading a directory?

Do you need to use the Image Rotator because you MUST have the transistions between images, or can you use the media player?

When an item on the video playlist is selected, it will have to trigger the loading of a new playlist into the slide show — there will have to be a slight delay while this happens — then the video and the slide show can both start synchronized. Pausing the video would pause the slideshow.

It seems that this would require some JavaScript on the client to detect the selection of a new item, which would trigger the pausing of the video player and the loading of the new slideshow playlist, then both players would be started when ready.

So things don't get out of sync, it would be best to use absolute synchronization such as: (for 30 second sync)
video => slide
0=>0
30=>1
60=>2
90=>3

So when the video player reported that it was at 30 seconds, the slide player would load slide 1.

(We always start with 0 because the first item on playlists is item 0.)

@Will

What I need to know, in plain English, is how you want this system to work. Forget about the code, that comes much later.

Page is here: [url=http://www.tui.edu/JimTest/testing-vid/videoplayer.html]click here[/url]

Select a course from the drop-down menu - the course selection loads an xml driven playlist of "classes."

Select a "class" from the playlist - this loads a video lecture in the large central window - *and* a slideshow in the lower left window that is particular to that individual class from the playlist.

Each playlist item will have its own video and its own slideshow.

The slides won't change on a regular basis (like every 30 seconds or so) - just like closed captioning, the slides would ideally change as appropriate to the lecture, just like a powerpoint presentation.

That's the ideal.

What I can live with is a slideshow that does *absolutely no slidechanges on its own* but instead waits for the user to navigate ahead on their own. In this instance, I would simply add something like (next slide) in the captions, so the user would know when to advance the slideshow.

In this case, all I'd need was the ability to load a particular slideshow along with a particular item in the playlist.

Of course - in all instances, the slideshow must always begin with "slide 1" and move on sequentially (many examples I've seen have random slides at the beginning).

That's it in a nutshell :-)

Where will the playlist for the slide show come from?

XML - I don't mind writing this up by hand - but certainly wouldn't turn away any sort of automation/scripting for it.

Do you need a PHP script to generate the playlist? Where will the actual list of slides come from? A list that you make; reading a directory?

Each class will have its own slideshow, which will have its own images directory.

Do you need to use the Image Rotator because you MUST have the transistions between images, or can you use the media player?

I'm not married to the Image Rotator - I'll use *anything* that will get the job done. :-)

When an item on the video playlist is selected, it will have to trigger the loading of a new playlist into the slide show — there will have to be a slight delay while this happens — then the video and the slide show can both start synchronized. Pausing the video would pause the slideshow.

Aye.

It seems that this would require some JavaScript on the client to detect the selection of a new item, which would trigger the pausing of the video player and the loading of the new slideshow playlist, then both players would be started when ready.

Aye - unless we're going with the user/manual slide advance, in which case all that would be important is the loading of the matching slideshow when a class is selected from the main mediaplayer playlist.

I really appreciate all this help - you guys are great. I promise TONS of credit if this project works! :-)

@James,

One thing we need to be really clear on here.

Each playlist item will have its own video and its own slideshow.

The slides won't change on a regular basis (like every 30 seconds or so) - just like closed captioning, the slides would ideally change as appropriate to the lecture, just like a powerpoint presentation.

This isn't going to happen without some "magic" connection between the video and the slide show. Closed captioning is based upon running time and duration. Somebody spent a lot of time watching a video and typing those captions...

Making a closed caption file for 2-3 minutes of a song takes an hour to type and time the captions, then touch them up so they are consistent with the beginning of each phrase. Maybe a professional captioneer can do it faster, but my point is that there has to be some connection between events, like the chapters.txt we're using here: [url=http://www.jeroenwijering.com/?thread=6080#msg33286]Chapterize - Town Meeting[/url]. Once that small file is done, most of the rest can be automated.

The reason that I'm making this point strongly, is that many users think the captions, music, whatever are just magically linked and coordinated with the video or song or images. No magic, a lot of boring, tedious work. That's why I'm trying to automate the process as much as possible.

Anyway, this is a very interesting application that I think a lot of users could apply to similar situations, so it's worth developing a system for doing it.

@Will,

Familiar with the work involved re: captions, etc. and understand that "the magaic" is *me* (trust me, I've thought this through - we're not a giant university by any means, but we're still large enough that I've done the math wrt "Now, what happens if *all* the professors want to offer *all* their classes in this format?" :-) - the budget proposal for hiring student workers is underway).

Now, I'm guessing that since it hasn't been directly addressed yet, that there's no "out of the box" method for loading the powerpoint/slideshow presentation along with the video when it's selected from the playlist, and so this whole thing will take some thinking/tweaking, yes?

Is there anything I can do - any more information I can provide to help? I feel somewhat useless at this point. :-)

@James,

OK, just wanted to be sure we were on the same page here.

Plus, a lot of the embellishment in these posts is for the benefit of other users who may not have an understanding of the topic.

There is no "out-of-the-box" solution, that's what we're going to build here. As we build it, I will try to keep it "generic" so it can be used for other similar applications.

The key point here is the "glue" or the "puppet strings" between the video and the slide show. The coding is easy once we know what we have to work with in what form, and then, what we want to happen.

For instance, the video "title" is available from the player when we load a video. That can be used to load the slide show playlist.

So, for example:

Video Title=>Course 121 (video file=>course_121.flv)
could load:
Slide Show Playlist=>course_121.xml

Then all that's left is the syncronization, which in this case, is the hard part.

We have the choices of:
1) video position (available from the player)
2) user action (click on a button)
3) automatically, every nn seconds
4) some sort of sync. file that is loaded by the player,
not supported that I know of, I don't know if the player outputs any information from the captions file that could be used to trigger the slide show change. This is worth looking into, because it is already built into the player.
5) pure "magic" (unknown methods that we may be able to dream up)
6) other... ;) (always have to have "other" on a "complete list")

The one thing you could do now, is to write a standard for naming the video (video title), the video filename, and the corresponding slide show playlist. Just a couple of paragraphs. Then we have something "hard" to work with. It can always be changed later, but at least we have a standard to adhere to or change. You should do it, because you know what your courses/video files are named. Keep it short & sweet, no special characters in the filenames, something to make it unique for each course, and corresponding to your catalog.

And, also, print this out, post it on the wall and throw a dart at the choices. Seriously, give me your thoughts on the available choices for syncing the video and the slideshow.

@Will,

Okay - let's go with this:

Video Title = "unit" followed by a three digit number, i.e. Unit 001 or Unit 021

Video file = unit_"corresponding three digit number".flv, i.e. unit_001.flv or unit_021.flv

Slideshow playlist = same pattern: unit_001.xml, unit_021.xml and so on.

Since each title represents a class in a course (first class is unit_001, second is unit_002, etc.), we shouldn't ever have a need for more than two digits, but you never know, so we might as well go for three and just have an extra 0 we don't need. :-)

As for our synch options, it looks like 1 and 2 are the best bets, with 2 looking a little easier from the coding perspective, but 1 looking more seamless and user-friendly for the student.

While option 1 is nice, option 2 is certainly acceptible, and still a whole lot better than "no option at all" - right? :-)

@James,

Opton 1) would require a set of "video seconds:slide number" pairs that could come from a simple text file stored with the video files and slide files. I think we could slip those pairs into the <annotation> element of the playlist like this:

<annotation>1:1,20:2,37:3>/annotation>

Then they could be read by JavaScript on the client and used to sync. the video player and image rotator. Maybe we should leave that for a version 2.0, since there is a lot of other stuff to do, and go with option 2) for the version 1.0??

This brings up two more questions:

1) How many seconds long are the video files and how many slides per video file?

2) Since you're setting the standards, can you give me detailed directory structure, not fixed in stone, but a working standard.

Should include:
a] video files
b] slide files
c] sync file for video:slide pairs
d] any thing else relevant

We will be looking through a directory(ies) of video files to make the video playlist (and sync files in v2) and a directory(ies) of slides to make the image playlist. Both can be done on-the-fly or static, depending on the frequency of changes (another thing we need to know). So the slides should maybe be in separate directories with a name corresponding to the video?

Just for future reference, is there anybody there who could do minor changes or tweaks (correcting typOs) in the PHP and JavaScript?

@Will - option 2 for version 1.0 it is!

We could even go all "Web 2.0" and call this one version 0.5 beta! ;)

1) Video length will vary - there will be no set standard. since these are class lectures, they can be anywhere from 30 minutes to two hours. We'll likely break the larger files down into managable chunks, but we still can't say for sure how long they'll be - same thing with the slides. could be 5 - could be 50 - it all depends on the professor and the class, and there's no way to impose a limitation there.

2) Directory structure: this will all assume that we're starting within the primary video player directory (www.thesitehere.com/videoplayer/) or similar.

a] video files - videos/coursename/unit_000.flv
(example: www.thesitehere.com/videoplayer/videos/p101/unit_001.flv)

b] slide files - slides/coursename/unit_000_slide1.jpg
(example: www.thesitehere.com/videoplayer/slides/p101/unit_001_slide1.jpg)

c] sync file for video:slide pairs - assuming this is an xml file:
videoplayer/xml/course/unit_001_sync.xml
(videoplayer/xml/p101/unit_001_sync.xml)

and captions will be:
videoplayer/xml/course/unit_001_captions.xml
(videoplayer/xml/p101/unit_001_captions.xml)

d) all my .js and .swf files are in a directory called "embed"
videoplayer/embed/swfobject.js - and so on.

I'm using the <info> tag in the playlist to link out to a printable version of the transcripts so students can print off the whole thing (great for study notes, and helps keep us ADA compliant). These will be:

videoplayer/transcripts/course/unit_001.html

As far as changes in the video and slide directories - more will be added with every class, until the course is done. Class frequency can be once, twice, or even three, four, or five times a week.

I don't mind making the playlists by hand, expecially since I'm re-purposing things like the <info> tag.

As far as minor changes or tweaks to PHP and JS - that would be me.

minor clarification on directory structure - within the xml directory will be:

COURSE_playlist.xml - example: videoplayer/xml/E101/E101_playlist.xml
(main playlist for the videoplayer, listing all the "units")

/xml/E101/unit_001_captions.xml
(caption files for each video)

/xml/E101/unit_001_slideshow.xml
(imagerotator/slideshow playlist for each unit)

/xml/E101/unit_001_sync.xml
(sync file between video and slideshow - unless I misunderstood what you meant with this item here)

bump :)

@James,

Update: You can see a working demo here: [url=http://willswonders.myip.org:8085/videoplayer/embed/basic.html]Courses - Video and Slides[/url]
(Disregard the page layout and content, it's the mechanism we're working on here. All of that other stuff just gets in the way. Once this is working, you only have to place the placeholder <div>s where you want the players to appear.)

This demo shows:

1) A master video playlist with a series of courses and the corresponding caption file playing in the JW Media Player. The current master playlist was constructed manually, but would eventually be constructed either on-the-fly, or on a daily basis (depending on change frequency), by a PHP script that rips through the course directories, reads the filenames and some content from the files and then spews out a master video playlist and optionally, the course slideshows (or maybe a different PHP script will make the slideshows.

2) A course slideshow playlist in the Image Rotator with a button to change slides. Eventually, the correct slideshow will be loaded when a video is selected.

3) The [video time:slide number] data pairs are being passed in the <annotation> element, parsed out, and will soon control the slideshow.

Now that I have my brain really wrapped around this application, I would like to propose a different directory structure with all the media for a specific course in one directory, like this:

Example files:
master_video.xml

<?xml version='1.0' encoding='UTF-8'?>
<playlist version='1' xmlns='http://xspf.org/ns/0/'>
  <trackList>
    <track>
      <creator>E101</creator>
      <title>Unit-001</title>
      <location>../media/E101/unit_001.flv</location>
      <link rel="captions">../media/E101/unit_001_captions.xml</link>
      <annotation>5:1,10:2,15:3,20:4,25:5,30:6</annotation>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>E101</creator>
      <title>Unit-002</title>
      <location>../media/E101/unit_002.flv</location>
      <link rel="captions">../media/E101/unit_002_captions.xml</link>
      <annotation>5:1,10:2,15:3,20:4,25:5,30:6</annotation>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>E102</creator>
      <title>Unit-001</title>
      <location>../media/E102/unit_001.flv</location>
      <link rel="captions">../media/E102/unit_001_captions.xml</link>
      <annotation>5:1,10:2,15:3,20:4,25:5,30:6</annotation>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>E102</creator>
      <title>Unit-002</title>
      <location>../media/E102/unit_002.flv</location>
      <link rel="captions">../media/E102/unit_002_captions.xml</link>
      <annotation>5:1,10:2,15:3,20:4,25:5,30:6</annotation>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>H101</creator>
      <title>Unit-001</title>
      <location>../media/H101/unit_001.flv</location>
      <link rel="captions">../media/H101/unit_001_captions.xml</link>
      <annotation>6:1,11:2,16:3,21:4,26:5,31:6</annotation>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>H101</creator>
      <title>Unit-002</title>
      <location>../media/H101/unit_002.flv</location>
      <link rel="captions">../media/H101/unit_002_captions.xml</link>
      <annotation>7:1,12:2,17:3,22:4,27:5,32:6</annotation>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>H102</creator>
      <title>Unit-001</title>
      <location>../media/H102/unit_001.flv</location>
      <link rel="captions">../media/H102/unit_001_captions.xml</link>
      <annotation>4:1,9:2,14:3,19:4,24:5,29:6</annotation>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>H102</creator>
      <title>Unit-002</title>
      <location>../media/H102/unit_002.flv</location>
      <link rel="captions">../media/H102/unit_001_captions.xml</link>
      <annotation>3:1,8:2,13:3,18:4,23:5,28:6</annotation>
      <info>http://my.domain.com</info>
    </track>
  </trackList>
</playlist>>

E101 - unit_001_captions.xml

<tt xml:lang="en" xmlns="http://www.w3.org/2006/10/ttaf1" xmlns:tts="http://www.w3.org/2006/10/ttaf1#style">
  <head>
  </head>
  <body tts:extent="475px 350px" xml:id="b1">
    <div xml:id="d1" begin="0s" dur="4s">
      <p xml:id="p1" region="r1"><![CDATA[<p align="right"><font size="9">E101 - Unit-001 This is a closed captions example file.</font></p>]]></p>
    </div>
    <div xml:id="d2" begin="5s" dur="4s">
      <p xml:id="p2" region="r1"><![CDATA[<p align="center"><font size="12">All header info of the TT format is neglected.</font></p>]]></p>
    </div>
    <div xml:id="d3" begin="10s" dur="4s">
      <p xml:id="p3" region="r1"><![CDATA[The file can, however, display HTML, like this <b>bold text</b>.]]></p>
    </div>
    <div xml:id="d4" begin="15s" dur="4s">
      <p xml:id="p4" region="r1"><![CDATA[The file can, however, display HTML, like this <i>italic text</i>.]]></p>
    </div>
    <div xml:id="d5" begin="20s" dur="4s">
      <p xml:id="p5" region="r1"><![CDATA[<p align="right"><font size="9">Note that you must put enclosing CDATA tags around HTML.</font></p>]]></p>
    </div>
    <div xml:id="d6" begin="25s" dur="4s">
      <p xml:id="p6" region="r1"><![CDATA[<p align="left"><font size="9">Sometimes it just doesn't work!</font></p>]]></p>
    </div>
    <div xml:id="d7" begin="30s" dur="4s">
      <p xml:id="p7" region="r1"><![CDATA[The text can be in <i>italics</i>.]]></p>
    </div>
    <div xml:id="d8" begin="35s" dur="4s">
      <p xml:id="p8" region="r1"><![CDATA[Also, it can be <font size="4">noted</font> that the font can change mid-sentence.]]></p>
    </div>
    <div xml:id="d9" begin="40s" dur="4s">
      <p xml:id="p9" region="r1"><![CDATA[Even basic Greek is possible<font style="font-style:Arial Unicode MS;size:2;">ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡςσυφχψωϊ</font>]]></p>
    </div>
  </body>
</tt>

default_slideshow.xml

<?xml version='1.0' encoding='UTF-8'?>
<playlist version='1' xmlns='http://xspf.org/ns/0/'>
  <trackList>
    <track>
      <creator>Course Overview</creator>
      <title>Slide 01</title>
      <location>../media/default/default_slide01.jpg</location>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>Course Overview</creator>
      <title>Slide 02</title>
      <location>../media/default/default_slide02.jpg</location>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>Course Overview</creator>
      <title>Slide 03</title>
      <location>../media/default/default_slide03.jpg</location>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>Course Overview</creator>
      <title>Slide 04</title>
      <location>../media/default/default_slide04.jpg</location>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>Course Overview</creator>
      <title>Slide 05</title>
      <location>../media/default/default_slide05.jpg</location>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>Course Overview</creator>
      <title>Slide 06</title>
      <location>../media/default/default_slide06.jpg</location>
      <info>http://my.domain.com</info>
    </track>
  </trackList>
</playlist>>

E101 - unit_001_sync.txt

0:1,5:2,10:3,15:4,20:5,25:6

videoplayer directory structure

TreePrint listing of: \videoplayer

\videoplayer
+---embed
|       basic.html
|       imagerotator.swf
|       mediaplayer.swf
|       swfobject.js
|    
+---media
    |   master_slideshow.xml
    |   master_video.xml
    |
    +---default
    |       default_001.flv
    |       default_002.flv
    |       default_captions.xml
    |       default_slide01.jpg
    |       default_slide02.jpg
    |       default_slide03.jpg
    |       default_slide04.jpg
    |       default_slide05.jpg
    |       default_slide06.jpg
    |       default_slideshow.xml
    |       default_video.xml
    |    
    +---E101
    |       unit_001.flv
    |       unit_001_captions.xml
    |       unit_001_slide01.jpg
    |       unit_001_slide02.jpg
    |       unit_001_slide03.jpg
    |       unit_001_slide04.jpg
    |       unit_001_slide05.jpg
    |       unit_001_slide06.jpg
    |       unit_001_slideshow.xml
    |       unit_001_sync.txt
    |       unit_002.flv
    |       unit_002_captions.xml
    |       unit_002_slide01.jpg
    |       unit_002_slide02.jpg
    |       unit_002_slide03.jpg
    |       unit_002_slide04.jpg
    |       unit_002_slide05.jpg
    |       unit_002_slide06.jpg
    |       unit_002_slideshow.xml
    |       unit_002sync.txt
    |    
    +---E102
    |       unit_001.flv
    |       unit_001_captions.xml
    |       unit_001_slide01.jpg
    |       unit_001_slide02.jpg
    |       unit_001_slide03.jpg
    |       unit_001_slide04.jpg
    |       unit_001_slide05.jpg
    |       unit_001_slide06.jpg
    |       unit_001_slideshow.xml
    |       unit_001_sync.txt
    |       unit_002.flv
    |       unit_002_captions.xml
    |       unit_002_slide01.jpg
    |       unit_002_slide02.jpg
    |       unit_002_slide03.jpg
    |       unit_002_slide04.jpg
    |       unit_002_slide05.jpg
    |       unit_002_slide06.jpg
    |       unit_002_slideshow.xml
    |       unit_002sync.txt
    |    
    +---H101
    |       unit_001.flv
    |       unit_001_captions.xml
    |       unit_001_slide01.jpg
    |       unit_001_slide02.jpg
    |       unit_001_slide03.jpg
    |       unit_001_slide04.jpg
    |       unit_001_slide05.jpg
    |       unit_001_slide06.jpg
    |       unit_001_slideshow.xml
    |       unit_001_sync.txt
    |       unit_002.flv
    |       unit_002_captions.xml
    |       unit_002_slide01.jpg
    |       unit_002_slide02.jpg
    |       unit_002_slide03.jpg
    |       unit_002_slide04.jpg
    |       unit_002_slide05.jpg
    |       unit_002_slide06.jpg
    |       unit_002_slideshow.xml
    |       unit_002sync.txt
    |    
    \---H102 
            unit_001.flv
            unit_001_captions.xml
            unit_001_slide01.jpg
            unit_001_slide02.jpg
            unit_001_slide03.jpg
            unit_001_slide04.jpg
            unit_001_slide05.jpg
            unit_001_slide06.jpg
            unit_001_slideshow.xml
            unit_001_sync.txt
            unit_002.flv
            unit_002_captions.xml
            unit_002_slide01.jpg
            unit_002_slide02.jpg
            unit_002_slide03.jpg
            unit_002_slide04.jpg
            unit_002_slide05.jpg
            unit_002_slide06.jpg
            unit_002_slideshow.xml
            unit_001_sync.txt

Everything looks great, with one exception.

The way this is laid out, you have the one master playlist, with all courses and all course classes/units listed. Given the eventual large number of courses/classes - and "per course" access issues (to be dealt with much later), we really need to stick with the "multiple playlist" approach, where an initial list of courses is presented, with the secondary playlist of classes/units called up from the course choice.

Otherwise - no problems.

@James,

I guess I didn't quite catch that before.

So there are three levels:

1) Course

2) Class

3) Unit

Would the course list even be a video playlist?

Seems like there would have to be a two-step selection process:

1) The user is presented with a video playlist of courses (would there be associated slideshows at the course level?) and selects a video which he watches.

2) When the user is done, he either selects another course video or he makes a selection (button?) to go to the class video playlist.

3) Then is there another level of playlists for the units?

Other stuff:
The playlist line is made up of "artist - title", can you give me a sample of what you would like it to look like, so I can see if we can get that information from the files?

I think that I'll go ahead with the main playlist generator which is almost done and then we will add functions/levels to it to deal with the two or three levels of video/slideshow playlists.

So far, no GOTCHAs, everythng looks doable. I'm a little concerned about the use of the <annotation> element because I vaguely recall that there was a 256 character limit and 6-8 characters per slide means that we can probably have about 35 slides if that limit exists.

@James,

Looking at your site again. I see that the initial course selection is by a drop down menu system that doesn't come from an XML playlist. so that reduces the levels to 2.

So, let's say I make a choice of E101 Learning to Look. How does that typically break down into classes and units? How many classes and how manu units in those classes.

So if I am understanding this right, you want a separate playlist for each course, such as the E101 Learning to Look. Then that playlist would have a series of classes on it. How do the units appear on that playlist?

Anyway, it's easily doable, each time the script hits a directory such as E101, it will grab all o the filenames and drop a video playlist and a slideshow playlist in that directory for the files in that directory.

I was set up to do that for the slideshow playlists, so it's easy to do the same for the video playlists. No more master list, just individual lists for each course.

@andersen,

If you're watching and reading, I have a question about the slideshow playlist.

The slideshow playlist needs to be selected and loaded when the video is selected from the playlist. Since I'm already passing a lot of data in the <annotation> element, should I just pass that playlist name also or is there another way to select the slideshow playlist based upon the video that was selected.

I'm thinking like this:

<annotation>4:1,9:2,14:3,19:4,24:5,29:6,34:7,39:8,44:9,49:10,unit_001_slideshow.xml</annotation>

I already know that I have the E101 video playlist loaded, so I just parse out the "unit_001_slideshow.xml" and go to the E101 directory to get it, load it into the Image Rotator and run, changing slides based on the position:slidenumber pairs that I got from the <annotation> element.

Make sense? :)

Will - you were busy last night! :d

So, let's say I make a choice of E101 Learning to Look. How does that typically break down into classes and units? How many classes and how manu units in those classes.

Units = classes (I started using the term "unit" rather than class to avoid confusing terminology when talking about the code to set this up). There's no guarantee of how many units/classes there will be for any one course. If we need to break a larger class into smaller segments because of time length, how many will just be determined by the overall length of the video. Ideally I'd like to have each video no more than 40 minutes or so... but these are college professors we're talking about here, and if any one can ramble on for *hours* - it's them.

So there are three levels:

1) Course

2) Class

3) Unit

Would the course list even be a video playlist?

As you can see above, it's even more simple than that, since class and unit are the same thing.

So if I am understanding this right, you want a separate playlist for each course, such as the E101 Learning to Look. Then that playlist would have a series of classes on it. How do the units appear on that playlist?

That's right - essentially, it would look just like it does now in my demo, only instead of only one unit/class per course (like I have for demo purposes now), there would be more of them.

Other stuff:
The playlist line is made up of "artist - title", can you give me a sample of what you would like it to look like, so I can see if we can get that information from the files?

Sure, here's an example from the current demo site:


     <track>
        <title>Unit 001</title>
<creator>Introduction</creator>
<location>../videos/E101/unit_001.flv</location>
<info>../transcripts/E101/unit_001.html</info>
  <link rel="captions">xml/E101/unit_001_captions.xml</link>
<image>images/thumb-video.png</image>
    </track>

With "title" being used to give the class/unit number, "creator" for the recognizable name for that class from the course syllabus.

Anyway, it's easily doable, each time the script hits a directory such as E101, it will grab all o the filenames and drop a video playlist and a slideshow playlist in that directory for the files in that directory.

I was set up to do that for the slideshow playlists, so it's easy to do the same for the video playlists. No more master list, just individual lists for each course.

Which of course leads me to the inevitable conclusion that you're a genius! (b)

@Will - make sense? - completely #)

@andersen,

Thanks, will proceed. :)

@James,

I was beginning to suspect that class=unit. So let's use the unit terminology since that's in the filename.

So, we need some more information for the automated playlist generator.

Breaking down your track:
<title>Unit 001</title>
This can be parsed from the unit file "unit_001.flv"

<creator>Introduction</creator>
This will have to come from some master lookup list.
Something like:
E101,Unit 001,Introduction
E101,Unit 002,Studies
E101,Unit 003,Advanced Studies
E101,Unit 004,Completion
Or whatever you have now or can make to link Course, Unit, and Creator

<location>../videos/E101/unit_001.flv</location>
We know this from the directory, etc.

<info>../transcripts/E101/unit_001.html</info>
Easy to construct in the form "somepath/Course/unit.html".

<link rel="captions">xml/E101/unit_001_captions.xml</link>
We know this from the directory, etc.

<image>images/thumb-video.png</image>
This looks generic, but will there be a thumbnail image specific to each video? If so, it would be best to name it "unit_001_thumb.jpg" in the same form as the slides "unit_001_slide01.jpg". Who makes that thumbnail image; do you want ffmpeg to make the thumbnail from a frame of the video if it doesn't exist?

So it looks like the <creator> element is the only one that needs an additional file, I guess "Professor Video" isn't going to work. If you have an existing list, let's use that, otherwise one master list in the "media" directory should suffice.

This looks generic, but will there be a thumbnail image specific to each video? If so, it would be best to name it "unit_001_thumb.jpg" in the same form as the slides "unit_001_slide01.jpg". Who makes that thumbnail image; do you want ffmpeg to make the thumbnail from a frame of the video if it doesn't exist?

It is generic - there will not be a thumbnail image specific to each video - they'll all use that thumbnail.

So it looks like the <creator> element is the only one that needs an additional file, I guess "Professor Video" isn't going to work. If you have an existing list, let's use that, otherwise one master list in the "media" directory should suffice.

We don't have an existing list, no - these will be pulled from the course syllabus, as it's created by the faculty for each course.

@James,

OK

Looks like the <annotation> element doesn't have a 256 character limit, which is nice for the "ramblers". But I eventually need to find the limit, if one exists, just so the code doesn't break somewhere in the future.

351 characters

<annotation>0:1,30:2,60:3,90:4,120:5,150:6,180:7,210:8,240:9,270:10,300:11,330:12,\
360:13,390:14,420:15,450:16,480:17,510:18,540:19,570:20,600:21,630:22,660:23,690:24,720:25,750:26,780:27,810:28,\
840:29,870:30,900:31,930:32,960:33,990:34,1020:35,1050:36,1080:37,1110:38,1140:39,1170:40,\
1200:41,1230:42,1260:43,1290:44,1320:45,1350:46,1380:47,1410:48,1440:49,1470:50</annotation>

@James,

You can see a functional player page here: [url=http://willswonders.myip.org:8085/videoplayer/embed/basic15.html]basic15[/url]

Load Course E101 using the button. The others all work, but E101 has the most images.

You can see the player loading the slideshow playlist corresponding to the video and then the images change according the the time:slide data that was passed in the <annotation> element.

So, that about does it for the player page. A little tweaking to smooth thngs out and you can paste the JavaScript into your page and position the players with the <div> elements. Of course, you don't need all the buttons and tables and instrumentation.

Next, I've got to get back to work on the playlist generator, but you can use the player with manually created playlists for now.

@andersen,

I could use some advice on the JavaScript. Especially, the Image Rotator doesn't seem to be too smooth, although that could just be Internet Explorer's weird cache lookup behavior.

Now that the basic system is in place and working, I'm going to concentrate on the playlist(sss) generator. Once that is working, I intend to return to the player page for some upgrading.

@Will - sorry, didnt look here for a while...
i have read through the code in the basic15 link a few times (i can only test it there, obviously)

and i get an error that breaks the script execution in line 42:
thats this one: thisMovie(jsid).sendEvent(typ, prm);

i suspect its because you use the same name for both a global var and a function parameter:

var jsid;

// these functions are caught by the JavascriptView object of the player.
function sendEvent(jsid, typ, prm)
{
thisMovie(jsid).sendEvent(typ, prm);
};

that confuses both me and the browser i think...

i prefere to assign such values to a global var before using it the call
(its only really required on rare occations i havent completely understood, but its related to calls in and out of .swfs and such, and its easier to remove when it works, than find where missing, when not)
like this:

var currentID;

// these functions are caught by the JavascriptView object of the player.
function sendEvent(jsid, typ, prm)
{
currentID=jsid;
thisMovie(currentID).sendEvent(typ, prm);
};

then just to make sure, id better point you to the js command:[url=http://www.w3schools.com/jsref/jsref_split.asp?output=print]split[/url]

concerning rotator vs. player - as they are so interchangeable, a quick test should show if theres a difference in smooth-runniningness

thats my thoughts - please ask more if needed, im here...

@andersen,

Thanks for taking a look. :)

You must have hit my page when I was experimenting with "jsid". I originally just had it in the function and got an undefined error when I tried to send it to sendEvent(), so I was trying it as a global, but that didn't work.

I did try a media player in place of the rotator, but now I suspect it's mostly IE's lousy cache lookup. Sometimes after playing a few media files, IE spins it's wheels for minutes trying to decide if it should load from the cache or the server.

Otherwise, the page is working, but needs a lot of cleanup and polish, especially since I'm still weak in JS and I don't fully understand the JW Player interaction with the functions. But this is really the way to learn.

I'm expecting James Foster to just grab the JS and put the <div>s where he wants them. He already has a nice page, just needs it to function. In my opinion, and I think you mostly think the same, the best way to do this stuff is to get the functionality, including the whole system behind the page, then put the pretty stuff on it (which I never get around to).

If you followed this thread, James and I went back and forth a bit to nail down what he had to work with and what he wanted the result to be. After that it was easy (except for the JS!). I'm a big believer in simplification to the extreme, one can always add complexity if it's really needed. Usually after you get an application done, you fully understand it and can simplify it quite a bit.

I'm building a demo page, not as nice as yours, but I'm just linking to all of the applications that I have developed and will make the source of the PHP scripts available for download. I'm about 1/3 of the way through the HTML & PHP. Lots of it needs to be completed or cleaned up before I can put it up.

Well, I've got to finish the playlist generator for this now.

Thanks again. :)

Will - here's a question: something I'm not seeing is how the slideshow is changed for each unit/class.

I can see where you've put the annotation information in to mark where the slides should change... but I don't see where the new unit/class slideshow is being loaded along with the new video... amd I just blind?

@James,

It's magic... a little voodoo, a little black, and some pixy dust.

starting at line 120

      <strong>// do we need to load a new slideshow file?</strong>
      currentFile = obj['file'];

      // Purely for debug
      fn = document.getElementById('filename');
      fn.innerHTML = "File Name: " + currentFile;

      newSlideshowPlaylist = currentFile.substring(0, currentFile.indexOf('.flv')) + '_slideshow.xml';

//      // Purely for debug
//      nSP = document.getElementById('slideshowplaylist');
//      nSP.innerHTML = 'New Slideshow Playlist: ' + newSlideshowPlaylist;

      <strong>if(newSlideshowPlaylist != currentSlideshowPlaylist)</strong>
      {
        sendEvent('rot1', 'stop');
        //setTimeout("loadFile('rot1', {file:newSlideshowPlaylist})", 150);
<strong>loadFile('rot1', {file:newSlideshowPlaylist});</strong>
        currentSlideshowPlaylist = newSlideshowPlaylist;

        // parse into Image Rotator control points
        anno = obj['description'];

        // Purely for debug
        des = document.getElementById('annotation');
        des.innerHTML = 'Annotation: ' + anno;

        if (anno.length < 1)
        {
          // !- Yikes -!
          // return false;
        }

        keypairs = new Object();
        numKP    = 1;

        while (anno.indexOf(',') > -1)
        {
          keypairs[numKP] = anno.substring(0, anno.indexOf(','));
          anno            = anno.substring((anno.indexOf(',')) + 1);
          numKP++;
        }

        // Store what's left in the query string as the final keypairs[] data.
        keypairs[numKP] = anno;

//        // Purely for debug
//        nkp = document.getElementById('numkeypairs');
//        nkp.innerHTML = 'Key Pairs: ' + numKP;
//        dbg = document.getElementById('debug');
//        dbg.innerHTML = 'Debug: ' + anno;

        for (var i in keypairs)
        {
          // Left of ':' is video time.
          keyTime = keypairs[i].substring(0, keypairs[i].indexOf(':'));

          // Right of ':' is slide number.
          keySlide = keypairs[i].substring((keypairs[i].indexOf(':')) + 1);

          sync[keyTime] = keySlide;
        }

//        // Purely for debug
//        var pairs = '';
//        for(var j in sync)
//        {
//          pairs += '<li>' + j + ' = ' + sync[j] + '</li>';
//        }
//        sy = document.getElementById('syncdata');
//        sy.innerHTML = pairs;

      }
    };

    // This is a javascript handler for the player and is always needed.

The rest is the code to parse the <annotation> element contents into an array of position:slidenumber.

And it knows where to nab the appropriate slideshow playlist based off of the directory structure and file-naming conventions outlined above?

It seems to be a bit wobbly for me on the viewing end - and like andersen, I'm getting that error at line 42, character 7 - 'undefined' is null or not an object - could that be the issue?

@James,

If you go to line 116, there are a couple of file path strings.

// typical filenames
// ../media/E101/unit_001.flv
// ../media/E101/unit_001_slideshow.xml

Then the next lines chop off ".flv"

../media/E101/unit_001

And add on "_slideshow.xml"

../media/E101/unit_001_slideshow.xml

So we have the path & filename for the slideshow playlist.

So really, the naming convention does all of the hard work for us.

Will - everything okay with the test site?

@James,

It's OK. I put the latest here: [url=http://willswonders.myip.org:8085/videoplayer/embed/basic.html]basic.html[/url] and started iterating from there: basic1.html, basic2.html, etc.

Here's the read directory part of the playlist generator and two examples of the arrays that it creates.

Now, I just have to include the playlist creating functions, which are already done, and we will have a complete playlist generator.

<?php

// just some code to get a list of the directories under "media"
// we don't need to go dowm any levels since there is only one

// get all of the Course directories and files into an array

$dir = './';

$media_dir = read_dir($dir);

// initialize variables
$this_course = '';
$this_dir = array();

// debug
// print_r($media_dir);
// exit;
// debug

// get the files for each Course into an array

foreach($media_dir as $entry)
{
 
//            .//E101/unit_001_sync.txt
  //            .//E101/unit_001_slide01.jpg
  //            .//E101/unit_001.flv
  //            .//E101/unit_001_captions.xml
  //            .//E101/course_101_video.xml
  // $matches[1] = Course "E101",
  // $matches[2] = first text string "unit" or "course",
  // $matches[3] = the rest of the text up to the period,
  // $matches[4] = extension "xml" or "flv" or "jpg" or "gif" or "txt"
 
preg_match('/\.\/\/([A-Z][0-9]{3})\/(.*?)_(.*?)\.(.*)/', $entry, $matches);

// debug
// print "Entry: " . $entry . "\n";
// print_r($matches);
// debug

 

if(preg_match('/([A-Z][0-9]{3})/', $matches[1], $course))
  {
    if((
$this_course == $matches[1]) || ($this_course == ''))
    {
     
$this_course = $matches[1];

      if(

$matches[4] == 'xml') // some playlist or captions file
     
{
        if(
$matches[2] == 'course'// playlist
       
{
         
$this_dir[$matches[1]]['course'] = $matches[2] . "_" . $matches[3] . "." . $matches[4];
        }
        else if((
$matches[2] == 'unit') && (substr($matches[3], -8) == 'captions'))  //captions
       
{
         
$this_dir[$matches[1]][substr($matches[3], 0, 3)]['captions'] = $matches[2] . "_" . $matches[3] . "." . $matches[4];
        }
      }
      else if((
$matches[2] == 'unit') && (($matches[4] == 'jpg') || ($matches[4] == 'png'))) // an image file
     
{
       
$this_dir[$matches[1]][substr($matches[3], 0, 3)]['image'][substr($matches[3], -2)] = $matches[2] . "_" . $matches[3] . "." . $matches[4];
      }
      else if((
$matches[2] == 'unit') && (substr($matches[3], -4) == 'sync')) // a sync file
     
{
       
$this_dir[$matches[1]][substr($matches[3], 0, 3)]['sync'] = $matches[2] . "_" . $matches[3] . "." . $matches[4];
      }
      else if((
$matches[2] == 'unit') && ($matches[4] == 'flv')) // a video file
     
{
       
$this_dir[$matches[1]][substr($matches[3], 0, 3)]['video'] = $matches[2] . "_" . $matches[3] . "." . $matches[4];
      }
    }
    else 
// looks like we're done with this directory, lets make a playlist
   
{
     
// call the function to make a video playlist
      // create_video_playlist($videoplaylist, $masterarray);

      // call the function to make a slideshow playlist
      // create_slideshow_playlist($directory, $unitnumber, $playlist_name, $slideshowcreatorname, $mediaurl, $infourl);

      // set $this_course to the current Course so we know when it changes
     

$this_course = $matches[1];

// debug
print_r($this_dir);
// debug

      // initialize the array for the next Course
     

$this_dir = array();
     
// actually the first one is a directory, so we don't have to worry about this
      // .//E102
      // don't lose the first entry for the next directory, backup one or something
   
}
  }
}

print_r($this_dir);

function

read_dir($dir)
{
 
$array = array();
 
$d     = dir($dir);

  while (

false !== ($entry = $d->read()))
  {
    if(
$entry!='.' && $entry!='..')
    {
     
$entry = $dir.'/'.$entry;

      if(

is_dir($entry))
      {
       
$array[] = $entry;
       
$array = array_merge($array, read_dir($entry));
      }
      else
      {
       
$array[] = $entry;
      }
    }
  }
 
$d->close();
  return
$array;
}

/*
$media_dir Array
(
    [0] => .//course_list.txt
    [1] => .//default
    [2] => .//default/default_001.flv
    [3] => .//default/default_001_slideshow.xml
    [4] => .//default/default_002.flv
    [5] => .//default/default_002_slideshow.xml
    [6] => .//default/default_003.flv
    [7] => .//default/default_003_slideshow.xml
    [8] => .//default/default_004.flv
    [9] => .//default/default_004_slideshow.xml
    [10] => .//default/default_captions.xml
    [11] => .//default/default_slide01.jpg
    [12] => .//default/default_slide02.jpg
    [13] => .//default/default_slide03.jpg
    [14] => .//default/default_slide04.jpg
    [15] => .//default/default_slide05.jpg
    [16] => .//default/default_slide06.jpg
    [17] => .//default/default_video.xml
    [18] => .//E101
    [19] => .//E101/course_101_video.xml
    [20] => .//E101/unit_001.flv
    [21] => .//E101/unit_001_captions.xml
    [22] => .//E101/unit_001_slide01.jpg
    [23] => .//E101/unit_001_slide02.jpg
    [24] => .//E101/unit_001_slide03.jpg
    [25] => .//E101/unit_001_slide04.jpg
    [26] => .//E101/unit_001_slide05.jpg
    [27] => .//E101/unit_001_slide06.jpg
    [28] => .//E101/unit_001_slide07.jpg
    [29] => .//E101/unit_001_slide08.jpg
    [30] => .//E101/unit_001_slide09.jpg
    [31] => .//E101/unit_001_slide10.jpg
    [32] => .//E101/unit_001_slide11.jpg
    [33] => .//E101/unit_001_slide12.jpg
    [34] => .//E101/unit_001_slideshow.xml
    [35] => .//E101/unit_001_sync.txt
    [36] => .//E101/unit_002.flv
    [37] => .//E101/unit_002_captions.xml
    [38] => .//E101/unit_002_slide01.jpg
    [39] => .//E101/unit_002_slide02.jpg
    [40] => .//E101/unit_002_slide03.jpg
    [41] => .//E101/unit_002_slide04.jpg
    [42] => .//E101/unit_002_slide05.jpg
    [43] => .//E101/unit_002_slide06.jpg
    [44] => .//E101/unit_002_slide07.jpg
    [45] => .//E101/unit_002_slide08.jpg
    [46] => .//E101/unit_002_slide09.jpg
    [47] => .//E101/unit_002_slide10.jpg
    [48] => .//E101/unit_002_slide11.jpg
    [49] => .//E101/unit_002_slide12.jpg
    [50] => .//E101/unit_002_slideshow.xml
    [51] => .//E101/unit_002_sync.txt
    [52] => .//E102
    [53] => .//E102/course_102_video.xml
    [54] => .//E102/unit_001.flv
    [55] => .//E102/unit_001_captions.xml
    [56] => .//E102/unit_001_slide01.jpg
    [57] => .//E102/unit_001_slide02.jpg
    [58] => .//E102/unit_001_slide03.jpg
    [59] => .//E102/unit_001_slide04.jpg
    [60] => .//E102/unit_001_slide05.jpg
    [61] => .//E102/unit_001_slide06.jpg
    [62] => .//E102/unit_001_slideshow.xml
    [63] => .//E102/unit_001_sync.txt
    [64] => .//E102/unit_002.flv
    [65] => .//E102/unit_002_captions.xml
    [66] => .//E102/unit_002_slide01.jpg
    [67] => .//E102/unit_002_slide02.jpg
    [68] => .//E102/unit_002_slide03.jpg
    [69] => .//E102/unit_002_slide04.jpg
    [70] => .//E102/unit_002_slide05.jpg
    [71] => .//E102/unit_002_slide06.jpg
    [72] => .//E102/unit_002_slideshow.xml
    [73] => .//E102/unit_002_sync.txt
    [74] => .//H101
    [75] => .//H101/course_101_video.xml
    [76] => .//H101/unit_001.flv
    [77] => .//H101/unit_001_captions.xml
    [78] => .//H101/unit_001_slide01.jpg
    [79] => .//H101/unit_001_slide02.jpg
    [80] => .//H101/unit_001_slide03.jpg
    [81] => .//H101/unit_001_slide04.jpg
    [82] => .//H101/unit_001_slide05.jpg
    [83] => .//H101/unit_001_slide06.jpg
    [84] => .//H101/unit_001_slideshow.xml
    [85] => .//H101/unit_001_sync.txt
    [86] => .//H101/unit_002.flv
    [87] => .//H101/unit_002_captions.xml
    [88] => .//H101/unit_002_slide01.jpg
    [89] => .//H101/unit_002_slide02.jpg
    [90] => .//H101/unit_002_slide03.jpg
    [91] => .//H101/unit_002_slide04.jpg
    [92] => .//H101/unit_002_slide05.jpg
    [93] => .//H101/unit_002_slide06.jpg
    [94] => .//H101/unit_002_slideshow.xml
    [95] => .//H101/unit_002_sync.txt
    [96] => .//H102
    [97] => .//H102/course_102_video.xml
    [98] => .//H102/unit_001.flv
    [99] => .//H102/unit_001_captions.xml
    [100] => .//H102/unit_001_slide01.jpg
    [101] => .//H102/unit_001_slide02.jpg
    [102] => .//H102/unit_001_slide03.jpg
    [103] => .//H102/unit_001_slide04.jpg
    [104] => .//H102/unit_001_slide05.jpg
    [105] => .//H102/unit_001_slide06.jpg
    [106] => .//H102/unit_001_slide07.jpg
    [107] => .//H102/unit_001_slide08.jpg
    [108] => .//H102/unit_001_slide09.jpg
    [109] => .//H102/unit_001_slide10.jpg
    [110] => .//H102/unit_001_slide11.jpg
    [111] => .//H102/unit_001_slide12.jpg
    [112] => .//H102/unit_001_slideshow.xml
    [113] => .//H102/unit_001_sync.txt
    [114] => .//H102/unit_002.flv
    [115] => .//H102/unit_002_captions.xml
    [116] => .//H102/unit_002_slide01.jpg
    [117] => .//H102/unit_002_slide02.jpg
    [118] => .//H102/unit_002_slide03.jpg
    [119] => .//H102/unit_002_slide04.jpg
    [120] => .//H102/unit_002_slide05.jpg
    [121] => .//H102/unit_002_slide06.jpg
    [122] => .//H102/unit_002_slide08.jpg
    [123] => .//H102/unit_002_slide09.jpg
    [124] => .//H102/unit_002_slide10.jpg
    [125] => .//H102/unit_002_slide11.jpg
    [126] => .//H102/unit_002_slide12.jpg
    [127] => .//H102/unit_002_slideshow.xml
    [128] => .//H102/unit_002_sync.txt
    [129] => .//H102/unit_00_slide07.jpg
    [130] => .//J101
    [131] => .//J101/course_101_video.xml
    [132] => .//J101/unit_001.flv
    [133] => .//J101/unit_001_captions.xml
    [134] => .//J101/unit_001_slide01.jpg
    [135] => .//J101/unit_001_slide02.jpg
    [136] => .//J101/unit_001_slide03.jpg
    [137] => .//J101/unit_001_slide04.jpg
    [138] => .//J101/unit_001_slide05.jpg
    [139] => .//J101/unit_001_slide06.jpg
    [140] => .//J101/unit_001_slide07.jpg
    [141] => .//J101/unit_001_slide08.jpg
    [142] => .//J101/unit_001_slide09.jpg
    [143] => .//J101/unit_001_slide10.jpg
    [144] => .//J101/unit_001_slide11.jpg
    [145] => .//J101/unit_001_slide12.jpg
    [146] => .//J101/unit_001_slideshow.xml
    [147] => .//J101/unit_001_sync.txt
    [148] => .//J101/unit_002.flv
    [149] => .//J101/unit_002_captions.xml
    [150] => .//J101/unit_002_slide01.jpg
    [151] => .//J101/unit_002_slide02.jpg
    [152] => .//J101/unit_002_slide03.jpg
    [153] => .//J101/unit_002_slide04.jpg
    [154] => .//J101/unit_002_slide05.jpg
    [155] => .//J101/unit_002_slide06.jpg
    [156] => .//J101/unit_002_slide07.jpg
    [157] => .//J101/unit_002_slide08.jpg
    [158] => .//J101/unit_002_slide09.jpg
    [159] => .//J101/unit_002_slide10.jpg
    [160] => .//J101/unit_002_slide11.jpg
    [161] => .//J101/unit_002_slide12.jpg
    [162] => .//J101/unit_002_slideshow.xml
    [163] => .//J101/unit_002_sync.txt
    [164] => .//J102
    [165] => .//J102/Copy of course_102_video.xml
    [166] => .//J102/Copy of unit_001.flv
    [167] => .//J102/Copy of unit_001_captions.xml
    [168] => .//J102/Copy of unit_001_slide01.jpg
    [169] => .//J102/Copy of unit_001_slide02.jpg
    [170] => .//J102/Copy of unit_001_slide03.jpg
    [171] => .//J102/Copy of unit_001_slide04.jpg
    [172] => .//J102/Copy of unit_001_slide05.jpg
    [173] => .//J102/Copy of unit_001_slide06.jpg
    [174] => .//J102/Copy of unit_001_slide07.jpg
    [175] => .//J102/Copy of unit_001_slide08.jpg
    [176] => .//J102/Copy of unit_001_slide09.jpg
    [177] => .//J102/Copy of unit_001_slide10.jpg
    [178] => .//J102/Copy of unit_001_slide11.jpg
    [179] => .//J102/Copy of unit_001_slide12.jpg
    [180] => .//J102/Copy of unit_001_slideshow.xml
    [181] => .//J102/Copy of unit_001_sync.txt
    [182] => .//J102/Copy of unit_002.flv
    [183] => .//J102/Copy of unit_002_captions.xml
    [184] => .//J102/Copy of unit_002_slide01.jpg
    [185] => .//J102/Copy of unit_002_slide02.jpg
    [186] => .//J102/Copy of unit_002_slide03.jpg
    [187] => .//J102/Copy of unit_002_slide04.jpg
    [188] => .//J102/Copy of unit_002_slide05.jpg
    [189] => .//J102/Copy of unit_002_slide06.jpg
    [190] => .//J102/Copy of unit_002_slide08.jpg
    [191] => .//J102/Copy of unit_002_slide09.jpg
    [192] => .//J102/Copy of unit_002_slide10.jpg
    [193] => .//J102/Copy of unit_002_slide11.jpg
    [194] => .//J102/Copy of unit_002_slide12.jpg
    [195] => .//J102/Copy of unit_002_slideshow.xml
    [196] => .//J102/Copy of unit_002_sync.txt
    [197] => .//J102/Copy of unit_00_slide07.jpg
    [198] => .//J102/course_102_video.xml
    [199] => .//J102/unit_001.flv
    [200] => .//J102/unit_001_captions.xml
    [201] => .//J102/unit_001_slide01.jpg
    [202] => .//J102/unit_001_slide02.jpg
    [203] => .//J102/unit_001_slide03.jpg
    [204] => .//J102/unit_001_slide04.jpg
    [205] => .//J102/unit_001_slide05.jpg
    [206] => .//J102/unit_001_slide06.jpg
    [207] => .//J102/unit_001_slide07.jpg
    [208] => .//J102/unit_001_slide08.jpg
    [209] => .//J102/unit_001_slide09.jpg
    [210] => .//J102/unit_001_slide10.jpg
    [211] => .//J102/unit_001_slide11.jpg
    [212] => .//J102/unit_001_slide12.jpg
    [213] => .//J102/unit_001_slideshow.xml
    [214] => .//J102/unit_001_sync.txt
    [215] => .//J102/unit_002.flv
    [216] => .//J102/unit_002_captions.xml
    [217] => .//J102/unit_002_slide01.jpg
    [218] => .//J102/unit_002_slide02.jpg
    [219] => .//J102/unit_002_slide03.jpg
    [220] => .//J102/unit_002_slide04.jpg
    [221] => .//J102/unit_002_slide05.jpg
    [222] => .//J102/unit_002_slide06.jpg
    [223] => .//J102/unit_002_slide08.jpg
    [224] => .//J102/unit_002_slide09.jpg
    [225] => .//J102/unit_002_slide10.jpg
    [226] => .//J102/unit_002_slide11.jpg
    [227] => .//J102/unit_002_slide12.jpg
    [228] => .//J102/unit_002_slideshow.xml
    [229] => .//J102/unit_002_sync.txt
    [230] => .//J102/unit_00_slide07.jpg
    [231] => .//master_slideshow.xml
    [232] => .//master_video.xml
    [233] => .//playlist_generator_course.php
    [234] => .//playlist_generator_ID3_switch.php
    [235] => .//read_dir.php
)

$this_dir Array
(
  [E101] => Array
    (
      [course] => course_101_video.xml
      [001] => Array
        (
          [video] => unit_001.flv
          [captions] => unit_001_captions.xml
          [image] => Array
            (
              [01] => unit_001_slide01.jpg
              [02] => unit_001_slide02.jpg
              [03] => unit_001_slide03.jpg
              [04] => unit_001_slide04.jpg
              [05] => unit_001_slide05.jpg
              [06] => unit_001_slide06.jpg
              [07] => unit_001_slide07.jpg
              [08] => unit_001_slide08.jpg
              [09] => unit_001_slide09.jpg
              [10] => unit_001_slide10.jpg
              [11] => unit_001_slide11.jpg
              [12] => unit_001_slide12.jpg
            )

          [sync] => unit_001_sync.txt
        )

      [002] => Array
        (
          [video] => unit_002.flv
          [captions] => unit_002_captions.xml
          [image] => Array
            (
              [01] => unit_002_slide01.jpg
              [02] => unit_002_slide02.jpg
              [03] => unit_002_slide03.jpg
              [04] => unit_002_slide04.jpg
              [05] => unit_002_slide05.jpg
              [06] => unit_002_slide06.jpg
              [07] => unit_002_slide07.jpg
              [08] => unit_002_slide08.jpg
              [09] => unit_002_slide09.jpg
              [10] => unit_002_slide10.jpg
              [11] => unit_002_slide11.jpg
              [12] => unit_002_slide12.jpg
            )

          [sync] => unit_002_sync.txt
        )

    )

)
*/

?>

gotcha - here's my local of your latest with the "pretty" wrapped around it:

[url=http://www.tui.edu/JimTest/videoplayer/embed/]click here[/url]

smooth #)
a few small/smaller points:
some sort of dummies or defaults seem needed for the startup state...
can other exeption situations arise?
are the user supposed to be able to advance the slides?

@andersen,

some sort of dummies or defaults seem needed for the startup state...

There is a default directory with default video, slideshow, etc. I just made it to be complete for other users, I don't know what James plans to do at the beginning, but there always has to be a default.

The buttons for next slide and first slide are mostly for testing. v1.0 was going to be manual slide change, but it turned our to be easy to automate it, so the final version won't have those buttons.

I have tried to forsee and accommodate many exception conditions, but as you know, the users will always find some, so James will have to report back on problems encountered.

If you see any problems, let me know and I will address them. :)

@James,

I have done a lot of testing of the page and it seems OK, if the images aren't cached. Having many images with the same name, i.e. "unit_001_slide03.jpg" and "unit_001_slide03.jpg" seems to confuse the browser. It may be necessary to serve the images through a small PHP script with no-store headers so the images don't get cached. My guess is that they will be small, so nothing lost there.

The video playlist generator is working and I hope to finish the slideshow playlist generator tonight. I will make it available for download then. Also, I will zip and make available for download my testing directory structure and files.

Then I'm taking a long vacation, so test it and let me know what needs attention.
generated video playlist

<?xml version='1.0' encoding='UTF-8'?>
<playlist version='1' xmlns='http://xspf.org/ns/0/'>
  <title>PHP Generated Playlist - Courses</title>
  <info>http://my.domain.com</info>
  <trackList>
    <track>
      <creator>Review</creator>
      <title>Unit 001</title>
      <location>http://my.domain.com/videoplayer/media/J101/unit_001.flv</location>
      <link rel='captions'>http://my.domain.com/videoplayer/media/J101/unit_001_captions.xml</link>
      <annotation>0:1,5:2,10:3,15:4,20:5,25:6,30:7,35:8,40:9,45:10,50:11,55:12,60:13,65:14,70:15,75:16,80:17,85:18,90:19,95:20,100:21,105:22,110:23,115:24,120:25,125:26,130:27,135:28,140:29,145:30</annotation>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>Start</creator>
      <title>Unit 002</title>
      <location>http://my.domain.com/videoplayer/media/J101/unit_002.flv</location>
      <link rel='captions'>http://my.domain.com/videoplayer/media/J101/unit_002_captions.xml</link>
      <annotation>0:1,30:2,60:3,90:4,120:5,150:6,180:7,210:8,240:9,270:10,300:11,330:12,360:13,390:14,420:15,450:16,480:17,510:18,540:19,570:20,600:21,630:22,660:23,690:24,720:25,750:26,780:27,810:28,840:29,870:30,900:31,930:32,960:33,990:34,1020:35,1050:36,1080:37,1110:38,1140:39,1170:40,1200:41,1230:42,1260:43,1290:44,1320:45,1350:46,1380:47,1410:48,1440:49,1470:50</annotation>
      <info>http://my.domain.com</info>
    </track>
  </trackList>
</playlist>

@James,

OK, the playlist generator is done. Get the whole package here: [url=http://willswonders.myip.org:8085/downloads/videoplayer.zip]videoplayer.zip[/url]

It's the complete package with all of the test directories, so unzip it into your document root, preserving the directory structure.

You will need to supply your own vidoe files, otherwise the package would have been too big. Each course directory needs two video files, named "unit_001.flv" & "unit_002.flv".

The generated playlists have an "X_" in front of the filename, so you don't accidentally destroy the other playlists. You can rename them or search and replace the "X_" in the code to generate the correct filenames.

X_unit_001_slideshow.xml

<?xml version='1.0' encoding='UTF-8'?>
<playlist version='1' xmlns='http://xspf.org/ns/0/'>
  <title>PHP Generated Playlist - Courses</title>
  <info>http://my.domain.com</info>
  <trackList>
    <track>
      <creator>Introduction</creator>
      <title>Slide 01</title>
      <location>http://my.domain.com/videoplayer/media/unit_001_slide01.jpg</location>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>Introduction</creator>
      <title>Slide 02</title>
      <location>http://my.domain.com/videoplayer/media/unit_001_slide02.jpg</location>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>Introduction</creator>
      <title>Slide 03</title>
      <location>http://my.domain.com/videoplayer/media/unit_001_slide03.jpg</location>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>Introduction</creator>
      <title>Slide 04</title>
      <location>http://my.domain.com/videoplayer/media/unit_001_slide04.jpg</location>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>Introduction</creator>
      <title>Slide 05</title>
      <location>http://my.domain.com/videoplayer/media/unit_001_slide05.jpg</location>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>Introduction</creator>
      <title>Slide 06</title>
      <location>http://my.domain.com/videoplayer/media/unit_001_slide06.jpg</location>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>Introduction</creator>
      <title>Slide 07</title>
      <location>http://my.domain.com/videoplayer/media/unit_001_slide07.jpg</location>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>Introduction</creator>
      <title>Slide 08</title>
      <location>http://my.domain.com/videoplayer/media/unit_001_slide08.jpg</location>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>Introduction</creator>
      <title>Slide 09</title>
      <location>http://my.domain.com/videoplayer/media/unit_001_slide09.jpg</location>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>Introduction</creator>
      <title>Slide 10</title>
      <location>http://my.domain.com/videoplayer/media/unit_001_slide10.jpg</location>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>Introduction</creator>
      <title>Slide 11</title>
      <location>http://my.domain.com/videoplayer/media/unit_001_slide11.jpg</location>
      <info>http://my.domain.com</info>
    </track>
    <track>
      <creator>Introduction</creator>
      <title>Slide 12</title>
      <location>http://my.domain.com/videoplayer/media/unit_001_slide12.jpg</location>
      <info>http://my.domain.com</info>
    </track>
</trackList>
</playlist>

@James,

The slideshow playlist above is missing the course directory. I've fixed it in the playlist generator in the zip file.

<?xml version='1.0' encoding='UTF-8'?>
<playlist version='1' xmlns='http://xspf.org/ns/0/'>
<title>PHP Generated Playlist - Courses</title>
<info>http://my.domain.com</info>
<trackList>
<track>
<creator>Introduction</creator>
<title>Slide 01</title>
<location>http://my.domain.com/videoplayer/media/unit_001_slide01.jpg</location>
<info>http://my.domain.com</info>
</track>
<track>
<creator>Introduction</creator>
<title>Slide 02</title>
<location>http://my.domain.com/videoplayer/media/unit_001_slide02.jpg</location>
<info>http://my.domain.com</info>
</track>
<track>
<creator>Introduction</creator>
<title>Slide 03</title>
<location>http://my.domain.com/videoplayer/media/unit_001_slide03.jpg</location>
<info>http://my.domain.com</info>
</track>
<track>
<creator>Introduction</creator>
<title>Slide 04</title>
<location>http://my.domain.com/videoplayer/media/unit_001_slide04.jpg</location>
<info>http://my.domain.com</info>
</track>
<track>
<creator>Introduction</creator>
<title>Slide 05</title>
<location>http://my.domain.com/videoplayer/media/unit_001_slide05.jpg</location>
<info>http://my.domain.com</info>
</track>
<track>
<creator>Introduction</creator>
<title>Slide 06</title>
<location>http://my.domain.com/videoplayer/media/unit_001_slide06.jpg</location>
<info>http://my.domain.com</info>
</track>
<track>
<creator>Introduction</creator>
<title>Slide 07</title>
<location>http://my.domain.com/videoplayer/media/unit_001_slide07.jpg</location>
<info>http://my.domain.com</info>
</track>
<track>
<creator>Introduction</creator>
<title>Slide 08</title>
<location>http://my.domain.com/videoplayer/media/unit_001_slide08.jpg</location>
<info>http://my.domain.com</info>
</track>
<track>
<creator>Introduction</creator>
<title>Slide 09</title>
<location>http://my.domain.com/videoplayer/media/unit_001_slide09.jpg</location>
<info>http://my.domain.com</info>
</track>
<track>
<creator>Introduction</creator>
<title>Slide 10</title>
<location>http://my.domain.com/videoplayer/media/unit_001_slide10.jpg</location>
<info>http://my.domain.com</info>
</track>
<track>
<creator>Introduction</creator>
<title>Slide 11</title>
<location>http://my.domain.com/videoplayer/media/unit_001_slide11.jpg</location>
<info>http://my.domain.com</info>
</track>
<track>
<creator>Introduction</creator>
<title>Slide 12</title>
<location>http://my.domain.com/videoplayer/media/unit_001_slide12.jpg</location>
<info>http://my.domain.com</info>
</track>
</trackList>
</playlist>

Can someone please post a link to this player with slides? We are interested in doing something very similar and I would like to see how it came out.

Thanks!

"OK, the playlist generator is done. Get the whole package here:"

Where? I don't see a link. I would like to see this. Can someone show me where to get it? Thank you

Link spammers caused the removal of all links.

Demo sometimes here: http://willswonders.myip.org:8085/videoplayer/embed/basic.html

Files sometimes here: http://willswonders.myip.org:8085/downloads/slide_show.zip (172739205 bytes)

Is it possible to have just one mp3 file and load the images into the mediaplayer? This seems to be overkill for what I want and very confusing for me.

I do not want a playlist of media. I will load one mp3 and one slideshow playlist.
I would prefer not to load the mediaplayer to play the mp3 and load the imagerotator to play the images. I would like to play the images in the mediaplayer that is playing the mp3.

Is it possible to play timed images by loading an xml file the same way you can load the xml file to play captions in text?
How would I change it from text to images?

Both the JW Media Player and the JW Image Rotator support an additional audio track that can be used for comments or background music.

The main difference between the two players, for displaying images, is that the Image Rotator has transition effects between the images.

Both players need only one playlist to display a series of images with the additional audio.

You can set the rotatetime to be the same for all images or set an individual duration ime in each track of the playlist.

My needs are the same as streamBabie's. So can we use the Image Rotator, give in an MP3 that will be managed by the controls, then get callbacks for "time" and use them to send events back to the player to change the image? I'm confused/concerned about "an additional" audio track? Does that mean it's not managed by controls?

Answering my own question: It looks like it won't work. The "controls" on the image viewer aren't audio controls; just next/previous slide. The only other option would be to use the Media Player, but I don't see any way in the API to programmaticaly change the (single) JPEG image.

@Ralph,

The Media Player can play a series of tracks that have images as the primary media instead of mp3 or video. Then the normal methods of changing tracks apply.

It's called an additional audio track because it is in addition to the primary mp3 or video audio track, obviously not in addition to the image audio track, even if your images have audio embedded in them. I'm not kidding here, an image can have audio embedded just like an mp3 can have images embedded.

Don't be so quick to dismiss the Image Rotator's volume control. If you have the additional audio track enabled, there is a mute/unmute button on the right end of the control bar. You can set the starting volume and control the volume level through the JavaScript API and the transition effects are worth it.

ok, works good. pretty good :) but i got one question: what if use non-local .flv files? hosted on streaming server. like in this:

s1.addVariable('file', 'rtmpt://blahblah.nl:80/VOD');
s1.addVariable('id','whatever_trial/video');

is this do-able?

Media files can come from any Web-accessible URI. The Adobe Flash Player security restrictions only apply to XML files (you can use an external server for XML if you put a crossdomain.xml policy file on that external server).

ok.fine. thanks for info, its important.

and what about syntax with embeding uri? for exemple, xml:

<track>
<creator>Review</creator>
<title>Unit 001</title>
<location>rtmpt://blahblah.nl:80/VOD</location>
<link rel='captions'>http://my.domain.com/videoplayer/media/J101/some_captions.xml</link>
<annotation>0:1,5:2,10:3,15:4,20:5,25:6,30:7,35:8,40:9,45:10,50:11,55:12,60:13,65:14</annotation>
<info>http://my.domain.com</info>
</track>

and call for this xml:

s1.addVariable('file',             '../media/default/default_video.xml');
s1.addVariable('id',               'whatever_trial/video');

not work :(

i think about simple app:
- one video hosted on external server,
- jw player playing this video and
- jw rotator with slideshow synchronizing with this video...
some simple solution? what do you think? unfortunately my js skills aren't advanced enough... :(

The RTMP protocol needs the name of the media file in the identifier element of the playlist track element.

<track>
<creator>Review</creator>
<title>Unit 001</title>
<location>rtmpt://blahblah.nl:80/VOD</location>
<strong><identifier>whatever_trial/video</identifier></strong>
<link rel='captions'>http://my.domain.com/videoplayer/media/J101/some_captions.xml</link>
<annotation>0:1,5:2,10:3,15:4,20:5,25:6,30:7,35:8,40:9,45:10,50:11,55:12,60:13,65:14</annotation>
<info>http://my.domain.com</info>
</track>

The location element should have the URL to your stream and the identifier element shuld have the name of your media file. Sometimes the identifier also includes some path information, such as yours, which has whatever_trial/ and may have the file extension (Red5) or may NOT have the file extension (FMS).

Post your full code or a link so I can have a look and advise you further.

very, very thanks for precise advice! now i can embed URL in xml. but slide synchro is gone... :(

http://www.livingmedia.pl/videoplayer/embed/basic-1.html

here, synchro works, but file is locally stored:

http://www.livingmedia.pl/videoplayer1/embed/basic-1.html

heres full code in a zip file:

http://livingmedia.pl/videoplayer.zip

OK. I have to study your code and test your application. Maybe Thursday.

At the bottom of the instrumentation data, in blue, it says, "Slideshow Playlist: _slideshow.xml". It should say, "Slideshow Playlist: ../media/default/jozin_z_bazin_slideshow.xml" like the captions "captions: ../media/default/default_captions.xml".

This is happening because we no longer have the location data, ending in ".flv" to use to construct the path for the slideshow.

In this code:

// change this: "../media/E101/unit_001.flv" to this: "../media/E101/unit_001_slideshow.xml"
newSlideshowPlaylist = currentFile.substring(0, currentFile.indexOf('.flv')) + '_slideshow.xml';

Therefore, we need a new way to construct the slideshow playlist path.

Perhaps we can use the identifier data which will again sync the slideshow playlist (by name) to the video file (by name).

Ultimately, we need to construct a URI like the one used by the non-RTMP page, which is "http://www.livingmedia.pl/video/jozin_z_bazin_slideshow.xml"

Comparing that URI to the corresponding identifier we get:

http://www.livingmedia.pl/video/jozin_z_bazin_slideshow.xml
                    livingmedia/jozin_z_bazin

So if the rest of the path is going to be consistently like this: ../media/default/XXXXXXXXXXXXX_slideshow.xml then we can just replace everything between " ../media/default/" and "_slideshow.xml" with the part of the identifier after the forward slash.

Therefore, the paths would be:

../media/default/<strong>jozin_z_bazin</strong>_slideshow.xml
../media/default/<strong>hoppe</strong>_slideshow.xml

Does this make sense to you?

ok, i try walk this way. very thanks. time for some testing...

I don't know how you guys are coming with the code changes, but this seeme to have survived testing.

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

<html lang="en">

<head>

  <title>livingmedia.pl</title>

  <meta http-equiv="content-type" content="text/html; charset=utf-8" />

  <style>
    td
    {
      vertical-align:               top;
      font-size:                   12px;
      font-family:  verdana, sans-serif;
    }

    li
    {
      font-family:                Arial;
      font-size:                   10px;
      text-align:                  left;
      color:                      black;
    }

    div#pid, div#data, div#timee, div#slide, div#filename, div#slideshowplaylist, div#annotation, div#numkeypairs, div#debug, div#syncdata
    {
      font-family:                Arial;
      font-size:                   10px;
      text-align:                  left; 
    }
  </style>

  <script type="text/javascript" src="swfobject.js"></script>

  <script type="text/javascript">
    var currentFile;
    var currentId;
    var currentItem;
    var currentSlide;
    var currentPosition;
    var currentSlideshowPlaylist;
    var currentVideoPlaylist;
    var newSlideshowPlaylist;
    var newSlide;
    var currentState;
    var instrumentation1 = 1; // timee slide
    var instrumentation2 = 0; // pid - player data
    var instrumentation3 = 0; // item data
    var instrumentation4 = 1; // filename - slideshowplaylist
    var instrumentation5 = 1; // annotation
    var instrumentation6 = 0; // numkeypairs
    var instrumentation7 = 0; // debug
    var instrumentation8 = 0; // syncdata

    // select and play chapters
    function openPlay(scrubNum)
    {
      if(currentState == 0)
      {
        thisMovie('mpl1').sendEvent('playitem', 0);
        setTimeout("thisMovie('mpl1').sendEvent('scrub', " + scrubNum + ")", 400);
      }
      else
      {
        thisMovie('mpl1').sendEvent('scrub', scrubNum);
      }
      setTimeout("checkState(" + scrubNum + ")", 1000);
    };

    function checkState(scrubPosition)
    {
      if((currentState == 0) || ((currentState == 2) && (currentPosition < (scrubPosition - 10))))
      {
        openPlay(scrubPosition);
      }
    };

    // this is a JavaScript handler for the player and is always needed.
    function thisMovie(movieName)
    {
      if(navigator.appName.indexOf('Microsoft') != -1)
      {
        return window[movieName];
      }
      else
      {
        return document[movieName];
      }
    };

    // these functions are caught by the feeder object of the player.
    function loadFile(jsid, obj)
    {
      thisMovie(jsid).loadFile(obj);
      if (jsid == 'mpl1')
      {
        // position the playlist to the first item, with the mediaplayer stopped
        setTimeout("thisMovie('mpl1').sendEvent('playitem', 0)", 300);
        setTimeout("thisMovie('mpl1').sendEvent('stop')", 450);
      }
      // reset the slide counter when a new video playlist is loaded
      currentSlide = 0;
    };

    function getUpdate(typ, pr1, pr2, pid)
    {
      if((pid != undefined) && (pid == 'mpl1'))
      {
        if(typ == 'time')
        {
          // advance the slideshow by going through the sync array,
          // until the position in the sync array is greater than
          // the currentPosition, then use that slide number - 1
          // newSlide = 0;
          currentPosition = pr1;

          for(var i in sync)
          {
            if(i >= currentPosition)
            {
              newSlide = sync[i] - 1;
              // newSlide = sync[i];
              break;
            }
          }

          // if the currentSlide hasn't been updated, do it now
          // slide number has to be - 1 because the playlist array starts at 0
          if(currentSlide != newSlide)
          {
            // this is where the slide is actually changed
            thisMovie('rot1').sendEvent('playitem', (newSlide - 1));
            currentSlide = newSlide;
          }

// Debug
if(instrumentation1)
{
  var tI       = document.getElementById('timee');
  tI.innerHTML = 'i1 Time: ' + currentPosition;
  var sL       = document.getElementById('slide');
  sL.innerHTML = 'i1 Current Slide: ' + currentSlide + '  New Slide: ' + newSlide;
}

        }
        else if(typ == 'item')
        {
          currentItem = pr1;
          setTimeout("getItemData(currentItem)", 100);
        }

// Debug
if((instrumentation2) && (pid == 'mpl1'))
{
  var dB       = document.getElementById('pid');
  dB.innerHTML = 'i2 Player ' + pid + ' Data:';
  var iD       = document.getElementById(typ);
  iD.innerHTML = '<li>' + typ + ': ' + Math.round(pr1);
  pr2 == undefined ? null: iD.innerHTML += ', ' + Math.round(pr2);
  iD.innerHTML += '</li>';
}

      }
    };
  </script>

  <script type="text/javascript">
    function getItemData(idx)
    {
      var obj = thisMovie('mpl1').itemData(idx);

// Debug
if(instrumentation3)
{
  var nodes = 'i3 Item Data:<ul>';
  for(var i in obj)
  { 
    nodes += '<li>' + i + ': ' + obj[i] + '</li>';
  }
  nodes += '</ul>';
  var dA       = document.getElementById('data');
  dA.innerHTML = nodes;
}

      // typical filenames
      // ../media/E101/unit_001.flv
      // ../media/E101/unit_001_slideshow.xml

      // do we need to load a new slideshow file?
      currentFile = obj['file'];
      currentId   = obj['id'];

      // old code to create a new slideshow playlist URL
      // change this: "../media/E101/unit_001.flv" to this: "../media/E101/unit_001_slideshow.xml"
      // newSlideshowPlaylist = currentFile.substring(0, currentFile.indexOf('.flv')) + '_slideshow.xml';

      // new code to create a new slideshow playlist
      //              change this: "../media/default/jozin_z_bazin_slideshow.xml"
      //                  to this: "../media/default/hoppe_slideshow.xml"
      // when the id changes from this: "livingmedia/jozin_z_bazin"
      //                       to this: "livingmedia/hoppe"
      currentId            = currentId.substring(currentId.indexOf('/') + 1);
      newSlideshowPlaylist = currentSlideshowPlaylist.substring(0, (currentSlideshowPlaylist.lastIndexOf('/'))) + '/' + currentId + '_slideshow.xml';

// Debug
if(instrumentation4)
{
  var fI        = document.getElementById('filename');
  fI.innerHTML  = 'i4 Video File Name :' + currentFile + ' ID: ' + currentId;
  var nS        = document.getElementById('slideshowplaylist');
  nS.innerHTML  = 'i4 Slideshow Playlist: ' + newSlideshowPlaylist;
}

      if(newSlideshowPlaylist != currentSlideshowPlaylist)
      {
        // this is where the new slideshow playlist is actually loaded
        loadFile('rot1', {file:newSlideshowPlaylist});
        setTimeout("thisMovie('rot1').sendEvent('playitem', 0)", 500);

        // this is so we know that the slideshow playlist was changed
        currentSlideshowPlaylist = newSlideshowPlaylist;

        // parse the playlist <annotation> element (flashvar 'description')
        // into Image Rotator time:slidenumber control points
        sync     = new Array();
        keypairs = new Object();
        numKP    = 1;
        anno     = obj['description'];

// Debug
if(instrumentation5)
{
  var aN       = document.getElementById('annotation');
  aN.innerHTML = 'i5 Annotation: ' + anno;
}

        while (anno.indexOf(',') > -1)
        {
          keypairs[numKP] = anno.substring(0, anno.indexOf(','));
          anno            = anno.substring((anno.indexOf(',')) + 1);
          numKP++;
        }

        // Store the last keypairs[] data.
        keypairs[numKP] = anno;

// Debug
if(instrumentation6)
{
  var nK       = document.getElementById('numkeypairs');
  nK.innerHTML = 'i6 Key Pairs: ' + numKP;
}
if(instrumentation7)
{
  var dE       = document.getElementById('debug');
  dE.innerHTML = 'i7 Debug: ' + anno;
}

        // split into time:slidenumber pairs
        for (var i in keypairs)
        {
          // Left of ':' is video time.
          keyTime = keypairs[i].substring(0, keypairs[i].indexOf(':'));

          // Right of ':' is slide number.
          keySlide = keypairs[i].substring((keypairs[i].indexOf(':')) + 1);

          // array of time:slidenumber pairs for syncing slides with video
          sync[keyTime] = keySlide;
        }

// Debug
if(instrumentation8)
{
  var pairs = 'i8 Sync Data Pairs:<ol>';
  for(var j in sync)
  {
    pairs += '<li>' + j + ' = ' + sync[j] + '</li>';
  }
  pairs += '</ol>';
  var sY       = document.getElementById('syncdata');
  sY.innerHTML = pairs;
}

      }
    };
  </script>

  <script type="text/javascript">
    function createPlayer(VideoPlaylist)
    {
      var s1 = new SWFObject('mediaplayer.swf', 'mpl1', '320', '277', '7', '#CCEEFF');
          s1.addVariable('width',               '320');
          s1.addVariable('height',              '277');
          s1.addVariable('displayheight',       '258');
          s1.addVariable('file',                 VideoPlaylist);
          s1.addVariable('overstretch',         'false'); // expands to fit h or v  "false" -will stretch them to fit
          s1.addVariable('showdigits',          'true');
          s1.addVariable('autostart',           'false');
          s1.addVariable('shuffle',             'false');
          s1.addVariable('repeat',              'false');
          s1.addVariable('showicons',           'false');
  s1.addVariable('showstop',            'true');
          s1.addVariable('enablejs',            'true');
          s1.addVariable('javascriptid',        'mpl1');
          s1.addVariable('usecaptions',         'true');
          s1.addVariable('backcolor',           '0xFFFFFF'); // face of buttons
          s1.addVariable('frontcolor',          '0x404040'); // button symbols & playlist text
          s1.addVariable('lightcolor',          '0x808080'); // highlighted playlist item
          s1.addVariable('screencolor',         '0xCCEEFF'); // screen background color
          s1.write('player');
    };

    function createRotator(SlidePlaylist)
    {
      var s2 = new SWFObject('imagerotator.swf', 'rot1', '540', '405', '7', '#CCEEFF');
          s2.addVariable('width',                '540');
          s2.addVariable('height',               '405');
          s2.addVariable('file',                  SlidePlaylist);
          s2.addVariable('overstretch',          'false'); // expands to fit h or v  "false" -will stretch them to fit
          s2.addVariable('autostart',            'false');
          s2.addVariable('shuffle',              'false');
          s2.addVariable('repeat',               'false');
          s2.addVariable('rotatetime',           '999');
          s2.addVariable('showicons',            'false');
          s2.addVariable('shownavigation',       'false');
          s2.addVariable('transition',           'bgfade');
          s2.addVariable('enablejs',             'true');
          s2.addVariable('javascriptid',         'rot1');
          s2.addVariable('backcolor',            '0xCCEEFF'); // face of buttons
          s2.addVariable('frontcolor',           '0x404040'); // button symbols & playlist text
          s2.addVariable('lightcolor',           '0x808080'); // highlighted playlist item
          s2.addVariable('screencolor',          '0xCCEEFF'); // screen background color
          s2.write('rotator');
    };

    function loadPlayers(initVideoPlaylist, initSlidePlaylist)
    {
      currentSlideshowPlaylist = initSlidePlaylist;

      createPlayer(initVideoPlaylist);
      createRotator(initSlidePlaylist);
    }
  </script>

</head>

<body onload="loadPlayers('../media/default/default_video.xml', '../media/default/jozin_z_bazin_slideshow.xml');">

  <table>
    <tr>
      <td>
        <div id="player">
          <a href="http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash">Get the Flash Plugin</a> 
          to see this gallery.
        </div>
      </td>
      <td align="left" valign="top">
      </td>
    </tr>
  </table>
  <table>
    <tr>
      <td valign="top">
        <div id="rotator">
          <a href="http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash">Get the Flash Plugin</a> 
          to see this gallery.
        </div>
      </td>
      <td>
        <div id="pid"               style="color: black">
        </div>
        <div id="item">
        </div>
        <div id="load">
        </div>
        <div id="size">
        </div> 
        <div id="state">
        </div>
        <div id="time">
        </div> 
        <div id="volume">
        </div>
        <div id="data"              style="color: black">
        </div>
        <div id="timee"             style="color: blue">
        </div>
        <div id="slide"             style="color: blue">
        </div>
        <div id="filename"          style="color: blue">
        </div>
        <div id="slideshowplaylist" style="color: blue">
        </div>
        <div id="annotation"        style="color: red">
        </div>
        <div id="numkeypairs"       style="color: green">
        </div>
        <div id="debug"             style="color: black">
        </div>
<div id="syncdata"          style="color: black">
        </div>
      </td>
    </tr>
  </table>
  <div id="chapters" style="position: absolute; left: 700px; top: 20px; border: 1px solid; font-family: 'Arial'; font-size: 12px; text-align: left; padding: 25px;">
    <p><b>CHAPTERS</b></p>
    <ol>
      <li><a href="#" onclick="javascript:openPlay(  0);">Początek: pierwsza zwrotka</a></li>
      <li><a href="#" onclick="javascript:openPlay( 20);">Pierwszy refren</a></li>
      <li><a href="#" onclick="javascript:openPlay( 50);">Druga zwrotka</a></li>
      <li><a href="#" onclick="javascript:openPlay( 70);">Drugi refren</a></li>
      <li><a href="#" onclick="javascript:openPlay(100);">Trzecia zwrotka</a></li>
      <li><a href="#" onclick="javascript:openPlay(117);">Trzeci refren (wchodzi ziutek z szybą)</a></li>
      <li><a href="#" onclick="javascript:openPlay(140);">Solówa na skrzekliwej fujarce</a></li>
    </ol>
  </div>

</body>

</html>

i walkaround problem in the meantime, but your solutions seems to be more elegant ;) many thanks!!

Anyone can help me in a solution for LIVE streaming sincronization? I can't write the XML with annotation where the seconds tell the rotator the image, because is in real time. Ideas? Thanks a lot guys.

Put the slide number in a file on your server, updated as the stream plays. Check the number in that file every 5-10 seconds with AJAX. If the number has changed, get the new slide and display it. You don't even need an Image Rotator for the image, just dump it into a div and replace it when necessary.

Hi Will,

We are trying to do the similar thing. Trying to figure out how to include power point slides that is synchronized with the flash videos, captions (on and off). Can we contact you with the details about the project? We would like to you to take on a flash project.

Thanks.

@Ashish,

Sorry, I don't do any Flash programming. If it's just HTML and JavaScript, I'd be interested. I use gmail.com with an email user name of wellitsme

Hi,

I would like to chat with you on gmail. I have already sent u an invitation for Gmail chat. Let me know if you prefer to be in contact any other way.

Thanks,

Ashish

@kLink

Hi,

I would like to chat with you on gmail. I have already sent u an invitation for Gmail chat. Let me know if you prefer to be in contact any other way.

Thanks,

Ashish

Hi All,

I read this thread in detail and need all of your help in PPT synchronisation for Live Flash Streaming.

Is this possible?? please let me know.

Thanks a lot for this knowledge sharing.

Warm Regards,
Pranav Gajjam

I'd like to find some help in this matter since I am a designer and I use powerpoint for presentations in court. We use a lot of video clips and I wonder if it's possible to embed the player in PowerPoint and get it working.

I embeded the player in ppt but I could not get to display my video playlists. HELP!

I believe it is NOT possible to load Flash in powerpoint. Alternatively, it's not possible to load Powerpoint in Flash.

However, if Powerpoint can export its slides as a series of JPG images, we can make a simple plugin that shows these slides next to the video. With a small XML file the slides can be timed to the video then.

Is the export to jpg image possible (Idon't have PPT)? If so, this seems like the way to go.

Google "Flash in PowerPoint"

First hit is: http://www.indezine.com/products/powerpoint/ppflash2.html which is an article titled "Inserting Flash in PowerPoint". The article mentions many tools like, "Shyam's Toolbox" , which is a collection of helper apps. for inserting Flash in PowerPoint.

Hi, yes Powerpoint can export jpg's. I'd be very interested in the kind of plugin and xml file with timing thah Jeroen is mentioning. Im usin wmv to solve this today, but would definately switch to Flash if possible.
Any progress in this matter?

Hi,

Any of you have the files of this post, please !

Rick

I have all of the files...

BUT, I would highly recommend that you use Cue Points instead.

See this thread: http://www.longtailvideo.com/support/forum/JavaScript-Interaction/18865/metadata-to-javascript#msg12...

Test Page: http://willswonders.myip.org:8074/Simple_SlideShow_CuePoints.html

@lost

Can you give me links for both so I can look them over since I want to learn more.

Thank's dude.

Rick

 
The JW FLV Player + JW Image Rotator is here:

    http://willswonders.myip.org:8074/videoplayer.zip

The link for the Cue Points is posted above.

@lost

Thank's mate

Hi,

I'm looking for the videoplayer.zip file - can anyone repost this? as the link above doesn't work. Many thanks.

Bob.

Yes - I'm looking for this file too... if anyone has this could they email it to igorbiscan @ gmail.com

....or repost

Thank you!