Streaming Media in OpenSim
From OpenSimulator
m (→General Steps) |
JeffKelley (Talk | contribs) m (Undo revision 53543 by JeffKelley (talk)) |
||
(11 intermediate revisions by 7 users not shown) | |||
Line 1: | Line 1: | ||
+ | {{Quicklinks}} | ||
+ | <br /> | ||
+ | {{obsolete}} | ||
+ | <div style="background-color:#ffcc99; padding:10px; padding-bottom:5px; border: 1px solid"> | ||
+ | Quicktime is no longer the technology supporting media streaming. | ||
+ | |||
+ | See https://wiki.secondlife.com/wiki/Streaming_Video_in_Second_Life | ||
+ | </div><br> | ||
+ | |||
== Introduction == | == Introduction == | ||
− | Streaming media in | + | Streaming media in OpenSimulator works the same way as in SL. One of the most frequent misconceptions about streaming content in OpenSimulator is the simulator or regions server is actually doing the streaming. This is not true, all streaming happens outside of the metaverse on a seperate dedicated server. The streaming content is fed directly to Quicktime from the viewer. Generally anything able to be played in Quicktime can be viewed in OpenSimulator through your viewer. Streaming does not impact the performance of the simulator since all content is sent to the viewer and Quicktime player. |
== QuickTime 7 Supported Audio/Video Formats == | == QuickTime 7 Supported Audio/Video Formats == | ||
Line 7: | Line 16: | ||
=== Supported Video Formats === | === Supported Video Formats === | ||
− | *Animation | + | * Animation |
− | *Apple BMP | + | * Apple BMP |
− | *Apple Pixlet (Mac OS X v10.3 only) | + | * Apple Pixlet (Mac OS X v10.3 only) |
− | *Apple Video | + | * Apple Video |
− | *Cinepak | + | * Cinepak |
− | *Component video | + | * Component video |
− | *DV and DVC Pro NTSC | + | * DV and DVC Pro NTSC |
− | *DV PAL | + | * DV PAL |
− | *DVC Pro PAL | + | * DVC Pro PAL |
− | *Graphics | + | * Graphics |
− | *H.261 | + | * H.261 |
− | *H.263 | + | * H.263 |
− | *H.264 | + | * H.264 |
− | *JPEG 2000 | + | * JPEG 2000 |
− | *Microsoft OLE (decode only) | + | * Microsoft OLE (decode only) |
− | *Microsoft Video 1 (decode only) | + | * Microsoft Video 1 (decode only) |
− | *Motion JPEG A | + | * Motion JPEG A |
− | *Motion JPEG B | + | * Motion JPEG B |
− | *MPEG-4 (Part 2) | + | * MPEG-4 (Part 2) |
− | *Photo JPEG | + | * Photo JPEG |
− | *Planar RGB | + | * Planar RGB |
− | *PNG | + | * PNG |
− | *Sorenson Video 2 | + | * Sorenson Video 2 |
− | *Sorenson Video 3 | + | * Sorenson Video 3 |
− | *TGA | + | * TGA |
− | *TIFF | + | * TIFF |
=== Supported Audio Formats === | === Supported Audio Formats === | ||
− | *24-bit integer | + | * 24-bit integer |
− | *32-bit floating point | + | * 32-bit floating point |
− | *32-bit integer | + | * 32-bit integer |
− | *64-bit floating point | + | * 64-bit floating point |
− | *AAC (MPEG-4 Audio) | + | * AAC (MPEG-4 Audio) |
− | *ALaw 2:1 | + | * ALaw 2:1 |
− | *AMR Narrowband | + | * AMR Narrowband |
− | *Apple Lossless Encoder | + | * Apple Lossless Encoder |
− | *IMA 4:1 | + | * IMA 4:1 |
− | *MACE 3:1 | + | * MACE 3:1 |
− | *MACE 6:1 | + | * MACE 6:1 |
− | *MS ADPCM (decode only) | + | * MS ADPCM (decode only) |
− | *QDesign Music 2 | + | * QDesign Music 2 |
− | *Qualcomm PureVoice (QCELP) | + | * Qualcomm PureVoice (QCELP) |
− | *ULaw 2:1 | + | * ULaw 2:1 |
− | == Creating a Media Screen in | + | == Creating a Media Screen in OpenSimulator == |
− | Now that you understand some of the fundamentals of what is going on with media content in | + | Now that you understand some of the fundamentals of what is going on with media content in OpenSimulator you are probably wanting to get started creating a video area so you and your friends can enjoy watching or listening to some media together. The best free script that I have come across is Freeview. The code for this script is listed below and you can simply copy and paste it into a script window to get you started. |
=== General Steps === | === General Steps === | ||
− | #Make sure you have a texture picked out to use as a media texture. Streaming media has to be displayed on a texture and unless you want to see your media playing all over the place make sure the texture is unique to just the prim you want to use as a view screen. [Note that svn 8118 onwards includes a default media etxture in the standard library, which | + | # Make sure you have a texture picked out to use as a media texture. Streaming media has to be displayed on a texture and unless you want to see your media playing all over the place make sure the texture is unique to just the prim you want to use as a view screen. [Note that svn 8118 onwards includes a default media etxture in the standard library, which corresponds with a UUID of 8b5fec65-8d8d-9dc5-cda8-8fdf2716e361 and that corresponds to the LSL constant TEXTURE_MEDIA] [See http://opensimulator.org/mantis/view.php?id=3030] |
− | #Create a prim that will display the media. | + | # Create a prim that will display the media. |
− | #For a good looking display choose a blank texture with a black color for all sides. | + | # For a good looking display choose a blank texture with a black color for all sides. |
− | #Select just the prim face for the screen and make the texture your media texture from Step 1 and choose white for the color. | + | # Select just the prim face for the screen and make the texture your media texture from Step 1 and choose white for the color. |
− | #Drop the Freeview script into the Contents tab. | + | # Drop the Freeview script into the Contents tab. |
− | #In the About Land window Media tab change your Replace Texture to the one in Step 1. | + | # In the About Land window Media tab change your Replace Texture to the one in Step 1. |
− | #In the About Land window General tab make sure the Allow Deed To Group item is checked. | + | # In the About Land window General tab make sure the Allow Deed To Group item is checked. |
At this point if your script compiled correctly then you should be able to click on the media view screen and a menu will pop up. A good test would be to choose the Video button and then the Set URL button. In the chat window type /1 and then a URL to a video that you know exists on a streaming server. The video should begin playing within a minute or so. | At this point if your script compiled correctly then you should be able to click on the media view screen and a menu will pop up. A good test would be to choose the Video button and then the Set URL button. In the chat window type /1 and then a URL to a video that you know exists on a streaming server. The video should begin playing within a minute or so. | ||
Line 67: | Line 76: | ||
=== Tips for Using Freeview === | === Tips for Using Freeview === | ||
Need some info here. | Need some info here. | ||
+ | |||
+ | The domain inside the script and the function inside the menu (TV Guide) are out of date. | ||
+ | |||
+ | Domain slguide.com is without any information, it is park as Free-Domain for register. | ||
=== Freeview Code === | === Freeview Code === | ||
− | < | + | <source lang="lsl"> |
//XEngine: | //XEngine: | ||
//FreeView 1.2 WebGuide (revision 3) - By CrystalShard Foo | //FreeView 1.2 WebGuide (revision 3) - By CrystalShard Foo | ||
Line 75: | Line 88: | ||
//This script is distributed for free and must stay that way. | //This script is distributed for free and must stay that way. | ||
− | // | + | // *** DO NOT SELL THIS SCRIPT UNDER ANY CIRCUMSTANCE. *** |
//Help for using this script can be obtained at: http://www.slguide.com/help | //Help for using this script can be obtained at: http://www.slguide.com/help | ||
Line 92: | Line 105: | ||
//Constants | //Constants | ||
− | integer PICTURE_ROTATION_TIMER = 60; | + | integer PICTURE_ROTATION_TIMER = 60; //In whole seconds |
integer DISPLAY_ON_SIDE = ALL_SIDES; //Change this to change where the image will be displayed | integer DISPLAY_ON_SIDE = ALL_SIDES; //Change this to change where the image will be displayed | ||
− | key VIDEO_DEFAULT = "71b8ff26-087d-5f44-285b-d38df2e11a81"; | + | key VIDEO_DEFAULT = "71b8ff26-087d-5f44-285b-d38df2e11a81"; //Test pattern - Used as default video texture when one is missing in parcel media |
key BLANK = "5748decc-f629-461c-9a36-a35a221fe21f"; //Blank texture - Used when there are no textures to display in Picture mode | key BLANK = "5748decc-f629-461c-9a36-a35a221fe21f"; //Blank texture - Used when there are no textures to display in Picture mode | ||
− | string NOTECARD = "bookmarks"; | + | string NOTECARD = "bookmarks"; //Used to host URL bookmarks for video streams |
− | integer VIDEO_BRIGHT = TRUE; | + | integer VIDEO_BRIGHT = TRUE; //FULL_BRIGHT status for Video |
− | integer PICTURE_BRIGHT = TRUE; | + | integer PICTURE_BRIGHT = TRUE; //FULL_BRIGHT status for Picture |
integer REMOTE_CHANNEL = 9238742; | integer REMOTE_CHANNEL = 9238742; | ||
− | integer mode = 0; | + | integer mode = 0; //Freeview mode. |
//Mode 0 - Power off | //Mode 0 - Power off | ||
//Mode 1 - Picture viewer | //Mode 1 - Picture viewer | ||
//Mode 2 - Video | //Mode 2 - Video | ||
− | integer listenHandle = -1; | + | integer listenHandle = -1; //Dialog menu listen handler |
− | integer listenUrl = -1; | + | integer listenUrl = -1; //listen handler for channel 1 for when a URL is being added |
− | integer listenTimer = -1; | + | integer listenTimer = -1; //Timer variable for removing all listeners after 2 minutes of listener inactivity |
− | integer listenRemote = -1; | + | integer listenRemote = -1; //listen handler for the remote during initial setup |
integer encryption = 0; | integer encryption = 0; | ||
− | integer numberofnotecardlines = 0; | + | integer numberofnotecardlines = 0; //Stores the current number of detected notecard lines. |
− | integer notecardline = 0; | + | integer notecardline = 0; //Current notecard line |
− | integer loop_image = FALSE; | + | integer loop_image = FALSE; //Are we looping pictures with a timer? (picture mode) |
− | integer current_texture = 0; | + | integer current_texture = 0; //Current texture number in inventory being displayed (picture mode) |
− | integer chan; | + | integer chan; //llDialog listen channel |
integer notecardcheck = 0; | integer notecardcheck = 0; | ||
− | key video_texture; | + | key video_texture; //Currently used video display texture for parcel media stream |
string moviename; | string moviename; | ||
string tempmoviename; | string tempmoviename; | ||
key notecardkey = NULL_KEY; | key notecardkey = NULL_KEY; | ||
− | key tempuser; | + | key tempuser; //Temp key storge variable |
− | string tempurl; | + | string tempurl; //Temp string storge variable |
integer isGroup = TRUE; | integer isGroup = TRUE; | ||
Line 135: | Line 148: | ||
key XML_channel; | key XML_channel; | ||
− | pictures() | + | pictures() //Change mode to Picture Viewer |
{ | { | ||
//Initilize variables | //Initilize variables | ||
Line 158: | Line 171: | ||
} | } | ||
− | video() | + | video() //Change mode to Video |
{ | { | ||
//Change prim to Light material while coloring face 0 black to prevent light-lag generation. | //Change prim to Light material while coloring face 0 black to prevent light-lag generation. | ||
Line 185: | Line 198: | ||
} | } | ||
− | integer finditem(string name) | + | integer finditem(string name) //Finds and returns an item's inventory number |
{ | { | ||
integer i; | integer i; | ||
Line 194: | Line 207: | ||
} | } | ||
− | seturl(string url, key id) | + | seturl(string url, key id) //Set parcel media URL |
{ | { | ||
if(mode != 2) | if(mode != 2) | ||
Line 224: | Line 237: | ||
} | } | ||
− | string mediatype(string ext) | + | string mediatype(string ext) //Returns a string stating the filetype of a file based on file extension |
{ | { | ||
ext = llToLower(ext); | ext = llToLower(ext); | ||
Line 240: | Line 253: | ||
} | } | ||
− | browse(key id) | + | browse(key id) //Image browser function for picture viewer mode |
{ | { | ||
integer check = llGetInventoryNumber(INVENTORY_TEXTURE); | integer check = llGetInventoryNumber(INVENTORY_TEXTURE); | ||
Line 257: | Line 270: | ||
} | } | ||
− | extendtimer() | + | extendtimer() //Add another 2 minute to the Listen Removal timer (use when a Listen event is triggered) |
{ | { | ||
if(listenHandle == -1) | if(listenHandle == -1) | ||
Line 266: | Line 279: | ||
} | } | ||
− | config(key id) | + | config(key id) //Configuration menu |
{ | { | ||
extendtimer(); | extendtimer(); | ||
Line 277: | Line 290: | ||
} | } | ||
− | menu(key id) | + | menu(key id) //Dialog menus for all 3 modes |
{ | { | ||
list buttons = []; | list buttons = []; | ||
Line 308: | Line 321: | ||
} | } | ||
− | display_texture(integer check) | + | display_texture(integer check) //Display texture and set name in description (picture mode) |
− | { | + | { //"Check" holds the number of textures in contents. The function uses "current_texture" to display. |
string name = llGetInventoryName(INVENTORY_TEXTURE,current_texture); | string name = llGetInventoryName(INVENTORY_TEXTURE,current_texture); | ||
llSetTexture(name,DISPLAY_ON_SIDE); | llSetTexture(name,DISPLAY_ON_SIDE); | ||
Line 316: | Line 329: | ||
− | next() | + | next() //Change to next texture (picture mode) |
− | { | + | { //This function is used twice - by the menu and timer. Therefor, it is a dedicated function. |
current_texture++; | current_texture++; | ||
integer check = llGetInventoryNumber(INVENTORY_TEXTURE); | integer check = llGetInventoryNumber(INVENTORY_TEXTURE); | ||
Line 759: | Line 772: | ||
} | } | ||
} | } | ||
− | </ | + | </source> |
+ | |||
== Additional Information == | == Additional Information == | ||
[[Category:Media]] | [[Category:Media]] | ||
+ | [[Category:Scripts]] |
Latest revision as of 15:07, 2 June 2023
This article or section contains obsolete and possibly misleading information. Please integrate this information into existing pages, update it to something more recent, or remove it. |
Quicktime is no longer the technology supporting media streaming.
See https://wiki.secondlife.com/wiki/Streaming_Video_in_Second_Life
Contents |
[edit] Introduction
Streaming media in OpenSimulator works the same way as in SL. One of the most frequent misconceptions about streaming content in OpenSimulator is the simulator or regions server is actually doing the streaming. This is not true, all streaming happens outside of the metaverse on a seperate dedicated server. The streaming content is fed directly to Quicktime from the viewer. Generally anything able to be played in Quicktime can be viewed in OpenSimulator through your viewer. Streaming does not impact the performance of the simulator since all content is sent to the viewer and Quicktime player.
[edit] QuickTime 7 Supported Audio/Video Formats
Current supported formats as listed by Apple are:
[edit] Supported Video Formats
- Animation
- Apple BMP
- Apple Pixlet (Mac OS X v10.3 only)
- Apple Video
- Cinepak
- Component video
- DV and DVC Pro NTSC
- DV PAL
- DVC Pro PAL
- Graphics
- H.261
- H.263
- H.264
- JPEG 2000
- Microsoft OLE (decode only)
- Microsoft Video 1 (decode only)
- Motion JPEG A
- Motion JPEG B
- MPEG-4 (Part 2)
- Photo JPEG
- Planar RGB
- PNG
- Sorenson Video 2
- Sorenson Video 3
- TGA
- TIFF
[edit] Supported Audio Formats
- 24-bit integer
- 32-bit floating point
- 32-bit integer
- 64-bit floating point
- AAC (MPEG-4 Audio)
- ALaw 2:1
- AMR Narrowband
- Apple Lossless Encoder
- IMA 4:1
- MACE 3:1
- MACE 6:1
- MS ADPCM (decode only)
- QDesign Music 2
- Qualcomm PureVoice (QCELP)
- ULaw 2:1
[edit] Creating a Media Screen in OpenSimulator
Now that you understand some of the fundamentals of what is going on with media content in OpenSimulator you are probably wanting to get started creating a video area so you and your friends can enjoy watching or listening to some media together. The best free script that I have come across is Freeview. The code for this script is listed below and you can simply copy and paste it into a script window to get you started.
[edit] General Steps
- Make sure you have a texture picked out to use as a media texture. Streaming media has to be displayed on a texture and unless you want to see your media playing all over the place make sure the texture is unique to just the prim you want to use as a view screen. [Note that svn 8118 onwards includes a default media etxture in the standard library, which corresponds with a UUID of 8b5fec65-8d8d-9dc5-cda8-8fdf2716e361 and that corresponds to the LSL constant TEXTURE_MEDIA] [See http://opensimulator.org/mantis/view.php?id=3030]
- Create a prim that will display the media.
- For a good looking display choose a blank texture with a black color for all sides.
- Select just the prim face for the screen and make the texture your media texture from Step 1 and choose white for the color.
- Drop the Freeview script into the Contents tab.
- In the About Land window Media tab change your Replace Texture to the one in Step 1.
- In the About Land window General tab make sure the Allow Deed To Group item is checked.
At this point if your script compiled correctly then you should be able to click on the media view screen and a menu will pop up. A good test would be to choose the Video button and then the Set URL button. In the chat window type /1 and then a URL to a video that you know exists on a streaming server. The video should begin playing within a minute or so.
[edit] Tips for Using Freeview
Need some info here.
The domain inside the script and the function inside the menu (TV Guide) are out of date.
Domain slguide.com is without any information, it is park as Free-Domain for register.
[edit] Freeview Code
//XEngine: //FreeView 1.2 WebGuide (revision 3) - By CrystalShard Foo //Multifunctional Picture viewer and Video control script with webguide support //This script is distributed for free and must stay that way. // *** DO NOT SELL THIS SCRIPT UNDER ANY CIRCUMSTANCE. *** //Help for using this script can be obtained at: http://www.slguide.com/help //Feel free to modify this script and post your improvement. Leave the credits intact but feel free to add your name at its bottom. //Whats new: //- Now using FULL_BRIGHT instead of PRIM_MATERIAL_LIGHT for the screen display //- Added an ownership-change code to handle cases where FreeView gets deeded to group post Video Init. //- Renamed WebGuide to TV-Guide to reflect what this thing does better. //- Added a 'Fix Scale' button to Picture mode to help against user texture-scale changes. //- Additional minor help-tips and code improvements //Enjoy! //Constants integer PICTURE_ROTATION_TIMER = 60; //In whole seconds integer DISPLAY_ON_SIDE = ALL_SIDES; //Change this to change where the image will be displayed key VIDEO_DEFAULT = "71b8ff26-087d-5f44-285b-d38df2e11a81"; //Test pattern - Used as default video texture when one is missing in parcel media key BLANK = "5748decc-f629-461c-9a36-a35a221fe21f"; //Blank texture - Used when there are no textures to display in Picture mode string NOTECARD = "bookmarks"; //Used to host URL bookmarks for video streams integer VIDEO_BRIGHT = TRUE; //FULL_BRIGHT status for Video integer PICTURE_BRIGHT = TRUE; //FULL_BRIGHT status for Picture integer REMOTE_CHANNEL = 9238742; integer mode = 0; //Freeview mode. //Mode 0 - Power off //Mode 1 - Picture viewer //Mode 2 - Video integer listenHandle = -1; //Dialog menu listen handler integer listenUrl = -1; //listen handler for channel 1 for when a URL is being added integer listenTimer = -1; //Timer variable for removing all listeners after 2 minutes of listener inactivity integer listenRemote = -1; //listen handler for the remote during initial setup integer encryption = 0; integer numberofnotecardlines = 0; //Stores the current number of detected notecard lines. integer notecardline = 0; //Current notecard line integer loop_image = FALSE; //Are we looping pictures with a timer? (picture mode) integer current_texture = 0; //Current texture number in inventory being displayed (picture mode) integer chan; //llDialog listen channel integer notecardcheck = 0; key video_texture; //Currently used video display texture for parcel media stream string moviename; string tempmoviename; key notecardkey = NULL_KEY; key tempuser; //Temp key storge variable string tempurl; //Temp string storge variable integer isGroup = TRUE; key groupcheck = NULL_KEY; key last_owner; key XML_channel; pictures() //Change mode to Picture Viewer { //Initilize variables //Change prim to Light material while coloring face 0 black to prevent light-lag generation. llSetPrimitiveParams([PRIM_BUMP_SHINY, DISPLAY_ON_SIDE, PRIM_SHINY_NONE, PRIM_BUMP_NONE, PRIM_COLOR, DISPLAY_ON_SIDE, <1,1,1>, 1.0, PRIM_MATERIAL, PRIM_MATERIAL_PLASTIC, PRIM_FULLBRIGHT, DISPLAY_ON_SIDE, PICTURE_BRIGHT]); integer check = llGetInventoryNumber(INVENTORY_TEXTURE); if(check == 0) { report("No pictures found."); llSetTexture(BLANK,DISPLAY_ON_SIDE); return; } else if(current_texture > check) //Set to first texture if available current_texture = 0; display_texture(current_texture); } video() //Change mode to Video { //Change prim to Light material while coloring face 0 black to prevent light-lag generation. llSetPrimitiveParams([PRIM_BUMP_SHINY, DISPLAY_ON_SIDE, PRIM_SHINY_NONE, PRIM_BUMP_NONE, PRIM_COLOR, DISPLAY_ON_SIDE, <1,1,1>, 1.0, PRIM_MATERIAL, PRIM_MATERIAL_PLASTIC, PRIM_FULLBRIGHT, DISPLAY_ON_SIDE, VIDEO_BRIGHT, PRIM_TEXTURE, DISPLAY_ON_SIDE, "62dc73ca-265f-7ca0-0453-e2a6aa60bb6f", llGetTextureScale(DISPLAY_ON_SIDE), llGetTextureOffset(DISPLAY_ON_SIDE), llGetTextureRot(DISPLAY_ON_SIDE)]); report("Video mode"+moviename+": Stopped"); if(finditem(NOTECARD) != -1) tempuser = llGetNumberOfNotecardLines(NOTECARD); video_texture = llList2Key(llParcelMediaQuery([PARCEL_MEDIA_COMMAND_TEXTURE]),0); if(video_texture == NULL_KEY) { video_texture = VIDEO_DEFAULT; llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_TEXTURE,VIDEO_DEFAULT]); llSay(0,"No parcel media texture found. Setting texture to default: "+(string)VIDEO_DEFAULT); if(llGetLandOwnerAt(llGetPos()) != llGetOwner()) llSay(0,"Error: Cannot modify parcel media settings. "+llGetObjectName()+" is not owned by parcel owner."); } llSetTexture(video_texture,DISPLAY_ON_SIDE); } off() { report("Click to power on."); llSetPrimitiveParams([PRIM_BUMP_SHINY, DISPLAY_ON_SIDE, PRIM_SHINY_LOW, PRIM_BUMP_NONE, PRIM_COLOR, DISPLAY_ON_SIDE, <0.1,0.1,0.1>, 1.0,PRIM_MATERIAL, PRIM_MATERIAL_PLASTIC, PRIM_FULLBRIGHT, DISPLAY_ON_SIDE, FALSE, PRIM_TEXTURE, DISPLAY_ON_SIDE, BLANK, llGetTextureScale(DISPLAY_ON_SIDE), llGetTextureOffset(DISPLAY_ON_SIDE), llGetTextureRot(DISPLAY_ON_SIDE)]); } integer finditem(string name) //Finds and returns an item's inventory number { integer i; for(i=0;i<llGetInventoryNumber(INVENTORY_NOTECARD);i++) if(llGetInventoryName(INVENTORY_NOTECARD,i) == NOTECARD) return i; return -1; } seturl(string url, key id) //Set parcel media URL { if(mode != 2) { video(); mode = 2; } moviename = tempmoviename; if(moviename) moviename = " ["+moviename+"]"; tempmoviename = ""; string oldurl = llList2String(llParcelMediaQuery([PARCEL_MEDIA_COMMAND_URL]),0); if(oldurl != "") llOwnerSay("Setting new media URL. The old URL was: "+oldurl); llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_URL,url]); if(id!=NULL_KEY) menu(id); else { report("Video mode"+moviename+": Playing"); llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_PLAY]); } if(isGroup) llSay(0,"New media URL set."); else llOwnerSay("New media URL set: "+url); } string mediatype(string ext) //Returns a string stating the filetype of a file based on file extension { ext = llToLower(ext); if(ext == "swf") return "Flash"; if(ext == "mov" || ext == "avi" || ext == "mpg" || ext == "mpeg" || ext == "smil") return "Video"; if(ext == "jpg" || ext == "mpeg" || ext == "gif" || ext == "png" || ext == "pict" || ext == "tga" || ext == "tiff" || ext == "sgi" || ext == "bmp") return "Image"; if(ext == "txt") return "Text"; if(ext == "mp3" || ext == "wav") return "Audio"; return "Unknown"; } browse(key id) //Image browser function for picture viewer mode { integer check = llGetInventoryNumber(INVENTORY_TEXTURE); string header; if(check > 0) header = "("+(string)(current_texture+1)+"/"+(string)check+") "+llGetInventoryName(INVENTORY_TEXTURE,current_texture); else header = "No pictures found."; llDialog(id,"** Monitor Control **\n Picture Viewer mode\n- Image browser\n- "+header,["Back","Next","Menu"],chan); extendtimer(); } report(string str) { llSetObjectDesc(str); } extendtimer() //Add another 2 minute to the Listen Removal timer (use when a Listen event is triggered) { if(listenHandle == -1) listenHandle = llListen(chan,"","",""); listenTimer = (integer)llGetTime() + 120; if(loop_image == FALSE) llSetTimerEvent(45); } config(key id) //Configuration menu { extendtimer(); llDialog(id,"Current media URL:\n"+llList2String(llParcelMediaQuery([PARCEL_MEDIA_COMMAND_URL]),0)+"\nTip: If the picture is abit off, try 'Align ON'",["Set URL","Align ON","Align OFF","Menu","Set Remote"],chan); } tell_remote(string str) { llShout(REMOTE_CHANNEL,llXorBase64Strings(llStringToBase64((string)encryption + str), llStringToBase64((string)encryption))); } menu(key id) //Dialog menus for all 3 modes { list buttons = []; string title = "** Monitor control **"; extendtimer(); if(mode != 0) { if(mode == 1) //Pictures menu { title+="\n Picture Viewer mode"; buttons+=["Browse"]; if(loop_image == FALSE) buttons+=["Loop"]; else buttons+=["Unloop"]; buttons+=["Video","Power off","Help","Fix scale"]; } else //Video menu { title+="\n Video display mode\n"+moviename+"\nTip:\nClick 'TV Guide' to view the Online bookmarks."; buttons+=["Pictures","Configure","Power off","Loop","Unload","Help","Play","Stop","Pause","TV Guide","Bookmarks","Set URL"]; } } else buttons += ["Pictures","Video","Help"]; llDialog(id,title,buttons,chan); } display_texture(integer check) //Display texture and set name in description (picture mode) { //"Check" holds the number of textures in contents. The function uses "current_texture" to display. string name = llGetInventoryName(INVENTORY_TEXTURE,current_texture); llSetTexture(name,DISPLAY_ON_SIDE); report("Showing picture: "+name+" ("+(string)(current_texture+1)+"/"+(string)check+")"); } next() //Change to next texture (picture mode) { //This function is used twice - by the menu and timer. Therefor, it is a dedicated function. current_texture++; integer check = llGetInventoryNumber(INVENTORY_TEXTURE); if(check == 0) { llSetTexture(BLANK,DISPLAY_ON_SIDE); current_texture = 0; report("No pictures found."); return; } if(check == current_texture) current_texture = 0; display_texture(check); return; } default { state_entry() { chan = (integer)llFrand(1000) + 1000; //Pick a random listen channel for the listener if(PICTURE_ROTATION_TIMER <= 0) //Ensure the value is no less or equal 0 PICTURE_ROTATION_TIMER = 1; llListenRemove(listenHandle); listenHandle = -1; last_owner = llGetOwner(); groupcheck = llRequestAgentData(llGetOwner(),DATA_NAME); off(); llOpenRemoteDataChannel(); } on_rez(integer i) { llResetScript(); } touch_start(integer total_number) { //------------------------------------------------------------------------------- //Listen only to owner or group member. Edit this code to change access controls. if(llDetectedKey(0) != llGetOwner() && llDetectedGroup(0) == FALSE) return; //------------------------------------------------------------------------------- if(llGetOwnerKey(llGetKey()) != last_owner) //Sense if object has been deeded to group for Web Guide function { isGroup = TRUE; last_owner = llGetOwner(); groupcheck = llRequestAgentData(llGetOwner(),DATA_NAME); if(mode == 2) { llSay(0,"Detected change in ownership. Attempting to obtain current parcel media texture..."); video(); } } menu(llDetectedKey(0)); } changed(integer change) { if(change == CHANGED_INVENTORY) //If inventory change if(mode == 1) //If picture mode { integer check = llGetInventoryNumber(INVENTORY_TEXTURE); if(check != 0) { current_texture = 0; display_texture(check); } else { llSetTexture(BLANK,DISPLAY_ON_SIDE); report("No pictures found."); } } else if(mode == 2) //If video mode if(finditem(NOTECARD) != -1) //And bookmarks notecard present if(notecardkey != llGetInventoryKey(NOTECARD)) tempuser = llGetNumberOfNotecardLines(NOTECARD); //Reload number of lines } listen(integer channel, string name, key id, string message) { if(message == "Pictures") { if(mode == 2) llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_STOP]); pictures(); mode = 1; menu(id); return; } if(message == "Video") { video(); mode = 2; menu(id); return; } if(message == "Power off") { if(mode == 2) llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_UNLOAD]); off(); mode = 0; return; } if(message == "Help") { llSay(0,"Help documentation is available at: http://www.slguide.com/help"); if(isGroup) { if(id == NULL_KEY) { llSay(0,"FreeView cannot load help pages while set to group without the remote."); llSay(0,"For further assistance, please consult: http://slguide.com/help"); } else tell_remote("HELP"+(string)id+(string)XML_channel); } else llLoadURL(id,"Help pages for FreeView","http://www.slguide.com?c="+(string)XML_channel+"&help=1"); } if(mode == 1) { if(message == "Browse") { loop_image = FALSE; browse(id); return; } if(message == "Next") { extendtimer(); next(); browse(id); } if(message == "Back") { extendtimer(); current_texture--; integer check = llGetInventoryNumber(INVENTORY_TEXTURE); if(check == 0) { llSetTexture(BLANK,DISPLAY_ON_SIDE); current_texture = 0; report("No pictures found."); return; } if(current_texture < 0) current_texture = check - 1; display_texture(check); browse(id); return; } if(message == "Menu") { menu(id); return; } if(message == "Loop") { llSetTimerEvent(PICTURE_ROTATION_TIMER); loop_image = TRUE; llOwnerSay("Picture will change every "+(string)PICTURE_ROTATION_TIMER+" seconds."); return; } if(message == "Unloop") { loop_image = FALSE; llOwnerSay("Picture loop disabled."); return; } if(message == "Fix scale") { llSay(0,"Setting display texture to 1,1 repeats and 0,0 offset."); llScaleTexture(1, 1, DISPLAY_ON_SIDE); llOffsetTexture(0, 0, DISPLAY_ON_SIDE); return; } } if(mode == 2) { if(channel == REMOTE_CHANNEL) { if(encryption == 0) encryption = (integer)message; llListenRemove(listenRemote); listenRemote = -1; llSay(0,"Remote configured ("+(string)id+")"); } if(message == "TV Guide") { if(isGroup) { if(!encryption) { llSay(0,"** Error - This FreeView object has been deeded to group. You must use a Remote control to open the TV Guide."); llSay(0,"You can set up the remote control from the Video -> Configuration menu. Please refer to the notecard for further assistance."); return; } tell_remote((string)id+(string)XML_channel+(string)llGetOwner()); } else llLoadURL(id, "Come to the Guide to Start Your Viewer Playing!", "http://slguide.com/index.php?v=" + (string)llGetKey() + "&c=" + (string)XML_channel + "&o=" + (string)llGetOwner() + "&"); return; } string header = "Video mode"+moviename+": "; if(message == "<< Prev") { notecardline--; if(notecardline < 0) notecardline = numberofnotecardlines - 1; tempuser = id; llGetNotecardLine(NOTECARD,notecardline); return; } if(message == "Next >>") { notecardline++; if(notecardline >= numberofnotecardlines) notecardline = 0; tempuser = id; llGetNotecardLine(NOTECARD,notecardline); return; } if(message == "Use") { if(tempurl == "** No URL specified! **") tempurl = ""; seturl(tempurl,id); return; } if(message == "Menu") { menu(id); return; } if(message == "Configure") { config(id); return; } if(message == "Bookmarks") { if(notecardcheck != -1) { llDialog(id,"Error: No valid bookmark data found in notecard '"+NOTECARD+"'.",["Menu"],chan); return; } if(finditem(NOTECARD) != -1) { tempuser = id; if(numberofnotecardlines < notecardline) notecardline = 0; llGetNotecardLine(NOTECARD,notecardline); } else llDialog(id,"Error: No notecard named "+NOTECARD+" found in contents.",["Menu"],chan); return; } if(llGetLandOwnerAt(llGetPos()) != llGetOwner()) //If we do not have permissions to actually do the following functions { llSay(0,"Error: Cannot modify parcel media settings. "+llGetObjectName()+" is not owned by parcel owner."); menu(id); return; //Abort } if(listenUrl != -1 && channel == 1) //Incoming data from "Set URL" command (user spoke on channel 1) { llListenRemove(listenUrl); listenUrl = -1; tempmoviename = ""; seturl(message,id); } if(message == "Play") { report(header+"Playing"); llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_PLAY]); return; } if(message == "Stop") { report(header+"Stopped"); llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_STOP]); return; } if(message == "Pause") { report(header+"Paused"); llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_PAUSE]); return; } if(message == "Unload") { report(header+"Stopped"); llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_UNLOAD]); return; } if(message == "Loop") { llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_LOOP]); return; } //URL , Auto-Scale, if(message == "Set URL") { report(header+"Stopped"); listenUrl = llListen(1,"",id,""); llDialog(id,"Please type the URL of your choice with /1 in thebegining. For example, /1 www.google.com",["Ok"],938); return; } if(message == "Align ON") { report(header+"Stopped"); llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_AUTO_ALIGN,TRUE]); menu(id); return; } if(message == "Align OFF") { report(header+"Stopped"); llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_AUTO_ALIGN,FALSE]); menu(id); return; } if(message == "Set Remote") { llSay(0,"Configuring remote..."); encryption = 0; llListenRemove(listenRemote); listenRemote = llListen(REMOTE_CHANNEL,"","",""); llSay(REMOTE_CHANNEL,"SETUP"); } } } dataserver(key queryid, string data) { if(queryid == groupcheck) //Test if object is deeded to group { groupcheck = NULL_KEY; isGroup = FALSE; return; } if(queryid == tempuser) //If just checking number of notecard lines { numberofnotecardlines = (integer)data; notecardkey = llGetInventoryKey(NOTECARD); notecardcheck = 0; llGetNotecardLine(NOTECARD,notecardcheck); return; } if(notecardcheck != -1) { if(data != EOF) { if(data == "") { notecardcheck++; llGetNotecardLine(NOTECARD,notecardcheck); } else { notecardcheck = -1; return; } } else return; } if(data == "" && notecardline < numberofnotecardlines) //If user just pressed "enter" in bookmarks, skip { notecardline++; llGetNotecardLine(NOTECARD,notecardline); return; } if(data == EOF) { notecardline = 0; llGetNotecardLine(NOTECARD,notecardline); return; } list parsed = llParseString2List(data,["|","| "," |"," | "],[]); //Ensure no blank spaces before "http://". string name = llList2String(parsed,0); tempurl = llList2String(parsed,1); if(tempurl == "") tempurl = "** No URL specified! **"; tempmoviename = name; llDialog(tempuser,"Bookmarks notecard ("+(string)(notecardline+1)+"/"+(string)numberofnotecardlines+")\n"+name+" ("+mediatype(llList2String(llParseString2List(tempurl,["."],[]),-1))+")\n"+tempurl,["<< Prev","Use","Next >>","Menu"],chan); } remote_data(integer type, key channel, key message_id, string sender, integer ival, string sval) { if (type == REMOTE_DATA_CHANNEL) { XML_channel = channel; } else if(type == REMOTE_DATA_REQUEST) { list media_info = llParseString2List(sval, ["|"], []); tempmoviename = llList2String(media_info,0); seturl(llList2String(media_info,1),NULL_KEY); llRemoteDataReply(channel, message_id, sval, 1); } } timer() { if(llGetTime() > listenTimer) //If listener time expired... { llListenRemove(listenHandle); //Remove listeneres. llListenRemove(listenUrl); llListenRemove(listenRemote); listenHandle = -1; listenUrl = -1; listenRemote = -1; listenTimer = -1; if(loop_image == FALSE || mode != 1) //If we're not looping pictures or are in picture mode at all llSetTimerEvent(0.0); //Remove timer } if(loop_image == TRUE && mode == 1) //If we're looping pictures and and we're in picture mode... next(); //Next picture } }