mirror of
				https://github.com/ossrs/srs.git
				synced 2025-03-09 15:49:59 +00:00 
			
		
		
		
	merge upstream
This commit is contained in:
		
						commit
						3753e8c5f1
					
				
					 47 changed files with 3285 additions and 1178 deletions
				
			
		
							
								
								
									
										44
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										44
									
								
								README.md
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -43,13 +43,13 @@ python ./research/api-server/server.py 8085
 | 
			
		|||
</pre>
 | 
			
		||||
<strong>step 6:</strong> publish live stream <br/>
 | 
			
		||||
<pre>
 | 
			
		||||
FMS URL: rtmp://127.0.0.1:1935/live
 | 
			
		||||
FMS URL: rtmp://127.0.0.1/live
 | 
			
		||||
Stream:  livestream
 | 
			
		||||
For example, use ffmpeg to publish:
 | 
			
		||||
    for((;;)); do \
 | 
			
		||||
        ./objs/ffmpeg/bin/ffmpeg -re -i ./doc/source.200kbps.768x320.flv \
 | 
			
		||||
        -vcodec copy -acodec copy \
 | 
			
		||||
        -f flv -y rtmp://127.0.0.1:1935/live/livestream; \
 | 
			
		||||
        -f flv -y rtmp://127.0.0.1/live?vhost=demo.srs.com/livestream; \
 | 
			
		||||
        sleep 1; \
 | 
			
		||||
    done
 | 
			
		||||
</pre>
 | 
			
		||||
| 
						 | 
				
			
			@ -59,35 +59,35 @@ For example, use ffmpeg to publish:
 | 
			
		|||
# linux: /etc/hosts
 | 
			
		||||
# windows: C:\Windows\System32\drivers\etc\hosts
 | 
			
		||||
# where server ip is 192.168.2.111
 | 
			
		||||
192.168.2.111 demo 
 | 
			
		||||
192.168.2.111 demo.srs.com
 | 
			
		||||
</pre>
 | 
			
		||||
<strong>step 8:</strong> play live stream. <br/>
 | 
			
		||||
<pre>
 | 
			
		||||
players: http://demo:80/players
 | 
			
		||||
rtmp url: rtmp://demo:1935/live/livestream
 | 
			
		||||
m3u8 url: http://demo:80/live/livestream.m3u8
 | 
			
		||||
for android: http://demo:80/live/livestream.html
 | 
			
		||||
players: [http://demo.srs.com/players](http://demo.srs.com/players)
 | 
			
		||||
rtmp url: rtmp://demo.srs.com/live/livestream
 | 
			
		||||
m3u8 url: http://demo.srs.com/live/livestream.m3u8
 | 
			
		||||
for android: http://demo.srs.com/live/livestream.html
 | 
			
		||||
</pre>
 | 
			
		||||
<strong>step 9(optinal):</strong> play live stream auto transcoded<br/>
 | 
			
		||||
<pre>
 | 
			
		||||
rtmp url: rtmp://demo:1935/live/livestream_ld
 | 
			
		||||
m3u8 url: http://demo:80/live/livestream_ld.m3u8
 | 
			
		||||
for android: http://demo:80/live/livestream_ld.html
 | 
			
		||||
rtmp url: rtmp://demo:1935/live/livestream_sd
 | 
			
		||||
m3u8 url: http://demo:80/live/livestream_sd.m3u8
 | 
			
		||||
for android: http://demo:80/live/livestream_sd.html
 | 
			
		||||
rtmp url: rtmp://demo.srs.com/live/livestream_ld
 | 
			
		||||
m3u8 url: http://demo.srs.com/live/livestream_ld.m3u8
 | 
			
		||||
for android: [http://demo.srs.com/live/livestream_ld.html](http://demo.srs.com/live/livestream_ld.html)
 | 
			
		||||
rtmp url: rtmp://demo.srs.com/live/livestream_sd
 | 
			
		||||
m3u8 url: http://demo.srs.com/live/livestream_sd.m3u8
 | 
			
		||||
for android: [http://demo.srs.com/live/livestream_sd.html](http://demo.srs.com/live/livestream_sd.html)
 | 
			
		||||
</pre>
 | 
			
		||||
<strong>step 10(optinal):</strong> play live stream auto forwarded, the hls dir change to /forward<br/>
 | 
			
		||||
<pre>
 | 
			
		||||
rtmp url: rtmp://demo:19350/live/livestream
 | 
			
		||||
m3u8 url: http://demo:80/forward/live/livestream.m3u8
 | 
			
		||||
for android: http://demo:80/forward/live/livestream.html
 | 
			
		||||
rtmp url: rtmp://demo:19350/live/livestream_ld
 | 
			
		||||
m3u8 url: http://demo:80/forward/live/livestream_ld.m3u8
 | 
			
		||||
for android: http://demo:80/forward/live/livestream_ld.html
 | 
			
		||||
rtmp url: rtmp://demo:19350/live/livestream_sd
 | 
			
		||||
m3u8 url: http://demo:80/forward/live/livestream_sd.m3u8
 | 
			
		||||
for android: http://demo:80/forward/live/livestream_sd.html
 | 
			
		||||
rtmp url: rtmp://demo.srs.com:19350/live/livestream
 | 
			
		||||
m3u8 url: http://demo.srs.com/forward/live/livestream.m3u8
 | 
			
		||||
for android: [http://demo.srs.com/forward/live/livestream.html](http://demo.srs.com/forward/live/livestream.html)
 | 
			
		||||
rtmp url: rtmp://demo.srs.com:19350/live/livestream_ld
 | 
			
		||||
m3u8 url: http://demo.srs.com/forward/live/livestream_ld.m3u8
 | 
			
		||||
for android: [http://demo.srs.com/forward/live/livestream_ld.html](http://demo.srs.com/forward/live/livestream_ld.html)
 | 
			
		||||
rtmp url: rtmp://demo.srs.com:19350/live/livestream_sd
 | 
			
		||||
m3u8 url: http://demo.srs.com/forward/live/livestream_sd.m3u8
 | 
			
		||||
for android: [http://demo.srs.com/forward/live/livestream_sd.html](http://demo.srs.com/forward/live/livestream_sd.html)
 | 
			
		||||
</pre>
 | 
			
		||||
<strong>step 11(optinal):</strong> modify the config and reload it (all features support reload)<br/>
 | 
			
		||||
<pre>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -243,7 +243,8 @@ if [ $SRS_HLS = YES ]; then
 | 
			
		|||
    sed -i "s/^.user  nobody;/user `whoami`;/g" ${SRS_OBJS}/nginx/conf/nginx.conf
 | 
			
		||||
    
 | 
			
		||||
    # create forward dir
 | 
			
		||||
    mkdir -p ${SRS_OBJS}/nginx/html/forward
 | 
			
		||||
    mkdir -p ${SRS_OBJS}/nginx/html/live &&
 | 
			
		||||
    mkdir -p ${SRS_OBJS}/nginx/html/forward/live
 | 
			
		||||
    
 | 
			
		||||
    # generate default html pages for android.
 | 
			
		||||
    html_file=${SRS_OBJS}/nginx/html/live/livestream.html && hls_stream=livestream.m3u8 && write_nginx_html5
 | 
			
		||||
| 
						 | 
				
			
			@ -254,7 +255,17 @@ if [ $SRS_HLS = YES ]; then
 | 
			
		|||
    html_file=${SRS_OBJS}/nginx/html/forward/live/livestream_sd.html && hls_stream=livestream_sd.m3u8 && write_nginx_html5
 | 
			
		||||
    
 | 
			
		||||
    # copy players to nginx html dir.
 | 
			
		||||
    cp research/players ${SRS_OBJS}/nginx/html/ -r
 | 
			
		||||
    rm -rf ${SRS_OBJS}/nginx/html/players &&
 | 
			
		||||
    ln -sf `pwd`/research/players ${SRS_OBJS}/nginx/html/players &&
 | 
			
		||||
    rm -f ${SRS_OBJS}/nginx/crossdomain.xml &&
 | 
			
		||||
    ln -sf `pwd`/research/players/crossdomain.xml ${SRS_OBJS}/nginx/html/crossdomain.xml
 | 
			
		||||
    
 | 
			
		||||
    # override the default index.
 | 
			
		||||
    cat <<END > ${SRS_OBJS}/nginx/html/index.html
 | 
			
		||||
    <script type="text/javascript">
 | 
			
		||||
        window.location.href = "players/index.html";
 | 
			
		||||
    </script>
 | 
			
		||||
END
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ $SRS_HLS = YES ]; then
 | 
			
		||||
| 
						 | 
				
			
			@ -327,8 +338,10 @@ fi
 | 
			
		|||
#####################################################################################
 | 
			
		||||
# build research code
 | 
			
		||||
#####################################################################################
 | 
			
		||||
(cd research/hls && make)
 | 
			
		||||
mkdir -p ${SRS_OBJS}/research
 | 
			
		||||
 | 
			
		||||
(cd research/hls && make && mv ts_info ../../${SRS_OBJS}/research)
 | 
			
		||||
ret=$?; if [[ $ret -ne 0 ]]; then echo "build research/hls failed, ret=$ret"; exit $ret; fi
 | 
			
		||||
 | 
			
		||||
(cd research/ffempty && make)
 | 
			
		||||
(cd research/ffempty && make && mv ffempty ../../${SRS_OBJS}/research)
 | 
			
		||||
ret=$?; if [[ $ret -ne 0 ]]; then echo "build research/ffempty failed, ret=$ret"; exit $ret; fi
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,9 +3,11 @@ vhost __defaultVhost__ {
 | 
			
		|||
	chunk_size		65000;
 | 
			
		||||
    enabled         on;
 | 
			
		||||
    gop_cache       on;
 | 
			
		||||
    hls             on;
 | 
			
		||||
    hls {
 | 
			
		||||
        enabled         on;
 | 
			
		||||
        hls_path        ./objs/nginx/html/forward;
 | 
			
		||||
        hls_fragment    5;
 | 
			
		||||
        hls_window      30;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,11 +18,18 @@ chunk_size		65000;
 | 
			
		|||
# vhost list, the __defaultVhost__ is the default vhost
 | 
			
		||||
# for example, user use ip to access the stream: rtmp://192.168.1.2/live/livestream.
 | 
			
		||||
# for which cannot identify the required vhost.
 | 
			
		||||
# for default demo.
 | 
			
		||||
vhost __defaultVhost__ {
 | 
			
		||||
	chunk_size		65000;
 | 
			
		||||
    enabled         on;
 | 
			
		||||
    gop_cache       on;
 | 
			
		||||
}
 | 
			
		||||
# vhost list, the __defaultVhost__ is the default vhost
 | 
			
		||||
# for example, user use ip to access the stream: rtmp://192.168.1.2/live/livestream.
 | 
			
		||||
# for which cannot identify the required vhost.
 | 
			
		||||
# for default demo.
 | 
			
		||||
vhost demo.srs.com {
 | 
			
		||||
    enabled         on;
 | 
			
		||||
    gop_cache       on;
 | 
			
		||||
    queue_length    30;
 | 
			
		||||
    forward         127.0.0.1:19350;
 | 
			
		||||
    hls {
 | 
			
		||||
| 
						 | 
				
			
			@ -32,7 +39,7 @@ vhost __defaultVhost__ {
 | 
			
		|||
        hls_window      30;
 | 
			
		||||
    }
 | 
			
		||||
    http_hooks {
 | 
			
		||||
        enabled         off;
 | 
			
		||||
        enabled         on;
 | 
			
		||||
        on_connect      http://127.0.0.1:8085/api/v1/clients;
 | 
			
		||||
        on_close        http://127.0.0.1:8085/api/v1/clients;
 | 
			
		||||
        on_publish      http://127.0.0.1:8085/api/v1/streams;
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +53,7 @@ vhost __defaultVhost__ {
 | 
			
		|||
        engine ld {
 | 
			
		||||
            enabled         on;
 | 
			
		||||
            vfilter {
 | 
			
		||||
                vf                  'drawtext=text=SimpleRtmpServer(SRS):x=10:y=10:fontcolor=#cccccc:fontfile=./doc/FreeSerifBold.ttf';
 | 
			
		||||
                vf                  'drawtext=text=SimpleRtmpServer(SRS):x=10:y=10:fontsize=30:fontcolor=#cccccc:fontfile=./doc/FreeSerifBold.ttf';
 | 
			
		||||
            }
 | 
			
		||||
            vcodec          libx264;
 | 
			
		||||
            vbitrate        300;
 | 
			
		||||
| 
						 | 
				
			
			@ -91,15 +98,57 @@ vhost __defaultVhost__ {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
# for the players site, to play or publish.
 | 
			
		||||
# the flash player publisher need to transcode to support hls,
 | 
			
		||||
# we add players_hls vhost to support it.
 | 
			
		||||
vhost players {
 | 
			
		||||
    enabled         on;
 | 
			
		||||
    gop_cache       on;
 | 
			
		||||
    transcode {
 | 
			
		||||
        enabled         on;
 | 
			
		||||
        ffmpeg          ./objs/ffmpeg/bin/ffmpeg;
 | 
			
		||||
        engine hls {
 | 
			
		||||
            enabled         on;
 | 
			
		||||
            vfilter {
 | 
			
		||||
                vf                  'drawtext=text=SRS(SimpleRtmpServer):x=10:y=10:fontcolor=#cccccc:fontfile=./doc/FreeSerifBold.ttf';
 | 
			
		||||
            }
 | 
			
		||||
            vcodec          libx264;
 | 
			
		||||
            vbitrate        300;
 | 
			
		||||
            vfps            20;
 | 
			
		||||
            vwidth          768;
 | 
			
		||||
            vheight         320;
 | 
			
		||||
            vthreads        1;
 | 
			
		||||
            vprofile        baseline;
 | 
			
		||||
            vpreset         superfast;
 | 
			
		||||
            vparams {
 | 
			
		||||
            }
 | 
			
		||||
            acodec          libaacplus;
 | 
			
		||||
            abitrate        30;
 | 
			
		||||
            asample_rate    44100;
 | 
			
		||||
            achannels       2;
 | 
			
		||||
            aparams {
 | 
			
		||||
            }
 | 
			
		||||
            output          rtmp://127.0.0.1:[port]/[app]?vhost=players_pub/[stream];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
vhost players_pub {
 | 
			
		||||
    hls {
 | 
			
		||||
        enabled         on;
 | 
			
		||||
        hls_path        ./objs/nginx/html;
 | 
			
		||||
        hls_fragment    5;
 | 
			
		||||
        hls_window      30;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
# for development
 | 
			
		||||
vhost dev {
 | 
			
		||||
	chunk_size		65000;
 | 
			
		||||
    enabled         on;
 | 
			
		||||
    gop_cache       on;
 | 
			
		||||
    queue_length    10;
 | 
			
		||||
    forward         127.0.0.1:19350;
 | 
			
		||||
    #forward         127.0.0.1:19350;
 | 
			
		||||
    hls {
 | 
			
		||||
        enabled         on;
 | 
			
		||||
        enabled         off;
 | 
			
		||||
        hls_path        ./objs/nginx/html;
 | 
			
		||||
        hls_fragment    5;
 | 
			
		||||
        hls_window      30;
 | 
			
		||||
| 
						 | 
				
			
			@ -587,7 +636,7 @@ vhost all.transcode.vhost.com {
 | 
			
		|||
vhost ffempty.transcode.vhost.com {
 | 
			
		||||
    transcode {
 | 
			
		||||
        enabled     on;
 | 
			
		||||
        ffmpeg ./research/ffempty/ffempty;
 | 
			
		||||
        ffmpeg ./objs/research/ffempty;
 | 
			
		||||
        engine empty {
 | 
			
		||||
            enabled         on;
 | 
			
		||||
            vcodec          libx264;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								trunk/research/players/crossdomain.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								trunk/research/players/crossdomain.xml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
<cross-domain-policy>
 | 
			
		||||
  <allow-access-from domain="*"/>
 | 
			
		||||
</cross-domain-policy>
 | 
			
		||||
							
								
								
									
										9
									
								
								trunk/research/players/css/bootstrap.min.css
									
										
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										9
									
								
								trunk/research/players/css/bootstrap.min.css
									
										
									
									
										vendored
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								trunk/research/players/img/tooltip.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								trunk/research/players/img/tooltip.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 783 B  | 
| 
						 | 
				
			
			@ -1,13 +1,50 @@
 | 
			
		|||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
    <title>Players</title>
 | 
			
		||||
    <meta http-equiv=Content-Type content="text/html;charset=utf-8">
 | 
			
		||||
    <title>SRS</title>   
 | 
			
		||||
    <meta charset="utf-8">
 | 
			
		||||
    <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
 | 
			
		||||
    <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/bootstrap.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/swfobject.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/srs.js"></script>
 | 
			
		||||
    <style>
 | 
			
		||||
        body{
 | 
			
		||||
            padding-top: 55px;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
    <script type="text/javascript">
 | 
			
		||||
        $(function(){
 | 
			
		||||
            update_nav();
 | 
			
		||||
            
 | 
			
		||||
            // direct to the default vhost for players.
 | 
			
		||||
            window.location.href = "srs_player.html?vhost=" + srs_get_player_vhost();
 | 
			
		||||
        });
 | 
			
		||||
    </script>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
    welcome!</p>
 | 
			
		||||
    <hr/>
 | 
			
		||||
    <p><a href="rtmp/index.html">Rtmp流播放器</a></p>
 | 
			
		||||
    <p><a href="osmf/index.html">OSMF播放器</a></p>
 | 
			
		||||
    <p><a href="jwplayer5/index.html">JWPlayer5</a></p>
 | 
			
		||||
    <p><a href="jwplayer6/index.html">JWPlayer6</a></p>
 | 
			
		||||
    <p><a href="http://www.videolan.org/vlc/">VLC for HLS/rtmp/rtsp/http....</a></p>
 | 
			
		||||
<div class="navbar navbar-fixed-top">
 | 
			
		||||
    <div class="navbar-inner">
 | 
			
		||||
        <div class="container">
 | 
			
		||||
        <a class="brand" href="index.html">SRS</a>
 | 
			
		||||
            <div class="nav-collapse collapse">
 | 
			
		||||
                <ul class="nav">
 | 
			
		||||
                    <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
 | 
			
		||||
                    <li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
 | 
			
		||||
                    <li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
 | 
			
		||||
                    <li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>
 | 
			
		||||
                    <li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>
 | 
			
		||||
                    <li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
<div class="container">
 | 
			
		||||
    <hr>
 | 
			
		||||
    <footer>
 | 
			
		||||
        <p><a href="https://github.com/winlinvip/simple-rtmp-server">SRS Team © 2013</a></p>
 | 
			
		||||
    </footer>
 | 
			
		||||
</div>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										0
									
								
								trunk/research/players/osmf/AdobeFlashPlayerInstall.swf → trunk/research/players/js/AdobeFlashPlayerInstall.swf
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										0
									
								
								trunk/research/players/osmf/AdobeFlashPlayerInstall.swf → trunk/research/players/js/AdobeFlashPlayerInstall.swf
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
								
								
									
										6
									
								
								trunk/research/players/js/bootstrap.min.js
									
										
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										6
									
								
								trunk/research/players/js/bootstrap.min.js
									
										
									
									
										vendored
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										6
									
								
								trunk/research/players/js/jquery-1.10.2.min.js
									
										
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										6
									
								
								trunk/research/players/js/jquery-1.10.2.min.js
									
										
									
									
										vendored
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								trunk/research/players/js/jquery-1.10.2.min.map
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										1
									
								
								trunk/research/players/js/jquery-1.10.2.min.map
									
										
									
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								trunk/research/players/js/jwplayer.flash.swf
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								trunk/research/players/js/jwplayer.flash.swf
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										194
									
								
								trunk/research/players/js/jwplayer.html5.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								trunk/research/players/js/jwplayer.html5.js
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										76
									
								
								trunk/research/players/js/jwplayer.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								trunk/research/players/js/jwplayer.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,76 @@
 | 
			
		|||
"undefined"==typeof jwplayer&&(jwplayer=function(f){if(jwplayer.api)return jwplayer.api.selectPlayer(f)},jwplayer.version="6.4.3359",jwplayer.vid=document.createElement("video"),jwplayer.audio=document.createElement("audio"),jwplayer.source=document.createElement("source"),function(f){function a(g){return function(){return c(g)}}var l=document,e=window,j=navigator,b=f.utils=function(){};b.exists=function(g){switch(typeof g){case "string":return 0<g.length;case "object":return null!==g;case "undefined":return!1}return!0};
 | 
			
		||||
b.styleDimension=function(g){return g+(0<g.toString().indexOf("%")?"":"px")};b.getAbsolutePath=function(g,a){b.exists(a)||(a=l.location.href);if(b.exists(g)){var c;if(b.exists(g)){c=g.indexOf("://");var j=g.indexOf("?");c=0<c&&(0>j||j>c)}else c=void 0;if(c)return g;c=a.substring(0,a.indexOf("://")+3);var j=a.substring(c.length,a.indexOf("/",c.length+1)),d;0===g.indexOf("/")?d=g.split("/"):(d=a.split("?")[0],d=d.substring(c.length+j.length+1,d.lastIndexOf("/")),d=d.split("/").concat(g.split("/")));
 | 
			
		||||
for(var h=[],e=0;e<d.length;e++)d[e]&&(b.exists(d[e])&&"."!=d[e])&&(".."==d[e]?h.pop():h.push(d[e]));return c+j+"/"+h.join("/")}};b.extend=function(){var a=b.extend.arguments;if(1<a.length){for(var c=1;c<a.length;c++)b.foreach(a[c],function(c,d){try{b.exists(d)&&(a[0][c]=d)}catch(j){}});return a[0]}return null};b.log=function(a,b){"undefined"!=typeof console&&"undefined"!=typeof console.log&&(b?console.log(a,b):console.log(a))};var c=b.userAgentMatch=function(a){return null!==j.userAgent.toLowerCase().match(a)};
 | 
			
		||||
b.isIE=a(/msie/i);b.isFF=a(/firefox/i);b.isChrome=a(/chrome/i);b.isIOS=a(/iP(hone|ad|od)/i);b.isIPod=a(/iP(hone|od)/i);b.isIPad=a(/iPad/i);b.isSafari602=a(/Macintosh.*Mac OS X 10_8.*6\.0\.\d* Safari/i);b.isAndroid=function(a){return a?c(RegExp("android.*"+a,"i")):c(/android/i)};b.isMobile=function(){return b.isIOS()||b.isAndroid()};b.saveCookie=function(a,b){l.cookie="jwplayer."+a+"\x3d"+b+"; path\x3d/"};b.getCookies=function(){for(var a={},b=l.cookie.split("; "),c=0;c<b.length;c++){var d=b[c].split("\x3d");
 | 
			
		||||
0==d[0].indexOf("jwplayer.")&&(a[d[0].substring(9,d[0].length)]=d[1])}return a};b.typeOf=function(a){var b=typeof a;return"object"===b?!a?"null":a instanceof Array?"array":b:b};b.translateEventResponse=function(a,c){var d=b.extend({},c);a==f.events.JWPLAYER_FULLSCREEN&&!d.fullscreen?(d.fullscreen="true"==d.message?!0:!1,delete d.message):"object"==typeof d.data?(d=b.extend(d,d.data),delete d.data):"object"==typeof d.metadata&&b.deepReplaceKeyName(d.metadata,["__dot__","__spc__","__dsh__","__default__"],
 | 
			
		||||
["."," ","-","default"]);b.foreach(["position","duration","offset"],function(a,b){d[b]&&(d[b]=Math.round(1E3*d[b])/1E3)});return d};b.flashVersion=function(){if(b.isAndroid())return 0;var a=j.plugins,d;try{if("undefined"!==a&&(d=a["Shockwave Flash"]))return parseInt(d.description.replace(/\D+(\d+)\..*/,"$1"))}catch(c){}if("undefined"!=typeof e.ActiveXObject)try{if(d=new ActiveXObject("ShockwaveFlash.ShockwaveFlash"))return parseInt(d.GetVariable("$version").split(" ")[1].split(",")[0])}catch(f){}return 0};
 | 
			
		||||
b.getScriptPath=function(a){for(var b=l.getElementsByTagName("script"),d=0;d<b.length;d++){var c=b[d].src;if(c&&0<=c.indexOf(a))return c.substr(0,c.indexOf(a))}return""};b.deepReplaceKeyName=function(a,d,c){switch(f.utils.typeOf(a)){case "array":for(var j=0;j<a.length;j++)a[j]=f.utils.deepReplaceKeyName(a[j],d,c);break;case "object":b.foreach(a,function(b,h){var j;if(d instanceof Array&&c instanceof Array){if(d.length!=c.length)return;j=d}else j=[d];for(var e=b,l=0;l<j.length;l++)e=e.replace(RegExp(d[l],
 | 
			
		||||
"g"),c[l]);a[e]=f.utils.deepReplaceKeyName(h,d,c);b!=e&&delete a[b]})}return a};var d=b.pluginPathType={ABSOLUTE:0,RELATIVE:1,CDN:2};b.getPluginPathType=function(a){if("string"==typeof a){a=a.split("?")[0];var c=a.indexOf("://");if(0<c)return d.ABSOLUTE;var j=a.indexOf("/");a=b.extension(a);return 0>c&&0>j&&(!a||!isNaN(a))?d.CDN:d.RELATIVE}};b.getPluginName=function(a){return a.replace(/^(.*\/)?([^-]*)-?.*\.(swf|js)$/,"$2")};b.getPluginVersion=function(a){return a.replace(/[^-]*-?([^\.]*).*$/,"$1")};
 | 
			
		||||
b.isYouTube=function(a){return-1<a.indexOf("youtube.com")||-1<a.indexOf("youtu.be")};b.isRtmp=function(a,b){return 0==a.indexOf("rtmp")||"rtmp"==b};b.foreach=function(a,b){var d,c;for(d in a)a.hasOwnProperty(d)&&(c=a[d],b(d,c))};b.isHTTPS=function(){return 0==e.location.href.indexOf("https")};b.repo=function(){var a=""+f.version.split(/\W/).splice(0,2).join("/")+"/";try{b.isHTTPS()&&(a=a.replace("http://","https://ssl."))}catch(d){}return a}}(jwplayer),function(f){var a="video/",
 | 
			
		||||
l=f.foreach,e={mp4:a+"mp4",vorbis:"audio/ogg",ogg:a+"ogg",webm:a+"webm",aac:"audio/mp4",mp3:"audio/mpeg",hls:"application/vnd.apple.mpegurl"},j={mp4:e.mp4,f4v:e.mp4,m4v:e.mp4,mov:e.mp4,m4a:e.aac,f4a:e.aac,aac:e.aac,mp3:e.mp3,ogv:e.ogg,ogg:e.vorbis,oga:e.vorbis,webm:e.webm,m3u8:e.hls,hls:e.hls},a="video",a={flv:a,f4v:a,mov:a,m4a:a,m4v:a,mp4:a,aac:a,f4a:a,mp3:"sound",smil:"rtmp",m3u8:"hls",hls:"hls"},b=f.extensionmap={};l(j,function(a,d){b[a]={html5:d}});l(a,function(a,d){b[a]||(b[a]={});b[a].flash=
 | 
			
		||||
d});b.types=e;b.mimeType=function(a){var b;l(e,function(j,e){!b&&e==a&&(b=j)});return b};b.extType=function(a){return b.mimeType(j[a])}}(jwplayer.utils),function(f){var a=f.loaderstatus={NEW:0,LOADING:1,ERROR:2,COMPLETE:3},l=document;f.scriptloader=function(e){function j(){c=a.ERROR;g.sendEvent(d.ERROR)}function b(){c=a.COMPLETE;g.sendEvent(d.COMPLETE)}var c=a.NEW,d=jwplayer.events,g=new d.eventdispatcher;f.extend(this,g);this.load=function(){var g=f.scriptloader.loaders[e];if(g&&(g.getStatus()==
 | 
			
		||||
a.NEW||g.getStatus()==a.LOADING))g.addEventListener(d.ERROR,j),g.addEventListener(d.COMPLETE,b);else if(f.scriptloader.loaders[e]=this,c==a.NEW){c=a.LOADING;var m=l.createElement("script");m.addEventListener?(m.onload=b,m.onerror=j):m.readyState&&(m.onreadystatechange=function(){("loaded"==m.readyState||"complete"==m.readyState)&&b()});l.getElementsByTagName("head")[0].appendChild(m);m.src=e}};this.getStatus=function(){return c}};f.scriptloader.loaders={}}(jwplayer.utils),function(f){f.trim=function(a){return a.replace(/^\s*/,
 | 
			
		||||
"").replace(/\s*$/,"")};f.pad=function(a,f,e){for(e||(e="0");a.length<f;)a=e+a;return a};f.xmlAttribute=function(a,f){for(var e=0;e<a.attributes.length;e++)if(a.attributes[e].name&&a.attributes[e].name.toLowerCase()==f.toLowerCase())return a.attributes[e].value.toString();return""};f.extension=function(a){if(!a||"rtmp"==a.substr(0,4))return"";a=a.substring(a.lastIndexOf("/")+1,a.length).split("?")[0].split("#")[0];if(-1<a.lastIndexOf("."))return a.substr(a.lastIndexOf(".")+1,a.length).toLowerCase()};
 | 
			
		||||
f.stringToColor=function(a){a=a.replace(/(#|0x)?([0-9A-F]{3,6})$/gi,"$2");3==a.length&&(a=a.charAt(0)+a.charAt(0)+a.charAt(1)+a.charAt(1)+a.charAt(2)+a.charAt(2));return parseInt(a,16)}}(jwplayer.utils),function(f){f.key=function(a){var l,e,j;this.edition=function(){return j&&j.getTime()<(new Date).getTime()?"invalid":l};this.token=function(){return e};f.exists(a)||(a="");try{a=f.tea.decrypt(a,"36QXq4W@GSBV^teR");var b=a.split("/");(l=b[0])||(l="free");e=b[1];b[2]&&0<parseInt(b[2])&&(j=new Date,j.setTime(String(b[2])))}catch(c){l=
 | 
			
		||||
"invalid"}}}(jwplayer.utils),function(f){var a=f.tea={};a.encrypt=function(j,b){if(0==j.length)return"";var c=a.strToLongs(e.encode(j));1>=c.length&&(c[1]=0);for(var d=a.strToLongs(e.encode(b).slice(0,16)),g=c.length,f=c[g-1],m=c[0],n,k=Math.floor(6+52/g),h=0;0<k--;){h+=2654435769;n=h>>>2&3;for(var r=0;r<g;r++)m=c[(r+1)%g],f=(f>>>5^m<<2)+(m>>>3^f<<4)^(h^m)+(d[r&3^n]^f),f=c[r]+=f}c=a.longsToStr(c);return l.encode(c)};a.decrypt=function(j,b){if(0==j.length)return"";for(var c=a.strToLongs(l.decode(j)),
 | 
			
		||||
d=a.strToLongs(e.encode(b).slice(0,16)),g=c.length,f=c[g-1],m=c[0],n,k=2654435769*Math.floor(6+52/g);0!=k;){n=k>>>2&3;for(var h=g-1;0<=h;h--)f=c[0<h?h-1:g-1],f=(f>>>5^m<<2)+(m>>>3^f<<4)^(k^m)+(d[h&3^n]^f),m=c[h]-=f;k-=2654435769}c=a.longsToStr(c);c=c.replace(/\0+$/,"");return e.decode(c)};a.strToLongs=function(a){for(var b=Array(Math.ceil(a.length/4)),c=0;c<b.length;c++)b[c]=a.charCodeAt(4*c)+(a.charCodeAt(4*c+1)<<8)+(a.charCodeAt(4*c+2)<<16)+(a.charCodeAt(4*c+3)<<24);return b};a.longsToStr=function(a){for(var b=
 | 
			
		||||
Array(a.length),c=0;c<a.length;c++)b[c]=String.fromCharCode(a[c]&255,a[c]>>>8&255,a[c]>>>16&255,a[c]>>>24&255);return b.join("")};var l={code:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\x3d",encode:function(a,b){var c,d,g,f,m=[],n="",k,h,r=l.code;h=("undefined"==typeof b?0:b)?e.encode(a):a;k=h.length%3;if(0<k)for(;3>k++;)n+="\x3d",h+="\x00";for(k=0;k<h.length;k+=3)c=h.charCodeAt(k),d=h.charCodeAt(k+1),g=h.charCodeAt(k+2),f=c<<16|d<<8|g,c=f>>18&63,d=f>>12&63,g=f>>6&63,f&=63,m[k/
 | 
			
		||||
3]=r.charAt(c)+r.charAt(d)+r.charAt(g)+r.charAt(f);m=m.join("");return m=m.slice(0,m.length-n.length)+n},decode:function(a,b){b="undefined"==typeof b?!1:b;var c,d,g,f,m,n=[],k,h=l.code;k=b?e.decode(a):a;for(var r=0;r<k.length;r+=4)c=h.indexOf(k.charAt(r)),d=h.indexOf(k.charAt(r+1)),f=h.indexOf(k.charAt(r+2)),m=h.indexOf(k.charAt(r+3)),g=c<<18|d<<12|f<<6|m,c=g>>>16&255,d=g>>>8&255,g&=255,n[r/4]=String.fromCharCode(c,d,g),64==m&&(n[r/4]=String.fromCharCode(c,d)),64==f&&(n[r/4]=String.fromCharCode(c));
 | 
			
		||||
f=n.join("");return b?e.decode(f):f}},e={encode:function(a){a=a.replace(/[\u0080-\u07ff]/g,function(a){a=a.charCodeAt(0);return String.fromCharCode(192|a>>6,128|a&63)});return a=a.replace(/[\u0800-\uffff]/g,function(a){a=a.charCodeAt(0);return String.fromCharCode(224|a>>12,128|a>>6&63,128|a&63)})},decode:function(a){a=a.replace(/[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g,function(a){a=(a.charCodeAt(0)&15)<<12|(a.charCodeAt(1)&63)<<6|a.charCodeAt(2)&63;return String.fromCharCode(a)});return a=
 | 
			
		||||
a.replace(/[\u00c0-\u00df][\u0080-\u00bf]/g,function(a){a=(a.charCodeAt(0)&31)<<6|a.charCodeAt(1)&63;return String.fromCharCode(a)})}}}(jwplayer.utils),function(f){f.events={COMPLETE:"COMPLETE",ERROR:"ERROR",API_READY:"jwplayerAPIReady",JWPLAYER_READY:"jwplayerReady",JWPLAYER_FULLSCREEN:"jwplayerFullscreen",JWPLAYER_RESIZE:"jwplayerResize",JWPLAYER_ERROR:"jwplayerError",JWPLAYER_MEDIA_BEFOREPLAY:"jwplayerMediaBeforePlay",JWPLAYER_MEDIA_BEFORECOMPLETE:"jwplayerMediaBeforeComplete",JWPLAYER_COMPONENT_SHOW:"jwplayerComponentShow",
 | 
			
		||||
JWPLAYER_COMPONENT_HIDE:"jwplayerComponentHide",JWPLAYER_MEDIA_BUFFER:"jwplayerMediaBuffer",JWPLAYER_MEDIA_BUFFER_FULL:"jwplayerMediaBufferFull",JWPLAYER_MEDIA_ERROR:"jwplayerMediaError",JWPLAYER_MEDIA_LOADED:"jwplayerMediaLoaded",JWPLAYER_MEDIA_COMPLETE:"jwplayerMediaComplete",JWPLAYER_MEDIA_SEEK:"jwplayerMediaSeek",JWPLAYER_MEDIA_TIME:"jwplayerMediaTime",JWPLAYER_MEDIA_VOLUME:"jwplayerMediaVolume",JWPLAYER_MEDIA_META:"jwplayerMediaMeta",JWPLAYER_MEDIA_MUTE:"jwplayerMediaMute",JWPLAYER_MEDIA_LEVELS:"jwplayerMediaLevels",
 | 
			
		||||
JWPLAYER_MEDIA_LEVEL_CHANGED:"jwplayerMediaLevelChanged",JWPLAYER_CAPTIONS_CHANGED:"jwplayerCaptionsChanged",JWPLAYER_CAPTIONS_LIST:"jwplayerCaptionsList",JWPLAYER_PLAYER_STATE:"jwplayerPlayerState",state:{BUFFERING:"BUFFERING",IDLE:"IDLE",PAUSED:"PAUSED",PLAYING:"PLAYING"},JWPLAYER_PLAYLIST_LOADED:"jwplayerPlaylistLoaded",JWPLAYER_PLAYLIST_ITEM:"jwplayerPlaylistItem",JWPLAYER_PLAYLIST_COMPLETE:"jwplayerPlaylistComplete",JWPLAYER_DISPLAY_CLICK:"jwplayerViewClick",JWPLAYER_CONTROLS:"jwplayerViewControls",
 | 
			
		||||
JWPLAYER_INSTREAM_CLICK:"jwplayerInstreamClicked",JWPLAYER_INSTREAM_DESTROYED:"jwplayerInstreamDestroyed"}}(jwplayer),function(f){var a=jwplayer.utils;f.eventdispatcher=function(f,e){var j,b;this.resetEventListeners=function(){j={};b=[]};this.resetEventListeners();this.addEventListener=function(b,d,g){try{a.exists(j[b])||(j[b]=[]),"string"==a.typeOf(d)&&(d=(new Function("return "+d))()),j[b].push({listener:d,count:g})}catch(e){a.log("error",e)}return!1};this.removeEventListener=function(b,d){if(j[b]){try{for(var g=
 | 
			
		||||
0;g<j[b].length;g++)if(j[b][g].listener.toString()==d.toString()){j[b].splice(g,1);break}}catch(e){a.log("error",e)}return!1}};this.addGlobalListener=function(c,d){try{"string"==a.typeOf(c)&&(c=(new Function("return "+c))()),b.push({listener:c,count:d})}catch(g){a.log("error",g)}return!1};this.removeGlobalListener=function(c){if(c){try{for(var d=0;d<b.length;d++)if(b[d].listener.toString()==c.toString()){b.splice(d,1);break}}catch(g){a.log("error",g)}return!1}};this.sendEvent=function(c,d){a.exists(d)||
 | 
			
		||||
(d={});a.extend(d,{id:f,version:jwplayer.version,type:c});e&&a.log(c,d);if("undefined"!=a.typeOf(j[c]))for(var g=0;g<j[c].length;g++){try{j[c][g].listener(d)}catch(q){a.log("There was an error while handling a listener: "+q.toString(),j[c][g].listener)}j[c][g]&&(1===j[c][g].count?delete j[c][g]:0<j[c][g].count&&(j[c][g].count-=1))}for(g=0;g<b.length;g++){try{b[g].listener(d)}catch(m){a.log("There was an error while handling a listener: "+m.toString(),b[g].listener)}b[g]&&(1===b[g].count?delete b[g]:
 | 
			
		||||
0<b[g].count&&(b[g].count-=1))}}}}(jwplayer.events),function(f){var a={},l={};f.plugins=function(){};f.plugins.loadPlugins=function(e,j){l[e]=new f.plugins.pluginloader(new f.plugins.model(a),j);return l[e]};f.plugins.registerPlugin=function(e,j,b,c){var d=f.utils.getPluginName(e);a[d]||(a[d]=new f.plugins.plugin(e));a[d].registerPlugin(e,j,b,c)}}(jwplayer),function(f){f.plugins.model=function(a){this.addPlugin=function(l){var e=f.utils.getPluginName(l);a[e]||(a[e]=new f.plugins.plugin(l));return a[e]};
 | 
			
		||||
this.getPlugins=function(){return a}}}(jwplayer),function(f){var a=jwplayer.utils,l=jwplayer.events;f.pluginmodes={FLASH:0,JAVASCRIPT:1,HYBRID:2};f.plugin=function(e){function j(){switch(a.getPluginPathType(e)){case a.pluginPathType.ABSOLUTE:return e;case a.pluginPathType.RELATIVE:return a.getAbsolutePath(e,window.location.href)}}function b(){n=setTimeout(function(){d=a.loaderstatus.COMPLETE;k.sendEvent(l.COMPLETE)},1E3)}function c(){d=a.loaderstatus.ERROR;k.sendEvent(l.ERROR)}var d=a.loaderstatus.NEW,
 | 
			
		||||
g,q,m,n,k=new l.eventdispatcher;a.extend(this,k);this.load=function(){if(d==a.loaderstatus.NEW)if(0<e.lastIndexOf(".swf"))g=e,d=a.loaderstatus.COMPLETE,k.sendEvent(l.COMPLETE);else if(a.getPluginPathType(e)==a.pluginPathType.CDN)d=a.loaderstatus.COMPLETE,k.sendEvent(l.COMPLETE);else{d=a.loaderstatus.LOADING;var h=new a.scriptloader(j());h.addEventListener(l.COMPLETE,b);h.addEventListener(l.ERROR,c);h.load()}};this.registerPlugin=function(b,c,e,j){n&&(clearTimeout(n),n=void 0);m=c;e&&j?(g=j,q=e):"string"==
 | 
			
		||||
typeof e?g=e:"function"==typeof e?q=e:!e&&!j&&(g=b);d=a.loaderstatus.COMPLETE;k.sendEvent(l.COMPLETE)};this.getStatus=function(){return d};this.getPluginName=function(){return a.getPluginName(e)};this.getFlashPath=function(){if(g)switch(a.getPluginPathType(g)){case a.pluginPathType.ABSOLUTE:return g;case a.pluginPathType.RELATIVE:return 0<e.lastIndexOf(".swf")?a.getAbsolutePath(g,window.location.href):a.getAbsolutePath(g,j())}return null};this.getJS=function(){return q};this.getTarget=function(){return m};
 | 
			
		||||
this.getPluginmode=function(){if("undefined"!=typeof g&&"undefined"!=typeof q)return f.pluginmodes.HYBRID;if("undefined"!=typeof g)return f.pluginmodes.FLASH;if("undefined"!=typeof q)return f.pluginmodes.JAVASCRIPT};this.getNewInstance=function(a,b,d){return new q(a,b,d)};this.getURL=function(){return e}}}(jwplayer.plugins),function(f){var a=f.utils,l=f.events,e=a.foreach;f.plugins.pluginloader=function(j,b){function c(){m?h.sendEvent(l.ERROR,{message:n}):q||(q=!0,g=a.loaderstatus.COMPLETE,h.sendEvent(l.COMPLETE))}
 | 
			
		||||
function d(){k||c();if(!q&&!m){var b=0,d=j.getPlugins();a.foreach(k,function(g){g=a.getPluginName(g);var e=d[g];g=e.getJS();var h=e.getTarget(),e=e.getStatus();if(e==a.loaderstatus.LOADING||e==a.loaderstatus.NEW)b++;else if(g&&(!h||parseFloat(h)>parseFloat(f.version)))m=!0,n="Incompatible player version",c()});0==b&&c()}}var g=a.loaderstatus.NEW,q=!1,m=!1,n,k=b,h=new l.eventdispatcher;a.extend(this,h);this.setupPlugins=function(b,d,c){var g={length:0,plugins:{}},h=0,f={},r=j.getPlugins();e(d.plugins,
 | 
			
		||||
function(e,j){var k=a.getPluginName(e),l=r[k],m=l.getFlashPath(),n=l.getJS(),q=l.getURL();m&&(g.plugins[m]=a.extend({},j),g.plugins[m].pluginmode=l.getPluginmode(),g.length++);try{if(n&&d.plugins&&d.plugins[q]){var v=document.createElement("div");v.id=b.id+"_"+k;v.style.position="absolute";v.style.top=0;v.style.zIndex=h+10;f[k]=l.getNewInstance(b,a.extend({},d.plugins[q]),v);h++;b.onReady(c(f[k],v,!0));b.onResize(c(f[k],v))}}catch(B){a.log("ERROR: Failed to load "+k+".")}});b.plugins=f;return g};
 | 
			
		||||
this.load=function(){if(!(a.exists(b)&&"object"!=a.typeOf(b))){g=a.loaderstatus.LOADING;e(b,function(b){a.exists(b)&&(b=j.addPlugin(b),b.addEventListener(l.COMPLETE,d),b.addEventListener(l.ERROR,r))});var c=j.getPlugins();e(c,function(a,b){b.load()})}d()};var r=this.pluginFailed=function(){m||(m=!0,n="File not found",c())};this.getStatus=function(){return g}}}(jwplayer),function(f){f.playlist=function(a){var l=[];if("array"==f.utils.typeOf(a))for(var e=0;e<a.length;e++)l.push(new f.playlist.item(a[e]));
 | 
			
		||||
else l.push(new f.playlist.item(a));return l}}(jwplayer),function(f){var a=f.item=function(l){var e=jwplayer.utils,j=e.extend({},a.defaults,l);j.tracks=e.exists(l.tracks)?l.tracks:[];0==j.sources.length&&(j.sources=[new f.source(j)]);for(var b=0;b<j.sources.length;b++){var c=j.sources[b]["default"];j.sources[b]["default"]=c?"true"==c.toString():!1;j.sources[b]=new f.source(j.sources[b])}if(j.captions&&!e.exists(l.tracks)){for(l=0;l<j.captions.length;l++)j.tracks.push(j.captions[l]);delete j.captions}for(b=
 | 
			
		||||
0;b<j.tracks.length;b++)j.tracks[b]=new f.track(j.tracks[b]);return j};a.defaults={description:"",image:"",mediaid:"",title:"",sources:[],tracks:[]}}(jwplayer.playlist),function(f){var a=jwplayer.utils,l={file:void 0,label:void 0,type:void 0,"default":void 0};f.source=function(e){var j=a.extend({},l);a.foreach(l,function(b){a.exists(e[b])&&(j[b]=e[b],delete e[b])});j.type&&0<j.type.indexOf("/")&&(j.type=a.extensionmap.mimeType(j.type));"m3u8"==j.type&&(j.type="hls");"smil"==j.type&&(j.type="rtmp");
 | 
			
		||||
return j}}(jwplayer.playlist),function(f){var a=jwplayer.utils,l={file:void 0,label:void 0,kind:"captions","default":!1};f.track=function(e){var j=a.extend({},l);e||(e={});a.foreach(l,function(b){a.exists(e[b])&&(j[b]=e[b],delete e[b])});return j}}(jwplayer.playlist),function(f){var a=f.utils,l=f.events,e=document,j=f.embed=function(b){function c(b,d){a.foreach(d,function(a,d){"function"==typeof b[a]&&b[a].call(b,d)})}function d(a){q(n,t+a.message)}function g(){q(n,t+"No playable sources found")}
 | 
			
		||||
function q(b,d){if(m.fallback){var c=b.style;c.backgroundColor="#000";c.color="#FFF";c.width=a.styleDimension(m.width);c.height=a.styleDimension(m.height);c.display="table";c.opacity=1;var c=document.createElement("p"),g=c.style;g.verticalAlign="middle";g.textAlign="center";g.display="table-cell";g.font="15px/20px Arial, Helvetica, sans-serif";c.innerHTML=d.replace(":",":\x3cbr\x3e");b.innerHTML="";b.appendChild(c)}}var m=new j.config(b.config),n,k,h,r=m.width,p=m.height,t="Error loading player: ",
 | 
			
		||||
s=f.plugins.loadPlugins(b.id,m.plugins);m.fallbackDiv&&(h=m.fallbackDiv,delete m.fallbackDiv);m.id=b.id;k=e.getElementById(b.id);m.aspectratio?b.config.aspectratio=m.aspectratio:delete b.config.aspectratio;n=e.createElement("div");n.id=k.id;n.style.width=0<r.toString().indexOf("%")?r:r+"px";n.style.height=0<p.toString().indexOf("%")?p:p+"px";k.parentNode.replaceChild(n,k);f.embed.errorScreen=q;s.addEventListener(l.COMPLETE,function(){if("array"==a.typeOf(m.playlist)&&2>m.playlist.length&&(0==m.playlist.length||
 | 
			
		||||
!m.playlist[0].sources||0==m.playlist[0].sources.length))g();else if(s.getStatus()==a.loaderstatus.COMPLETE){for(var e=0;e<m.modes.length;e++)if(m.modes[e].type&&j[m.modes[e].type]){var f=a.extend({},m),r=new j[m.modes[e].type](n,m.modes[e],f,s,b);if(r.supportsConfig())return r.addEventListener(l.ERROR,d),r.embed(),c(b,f.events),b}m.fallback?(a.log("No suitable players found and fallback enabled"),new j.download(n,m,g)):(a.log("No suitable players found and fallback disabled"),n.parentNode.replaceChild(h,
 | 
			
		||||
n))}});s.addEventListener(l.ERROR,function(a){q(n,"Could not load plugins: "+a.message)});s.load();return b}}(jwplayer),function(f){function a(a){if(a.playlist)for(var c=0;c<a.playlist.length;c++)a.playlist[c]=new j(a.playlist[c]);else{var d={};e.foreach(j.defaults,function(c){l(a,d,c)});d.sources||(a.levels?(d.sources=a.levels,delete a.levels):(c={},l(a,c,"file"),l(a,c,"type"),d.sources=c.file?[c]:[]));a.playlist=[new j(d)]}}function l(a,c,d){e.exists(a[d])&&(c[d]=a[d],delete a[d])}var e=f.utils,
 | 
			
		||||
j=f.playlist.item;(f.embed.config=function(b){var c={fallback:!0,height:270,primary:"html5",width:480,base:b.base?b.base:e.getScriptPath("jwplayer.js"),aspectratio:""};b=e.extend(c,f.defaults,b);var c={type:"html5",src:b.base+"jwplayer.html5.js"},d={type:"flash",src:b.base+"jwplayer.flash.swf"};b.modes="flash"==b.primary?[d,c]:[c,d];b.listbar&&(b.playlistsize=b.listbar.size,b.playlistposition=b.listbar.position);b.flashplayer&&(d.src=b.flashplayer);b.html5player&&(c.src=b.html5player);a(b);d=b.aspectratio;
 | 
			
		||||
if("string"!=typeof d||!e.exists(d))c=0;else{var g=d.indexOf(":");-1==g?c=0:(c=parseFloat(d.substr(0,g)),d=parseFloat(d.substr(g+1)),c=0>=c||0>=d?0:100*(d/c)+"%")}-1==b.width.toString().indexOf("%")?delete b.aspectratio:c?b.aspectratio=c:delete b.aspectratio;return b}).addConfig=function(b,c){a(c);return e.extend(b,c)}}(jwplayer),function(f){var a=f.utils,l=document;f.embed.download=function(e,f,b){function c(b,d){for(var c=l.querySelectorAll(b),g=0;g<c.length;g++)a.foreach(d,function(a,b){c[g].style[a]=
 | 
			
		||||
b})}function d(a,b,d){a=l.createElement(a);b&&(a.className="jwdownload"+b);d&&d.appendChild(a);return a}var g=a.extend({},f),q=g.width?g.width:480,m=g.height?g.height:320,n;f=f.logo?f.logo:{prefix:a.repo(),file:"logo.png",margin:10};var k,h,r,g=g.playlist,p,t=["mp4","aac","mp3"];if(g&&g.length){p=g[0];n=p.sources;for(g=0;g<n.length;g++){var s=n[g],u=s.type?s.type:a.extensionmap.extType(a.extension(s.file));s.file&&a.foreach(t,function(b){u==t[b]?(k=s.file,h=p.image):a.isYouTube(s.file)&&(r=s.file)})}k?
 | 
			
		||||
(n=k,b=h,e&&(g=d("a","display",e),d("div","icon",g),d("div","logo",g),n&&g.setAttribute("href",a.getAbsolutePath(n))),g="#"+e.id+" .jwdownload",e.style.width="",e.style.height="",c(g+"display",{width:a.styleDimension(Math.max(320,q)),height:a.styleDimension(Math.max(180,m)),background:"black center no-repeat "+(b?"url("+b+")":""),backgroundSize:"contain",position:"relative",border:"none",display:"block"}),c(g+"display div",{position:"absolute",width:"100%",height:"100%"}),c(g+"logo",{top:f.margin+
 | 
			
		||||
"px",right:f.margin+"px",background:"top right no-repeat url("+f.prefix+f.file+")"}),c(g+"icon",{background:"center no-repeat url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAgNJREFUeNrs28lqwkAYB/CZqNVDDj2r6FN41QeIy8Fe+gj6BL275Q08u9FbT8ZdwVfotSBYEPUkxFOoks4EKiJdaDuTjMn3wWBO0V/+sySR8SNSqVRKIR8qaXHkzlqS9jCfzzWcTCYp9hF5o+59sVjsiRzcegSckFzcjT+ruN80TeSlAjCAAXzdJSGPFXRpAAMYwACGZQkSdhG4WCzehMNhqV6vG6vVSrirKVEw66YoSqDb7cqlUilE8JjHd/y1MQefVzqdDmiaJpfLZWHgXMHn8F6vJ1cqlVAkEsGuAn83J4gAd2RZymQygX6/L1erVQt+9ZPWb+CDwcCC2zXGJaewl/DhcHhK3DVj+KfKZrMWvFarcYNLomAv4aPRSFZVlTlcSPA5fDweW/BoNIqFnKV53JvncjkLns/n/cLdS+92O7RYLLgsKfv9/t8XlDn4eDyiw+HA9Jyz2eyt0+kY2+3WFC5hluej0Ha7zQQq9PPwdDq1Et1sNsx/nFBgCqWJ8oAK1aUptNVqcYWewE4nahfU0YQnk4ntUEfGMIU2m01HoLaCKbTRaDgKtaVLk9tBYaBcE/6Artdr4RZ5TB6/dC+9iIe/WgAMYADDpAUJAxjAAAYwgGFZgoS/AtNNTF7Z2bL0BYPBV3Jw5xFwwWcYxgtBP5OkE8i9G7aWGOOCruvauwADALMLMEbKf4SdAAAAAElFTkSuQmCC)"})):
 | 
			
		||||
r?(f=r,e=d("embed","",e),e.src="http://www.youtube.com/v/"+/v[=\/](\w*)|\/(\w+)$|^(\w+)$/i.exec(f).slice(1).join(""),e.type="application/x-shockwave-flash",e.width=q,e.height=m):b()}}}(jwplayer),function(f){var a=f.utils,l=f.events,e={};(f.embed.flash=function(j,b,c,d,g){function q(a,b,d){var c=document.createElement("param");c.setAttribute("name",b);c.setAttribute("value",d);a.appendChild(c)}function m(a,b,d){return function(){try{d&&document.getElementById(g.id+"_wrapper").appendChild(b);var c=
 | 
			
		||||
document.getElementById(g.id).getPluginConfig("display");"function"==typeof a.resize&&a.resize(c.width,c.height);b.style.left=c.x;b.style.top=c.h}catch(e){}}}function n(b){if(!b)return{};var d={},c=[];a.foreach(b,function(b,g){var e=a.getPluginName(b);c.push(b);a.foreach(g,function(a,b){d[e+"."+a]=b})});d.plugins=c.join(",");return d}var k=new f.events.eventdispatcher,h=a.flashVersion();a.extend(this,k);this.embed=function(){c.id=g.id;if(10>h)return k.sendEvent(l.ERROR,{message:"Flash version must be 10.0 or greater"}),
 | 
			
		||||
!1;var f,p,t=g.config.listbar,s=a.extend({},c);if(j.id+"_wrapper"==j.parentNode.id)f=document.getElementById(j.id+"_wrapper");else{f=document.createElement("div");p=document.createElement("div");p.style.display="none";p.id=j.id+"_aspect";f.id=j.id+"_wrapper";f.style.position="relative";f.style.display="block";f.style.width=a.styleDimension(s.width);f.style.height=a.styleDimension(s.height);if(g.config.aspectratio){var u=parseFloat(g.config.aspectratio);p.style.display="block";p.style.marginTop=g.config.aspectratio;
 | 
			
		||||
f.style.height="auto";f.style.display="inline-block";t&&("bottom"==t.position?p.style.paddingBottom=t.size+"px":"right"==t.position&&(p.style.marginBottom=-1*t.size*(u/100)+"px"))}j.parentNode.replaceChild(f,j);f.appendChild(j);f.appendChild(p)}f=d.setupPlugins(g,s,m);0<f.length?a.extend(s,n(f.plugins)):delete s.plugins;"undefined"!=typeof s["dock.position"]&&"false"==s["dock.position"].toString().toLowerCase()&&(s.dock=s["dock.position"],delete s["dock.position"]);f=s.wmode?s.wmode:s.height&&40>=
 | 
			
		||||
s.height?"transparent":"opaque";p="height width modes events primary base fallback volume".split(" ");for(t=0;t<p.length;t++)delete s[p[t]];p=a.getCookies();a.foreach(p,function(a,b){"undefined"==typeof s[a]&&(s[a]=b)});p=window.location.href.split("/");p.splice(p.length-1,1);p=p.join("/");s.base=p+"/";e[j.id]=s;a.isIE()?(p='\x3cobject classid\x3d"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" " width\x3d"100%" height\x3d"100%"id\x3d"'+j.id+'" name\x3d"'+j.id+'" tabindex\x3d0""\x3e',p+='\x3cparam name\x3d"movie" value\x3d"'+
 | 
			
		||||
b.src+'"\x3e',p+='\x3cparam name\x3d"allowfullscreen" value\x3d"true"\x3e\x3cparam name\x3d"allowscriptaccess" value\x3d"always"\x3e',p+='\x3cparam name\x3d"seamlesstabbing" value\x3d"true"\x3e',p+='\x3cparam name\x3d"wmode" value\x3d"'+f+'"\x3e',p+='\x3cparam name\x3d"bgcolor" value\x3d"#000000"\x3e',p+="\x3c/object\x3e",j.outerHTML=p,f=document.getElementById(j.id)):(p=document.createElement("object"),p.setAttribute("type","application/x-shockwave-flash"),p.setAttribute("data",b.src),p.setAttribute("width",
 | 
			
		||||
"100%"),p.setAttribute("height","100%"),p.setAttribute("bgcolor","#000000"),p.setAttribute("id",j.id),p.setAttribute("name",j.id),p.setAttribute("tabindex",0),q(p,"allowfullscreen","true"),q(p,"allowscriptaccess","always"),q(p,"seamlesstabbing","true"),q(p,"wmode",f),j.parentNode.replaceChild(p,j),f=p);g.config.aspectratio&&(f.style.position="absolute");g.container=f;g.setPlayer(f,"flash")};this.supportsConfig=function(){if(h)if(c){if("string"==a.typeOf(c.playlist))return!0;try{var b=c.playlist[0].sources;
 | 
			
		||||
if("undefined"==typeof b)return!0;for(var d=0;d<b.length;d++){var g;if(g=b[d].file){var e=b[d].file,f=b[d].type;if(a.isYouTube(e)||a.isRtmp(e,f)||"hls"==f)g=!0;else{var j=a.extensionmap[f?f:a.extension(e)];g=!j?!1:!!j.flash}}if(g)return!0}}catch(k){}}else return!0;return!1}}).getVars=function(a){return e[a]}}(jwplayer),function(f){var a=f.utils,l=a.extensionmap,e=f.events;f.embed.html5=function(j,b,c,d,g){function q(a,b,d){return function(){try{var c=document.querySelector("#"+j.id+" .jwmain");d&&
 | 
			
		||||
c.appendChild(b);"function"==typeof a.resize&&(a.resize(c.clientWidth,c.clientHeight),setTimeout(function(){a.resize(c.clientWidth,c.clientHeight)},400));b.left=c.style.left;b.top=c.style.top}catch(g){}}}function m(a){n.sendEvent(a.type,{message:"HTML5 player not found"})}var n=this,k=new e.eventdispatcher;a.extend(n,k);n.embed=function(){if(f.html5){d.setupPlugins(g,c,q);j.innerHTML="";var h=f.utils.extend({},c);delete h.volume;h=new f.html5.player(h);g.container=document.getElementById(g.id);g.setPlayer(h,
 | 
			
		||||
"html5")}else h=new a.scriptloader(b.src),h.addEventListener(e.ERROR,m),h.addEventListener(e.COMPLETE,n.embed),h.load()};n.supportsConfig=function(){if(f.vid.canPlayType)try{if("string"==a.typeOf(c.playlist))return!0;for(var b=c.playlist[0].sources,d=0;d<b.length;d++){var g;var e=b[d].file,j=b[d].type;if(null!==navigator.userAgent.match(/BlackBerry/i)||a.isAndroid()&&("m3u"==a.extension(e)||"m3u8"==a.extension(e))||a.isRtmp(e,j))g=!1;else{var k=l[j?j:a.extension(e)],m;if(!k||k.flash&&!k.html5)m=!1;
 | 
			
		||||
else{var n=k.html5,q=f.vid;if(n)try{m=q.canPlayType(n)?!0:!1}catch(z){m=!1}else m=!0}g=m}if(g)return!0}}catch(A){}return!1}}}(jwplayer),function(f){var a=f.embed,l=f.utils,e=l.extend(function(e){var b=l.repo(),c=l.extend({},f.defaults),d=l.extend({},c,e.config),g=e.config,q=d.plugins,m=d.analytics,n=b+"jwpsrv.js",k=b+"sharing.js",h=b+"related.js",r=b+"gapro.js",c=f.key?f.key:c.key,p="premium"/*(new f.utils.key(c)).edition()*/,q=q?q:{}; /*alert(c);*/ "ads"==p&&d.advertising&&(d.advertising.client.match(".js$|.swf$")?q[d.advertising.client]=
 | 
			
		||||
d.advertising:q[b+d.advertising.client+".js"]=d.advertising);delete g.advertising;g.key=c;d.analytics&&(d.analytics.client&&d.analytics.client.match(".js$|.swf$"))&&(n=d.analytics.client);delete g.analytics;if("free"==p||!m||!1!==m.enabled)q[n]=m?m:{};delete q.sharing;delete q.related;if("premium"==p||"ads"==p)d.sharing&&(d.sharing.client&&d.sharing.client.match(".js$|.swf$")&&(k=d.sharing.client),q[k]=d.sharing),d.related&&(d.related.client&&d.related.client.match(".js$|.swf$")&&(h=d.related.client),
 | 
			
		||||
q[h]=d.related),d.ga&&(d.ga.client&&d.ga.client.match(".js$|.swf$")&&(r=d.ga.client),q[r]=d.ga),d.skin&&(g.skin=d.skin.replace(/^(beelden|bekle|five|glow|modieus|roundster|stormtrooper|vapor)$/i,l.repo()+"skins/$1.xml"));g.plugins=q;return new a(e)},a);f.embed=e}(jwplayer),function(f){var a=[],l=f.utils,e=f.events,j=e.state,b=document,c=f.api=function(a){function g(a,b){return function(d){return b(a,d)}}function q(a,b){p[a]||(p[a]=[],n(e.JWPLAYER_PLAYER_STATE,function(b){var d=b.newstate;b=b.oldstate;
 | 
			
		||||
if(d==a){var c=p[d];if(c)for(var g=0;g<c.length;g++)"function"==typeof c[g]&&c[g].call(this,{oldstate:b,newstate:d})}}));p[a].push(b);return h}function m(a,b){try{a.jwAddEventListener(b,'function(dat) { jwplayer("'+h.id+'").dispatchEvent("'+b+'", dat); }')}catch(d){l.log("Could not add internal listener")}}function n(a,b){r[a]||(r[a]=[],t&&s&&m(t,a));r[a].push(b);return h}function k(){if(s){for(var a=arguments[0],b=[],d=1;d<arguments.length;d++)b.push(arguments[d]);if("undefined"!=typeof t&&"function"==
 | 
			
		||||
typeof t[a])switch(b.length){case 4:return t[a](b[0],b[1],b[2],b[3]);case 3:return t[a](b[0],b[1],b[2]);case 2:return t[a](b[0],b[1]);case 1:return t[a](b[0]);default:return t[a]()}return null}u.push(arguments)}var h=this,r={},p={},t=void 0,s=!1,u=[],w=void 0,x={},y={};h.container=a;h.id=a.id;h.getBuffer=function(){return k("jwGetBuffer")};h.getContainer=function(){return h.container};h.addButton=function(a,b,d,c){try{y[c]=d,k("jwDockAddButton",a,b,"jwplayer('"+h.id+"').callback('"+c+"')",c)}catch(g){l.log("Could not add dock button"+
 | 
			
		||||
g.message)}};h.removeButton=function(a){k("jwDockRemoveButton",a)};h.callback=function(a){if(y[a])y[a]()};h.forceState=function(a){k("jwForceState",a);return h};h.releaseState=function(){return k("jwReleaseState")};h.getDuration=function(){return k("jwGetDuration")};h.getFullscreen=function(){return k("jwGetFullscreen")};h.getStretching=function(){return k("jwGetStretching")};h.getHeight=function(){return k("jwGetHeight")};h.getLockState=function(){return k("jwGetLockState")};h.getMeta=function(){return h.getItemMeta()};
 | 
			
		||||
h.getMute=function(){return k("jwGetMute")};h.getPlaylist=function(){var a=k("jwGetPlaylist");"flash"==h.renderingMode&&l.deepReplaceKeyName(a,["__dot__","__spc__","__dsh__","__default__"],["."," ","-","default"]);return a};h.getPlaylistItem=function(a){l.exists(a)||(a=h.getCurrentItem());return h.getPlaylist()[a]};h.getPosition=function(){return k("jwGetPosition")};h.getRenderingMode=function(){return h.renderingMode};h.getState=function(){return k("jwGetState")};h.getVolume=function(){return k("jwGetVolume")};
 | 
			
		||||
h.getWidth=function(){return k("jwGetWidth")};h.setFullscreen=function(a){l.exists(a)?k("jwSetFullscreen",a):k("jwSetFullscreen",!k("jwGetFullscreen"));return h};h.setStretching=function(a){k("jwSetStretching",a);return h};h.setMute=function(a){l.exists(a)?k("jwSetMute",a):k("jwSetMute",!k("jwGetMute"));return h};h.lock=function(){return h};h.unlock=function(){return h};h.load=function(a){k("jwLoad",a);return h};h.playlistItem=function(a){k("jwPlaylistItem",parseInt(a));return h};h.playlistPrev=function(){k("jwPlaylistPrev");
 | 
			
		||||
return h};h.playlistNext=function(){k("jwPlaylistNext");return h};h.resize=function(a,d){if("flash"!=h.renderingMode){var c=document.getElementById(h.id);c.className=c.className.replace(/\s+aspectMode/,"");c.style.display="block";k("jwResize",a,d)}else{var c=b.getElementById(h.id+"_wrapper"),g=b.getElementById(h.id+"_aspect");g&&(g.style.display="none");c&&(c.style.display="block",c.style.width=l.styleDimension(a),c.style.height=l.styleDimension(d))}return h};h.play=function(a){"undefined"==typeof a?
 | 
			
		||||
(a=h.getState(),a==j.PLAYING||a==j.BUFFERING?k("jwPause"):k("jwPlay")):k("jwPlay",a);return h};h.pause=function(a){"undefined"==typeof a?(a=h.getState(),a==j.PLAYING||a==j.BUFFERING?k("jwPause"):k("jwPlay")):k("jwPause",a);return h};h.stop=function(){k("jwStop");return h};h.seek=function(a){k("jwSeek",a);return h};h.setVolume=function(a){k("jwSetVolume",a);return h};h.loadInstream=function(a,b){return w=new c.instream(this,t,a,b)};h.getQualityLevels=function(){return k("jwGetQualityLevels")};h.getCurrentQuality=
 | 
			
		||||
function(){return k("jwGetCurrentQuality")};h.setCurrentQuality=function(a){k("jwSetCurrentQuality",a)};h.getCaptionsList=function(){return k("jwGetCaptionsList")};h.getCurrentCaptions=function(){return k("jwGetCurrentCaptions")};h.setCurrentCaptions=function(a){k("jwSetCurrentCaptions",a)};h.getControls=function(){return k("jwGetControls")};h.getSafeRegion=function(){return k("jwGetSafeRegion")};h.setControls=function(a){k("jwSetControls",a)};h.destroyPlayer=function(){k("jwPlayerDestroy")};var z=
 | 
			
		||||
{onBufferChange:e.JWPLAYER_MEDIA_BUFFER,onBufferFull:e.JWPLAYER_MEDIA_BUFFER_FULL,onError:e.JWPLAYER_ERROR,onFullscreen:e.JWPLAYER_FULLSCREEN,onMeta:e.JWPLAYER_MEDIA_META,onMute:e.JWPLAYER_MEDIA_MUTE,onPlaylist:e.JWPLAYER_PLAYLIST_LOADED,onPlaylistItem:e.JWPLAYER_PLAYLIST_ITEM,onPlaylistComplete:e.JWPLAYER_PLAYLIST_COMPLETE,onReady:e.API_READY,onResize:e.JWPLAYER_RESIZE,onComplete:e.JWPLAYER_MEDIA_COMPLETE,onSeek:e.JWPLAYER_MEDIA_SEEK,onTime:e.JWPLAYER_MEDIA_TIME,onVolume:e.JWPLAYER_MEDIA_VOLUME,
 | 
			
		||||
onBeforePlay:e.JWPLAYER_MEDIA_BEFOREPLAY,onBeforeComplete:e.JWPLAYER_MEDIA_BEFORECOMPLETE,onDisplayClick:e.JWPLAYER_DISPLAY_CLICK,onControls:e.JWPLAYER_CONTROLS,onQualityLevels:e.JWPLAYER_MEDIA_LEVELS,onQualityChange:e.JWPLAYER_MEDIA_LEVEL_CHANGED,onCaptionsList:e.JWPLAYER_CAPTIONS_LIST,onCaptionsChange:e.JWPLAYER_CAPTIONS_CHANGED};l.foreach(z,function(a){h[a]=g(z[a],n)});var A={onBuffer:j.BUFFERING,onPause:j.PAUSED,onPlay:j.PLAYING,onIdle:j.IDLE};l.foreach(A,function(a){h[a]=g(A[a],q)});h.remove=
 | 
			
		||||
function(){if(!s)throw"Cannot call remove() before player is ready";u=[];c.destroyPlayer(this.id)};h.setup=function(a){if(f.embed){var d=b.getElementById(h.id);d&&(a.fallbackDiv=d);d=h;u=[];c.destroyPlayer(d.id);d=f(h.id);d.config=a;return new f.embed(d)}return h};h.registerPlugin=function(a,b,d,c){f.plugins.registerPlugin(a,b,d,c)};h.setPlayer=function(a,b){t=a;h.renderingMode=b};h.detachMedia=function(){if("html5"==h.renderingMode)return k("jwDetachMedia")};h.attachMedia=function(a){if("html5"==
 | 
			
		||||
h.renderingMode)return k("jwAttachMedia",a)};h.dispatchEvent=function(a,b){if(r[a])for(var d=l.translateEventResponse(a,b),c=0;c<r[a].length;c++)if("function"==typeof r[a][c])try{a==e.JWPLAYER_PLAYLIST_LOADED&&l.deepReplaceKeyName(d.playlist,["__dot__","__spc__","__dsh__","__default__"],["."," ","-","default"]),r[a][c].call(this,d)}catch(g){l.log("There was an error calling back an event handler")}};h.dispatchInstreamEvent=function(a){w&&w.dispatchEvent(a,arguments)};h.callInternal=k;h.playerReady=
 | 
			
		||||
function(a){s=!0;t||h.setPlayer(b.getElementById(a.id));h.container=b.getElementById(h.id);l.foreach(r,function(a){m(t,a)});n(e.JWPLAYER_PLAYLIST_ITEM,function(){x={}});n(e.JWPLAYER_MEDIA_META,function(a){l.extend(x,a.metadata)});for(h.dispatchEvent(e.API_READY);0<u.length;)k.apply(this,u.shift())};h.getItemMeta=function(){return x};h.getCurrentItem=function(){return k("jwGetPlaylistIndex")};return h};c.selectPlayer=function(d){var g;l.exists(d)||(d=0);d.nodeType?g=d:"string"==typeof d&&(g=b.getElementById(d));
 | 
			
		||||
return g?(d=c.playerById(g.id))?d:c.addPlayer(new c(g)):"number"==typeof d?a[d]:null};c.playerById=function(b){for(var c=0;c<a.length;c++)if(a[c].id==b)return a[c];return null};c.addPlayer=function(b){for(var c=0;c<a.length;c++)if(a[c]==b)return b;a.push(b);return b};c.destroyPlayer=function(d){for(var c=-1,e,f=0;f<a.length;f++)a[f].id==d&&(c=f,e=a[f]);0<=c&&(d=e.id,f=b.getElementById(d+("flash"==e.renderingMode?"_wrapper":"")),l.clearCss&&l.clearCss("#"+d),f&&("html5"==e.renderingMode&&e.destroyPlayer(),
 | 
			
		||||
e=b.createElement("div"),e.id=d,f.parentNode.replaceChild(e,f)),a.splice(c,1));return null};f.playerReady=function(a){var b=f.api.playerById(a.id);b?b.playerReady(a):f.api.selectPlayer(a.id).playerReady(a)}}(jwplayer),function(f){var a=f.events,l=f.utils,e=a.state;f.api.instream=function(f,b,c,d){function g(a,b){k[a]||(k[a]=[],n.jwInstreamAddEventListener(a,'function(dat) { jwplayer("'+m.id+'").dispatchInstreamEvent("'+a+'", dat); }'));k[a].push(b);return this}function q(b,c){h[b]||(h[b]=[],g(a.JWPLAYER_PLAYER_STATE,
 | 
			
		||||
function(a){var c=a.newstate,d=a.oldstate;if(c==b){var e=h[c];if(e)for(var f=0;f<e.length;f++)"function"==typeof e[f]&&e[f].call(this,{oldstate:d,newstate:c,type:a.type})}}));h[b].push(c);return this}var m=f,n=b,k={},h={};this.dispatchEvent=function(a,b){if(k[a])for(var c=l.translateEventResponse(a,b[1]),d=0;d<k[a].length;d++)"function"==typeof k[a][d]&&k[a][d].call(this,c)};this.onError=function(b){return g(a.JWPLAYER_ERROR,b)};this.onFullscreen=function(b){return g(a.JWPLAYER_FULLSCREEN,b)};this.onMeta=
 | 
			
		||||
function(b){return g(a.JWPLAYER_MEDIA_META,b)};this.onMute=function(b){return g(a.JWPLAYER_MEDIA_MUTE,b)};this.onComplete=function(b){return g(a.JWPLAYER_MEDIA_COMPLETE,b)};this.onTime=function(b){return g(a.JWPLAYER_MEDIA_TIME,b)};this.onBuffer=function(a){return q(e.BUFFERING,a)};this.onPause=function(a){return q(e.PAUSED,a)};this.onPlay=function(a){return q(e.PLAYING,a)};this.onIdle=function(a){return q(e.IDLE,a)};this.onClick=function(b){return g(a.JWPLAYER_INSTREAM_CLICK,b)};this.onInstreamDestroyed=
 | 
			
		||||
function(b){return g(a.JWPLAYER_INSTREAM_DESTROYED,b)};this.play=function(a){n.jwInstreamPlay(a)};this.pause=function(a){n.jwInstreamPause(a)};this.destroy=function(){n.jwInstreamDestroy()};m.callInternal("jwLoadInstream",c,d?d:{})}}(jwplayer),function(f){var a=f.api,l=a.selectPlayer;a.selectPlayer=function(a){return(a=l(a))?a:{registerPlugin:function(a,b,c){f.plugins.registerPlugin(a,b,c)}}}}(jwplayer));
 | 
			
		||||
							
								
								
									
										516
									
								
								trunk/research/players/js/srs.js
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										516
									
								
								trunk/research/players/js/srs.js
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,516 @@
 | 
			
		|||
//////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
//////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
//////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
/**
 | 
			
		||||
* padding the output.
 | 
			
		||||
* padding(3, 5, '0') is 00003
 | 
			
		||||
* padding(3, 5, 'x') is xxxx3
 | 
			
		||||
* @see http://blog.csdn.net/win_lin/article/details/12065413
 | 
			
		||||
*/
 | 
			
		||||
function padding(number, length, prefix) {
 | 
			
		||||
    if(String(number).length >= length){
 | 
			
		||||
        return String(number);
 | 
			
		||||
    }
 | 
			
		||||
    return padding(prefix+number, length, prefix);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* update the navigator, add same query string.
 | 
			
		||||
*/
 | 
			
		||||
function update_nav() {
 | 
			
		||||
    $("#nav_srs_player").attr("href", "srs_player.html" + window.location.search);
 | 
			
		||||
    $("#nav_srs_publisher").attr("href", "srs_publisher.html" + window.location.search);
 | 
			
		||||
    $("#nav_srs_bwt").attr("href", "srs_bwt.html" + window.location.search);
 | 
			
		||||
    $("#nav_jwplayer6").attr("href", "jwplayer6.html" + window.location.search);
 | 
			
		||||
    $("#nav_osmf").attr("href", "osmf.html" + window.location.search);
 | 
			
		||||
    $("#nav_vlc").attr("href", "vlc.html" + window.location.search);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* parse the query string to object.
 | 
			
		||||
*/
 | 
			
		||||
function parse_query_string(){
 | 
			
		||||
    var obj = {};
 | 
			
		||||
    
 | 
			
		||||
    // parse the host(hostname:http_port), pathname(dir/filename)
 | 
			
		||||
    obj.host = window.location.host;
 | 
			
		||||
    obj.hostname = window.location.hostname;
 | 
			
		||||
    obj.http_port = (window.location.port == "")? 80:window.location.port;
 | 
			
		||||
    obj.pathname = window.location.pathname;
 | 
			
		||||
    if (obj.pathname.lastIndexOf("/") <= 0) {
 | 
			
		||||
        obj.dir = "/";
 | 
			
		||||
        obj.filename = "";
 | 
			
		||||
    } else {
 | 
			
		||||
        obj.dir = obj.pathname.substr(0, obj.pathname.lastIndexOf("/"));
 | 
			
		||||
        obj.filename = obj.pathname.substr(obj.pathname.lastIndexOf("/"));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // parse the query string.
 | 
			
		||||
    var query_string = String(window.location.search).replace(" ", "").split("?")[1];
 | 
			
		||||
    if(query_string == undefined){
 | 
			
		||||
        return obj;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    var queries = query_string.split("&");
 | 
			
		||||
    $(queries).each(function(){
 | 
			
		||||
        var query = this.split("=");
 | 
			
		||||
        obj[query[0]] = query[1];
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    return obj;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@param server the ip of server. default to window.location.hostname
 | 
			
		||||
@param vhost the vhost of rtmp. default to window.location.hostname
 | 
			
		||||
@param port the port of rtmp. default to 1935
 | 
			
		||||
@param app the app of rtmp. default to live.
 | 
			
		||||
@param stream the stream of rtmp. default to livestream.
 | 
			
		||||
*/
 | 
			
		||||
function build_default_rtmp_url() {
 | 
			
		||||
    var query = parse_query_string();
 | 
			
		||||
 | 
			
		||||
    var server = (query.server == undefined)? window.location.hostname:query.server;
 | 
			
		||||
    var port = (query.port == undefined)? 1935:query.port;
 | 
			
		||||
    var vhost = (query.vhost == undefined)? window.location.hostname:query.vhost;
 | 
			
		||||
    var app = (query.app == undefined)? "live":query.app;
 | 
			
		||||
    var stream = (query.stream == undefined)? "livestream":query.stream;
 | 
			
		||||
 | 
			
		||||
    if (server == vhost || vhost == "") {
 | 
			
		||||
        return "rtmp://" + server + ":" + port + "/" + app + "/" + stream;
 | 
			
		||||
    } else {
 | 
			
		||||
        return "rtmp://" + server + ":" + port + "/" + app + "...vhost..." + vhost + "/" + stream;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@param server the ip of server. default to window.location.hostname
 | 
			
		||||
@param vhost the vhost of hls. default to window.location.hostname
 | 
			
		||||
@param hls_vhost the vhost of hls. override the server if specified.
 | 
			
		||||
@param hls_port the port of hls. default to window.location.port
 | 
			
		||||
@param app the app of hls. default to live.
 | 
			
		||||
@param stream the stream of hls. default to livestream.
 | 
			
		||||
*/
 | 
			
		||||
function build_default_hls_url() {
 | 
			
		||||
    var query = parse_query_string();
 | 
			
		||||
 | 
			
		||||
    // for http, use hls_vhost to override server if specified.
 | 
			
		||||
    var server = window.location.hostname;
 | 
			
		||||
    if (query.server != undefined) {
 | 
			
		||||
        server = query.server;
 | 
			
		||||
    } else if (query.hls_vhost != undefined) {
 | 
			
		||||
        server = query.hls_vhost;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    var port = (query.hls_port == undefined)? window.location.port:query.hls_port;
 | 
			
		||||
    var app = (query.app == undefined)? "live":query.app;
 | 
			
		||||
    var stream = (query.stream == undefined)? "livestream":query.stream;
 | 
			
		||||
 | 
			
		||||
    if (port == "" || port == null || port == undefined) {
 | 
			
		||||
        port = 80;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return "http://" + server + ":" + port + "/" + app + "/" + stream + ".m3u8";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* parse the rtmp url,
 | 
			
		||||
* for example: rtmp://demo.srs.com:1935/live...vhost...players/livestream
 | 
			
		||||
* @return object {server, port, vhost, app, stream}
 | 
			
		||||
*/
 | 
			
		||||
function srs_parse_rtmp_url(rtmp_url) {
 | 
			
		||||
    // @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri
 | 
			
		||||
    var a = document.createElement("a");
 | 
			
		||||
    a.href = rtmp_url.replace("rtmp://", "http://");
 | 
			
		||||
    
 | 
			
		||||
    var vhost = a.hostname;
 | 
			
		||||
    var port = (a.port == "")? "1935":a.port;
 | 
			
		||||
    var app = a.pathname.substr(1, a.pathname.lastIndexOf("/") - 1);
 | 
			
		||||
    var stream = a.pathname.substr(a.pathname.lastIndexOf("/") + 1);
 | 
			
		||||
 | 
			
		||||
    // parse the vhost in the params of app, that srs supports.
 | 
			
		||||
    app = app.replace("...vhost...", "?vhost=");
 | 
			
		||||
    if (app.indexOf("?") >= 0) {
 | 
			
		||||
        var params = app.substr(app.indexOf("?"));
 | 
			
		||||
        app = app.substr(0, app.indexOf("?"));
 | 
			
		||||
        
 | 
			
		||||
        if (params.indexOf("vhost=") > 0) {
 | 
			
		||||
            vhost = params.substr(params.indexOf("vhost=") + "vhost=".length);
 | 
			
		||||
            if (vhost.indexOf("&") > 0) {
 | 
			
		||||
                vhost = vhost.substr(0, vhost.indexOf("&"));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    var ret = {
 | 
			
		||||
        server: a.hostname, port: port, 
 | 
			
		||||
        vhost: vhost, app: app, stream: stream
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* player specified size.
 | 
			
		||||
*/
 | 
			
		||||
function srs_get_player_modal() { return 740; }
 | 
			
		||||
function srs_get_player_width() { return srs_get_player_modal() - 30; }
 | 
			
		||||
function srs_get_player_height() { return srs_get_player_width() * 9 / 19; }
 | 
			
		||||
 | 
			
		||||
// to query the swf anti cache.
 | 
			
		||||
function srs_get_version_code() { return "1.5"; }
 | 
			
		||||
// get the default vhost for players.
 | 
			
		||||
function srs_get_player_vhost() { return "players"; }
 | 
			
		||||
// get the stream published to vhost,
 | 
			
		||||
// generally we need to transcode the stream to support HLS and filters.
 | 
			
		||||
// for example, src_vhost is "players", we transcode stream to vhost "players_pub".
 | 
			
		||||
// if not equals to the player vhost, return the orignal vhost.
 | 
			
		||||
function srs_get_player_publish_vhost(src_vhost) { return (src_vhost != srs_get_player_vhost())? src_vhost:(src_vhost + "_pub"); }
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* initialize the page.
 | 
			
		||||
* @param rtmp_url the div id contains the rtmp stream url to play
 | 
			
		||||
* @param hls_url the div id contains the hls stream url to play
 | 
			
		||||
* @param modal_player the div id contains the modal player
 | 
			
		||||
*/
 | 
			
		||||
function srs_init(rtmp_url, hls_url, modal_player) {
 | 
			
		||||
    update_nav();
 | 
			
		||||
    
 | 
			
		||||
    if (rtmp_url) {
 | 
			
		||||
        $(rtmp_url).val(build_default_rtmp_url());
 | 
			
		||||
    }
 | 
			
		||||
    if (hls_url) {
 | 
			
		||||
        $(hls_url).val(build_default_hls_url());
 | 
			
		||||
    }
 | 
			
		||||
    if (modal_player) {
 | 
			
		||||
        $(modal_player).width(srs_get_player_modal() + "px");
 | 
			
		||||
        $(modal_player).css("margin-left", "-" + srs_get_player_modal() / 2 +"px");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
//////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
//////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
/**
 | 
			
		||||
* the SrsPlayer object.
 | 
			
		||||
* @param container the html container id.
 | 
			
		||||
* @param width a float value specifies the width of player.
 | 
			
		||||
* @param height a float value specifies the height of player.
 | 
			
		||||
*/
 | 
			
		||||
function SrsPlayer(container, width, height) {
 | 
			
		||||
    if (!SrsPlayer.__id) {
 | 
			
		||||
        SrsPlayer.__id = 100;
 | 
			
		||||
    }
 | 
			
		||||
    if (!SrsPlayer.__players) {
 | 
			
		||||
        SrsPlayer.__players = [];
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    SrsPlayer.__players.push(this);
 | 
			
		||||
    
 | 
			
		||||
    this.container = container;
 | 
			
		||||
    this.width = width;
 | 
			
		||||
    this.height = height;
 | 
			
		||||
    this.id = SrsPlayer.__id++;
 | 
			
		||||
    this.stream_url = null;
 | 
			
		||||
    this.buffer_time = 0.8; // default to 0.8
 | 
			
		||||
    this.callbackObj = null;
 | 
			
		||||
    
 | 
			
		||||
    // callback set the following values.
 | 
			
		||||
    this.meatadata = {}; // for on_player_metadata
 | 
			
		||||
    this.time = 0; // current stream time.
 | 
			
		||||
    this.buffer_length = 0; // current stream buffer length.
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
* user can set some callback, then start the player.
 | 
			
		||||
* callbacks:
 | 
			
		||||
*      on_player_ready():int, when srs player ready, user can play.
 | 
			
		||||
*      on_player_metadata(metadata:Object):int, when srs player get metadata.
 | 
			
		||||
*/
 | 
			
		||||
SrsPlayer.prototype.start = function() {
 | 
			
		||||
    // embed the flash.
 | 
			
		||||
    var flashvars = {};
 | 
			
		||||
    flashvars.id = this.id;
 | 
			
		||||
    flashvars.on_player_ready = "__srs_on_player_ready";
 | 
			
		||||
    flashvars.on_player_metadata = "__srs_on_player_metadata";
 | 
			
		||||
    flashvars.on_player_timer = "__srs_on_player_timer";
 | 
			
		||||
    
 | 
			
		||||
    var params = {};
 | 
			
		||||
    params.wmode = "opaque";
 | 
			
		||||
    params.allowFullScreen = "true";
 | 
			
		||||
    params.allowScriptAccess = "always";
 | 
			
		||||
    
 | 
			
		||||
    var attributes = {};
 | 
			
		||||
    
 | 
			
		||||
    var self = this;
 | 
			
		||||
    
 | 
			
		||||
    swfobject.embedSWF(
 | 
			
		||||
        "srs_player/release/srs_player.swf?_version="+srs_get_version_code(), 
 | 
			
		||||
        this.container,
 | 
			
		||||
        this.width, this.height,
 | 
			
		||||
        "11.1", "js/AdobeFlashPlayerInstall.swf",
 | 
			
		||||
        flashvars, params, attributes,
 | 
			
		||||
        function(callbackObj){
 | 
			
		||||
            self.callbackObj = callbackObj;
 | 
			
		||||
        }
 | 
			
		||||
    );
 | 
			
		||||
    
 | 
			
		||||
    return this;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
* play the stream.
 | 
			
		||||
* @param stream_url the url of stream, rtmp or http.
 | 
			
		||||
*/
 | 
			
		||||
SrsPlayer.prototype.play = function(url) {
 | 
			
		||||
    this.stream_url = url;
 | 
			
		||||
    this.callbackObj.ref.__play(this.stream_url, this.width, this.height, this.buffer_time);
 | 
			
		||||
}
 | 
			
		||||
SrsPlayer.prototype.stop = function() {
 | 
			
		||||
    for (var i = 0; i < SrsPlayer.__players.length; i++) {
 | 
			
		||||
        var player = SrsPlayer.__players[i];
 | 
			
		||||
        
 | 
			
		||||
        if (player.id != this.id) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        SrsPlayer.__players.splice(i, 1);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    this.callbackObj.ref.__stop();
 | 
			
		||||
}
 | 
			
		||||
SrsPlayer.prototype.pause = function() {
 | 
			
		||||
    this.callbackObj.ref.__pause();
 | 
			
		||||
}
 | 
			
		||||
SrsPlayer.prototype.resume = function() {
 | 
			
		||||
    this.callbackObj.ref.__resume();
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
* to set the DAR, for example, DAR=16:9
 | 
			
		||||
* @param num, for example, 9. 
 | 
			
		||||
*       use metadata height if 0.
 | 
			
		||||
*       use user specified height if -1.
 | 
			
		||||
* @param den, for example, 16. 
 | 
			
		||||
*       use metadata width if 0.
 | 
			
		||||
*       use user specified width if -1.
 | 
			
		||||
*/
 | 
			
		||||
SrsPlayer.prototype.dar = function(num, den) {
 | 
			
		||||
    this.callbackObj.ref.__dar(num, den);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
* set the fullscreen size data.
 | 
			
		||||
* @refer the refer fullscreen mode. it can be:
 | 
			
		||||
*       video: use video orignal size.
 | 
			
		||||
*       screen: use screen size to rescale video.
 | 
			
		||||
* @param percent, the rescale percent, where
 | 
			
		||||
*       100 means 100%.
 | 
			
		||||
*/
 | 
			
		||||
SrsPlayer.prototype.set_fs = function(refer, percent) {
 | 
			
		||||
    this.callbackObj.ref.__set_fs(refer, percent);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
* set the stream buffer time in seconds.
 | 
			
		||||
* @buffer_time the buffer time in seconds.
 | 
			
		||||
*/
 | 
			
		||||
SrsPlayer.prototype.set_bt = function(buffer_time) {
 | 
			
		||||
    this.buffer_time = buffer_time;
 | 
			
		||||
    this.callbackObj.ref.__set_bt(buffer_time);
 | 
			
		||||
}
 | 
			
		||||
SrsPlayer.prototype.on_player_ready = function() {
 | 
			
		||||
}
 | 
			
		||||
SrsPlayer.prototype.on_player_metadata = function(metadata) {
 | 
			
		||||
    // ignore.
 | 
			
		||||
}
 | 
			
		||||
SrsPlayer.prototype.on_player_timer = function(time, buffer_length) {
 | 
			
		||||
    // ignore.
 | 
			
		||||
}
 | 
			
		||||
function __srs_find_player(id) {
 | 
			
		||||
    for (var i = 0; i < SrsPlayer.__players.length; i++) {
 | 
			
		||||
        var player = SrsPlayer.__players[i];
 | 
			
		||||
        
 | 
			
		||||
        if (player.id != id) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return player;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    throw new Error("player not found. id=" + id);
 | 
			
		||||
}
 | 
			
		||||
function __srs_on_player_ready(id) {
 | 
			
		||||
    var player = __srs_find_player(id);
 | 
			
		||||
    player.on_player_ready();
 | 
			
		||||
}
 | 
			
		||||
function __srs_on_player_metadata(id, metadata) {
 | 
			
		||||
    var player = __srs_find_player(id);
 | 
			
		||||
    
 | 
			
		||||
    // user may override the on_player_metadata, 
 | 
			
		||||
    // so set the data before invoke it.
 | 
			
		||||
    player.metadata = metadata;
 | 
			
		||||
    
 | 
			
		||||
    player.on_player_metadata(metadata);
 | 
			
		||||
}
 | 
			
		||||
function __srs_on_player_timer(id, time, buffer_length) {
 | 
			
		||||
    var player = __srs_find_player(id);
 | 
			
		||||
    
 | 
			
		||||
    buffer_length = Math.max(0, buffer_length);
 | 
			
		||||
    buffer_length = Math.min(player.buffer_time, buffer_length);
 | 
			
		||||
    
 | 
			
		||||
    time = Math.max(0, time);
 | 
			
		||||
    
 | 
			
		||||
    // user may override the on_player_timer, 
 | 
			
		||||
    // so set the data before invoke it.
 | 
			
		||||
    player.time = time;
 | 
			
		||||
    player.buffer_length = buffer_length;
 | 
			
		||||
    
 | 
			
		||||
    player.on_player_timer(time, buffer_length);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
//////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
//////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
/**
 | 
			
		||||
* the SrsPublisher object.
 | 
			
		||||
* @param container the html container id.
 | 
			
		||||
* @param width a float value specifies the width of publisher.
 | 
			
		||||
* @param height a float value specifies the height of publisher.
 | 
			
		||||
*/
 | 
			
		||||
function SrsPublisher(container, width, height) {
 | 
			
		||||
    if (!SrsPublisher.__id) {
 | 
			
		||||
        SrsPublisher.__id = 100;
 | 
			
		||||
    }
 | 
			
		||||
    if (!SrsPublisher.__publishers) {
 | 
			
		||||
        SrsPublisher.__publishers = [];
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    SrsPublisher.__publishers.push(this);
 | 
			
		||||
    
 | 
			
		||||
    this.container = container;
 | 
			
		||||
    this.width = width;
 | 
			
		||||
    this.height = height;
 | 
			
		||||
    this.id = SrsPublisher.__id++;
 | 
			
		||||
    this.callbackObj = null;
 | 
			
		||||
    
 | 
			
		||||
    // set the values when publish.
 | 
			
		||||
    this.url = null;
 | 
			
		||||
    this.vcodec = {};
 | 
			
		||||
    this.acodec = {};
 | 
			
		||||
    
 | 
			
		||||
    // callback set the following values.
 | 
			
		||||
    this.cameras = [];
 | 
			
		||||
    this.microphones = [];
 | 
			
		||||
    this.code = 0;
 | 
			
		||||
    
 | 
			
		||||
    // error code defines.
 | 
			
		||||
    this.errors = {
 | 
			
		||||
        "100": "无法获取指定的摄像头", //error_camera_get 
 | 
			
		||||
        "101": "无法获取指定的麦克风", //error_microphone_get 
 | 
			
		||||
        "102": "摄像头为禁用状态,推流时请允许flash访问摄像头", //error_camera_muted 
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
* user can set some callback, then start the publisher.
 | 
			
		||||
* callbacks:
 | 
			
		||||
*      on_publisher_ready(cameras, microphones):int, when srs publisher ready, user can publish.
 | 
			
		||||
*      on_publisher_error(code, desc):int, when srs publisher error, callback this method.
 | 
			
		||||
*      on_publisher_warn(code, desc):int, when srs publisher warn, callback this method.
 | 
			
		||||
*/
 | 
			
		||||
SrsPublisher.prototype.start = function() {
 | 
			
		||||
    // embed the flash.
 | 
			
		||||
    var flashvars = {};
 | 
			
		||||
    flashvars.id = this.id;
 | 
			
		||||
    flashvars.on_publisher_ready = "__srs_on_publisher_ready";
 | 
			
		||||
    flashvars.on_publisher_error = "__srs_on_publisher_error";
 | 
			
		||||
    flashvars.on_publisher_warn = "__srs_on_publisher_warn";
 | 
			
		||||
    
 | 
			
		||||
    var params = {};
 | 
			
		||||
    params.wmode = "opaque";
 | 
			
		||||
    params.allowFullScreen = "true";
 | 
			
		||||
    params.allowScriptAccess = "always";
 | 
			
		||||
    
 | 
			
		||||
    var attributes = {};
 | 
			
		||||
    
 | 
			
		||||
    var self = this;
 | 
			
		||||
    
 | 
			
		||||
    swfobject.embedSWF(
 | 
			
		||||
        "srs_publisher/release/srs_publisher.swf?_version="+srs_get_version_code(), 
 | 
			
		||||
        this.container,
 | 
			
		||||
        this.width, this.height,
 | 
			
		||||
        "11.1", "js/AdobeFlashPlayerInstall.swf",
 | 
			
		||||
        flashvars, params, attributes,
 | 
			
		||||
        function(callbackObj){
 | 
			
		||||
            self.callbackObj = callbackObj;
 | 
			
		||||
        }
 | 
			
		||||
    );
 | 
			
		||||
    
 | 
			
		||||
    return this;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
* publish stream to server.
 | 
			
		||||
* @param url a string indicates the rtmp url to publish.
 | 
			
		||||
* @param vcodec an object contains the video codec info.
 | 
			
		||||
* @param acodec an object contains the audio codec info.
 | 
			
		||||
*/
 | 
			
		||||
SrsPublisher.prototype.publish = function(url, vcodec, acodec) {
 | 
			
		||||
    this.url = url;
 | 
			
		||||
    this.vcodec = vcodec;
 | 
			
		||||
    this.acodec = acodec;
 | 
			
		||||
    
 | 
			
		||||
    this.callbackObj.ref.__publish(url, this.width, this.height, vcodec, acodec);
 | 
			
		||||
}
 | 
			
		||||
SrsPublisher.prototype.stop = function() {
 | 
			
		||||
    this.callbackObj.ref.__stop();
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
* when publisher ready.
 | 
			
		||||
* @param cameras a string array contains the names of cameras.
 | 
			
		||||
* @param microphones a string array contains the names of microphones.
 | 
			
		||||
*/
 | 
			
		||||
SrsPublisher.prototype.on_publisher_ready = function(cameras, microphones) {
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
* when publisher error.
 | 
			
		||||
* @code the error code.
 | 
			
		||||
* @desc the error desc message.
 | 
			
		||||
*/
 | 
			
		||||
SrsPublisher.prototype.on_publisher_error = function(code, desc) {
 | 
			
		||||
    throw new Error("publisher error. code=" + code + ", desc=" + desc);
 | 
			
		||||
}
 | 
			
		||||
SrsPublisher.prototype.on_publisher_warn = function(code, desc) {
 | 
			
		||||
    throw new Error("publisher warn. code=" + code + ", desc=" + desc);
 | 
			
		||||
}
 | 
			
		||||
function __srs_find_publisher(id) {
 | 
			
		||||
    for (var i = 0; i < SrsPublisher.__publishers.length; i++) {
 | 
			
		||||
        var publisher = SrsPublisher.__publishers[i];
 | 
			
		||||
        
 | 
			
		||||
        if (publisher.id != id) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return publisher;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    throw new Error("publisher not found. id=" + id);
 | 
			
		||||
}
 | 
			
		||||
function __srs_on_publisher_ready(id, cameras, microphones) {
 | 
			
		||||
    var publisher = __srs_find_publisher(id);
 | 
			
		||||
    
 | 
			
		||||
    publisher.cameras = cameras;
 | 
			
		||||
    publisher.microphones = microphones;
 | 
			
		||||
    
 | 
			
		||||
    publisher.on_publisher_ready(cameras, microphones);
 | 
			
		||||
}
 | 
			
		||||
function __srs_on_publisher_error(id, code) {
 | 
			
		||||
    var publisher = __srs_find_publisher(id);
 | 
			
		||||
    
 | 
			
		||||
    publisher.code = code;
 | 
			
		||||
    
 | 
			
		||||
    publisher.on_publisher_error(code, publisher.errors[""+code]);
 | 
			
		||||
}
 | 
			
		||||
function __srs_on_publisher_warn(id, code) {
 | 
			
		||||
    var publisher = __srs_find_publisher(id);
 | 
			
		||||
    
 | 
			
		||||
    publisher.code = code;
 | 
			
		||||
    
 | 
			
		||||
    publisher.on_publisher_warn(code, publisher.errors[""+code]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,50 +0,0 @@
 | 
			
		|||
<head>
 | 
			
		||||
    <title>JWPlayer5</title>
 | 
			
		||||
    <meta http-equiv=Content-Type content="text/html;charset=utf-8">
 | 
			
		||||
    <style>
 | 
			
		||||
    body{margin:0; padding:0; color:#EEEEEE;}
 | 
			
		||||
    input.url{width:400px; height:20px;}
 | 
			
		||||
    input.size{width:40px; height:20px;}
 | 
			
		||||
    input.buffer{width:20px; height:20px;}
 | 
			
		||||
    input.play{width:60px; height: 25px;}
 | 
			
		||||
    select.type{width:50px; }
 | 
			
		||||
    span.size{padding-left:10px; padding-right:10px;}
 | 
			
		||||
    div.main{font-size:12px; padding:5px 10px 0px 5px; background-color:#333333; width: 780px;}
 | 
			
		||||
    div.player{padding-top:3px; padding-bottom:10px;}
 | 
			
		||||
    div.control{padding-bottom:10px; background-color:#333333; margin-top:5px;}
 | 
			
		||||
    </style>
 | 
			
		||||
</head>
 | 
			
		||||
<div class="main">
 | 
			
		||||
    <div id="player"></div>
 | 
			
		||||
    <div class="control" id="control">
 | 
			
		||||
        Url(RTMP/HTTP): <input id="url" type="text" class="url" value="rtmp://demo:1935/live/livestream"></input>
 | 
			
		||||
        <input type="button" class="play" value="Play" onclick="play()"></input>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
<script type="text/javascript" src="jwplayer.js" ></script>
 | 
			
		||||
<script>jwplayer.key="L1P3Ig76mGOK94gZ9WAAGD+Fb1VCVhoZ/Dm0fg=="</script>
 | 
			
		||||
<script type='text/javascript'>
 | 
			
		||||
    function play(){
 | 
			
		||||
        var player = document.getElementById("player");
 | 
			
		||||
        player.innerHTML = "";
 | 
			
		||||
        
 | 
			
		||||
        var div = document.createElement("div");
 | 
			
		||||
        div.id = "player_div";
 | 
			
		||||
        player.appendChild(div);
 | 
			
		||||
        
 | 
			
		||||
        var url = document.getElementById("url").value;
 | 
			
		||||
        var provider = (url.indexOf("rtmp://") == 0) ? "rtmp":"http";
 | 
			
		||||
        var conf = {
 | 
			
		||||
            file: url.substr(url.lastIndexOf("/") + 1),
 | 
			
		||||
            streamer: url.substr(0, url.lastIndexOf("/")),
 | 
			
		||||
            provider: 'rtmp',
 | 
			
		||||
            width: "720",
 | 
			
		||||
            height: "576",
 | 
			
		||||
            autostart: true,
 | 
			
		||||
        };
 | 
			
		||||
        //console.log(conf);
 | 
			
		||||
        jwplayer('player_div').setup(conf);
 | 
			
		||||
    }
 | 
			
		||||
    play();
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										128
									
								
								trunk/research/players/jwplayer6.html
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										128
									
								
								trunk/research/players/jwplayer6.html
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,128 @@
 | 
			
		|||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
    <title>SRS</title>   
 | 
			
		||||
    <meta charset="utf-8">
 | 
			
		||||
    <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
 | 
			
		||||
    <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/bootstrap.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/srs.js"></script>
 | 
			
		||||
    <style>
 | 
			
		||||
        body{
 | 
			
		||||
            padding-top: 55px;
 | 
			
		||||
        }
 | 
			
		||||
        #main_modal {
 | 
			
		||||
            width: 700px;
 | 
			
		||||
            margin-left: -350px;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
    <script type="text/javascript" src="js/jwplayer.js" ></script>
 | 
			
		||||
    <script type='text/javascript'>jwplayer.key = 'N8zhkmYvvRwOhz4aTGkySoEri4x+9pQwR7GHIQ=='; </script>
 | 
			
		||||
    <script type="text/javascript">
 | 
			
		||||
        var _player = null;
 | 
			
		||||
        var _url = null;
 | 
			
		||||
        $(function(){
 | 
			
		||||
            // get the vhost and port to set the default url.
 | 
			
		||||
            // for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo
 | 
			
		||||
            // url set to: rtmp://demo:1935/live/livestream
 | 
			
		||||
            srs_init("#txt_rtmp_url", "#txt_hls_url", "#main_modal");
 | 
			
		||||
            
 | 
			
		||||
            $("#main_modal").on("hide", function(){
 | 
			
		||||
                $("#div_container").remove();
 | 
			
		||||
                _player.stop();
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            $("#main_modal").on("show", function(){
 | 
			
		||||
                $("#div_container").remove();
 | 
			
		||||
                
 | 
			
		||||
                var div_container = $("<div/>");
 | 
			
		||||
                $(div_container).attr("id", "div_container");
 | 
			
		||||
                $("#player").append(div_container);
 | 
			
		||||
                
 | 
			
		||||
                var player = $("<div/>");
 | 
			
		||||
                $(player).attr("id", "player_id");
 | 
			
		||||
                $(div_container).append(player);
 | 
			
		||||
                
 | 
			
		||||
                var conf = {
 | 
			
		||||
                    file: _url,
 | 
			
		||||
                    width: srs_get_player_width(),
 | 
			
		||||
                    height: srs_get_player_height(),
 | 
			
		||||
                    autostart: true,
 | 
			
		||||
                    analytics: { enabled: false}
 | 
			
		||||
                };
 | 
			
		||||
                _player = jwplayer('player_id').setup(conf);
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            $("#btn_play_rtmp").click(function(){
 | 
			
		||||
                _url = $("#txt_rtmp_url").val();
 | 
			
		||||
                $("#main_modal").modal({show:true, keyboard:false});
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            $("#btn_play_hls").click(function(){
 | 
			
		||||
                _url = $("#txt_hls_url").val();
 | 
			
		||||
                $("#main_modal").modal({show:true, keyboard:false});
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            var query = parse_query_string();
 | 
			
		||||
            if (query.hls_autostart == "true") {
 | 
			
		||||
                _url = $("#txt_hls_url").val();
 | 
			
		||||
                $("#main_modal").modal({show:true, keyboard:false});
 | 
			
		||||
            } else if (query.rtmp_autostart == "true") {
 | 
			
		||||
                _url = $("#txt_rtmp_url").val();
 | 
			
		||||
                $("#main_modal").modal({show:true, keyboard:false});
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    </script>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<div class="navbar navbar-fixed-top">
 | 
			
		||||
    <div class="navbar-inner">
 | 
			
		||||
        <div class="container">
 | 
			
		||||
        <a class="brand" href="index.html">SRS</a>
 | 
			
		||||
            <div class="nav-collapse collapse">
 | 
			
		||||
                <ul class="nav">
 | 
			
		||||
                    <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
 | 
			
		||||
                    <li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
 | 
			
		||||
                    <li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
 | 
			
		||||
                    <li class="active"><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>
 | 
			
		||||
                    <li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>
 | 
			
		||||
                    <li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
<div class="container">
 | 
			
		||||
    <div class="alert alert-info fade in">
 | 
			
		||||
        <button type="button" class="close" data-dismiss="alert">×</button>
 | 
			
		||||
        <strong><span>Usage:</span></strong> <span>输入地址后点击播放按钮</span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="form-inline">
 | 
			
		||||
        URL:
 | 
			
		||||
        <input type="text" id="txt_rtmp_url" class="input-xxlarge" value=""></input>
 | 
			
		||||
        <button class="btn btn-primary" id="btn_play_rtmp">播放RTMP</button>
 | 
			
		||||
    </div>
 | 
			
		||||
    <hr/>
 | 
			
		||||
    <div class="form-inline">
 | 
			
		||||
        URL:
 | 
			
		||||
        <input type="text" id="txt_hls_url" class="input-xxlarge" value=""></input>
 | 
			
		||||
        <button class="btn btn-primary" id="btn_play_hls"> 播放HLS </button>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div id="main_modal" class="modal hide fade">
 | 
			
		||||
        <div class="modal-header">
 | 
			
		||||
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
 | 
			
		||||
            <h3>JWPlayer6</h3>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="modal-body" id="player">
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="modal-footer">
 | 
			
		||||
            <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true"> 关闭 </button>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <hr>
 | 
			
		||||
    <footer>
 | 
			
		||||
        <p><a href="https://github.com/winlinvip/simple-rtmp-server">SRS Team © 2013</a></p>
 | 
			
		||||
    </footer>
 | 
			
		||||
</div>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,47 +0,0 @@
 | 
			
		|||
<head>
 | 
			
		||||
    <title>JWPlayer6</title>
 | 
			
		||||
    <meta http-equiv=Content-Type content="text/html;charset=utf-8">
 | 
			
		||||
    <style>
 | 
			
		||||
    body{margin:0; padding:0; color:#EEEEEE;}
 | 
			
		||||
    input.url{width:400px; height:20px;}
 | 
			
		||||
    input.size{width:40px; height:20px;}
 | 
			
		||||
    input.buffer{width:20px; height:20px;}
 | 
			
		||||
    input.play{width:60px; height: 25px;}
 | 
			
		||||
    select.type{width:50px; }
 | 
			
		||||
    span.size{padding-left:10px; padding-right:10px;}
 | 
			
		||||
    div.main{font-size:12px; padding:5px 10px 0px 5px; background-color:#333333; width: 780px;}
 | 
			
		||||
    div.player{padding-top:3px; padding-bottom:10px;}
 | 
			
		||||
    div.control{padding-bottom:10px; background-color:#333333; margin-top:5px;}
 | 
			
		||||
    </style>
 | 
			
		||||
</head>
 | 
			
		||||
<div class="main">
 | 
			
		||||
    <div id="player"></div>
 | 
			
		||||
    <div class="control" id="control">
 | 
			
		||||
        Url(RTMP/HTTP): <input id="url" type="text" class="url" value="rtmp://demo:1935/live/livestream"></input>
 | 
			
		||||
        <input type="button" class="play" value="Play" onclick="play()"></input>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
<script type="text/javascript" src="jwplayer.js" ></script>
 | 
			
		||||
<script>jwplayer.key="L1P3Ig76mGOK94gZ9WAAGD+Fb1VCVhoZ/Dm0fg=="</script>
 | 
			
		||||
<script type='text/javascript'>
 | 
			
		||||
    function play(){
 | 
			
		||||
        var player = document.getElementById("player");
 | 
			
		||||
        player.innerHTML = "";
 | 
			
		||||
        
 | 
			
		||||
        var div = document.createElement("div");
 | 
			
		||||
        div.id = "player_div";
 | 
			
		||||
        player.appendChild(div);
 | 
			
		||||
        
 | 
			
		||||
        var url = document.getElementById("url").value;
 | 
			
		||||
        var conf = {
 | 
			
		||||
            file: url,
 | 
			
		||||
            width: "720",
 | 
			
		||||
            height: "576",
 | 
			
		||||
            autostart: true,
 | 
			
		||||
        };
 | 
			
		||||
        //console.log(conf);
 | 
			
		||||
        jwplayer('player_div').setup(conf);
 | 
			
		||||
    }
 | 
			
		||||
    play();
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										117
									
								
								trunk/research/players/osmf.html
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										117
									
								
								trunk/research/players/osmf.html
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,117 @@
 | 
			
		|||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
    <title>SRS</title>   
 | 
			
		||||
    <meta charset="utf-8">
 | 
			
		||||
    <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
 | 
			
		||||
    <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/bootstrap.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/swfobject.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/srs.js"></script>
 | 
			
		||||
    <style>
 | 
			
		||||
        body{
 | 
			
		||||
            padding-top: 55px;
 | 
			
		||||
        }
 | 
			
		||||
        #main_modal {
 | 
			
		||||
            width: 700px;
 | 
			
		||||
            margin-left: -350px;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
    <script type="text/javascript">
 | 
			
		||||
        function osmf_play(url) {
 | 
			
		||||
            $("#div_container").remove();
 | 
			
		||||
            
 | 
			
		||||
            var div_container = $("<div/>");
 | 
			
		||||
            $(div_container).attr("id", "div_container");
 | 
			
		||||
            $("#player").append(div_container);
 | 
			
		||||
            
 | 
			
		||||
            var player = $("<div/>");
 | 
			
		||||
            $(player).attr("id", "player_id");
 | 
			
		||||
            $(div_container).append(player);
 | 
			
		||||
            
 | 
			
		||||
            var flashvars = {};
 | 
			
		||||
            flashvars.src = url;
 | 
			
		||||
            flashvars.streamType = "live"; // live or recorded
 | 
			
		||||
            flashvars.autoPlay = true;
 | 
			
		||||
            flashvars.controlBarAutoHide = false;
 | 
			
		||||
            flashvars.scaleMode = "stretch";
 | 
			
		||||
            flashvars.bufferTime = 0.8;
 | 
			
		||||
            
 | 
			
		||||
            var params = {};
 | 
			
		||||
            params.allowFullScreen = true;
 | 
			
		||||
            
 | 
			
		||||
            var attributes = {};
 | 
			
		||||
            
 | 
			
		||||
            swfobject.embedSWF(
 | 
			
		||||
                "js/StrobeMediaPlayback.swf", "player_id",
 | 
			
		||||
                srs_get_player_width(), srs_get_player_height(),
 | 
			
		||||
                "11.1", "js/AdobeFlashPlayerInstall.swf",
 | 
			
		||||
                flashvars, params, attributes
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        $(function(){
 | 
			
		||||
            // get the vhost and port to set the default url.
 | 
			
		||||
            // for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo
 | 
			
		||||
            // url set to: rtmp://demo:1935/live/livestream
 | 
			
		||||
            srs_init("#txt_url", null, "#main_modal");
 | 
			
		||||
            
 | 
			
		||||
            $("#main_modal").on("hide", function(){
 | 
			
		||||
                osmf_play("http://localhost");
 | 
			
		||||
                $("#div_container").remove();
 | 
			
		||||
            });
 | 
			
		||||
            $("#main_modal").on("show", function(){
 | 
			
		||||
                var url = $("#txt_url").val();
 | 
			
		||||
                osmf_play(url);
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            $("#btn_play").click(function(){
 | 
			
		||||
                $("#main_modal").modal({show:true, keyboard:false});
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    </script>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<div class="navbar navbar-fixed-top">
 | 
			
		||||
    <div class="navbar-inner">
 | 
			
		||||
        <div class="container">
 | 
			
		||||
        <a class="brand" href="index.html">SRS</a>
 | 
			
		||||
            <div class="nav-collapse collapse">
 | 
			
		||||
                <ul class="nav">
 | 
			
		||||
                    <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
 | 
			
		||||
                    <li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
 | 
			
		||||
                    <li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
 | 
			
		||||
                    <li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>
 | 
			
		||||
                    <li class="active"><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>
 | 
			
		||||
                    <li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
<div class="container">
 | 
			
		||||
    <div class="alert alert-info fade in">
 | 
			
		||||
        <button type="button" class="close" data-dismiss="alert">×</button>
 | 
			
		||||
        <strong><span>Usage:</span></strong> <span>输入地址后点击播放按钮</span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="form-inline">
 | 
			
		||||
        URL:
 | 
			
		||||
        <input type="text" id="txt_url" class="input-xxlarge" value=""></input>
 | 
			
		||||
        <button class="btn btn-primary" id="btn_play">播放视频</button>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div id="main_modal" class="modal hide fade">
 | 
			
		||||
        <div class="modal-header">
 | 
			
		||||
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
 | 
			
		||||
            <h3>AdobeOSMF</h3>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="modal-body" id="player">
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="modal-footer">
 | 
			
		||||
            <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true"> 关闭 </button>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <hr>
 | 
			
		||||
    <footer>
 | 
			
		||||
        <p><a href="https://github.com/winlinvip/simple-rtmp-server">SRS Team © 2013</a></p>
 | 
			
		||||
    </footer>
 | 
			
		||||
</div>
 | 
			
		||||
</body>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,87 +0,0 @@
 | 
			
		|||
<head>
 | 
			
		||||
    <meta http-equiv=Content-Type content="text/html;charset=utf-8">
 | 
			
		||||
    <title>OSMFPlayer</title>
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
body{margin:0; padding:0; color:#EEEEEE;}
 | 
			
		||||
input.url{width:300px; height:20px;}
 | 
			
		||||
input.size{width:40px; height:20px;}
 | 
			
		||||
input.buffer{width:20px; height:20px;}
 | 
			
		||||
input.play{width:60px; height: 25px;}
 | 
			
		||||
select.type{width:50px; }
 | 
			
		||||
span.size{padding-left:10px; padding-right:10px;}
 | 
			
		||||
div.main{font-size:12px; padding:5px 10px 0px 5px; background-color:#333333;}
 | 
			
		||||
div.player{padding-top:3px; padding-bottom:10px;}
 | 
			
		||||
div.control{padding-bottom:10px; background-color:#333333; }
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<div class="main" id="main">
 | 
			
		||||
    <div id="player" class="player"></div>
 | 
			
		||||
    <div class="control" id="control">
 | 
			
		||||
        Url(RTMP/HTTP): <input id="url" type="text" class="url" value="rtmp://demo:1935/live/livestream"></input>
 | 
			
		||||
        <select class="type" id="type">
 | 
			
		||||
            <option value="live" selected>live</option>
 | 
			
		||||
            <option value="recorded">vod</option>
 | 
			
		||||
        </select>
 | 
			
		||||
        <span class="size">
 | 
			
		||||
            Width: <input id="width" type="text" class="size" value="720"></input>
 | 
			
		||||
            Height: <input id="height" type="text" class="size" value="576"></input>
 | 
			
		||||
            Buffer: <input id="buffer" type="text" class="buffer" value="2"></input>(s)
 | 
			
		||||
        </span>
 | 
			
		||||
        <input type="button" class="play" value="Play" onclick="play()"></input>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<script type="text/javascript" src="swfobject.js"></script>
 | 
			
		||||
 | 
			
		||||
<script type="text/javascript">
 | 
			
		||||
    player = document.getElementById("player");
 | 
			
		||||
    player_div = null;
 | 
			
		||||
    
 | 
			
		||||
    function play(){
 | 
			
		||||
        // remove old player
 | 
			
		||||
        if(player_div != null){
 | 
			
		||||
            player.innerHTML = "";
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // create new div
 | 
			
		||||
        player_div = document.createElement("div");
 | 
			
		||||
        player.appendChild(player_div);
 | 
			
		||||
        
 | 
			
		||||
        // set id to swfobject to create player.
 | 
			
		||||
        player_div.id = "player_div";
 | 
			
		||||
        
 | 
			
		||||
        // generate player.
 | 
			
		||||
        var width = document.getElementById("width").value;
 | 
			
		||||
        var height = document.getElementById("height").value;
 | 
			
		||||
 | 
			
		||||
        // set new style
 | 
			
		||||
        var main = document.getElementById("main");
 | 
			
		||||
        var min_width = 830;
 | 
			
		||||
        main.style.width = Math.max(min_width, width);
 | 
			
		||||
        
 | 
			
		||||
        var flashvars = {};
 | 
			
		||||
        flashvars.src = document.getElementById("url").value;
 | 
			
		||||
        flashvars.streamType = document.getElementById("type").value; // live or recorded
 | 
			
		||||
        flashvars.autoPlay = true;
 | 
			
		||||
        flashvars.controlBarAutoHide = false;
 | 
			
		||||
        flashvars.scaleMode = "stretch";
 | 
			
		||||
        flashvars.bufferTime = document.getElementById("buffer").value;
 | 
			
		||||
        
 | 
			
		||||
        var params = {};
 | 
			
		||||
        params.allowFullScreen = true;
 | 
			
		||||
        
 | 
			
		||||
        var attributes = {};
 | 
			
		||||
        
 | 
			
		||||
        swfobject.embedSWF(
 | 
			
		||||
            "StrobeMediaPlayback.swf", "player_div",
 | 
			
		||||
            width, height,
 | 
			
		||||
            "11.1", "AdobeFlashPlayerInstall.swf",
 | 
			
		||||
            flashvars, params, attributes
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // play the default stream.
 | 
			
		||||
    play();
 | 
			
		||||
</script>
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| 
						 | 
				
			
			@ -1,33 +0,0 @@
 | 
			
		|||
<head>
 | 
			
		||||
    <meta http-equiv=Content-Type content="text/html;charset=utf-8">
 | 
			
		||||
    <title>RtmpPlayer</title>
 | 
			
		||||
    <style>
 | 
			
		||||
    body{margin:0; padding:0; color:#EEEEEE;}
 | 
			
		||||
    input.url{width:400px; height:20px;}
 | 
			
		||||
    input.size{width:40px; height:20px;}
 | 
			
		||||
    input.buffer{width:20px; height:20px;}
 | 
			
		||||
    input.play{width:60px; height: 25px;}
 | 
			
		||||
    select.type{width:50px; }
 | 
			
		||||
    span.size{padding-left:10px; padding-right:10px;}
 | 
			
		||||
    div.main{font-size:12px; padding:5px 10px 0px 5px; background-color:#333333; width: 980px;}
 | 
			
		||||
    div.player{padding-top:3px; padding-bottom:10px;}
 | 
			
		||||
    div.control{padding-bottom:10px; background-color:#333333; }
 | 
			
		||||
    </style>
 | 
			
		||||
</head>
 | 
			
		||||
<script type="text/javascript" src="rtmp.player.js"></script>
 | 
			
		||||
<div>
 | 
			
		||||
    <div id="player"></div>
 | 
			
		||||
</div>
 | 
			
		||||
<script type="text/javascript">
 | 
			
		||||
    var o = new RtmpPlayer("player", "RtmpPlayer.swf", 1350, 1050);
 | 
			
		||||
 | 
			
		||||
    o.setRtmpUrl("rtmp://demo:1935/live/livestream");
 | 
			
		||||
    o.admin = "admin";
 | 
			
		||||
    o.password = "123456";
 | 
			
		||||
    o.loop = false;
 | 
			
		||||
    o.cansave = true;
 | 
			
		||||
    o.islive = true;
 | 
			
		||||
    o.autostart = true;
 | 
			
		||||
 | 
			
		||||
    o.run();
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,909 +0,0 @@
 | 
			
		|||
// china cache RTMP player:
 | 
			
		||||
// run() to run player.
 | 
			
		||||
// server: the RTMP server, e.g. 192.168.1.5
 | 
			
		||||
// port: the RTMP port, default is 1935.
 | 
			
		||||
// adminPort: the admin port, default is 1111.
 | 
			
		||||
// user: the admin login user name, default is admin.
 | 
			
		||||
// password: the admin login user password, default is null.
 | 
			
		||||
// app: the application of fms to play. e.g vod
 | 
			
		||||
// stream: the stream of fms to play. e.g mp4:sample1_1500kbps.f4v
 | 
			
		||||
// islive: if true, live mode.
 | 
			
		||||
// autostart:Boolean a property which specify auto play.
 | 
			
		||||
// loop:Boolean a property which specify auto loop.
 | 
			
		||||
// 
 | 
			
		||||
// generate the release js version using GC:
 | 
			
		||||
// java -jar google_closure_compiler/compiler.jar --js chinacache.src.js --js_output_file chinacache.js
 | 
			
		||||
function RtmpPlayer(div_container, swf_url, width, height){
 | 
			
		||||
    this.swf_url = swf_url;
 | 
			
		||||
    this.div_container = div_container;
 | 
			
		||||
    this.width = width;
 | 
			
		||||
    this.height = height;
 | 
			
		||||
    
 | 
			
		||||
    this.flashvars = {};
 | 
			
		||||
    this.flashvars.width = width;
 | 
			
		||||
    this.flashvars.height = height;
 | 
			
		||||
 | 
			
		||||
    this.params = {};
 | 
			
		||||
    this.params.quality = "high";
 | 
			
		||||
    this.params.bgcolor = "#EEEEEE";
 | 
			
		||||
    this.params.allowscriptaccess = "always";
 | 
			
		||||
    this.params.allowfullscreen = "true";
 | 
			
		||||
    this.params.wmode = "Window";
 | 
			
		||||
 | 
			
		||||
    this.attributes = {};
 | 
			
		||||
    var html_element_id = "RtmpPlayer";
 | 
			
		||||
    this.attributes.id = html_element_id;
 | 
			
		||||
    this.attributes.name = html_element_id;
 | 
			
		||||
    this.attributes.align = "middle";
 | 
			
		||||
    
 | 
			
		||||
    this.autostart = false;
 | 
			
		||||
	this.appLevel = 1;
 | 
			
		||||
    this.loop = false;
 | 
			
		||||
    this.port = 1935;
 | 
			
		||||
    this.adminPort = 1111;
 | 
			
		||||
    this.server = null;
 | 
			
		||||
    this.app = null;
 | 
			
		||||
    this.stream = null;
 | 
			
		||||
    this.islive = false;
 | 
			
		||||
    this.cansave = true;
 | 
			
		||||
    this.user = "admin";
 | 
			
		||||
    this.password = null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RtmpPlayer.prototype.setRtmpUrl = function(url) {
 | 
			
		||||
    var s = this.trim(url.replace("rtmp://", ""), "/");
 | 
			
		||||
    
 | 
			
		||||
    if(s.indexOf(":") < 0 || s.indexOf(":") > s.indexOf("/")){
 | 
			
		||||
        this.server = s.substr(0, s.indexOf("/"));
 | 
			
		||||
        s = this.trim(s.substr(this.server.length), "/");
 | 
			
		||||
    }
 | 
			
		||||
    else{
 | 
			
		||||
        this.server = s.substr(0, s.indexOf(":"));
 | 
			
		||||
        s = this.trim(s.substr(this.server.length), ":");
 | 
			
		||||
        
 | 
			
		||||
        this.port = s.substr(0, s.indexOf("/"));
 | 
			
		||||
        s = this.trim(s.substr(this.port.length), "/");
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    this.app = s.substr(0, s.indexOf("/"));
 | 
			
		||||
    s = this.trim(s.substr(this.app.length), "/");
 | 
			
		||||
    
 | 
			
		||||
    this.stream = s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RtmpPlayer.prototype.trim = function(s, str) {
 | 
			
		||||
    var r =  s;
 | 
			
		||||
    
 | 
			
		||||
    while(r.indexOf(str) == 0){
 | 
			
		||||
        r = r.substr(str.length);
 | 
			
		||||
    }
 | 
			
		||||
    while(r.lastIndexOf(str) == r.length - str.length){
 | 
			
		||||
        r = r.substr(0, r.length - str.length);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RtmpPlayer.prototype.ck = function(v, pro) {
 | 
			
		||||
    if(v == null || v == undefined){
 | 
			
		||||
        alert(pro + "不能为空!");
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RtmpPlayer.prototype.run = function() {
 | 
			
		||||
    // const values
 | 
			
		||||
    swfVersionStr = "11.1";
 | 
			
		||||
    xiSwfUrlStr = "AdobeFlashPlayerInstall.swf";
 | 
			
		||||
    
 | 
			
		||||
    // check
 | 
			
		||||
    if(this.ck(this.autostart, "autostart(是否自动播放)") || this.ck(this.port, "port(FMS服务器端口)")
 | 
			
		||||
        || this.ck(this.adminPort, "adminPort(FMS服务器管理端口)") || this.ck(this.server, "server(FMS服务器地址)")
 | 
			
		||||
        || this.ck(this.app, "app(FMS application)") || this.ck(this.stream, "stream(流名称)")
 | 
			
		||||
        || this.ck(this.user, "user(FMS登录用户名)") || this.ck(this.password, "password(FMS登录用户密码)")){
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    this.flashvars.autostart = this.autostart;
 | 
			
		||||
	this.flashvars.appLevel = this.appLevel;
 | 
			
		||||
    this.flashvars.loop = this.loop;
 | 
			
		||||
    this.flashvars.port = this.port;
 | 
			
		||||
    this.flashvars.adminPort = this.adminPort;
 | 
			
		||||
    this.flashvars.server = this.server;
 | 
			
		||||
    this.flashvars.app = this.app;
 | 
			
		||||
    this.flashvars.stream = this.stream;
 | 
			
		||||
    this.flashvars.islive = this.islive;
 | 
			
		||||
    this.flashvars.cansave = this.cansave;
 | 
			
		||||
    this.flashvars.user = this.user;
 | 
			
		||||
    this.flashvars.password = this.password;
 | 
			
		||||
    
 | 
			
		||||
    var chnvideoPlayerHost = this;
 | 
			
		||||
    swfobject.embedSWF(
 | 
			
		||||
        this.swf_url, this.div_container,
 | 
			
		||||
        this.width, this.height,
 | 
			
		||||
        swfVersionStr, xiSwfUrlStr,
 | 
			
		||||
        this.flashvars, this.params, this.attributes, 
 | 
			
		||||
        function(callbackObj){
 | 
			
		||||
            chnvideoPlayerHost.callbackObj = callbackObj;
 | 
			
		||||
        }
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*!	SWFObject v2.2 <http://code.google.com/p/swfobject/> 
 | 
			
		||||
	is released under the MIT License <http://www.opensource.org/licenses/mit-license.php> 
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
var swfobject = function() {
 | 
			
		||||
	
 | 
			
		||||
	var UNDEF = "undefined",
 | 
			
		||||
		OBJECT = "object",
 | 
			
		||||
		SHOCKWAVE_FLASH = "Shockwave Flash",
 | 
			
		||||
		SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash",
 | 
			
		||||
		FLASH_MIME_TYPE = "application/x-shockwave-flash",
 | 
			
		||||
		EXPRESS_INSTALL_ID = "SWFObjectExprInst",
 | 
			
		||||
		ON_READY_STATE_CHANGE = "onreadystatechange",
 | 
			
		||||
		
 | 
			
		||||
		win = window,
 | 
			
		||||
		doc = document,
 | 
			
		||||
		nav = navigator,
 | 
			
		||||
		
 | 
			
		||||
		plugin = false,
 | 
			
		||||
		domLoadFnArr = [main],
 | 
			
		||||
		regObjArr = [],
 | 
			
		||||
		objIdArr = [],
 | 
			
		||||
		listenersArr = [],
 | 
			
		||||
		storedAltContent,
 | 
			
		||||
		storedAltContentId,
 | 
			
		||||
		storedCallbackFn,
 | 
			
		||||
		storedCallbackObj,
 | 
			
		||||
		isDomLoaded = false,
 | 
			
		||||
		isExpressInstallActive = false,
 | 
			
		||||
		dynamicStylesheet,
 | 
			
		||||
		dynamicStylesheetMedia,
 | 
			
		||||
		autoHideShow = true,
 | 
			
		||||
	
 | 
			
		||||
	/* Centralized function for browser feature detection
 | 
			
		||||
		- User agent string detection is only used when no good alternative is possible
 | 
			
		||||
		- Is executed directly for optimal performance
 | 
			
		||||
	*/	
 | 
			
		||||
	ua = function() {
 | 
			
		||||
		var w3cdom = typeof doc.getElementById != UNDEF && typeof doc.getElementsByTagName != UNDEF && typeof doc.createElement != UNDEF,
 | 
			
		||||
			u = nav.userAgent.toLowerCase(),
 | 
			
		||||
			p = nav.platform.toLowerCase(),
 | 
			
		||||
			windows = p ? /win/.test(p) : /win/.test(u),
 | 
			
		||||
			mac = p ? /mac/.test(p) : /mac/.test(u),
 | 
			
		||||
			webkit = /webkit/.test(u) ? parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false, // returns either the webkit version or false if not webkit
 | 
			
		||||
			ie = !+"\v1", // feature detection based on Andrea Giammarchi's solution: http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html
 | 
			
		||||
			playerVersion = [0,0,0],
 | 
			
		||||
			d = null;
 | 
			
		||||
		if (typeof nav.plugins != UNDEF && typeof nav.plugins[SHOCKWAVE_FLASH] == OBJECT) {
 | 
			
		||||
			d = nav.plugins[SHOCKWAVE_FLASH].description;
 | 
			
		||||
			if (d && !(typeof nav.mimeTypes != UNDEF && nav.mimeTypes[FLASH_MIME_TYPE] && !nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { // navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+
 | 
			
		||||
				plugin = true;
 | 
			
		||||
				ie = false; // cascaded feature detection for Internet Explorer
 | 
			
		||||
				d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
 | 
			
		||||
				playerVersion[0] = parseInt(d.replace(/^(.*)\..*$/, "$1"), 10);
 | 
			
		||||
				playerVersion[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, "$1"), 10);
 | 
			
		||||
				playerVersion[2] = /[a-zA-Z]/.test(d) ? parseInt(d.replace(/^.*[a-zA-Z]+(.*)$/, "$1"), 10) : 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else if (typeof win.ActiveXObject != UNDEF) {
 | 
			
		||||
			try {
 | 
			
		||||
				var a = new ActiveXObject(SHOCKWAVE_FLASH_AX);
 | 
			
		||||
				if (a) { // a will return null when ActiveX is disabled
 | 
			
		||||
					d = a.GetVariable("$version");
 | 
			
		||||
					if (d) {
 | 
			
		||||
						ie = true; // cascaded feature detection for Internet Explorer
 | 
			
		||||
						d = d.split(" ")[1].split(",");
 | 
			
		||||
						playerVersion = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			catch(e) {}
 | 
			
		||||
		}
 | 
			
		||||
		return { w3:w3cdom, pv:playerVersion, wk:webkit, ie:ie, win:windows, mac:mac };
 | 
			
		||||
	}(),
 | 
			
		||||
	
 | 
			
		||||
	/* Cross-browser onDomLoad
 | 
			
		||||
		- Will fire an event as soon as the DOM of a web page is loaded
 | 
			
		||||
		- Internet Explorer workaround based on Diego Perini's solution: http://javascript.nwbox.com/IEContentLoaded/
 | 
			
		||||
		- Regular onload serves as fallback
 | 
			
		||||
	*/ 
 | 
			
		||||
	onDomLoad = function() {
 | 
			
		||||
		if (!ua.w3) { return; }
 | 
			
		||||
		if ((typeof doc.readyState != UNDEF && doc.readyState == "complete") || (typeof doc.readyState == UNDEF && (doc.getElementsByTagName("body")[0] || doc.body))) { // function is fired after onload, e.g. when script is inserted dynamically 
 | 
			
		||||
			callDomLoadFunctions();
 | 
			
		||||
		}
 | 
			
		||||
		if (!isDomLoaded) {
 | 
			
		||||
			if (typeof doc.addEventListener != UNDEF) {
 | 
			
		||||
				doc.addEventListener("DOMContentLoaded", callDomLoadFunctions, false);
 | 
			
		||||
			}		
 | 
			
		||||
			if (ua.ie && ua.win) {
 | 
			
		||||
				doc.attachEvent(ON_READY_STATE_CHANGE, function() {
 | 
			
		||||
					if (doc.readyState == "complete") {
 | 
			
		||||
						doc.detachEvent(ON_READY_STATE_CHANGE, arguments.callee);
 | 
			
		||||
						callDomLoadFunctions();
 | 
			
		||||
					}
 | 
			
		||||
				});
 | 
			
		||||
				if (win == top) { // if not inside an iframe
 | 
			
		||||
					(function(){
 | 
			
		||||
						if (isDomLoaded) { return; }
 | 
			
		||||
						try {
 | 
			
		||||
							doc.documentElement.doScroll("left");
 | 
			
		||||
						}
 | 
			
		||||
						catch(e) {
 | 
			
		||||
							setTimeout(arguments.callee, 0);
 | 
			
		||||
							return;
 | 
			
		||||
						}
 | 
			
		||||
						callDomLoadFunctions();
 | 
			
		||||
					})();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (ua.wk) {
 | 
			
		||||
				(function(){
 | 
			
		||||
					if (isDomLoaded) { return; }
 | 
			
		||||
					if (!/loaded|complete/.test(doc.readyState)) {
 | 
			
		||||
						setTimeout(arguments.callee, 0);
 | 
			
		||||
						return;
 | 
			
		||||
					}
 | 
			
		||||
					callDomLoadFunctions();
 | 
			
		||||
				})();
 | 
			
		||||
			}
 | 
			
		||||
			addLoadEvent(callDomLoadFunctions);
 | 
			
		||||
		}
 | 
			
		||||
	}();
 | 
			
		||||
	
 | 
			
		||||
	function callDomLoadFunctions() {
 | 
			
		||||
		if (isDomLoaded) { return; }
 | 
			
		||||
		try { // test if we can really add/remove elements to/from the DOM; we don't want to fire it too early
 | 
			
		||||
			var t = doc.getElementsByTagName("body")[0].appendChild(createElement("span"));
 | 
			
		||||
			t.parentNode.removeChild(t);
 | 
			
		||||
		}
 | 
			
		||||
		catch (e) { return; }
 | 
			
		||||
		isDomLoaded = true;
 | 
			
		||||
		var dl = domLoadFnArr.length;
 | 
			
		||||
		for (var i = 0; i < dl; i++) {
 | 
			
		||||
			domLoadFnArr[i]();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	function addDomLoadEvent(fn) {
 | 
			
		||||
		if (isDomLoaded) {
 | 
			
		||||
			fn();
 | 
			
		||||
		}
 | 
			
		||||
		else { 
 | 
			
		||||
			domLoadFnArr[domLoadFnArr.length] = fn; // Array.push() is only available in IE5.5+
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Cross-browser onload
 | 
			
		||||
		- Based on James Edwards' solution: http://brothercake.com/site/resources/scripts/onload/
 | 
			
		||||
		- Will fire an event as soon as a web page including all of its assets are loaded 
 | 
			
		||||
	 */
 | 
			
		||||
	function addLoadEvent(fn) {
 | 
			
		||||
		if (typeof win.addEventListener != UNDEF) {
 | 
			
		||||
			win.addEventListener("load", fn, false);
 | 
			
		||||
		}
 | 
			
		||||
		else if (typeof doc.addEventListener != UNDEF) {
 | 
			
		||||
			doc.addEventListener("load", fn, false);
 | 
			
		||||
		}
 | 
			
		||||
		else if (typeof win.attachEvent != UNDEF) {
 | 
			
		||||
			addListener(win, "onload", fn);
 | 
			
		||||
		}
 | 
			
		||||
		else if (typeof win.onload == "function") {
 | 
			
		||||
			var fnOld = win.onload;
 | 
			
		||||
			win.onload = function() {
 | 
			
		||||
				fnOld();
 | 
			
		||||
				fn();
 | 
			
		||||
			};
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			win.onload = fn;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Main function
 | 
			
		||||
		- Will preferably execute onDomLoad, otherwise onload (as a fallback)
 | 
			
		||||
	*/
 | 
			
		||||
	function main() { 
 | 
			
		||||
		if (plugin) {
 | 
			
		||||
			testPlayerVersion();
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			matchVersions();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Detect the Flash Player version for non-Internet Explorer browsers
 | 
			
		||||
		- Detecting the plug-in version via the object element is more precise than using the plugins collection item's description:
 | 
			
		||||
		  a. Both release and build numbers can be detected
 | 
			
		||||
		  b. Avoid wrong descriptions by corrupt installers provided by Adobe
 | 
			
		||||
		  c. Avoid wrong descriptions by multiple Flash Player entries in the plugin Array, caused by incorrect browser imports
 | 
			
		||||
		- Disadvantage of this method is that it depends on the availability of the DOM, while the plugins collection is immediately available
 | 
			
		||||
	*/
 | 
			
		||||
	function testPlayerVersion() {
 | 
			
		||||
		var b = doc.getElementsByTagName("body")[0];
 | 
			
		||||
		var o = createElement(OBJECT);
 | 
			
		||||
		o.setAttribute("type", FLASH_MIME_TYPE);
 | 
			
		||||
		var t = b.appendChild(o);
 | 
			
		||||
		if (t) {
 | 
			
		||||
			var counter = 0;
 | 
			
		||||
			(function(){
 | 
			
		||||
				if (typeof t.GetVariable != UNDEF) {
 | 
			
		||||
					var d = t.GetVariable("$version");
 | 
			
		||||
					if (d) {
 | 
			
		||||
						d = d.split(" ")[1].split(",");
 | 
			
		||||
						ua.pv = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				else if (counter < 10) {
 | 
			
		||||
					counter++;
 | 
			
		||||
					setTimeout(arguments.callee, 10);
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
				b.removeChild(o);
 | 
			
		||||
				t = null;
 | 
			
		||||
				matchVersions();
 | 
			
		||||
			})();
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			matchVersions();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Perform Flash Player and SWF version matching; static publishing only
 | 
			
		||||
	*/
 | 
			
		||||
	function matchVersions() {
 | 
			
		||||
		var rl = regObjArr.length;
 | 
			
		||||
		if (rl > 0) {
 | 
			
		||||
			for (var i = 0; i < rl; i++) { // for each registered object element
 | 
			
		||||
				var id = regObjArr[i].id;
 | 
			
		||||
				var cb = regObjArr[i].callbackFn;
 | 
			
		||||
				var cbObj = {success:false, id:id};
 | 
			
		||||
				if (ua.pv[0] > 0) {
 | 
			
		||||
					var obj = getElementById(id);
 | 
			
		||||
					if (obj) {
 | 
			
		||||
						if (hasPlayerVersion(regObjArr[i].swfVersion) && !(ua.wk && ua.wk < 312)) { // Flash Player version >= published SWF version: Houston, we have a match!
 | 
			
		||||
							setVisibility(id, true);
 | 
			
		||||
							if (cb) {
 | 
			
		||||
								cbObj.success = true;
 | 
			
		||||
								cbObj.ref = getObjectById(id);
 | 
			
		||||
								cb(cbObj);
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
						else if (regObjArr[i].expressInstall && canExpressInstall()) { // show the Adobe Express Install dialog if set by the web page author and if supported
 | 
			
		||||
							var att = {};
 | 
			
		||||
							att.data = regObjArr[i].expressInstall;
 | 
			
		||||
							att.width = obj.getAttribute("width") || "0";
 | 
			
		||||
							att.height = obj.getAttribute("height") || "0";
 | 
			
		||||
							if (obj.getAttribute("class")) { att.styleclass = obj.getAttribute("class"); }
 | 
			
		||||
							if (obj.getAttribute("align")) { att.align = obj.getAttribute("align"); }
 | 
			
		||||
							// parse HTML object param element's name-value pairs
 | 
			
		||||
							var par = {};
 | 
			
		||||
							var p = obj.getElementsByTagName("param");
 | 
			
		||||
							var pl = p.length;
 | 
			
		||||
							for (var j = 0; j < pl; j++) {
 | 
			
		||||
								if (p[j].getAttribute("name").toLowerCase() != "movie") {
 | 
			
		||||
									par[p[j].getAttribute("name")] = p[j].getAttribute("value");
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
							showExpressInstall(att, par, id, cb);
 | 
			
		||||
						}
 | 
			
		||||
						else { // Flash Player and SWF version mismatch or an older Webkit engine that ignores the HTML object element's nested param elements: display alternative content instead of SWF
 | 
			
		||||
							displayAltContent(obj);
 | 
			
		||||
							if (cb) { cb(cbObj); }
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				else {	// if no Flash Player is installed or the fp version cannot be detected we let the HTML object element do its job (either show a SWF or alternative content)
 | 
			
		||||
					setVisibility(id, true);
 | 
			
		||||
					if (cb) {
 | 
			
		||||
						var o = getObjectById(id); // test whether there is an HTML object element or not
 | 
			
		||||
						if (o && typeof o.SetVariable != UNDEF) { 
 | 
			
		||||
							cbObj.success = true;
 | 
			
		||||
							cbObj.ref = o;
 | 
			
		||||
						}
 | 
			
		||||
						cb(cbObj);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	function getObjectById(objectIdStr) {
 | 
			
		||||
		var r = null;
 | 
			
		||||
		var o = getElementById(objectIdStr);
 | 
			
		||||
		if (o && o.nodeName == "OBJECT") {
 | 
			
		||||
			if (typeof o.SetVariable != UNDEF) {
 | 
			
		||||
				r = o;
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				var n = o.getElementsByTagName(OBJECT)[0];
 | 
			
		||||
				if (n) {
 | 
			
		||||
					r = n;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Requirements for Adobe Express Install
 | 
			
		||||
		- only one instance can be active at a time
 | 
			
		||||
		- fp 6.0.65 or higher
 | 
			
		||||
		- Win/Mac OS only
 | 
			
		||||
		- no Webkit engines older than version 312
 | 
			
		||||
	*/
 | 
			
		||||
	function canExpressInstall() {
 | 
			
		||||
		return !isExpressInstallActive && hasPlayerVersion("6.0.65") && (ua.win || ua.mac) && !(ua.wk && ua.wk < 312);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Show the Adobe Express Install dialog
 | 
			
		||||
		- Reference: http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75
 | 
			
		||||
	*/
 | 
			
		||||
	function showExpressInstall(att, par, replaceElemIdStr, callbackFn) {
 | 
			
		||||
		isExpressInstallActive = true;
 | 
			
		||||
		storedCallbackFn = callbackFn || null;
 | 
			
		||||
		storedCallbackObj = {success:false, id:replaceElemIdStr};
 | 
			
		||||
		var obj = getElementById(replaceElemIdStr);
 | 
			
		||||
		if (obj) {
 | 
			
		||||
			if (obj.nodeName == "OBJECT") { // static publishing
 | 
			
		||||
				storedAltContent = abstractAltContent(obj);
 | 
			
		||||
				storedAltContentId = null;
 | 
			
		||||
			}
 | 
			
		||||
			else { // dynamic publishing
 | 
			
		||||
				storedAltContent = obj;
 | 
			
		||||
				storedAltContentId = replaceElemIdStr;
 | 
			
		||||
			}
 | 
			
		||||
			att.id = EXPRESS_INSTALL_ID;
 | 
			
		||||
			if (typeof att.width == UNDEF || (!/%$/.test(att.width) && parseInt(att.width, 10) < 310)) { att.width = "310"; }
 | 
			
		||||
			if (typeof att.height == UNDEF || (!/%$/.test(att.height) && parseInt(att.height, 10) < 137)) { att.height = "137"; }
 | 
			
		||||
			doc.title = doc.title.slice(0, 47) + " - Flash Player Installation";
 | 
			
		||||
			var pt = ua.ie && ua.win ? "ActiveX" : "PlugIn",
 | 
			
		||||
				fv = "MMredirectURL=" + encodeURI(window.location).toString().replace(/&/g,"%26") + "&MMplayerType=" + pt + "&MMdoctitle=" + doc.title;
 | 
			
		||||
			if (typeof par.flashvars != UNDEF) {
 | 
			
		||||
				par.flashvars += "&" + fv;
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				par.flashvars = fv;
 | 
			
		||||
			}
 | 
			
		||||
			// IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it,
 | 
			
		||||
			// because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
 | 
			
		||||
			if (ua.ie && ua.win && obj.readyState != 4) {
 | 
			
		||||
				var newObj = createElement("div");
 | 
			
		||||
				replaceElemIdStr += "SWFObjectNew";
 | 
			
		||||
				newObj.setAttribute("id", replaceElemIdStr);
 | 
			
		||||
				obj.parentNode.insertBefore(newObj, obj); // insert placeholder div that will be replaced by the object element that loads expressinstall.swf
 | 
			
		||||
				obj.style.display = "none";
 | 
			
		||||
				(function(){
 | 
			
		||||
					if (obj.readyState == 4) {
 | 
			
		||||
						obj.parentNode.removeChild(obj);
 | 
			
		||||
					}
 | 
			
		||||
					else {
 | 
			
		||||
						setTimeout(arguments.callee, 10);
 | 
			
		||||
					}
 | 
			
		||||
				})();
 | 
			
		||||
			}
 | 
			
		||||
			createSWF(att, par, replaceElemIdStr);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Functions to abstract and display alternative content
 | 
			
		||||
	*/
 | 
			
		||||
	function displayAltContent(obj) {
 | 
			
		||||
		if (ua.ie && ua.win && obj.readyState != 4) {
 | 
			
		||||
			// IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it,
 | 
			
		||||
			// because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
 | 
			
		||||
			var el = createElement("div");
 | 
			
		||||
			obj.parentNode.insertBefore(el, obj); // insert placeholder div that will be replaced by the alternative content
 | 
			
		||||
			el.parentNode.replaceChild(abstractAltContent(obj), el);
 | 
			
		||||
			obj.style.display = "none";
 | 
			
		||||
			(function(){
 | 
			
		||||
				if (obj.readyState == 4) {
 | 
			
		||||
					obj.parentNode.removeChild(obj);
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					setTimeout(arguments.callee, 10);
 | 
			
		||||
				}
 | 
			
		||||
			})();
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			obj.parentNode.replaceChild(abstractAltContent(obj), obj);
 | 
			
		||||
		}
 | 
			
		||||
	} 
 | 
			
		||||
 | 
			
		||||
	function abstractAltContent(obj) {
 | 
			
		||||
		var ac = createElement("div");
 | 
			
		||||
		if (ua.win && ua.ie) {
 | 
			
		||||
			ac.innerHTML = obj.innerHTML;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			var nestedObj = obj.getElementsByTagName(OBJECT)[0];
 | 
			
		||||
			if (nestedObj) {
 | 
			
		||||
				var c = nestedObj.childNodes;
 | 
			
		||||
				if (c) {
 | 
			
		||||
					var cl = c.length;
 | 
			
		||||
					for (var i = 0; i < cl; i++) {
 | 
			
		||||
						if (!(c[i].nodeType == 1 && c[i].nodeName == "PARAM") && !(c[i].nodeType == 8)) {
 | 
			
		||||
							ac.appendChild(c[i].cloneNode(true));
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return ac;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Cross-browser dynamic SWF creation
 | 
			
		||||
	*/
 | 
			
		||||
	function createSWF(attObj, parObj, id) {
 | 
			
		||||
		var r, el = getElementById(id);
 | 
			
		||||
		if (ua.wk && ua.wk < 312) { return r; }
 | 
			
		||||
		if (el) {
 | 
			
		||||
			if (typeof attObj.id == UNDEF) { // if no 'id' is defined for the object element, it will inherit the 'id' from the alternative content
 | 
			
		||||
				attObj.id = id;
 | 
			
		||||
			}
 | 
			
		||||
			if (ua.ie && ua.win) { // Internet Explorer + the HTML object element + W3C DOM methods do not combine: fall back to outerHTML
 | 
			
		||||
				var att = "";
 | 
			
		||||
				for (var i in attObj) {
 | 
			
		||||
					if (attObj[i] != Object.prototype[i]) { // filter out prototype additions from other potential libraries
 | 
			
		||||
						if (i.toLowerCase() == "data") {
 | 
			
		||||
							parObj.movie = attObj[i];
 | 
			
		||||
						}
 | 
			
		||||
						else if (i.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
 | 
			
		||||
							att += ' class="' + attObj[i] + '"';
 | 
			
		||||
						}
 | 
			
		||||
						else if (i.toLowerCase() != "classid") {
 | 
			
		||||
							att += ' ' + i + '="' + attObj[i] + '"';
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				var par = "";
 | 
			
		||||
				for (var j in parObj) {
 | 
			
		||||
					if (parObj[j] != Object.prototype[j]) { // filter out prototype additions from other potential libraries
 | 
			
		||||
						par += '<param name="' + j + '" value="' + parObj[j] + '" />';
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				el.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"' + att + '>' + par + '</object>';
 | 
			
		||||
				objIdArr[objIdArr.length] = attObj.id; // stored to fix object 'leaks' on unload (dynamic publishing only)
 | 
			
		||||
				r = getElementById(attObj.id);	
 | 
			
		||||
			}
 | 
			
		||||
			else { // well-behaving browsers
 | 
			
		||||
				var o = createElement(OBJECT);
 | 
			
		||||
				o.setAttribute("type", FLASH_MIME_TYPE);
 | 
			
		||||
				for (var m in attObj) {
 | 
			
		||||
					if (attObj[m] != Object.prototype[m]) { // filter out prototype additions from other potential libraries
 | 
			
		||||
						if (m.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
 | 
			
		||||
							o.setAttribute("class", attObj[m]);
 | 
			
		||||
						}
 | 
			
		||||
						else if (m.toLowerCase() != "classid") { // filter out IE specific attribute
 | 
			
		||||
							o.setAttribute(m, attObj[m]);
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				for (var n in parObj) {
 | 
			
		||||
					if (parObj[n] != Object.prototype[n] && n.toLowerCase() != "movie") { // filter out prototype additions from other potential libraries and IE specific param element
 | 
			
		||||
						createObjParam(o, n, parObj[n]);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				el.parentNode.replaceChild(o, el);
 | 
			
		||||
				r = o;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	function createObjParam(el, pName, pValue) {
 | 
			
		||||
		var p = createElement("param");
 | 
			
		||||
		p.setAttribute("name", pName);	
 | 
			
		||||
		p.setAttribute("value", pValue);
 | 
			
		||||
		el.appendChild(p);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Cross-browser SWF removal
 | 
			
		||||
		- Especially needed to safely and completely remove a SWF in Internet Explorer
 | 
			
		||||
	*/
 | 
			
		||||
	function removeSWF(id) {
 | 
			
		||||
		var obj = getElementById(id);
 | 
			
		||||
		if (obj && obj.nodeName == "OBJECT") {
 | 
			
		||||
			if (ua.ie && ua.win) {
 | 
			
		||||
				obj.style.display = "none";
 | 
			
		||||
				(function(){
 | 
			
		||||
					if (obj.readyState == 4) {
 | 
			
		||||
						removeObjectInIE(id);
 | 
			
		||||
					}
 | 
			
		||||
					else {
 | 
			
		||||
						setTimeout(arguments.callee, 10);
 | 
			
		||||
					}
 | 
			
		||||
				})();
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				obj.parentNode.removeChild(obj);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	function removeObjectInIE(id) {
 | 
			
		||||
		var obj = getElementById(id);
 | 
			
		||||
		if (obj) {
 | 
			
		||||
			for (var i in obj) {
 | 
			
		||||
				if (typeof obj[i] == "function") {
 | 
			
		||||
					obj[i] = null;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			obj.parentNode.removeChild(obj);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Functions to optimize JavaScript compression
 | 
			
		||||
	*/
 | 
			
		||||
	function getElementById(id) {
 | 
			
		||||
		var el = null;
 | 
			
		||||
		try {
 | 
			
		||||
			el = doc.getElementById(id);
 | 
			
		||||
		}
 | 
			
		||||
		catch (e) {}
 | 
			
		||||
		return el;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	function createElement(el) {
 | 
			
		||||
		return doc.createElement(el);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Updated attachEvent function for Internet Explorer
 | 
			
		||||
		- Stores attachEvent information in an Array, so on unload the detachEvent functions can be called to avoid memory leaks
 | 
			
		||||
	*/	
 | 
			
		||||
	function addListener(target, eventType, fn) {
 | 
			
		||||
		target.attachEvent(eventType, fn);
 | 
			
		||||
		listenersArr[listenersArr.length] = [target, eventType, fn];
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Flash Player and SWF content version matching
 | 
			
		||||
	*/
 | 
			
		||||
	function hasPlayerVersion(rv) {
 | 
			
		||||
		var pv = ua.pv, v = rv.split(".");
 | 
			
		||||
		v[0] = parseInt(v[0], 10);
 | 
			
		||||
		v[1] = parseInt(v[1], 10) || 0; // supports short notation, e.g. "9" instead of "9.0.0"
 | 
			
		||||
		v[2] = parseInt(v[2], 10) || 0;
 | 
			
		||||
		return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Cross-browser dynamic CSS creation
 | 
			
		||||
		- Based on Bobby van der Sluis' solution: http://www.bobbyvandersluis.com/articles/dynamicCSS.php
 | 
			
		||||
	*/	
 | 
			
		||||
	function createCSS(sel, decl, media, newStyle) {
 | 
			
		||||
		if (ua.ie && ua.mac) { return; }
 | 
			
		||||
		var h = doc.getElementsByTagName("head")[0];
 | 
			
		||||
		if (!h) { return; } // to also support badly authored HTML pages that lack a head element
 | 
			
		||||
		var m = (media && typeof media == "string") ? media : "screen";
 | 
			
		||||
		if (newStyle) {
 | 
			
		||||
			dynamicStylesheet = null;
 | 
			
		||||
			dynamicStylesheetMedia = null;
 | 
			
		||||
		}
 | 
			
		||||
		if (!dynamicStylesheet || dynamicStylesheetMedia != m) { 
 | 
			
		||||
			// create dynamic stylesheet + get a global reference to it
 | 
			
		||||
			var s = createElement("style");
 | 
			
		||||
			s.setAttribute("type", "text/css");
 | 
			
		||||
			s.setAttribute("media", m);
 | 
			
		||||
			dynamicStylesheet = h.appendChild(s);
 | 
			
		||||
			if (ua.ie && ua.win && typeof doc.styleSheets != UNDEF && doc.styleSheets.length > 0) {
 | 
			
		||||
				dynamicStylesheet = doc.styleSheets[doc.styleSheets.length - 1];
 | 
			
		||||
			}
 | 
			
		||||
			dynamicStylesheetMedia = m;
 | 
			
		||||
		}
 | 
			
		||||
		// add style rule
 | 
			
		||||
		if (ua.ie && ua.win) {
 | 
			
		||||
			if (dynamicStylesheet && typeof dynamicStylesheet.addRule == OBJECT) {
 | 
			
		||||
				dynamicStylesheet.addRule(sel, decl);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			if (dynamicStylesheet && typeof doc.createTextNode != UNDEF) {
 | 
			
		||||
				dynamicStylesheet.appendChild(doc.createTextNode(sel + " {" + decl + "}"));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	function setVisibility(id, isVisible) {
 | 
			
		||||
		if (!autoHideShow) { return; }
 | 
			
		||||
		var v = isVisible ? "visible" : "hidden";
 | 
			
		||||
		if (isDomLoaded && getElementById(id)) {
 | 
			
		||||
			getElementById(id).style.visibility = v;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			createCSS("#" + id, "visibility:" + v);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Filter to avoid XSS attacks
 | 
			
		||||
	*/
 | 
			
		||||
	function urlEncodeIfNecessary(s) {
 | 
			
		||||
		var regex = /[\\\"<>\.;]/;
 | 
			
		||||
		var hasBadChars = regex.exec(s) != null;
 | 
			
		||||
		return hasBadChars && typeof encodeURIComponent != UNDEF ? encodeURIComponent(s) : s;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Release memory to avoid memory leaks caused by closures, fix hanging audio/video threads and force open sockets/NetConnections to disconnect (Internet Explorer only)
 | 
			
		||||
	*/
 | 
			
		||||
	var cleanup = function() {
 | 
			
		||||
		if (ua.ie && ua.win) {
 | 
			
		||||
			window.attachEvent("onunload", function() {
 | 
			
		||||
				// remove listeners to avoid memory leaks
 | 
			
		||||
				var ll = listenersArr.length;
 | 
			
		||||
				for (var i = 0; i < ll; i++) {
 | 
			
		||||
					listenersArr[i][0].detachEvent(listenersArr[i][1], listenersArr[i][2]);
 | 
			
		||||
				}
 | 
			
		||||
				// cleanup dynamically embedded objects to fix audio/video threads and force open sockets and NetConnections to disconnect
 | 
			
		||||
				var il = objIdArr.length;
 | 
			
		||||
				for (var j = 0; j < il; j++) {
 | 
			
		||||
					removeSWF(objIdArr[j]);
 | 
			
		||||
				}
 | 
			
		||||
				// cleanup library's main closures to avoid memory leaks
 | 
			
		||||
				for (var k in ua) {
 | 
			
		||||
					ua[k] = null;
 | 
			
		||||
				}
 | 
			
		||||
				ua = null;
 | 
			
		||||
				for (var l in swfobject) {
 | 
			
		||||
					swfobject[l] = null;
 | 
			
		||||
				}
 | 
			
		||||
				swfobject = null;
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	}();
 | 
			
		||||
	
 | 
			
		||||
	return {
 | 
			
		||||
		/* Public API
 | 
			
		||||
			- Reference: http://code.google.com/p/swfobject/wiki/documentation
 | 
			
		||||
		*/ 
 | 
			
		||||
		registerObject: function(objectIdStr, swfVersionStr, xiSwfUrlStr, callbackFn) {
 | 
			
		||||
			if (ua.w3 && objectIdStr && swfVersionStr) {
 | 
			
		||||
				var regObj = {};
 | 
			
		||||
				regObj.id = objectIdStr;
 | 
			
		||||
				regObj.swfVersion = swfVersionStr;
 | 
			
		||||
				regObj.expressInstall = xiSwfUrlStr;
 | 
			
		||||
				regObj.callbackFn = callbackFn;
 | 
			
		||||
				regObjArr[regObjArr.length] = regObj;
 | 
			
		||||
				setVisibility(objectIdStr, false);
 | 
			
		||||
			}
 | 
			
		||||
			else if (callbackFn) {
 | 
			
		||||
				callbackFn({success:false, id:objectIdStr});
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		
 | 
			
		||||
		getObjectById: function(objectIdStr) {
 | 
			
		||||
			if (ua.w3) {
 | 
			
		||||
				return getObjectById(objectIdStr);
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		
 | 
			
		||||
		embedSWF: function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj, callbackFn) {
 | 
			
		||||
			var callbackObj = {success:false, id:replaceElemIdStr};
 | 
			
		||||
			if (ua.w3 && !(ua.wk && ua.wk < 312) && swfUrlStr && replaceElemIdStr && widthStr && heightStr && swfVersionStr) {
 | 
			
		||||
				setVisibility(replaceElemIdStr, false);
 | 
			
		||||
				addDomLoadEvent(function() {
 | 
			
		||||
					widthStr += ""; // auto-convert to string
 | 
			
		||||
					heightStr += "";
 | 
			
		||||
					var att = {};
 | 
			
		||||
					if (attObj && typeof attObj === OBJECT) {
 | 
			
		||||
						for (var i in attObj) { // copy object to avoid the use of references, because web authors often reuse attObj for multiple SWFs
 | 
			
		||||
							att[i] = attObj[i];
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					att.data = swfUrlStr;
 | 
			
		||||
					att.width = widthStr;
 | 
			
		||||
					att.height = heightStr;
 | 
			
		||||
					var par = {}; 
 | 
			
		||||
					if (parObj && typeof parObj === OBJECT) {
 | 
			
		||||
						for (var j in parObj) { // copy object to avoid the use of references, because web authors often reuse parObj for multiple SWFs
 | 
			
		||||
							par[j] = parObj[j];
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					if (flashvarsObj && typeof flashvarsObj === OBJECT) {
 | 
			
		||||
						for (var k in flashvarsObj) { // copy object to avoid the use of references, because web authors often reuse flashvarsObj for multiple SWFs
 | 
			
		||||
							if (typeof par.flashvars != UNDEF) {
 | 
			
		||||
								par.flashvars += "&" + k + "=" + flashvarsObj[k];
 | 
			
		||||
							}
 | 
			
		||||
							else {
 | 
			
		||||
								par.flashvars = k + "=" + flashvarsObj[k];
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					if (hasPlayerVersion(swfVersionStr)) { // create SWF
 | 
			
		||||
						var obj = createSWF(att, par, replaceElemIdStr);
 | 
			
		||||
						if (att.id == replaceElemIdStr) {
 | 
			
		||||
							setVisibility(replaceElemIdStr, true);
 | 
			
		||||
						}
 | 
			
		||||
						callbackObj.success = true;
 | 
			
		||||
						callbackObj.ref = obj;
 | 
			
		||||
					}
 | 
			
		||||
					else if (xiSwfUrlStr && canExpressInstall()) { // show Adobe Express Install
 | 
			
		||||
						att.data = xiSwfUrlStr;
 | 
			
		||||
						showExpressInstall(att, par, replaceElemIdStr, callbackFn);
 | 
			
		||||
						return;
 | 
			
		||||
					}
 | 
			
		||||
					else { // show alternative content
 | 
			
		||||
						setVisibility(replaceElemIdStr, true);
 | 
			
		||||
					}
 | 
			
		||||
					if (callbackFn) { callbackFn(callbackObj); }
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
			else if (callbackFn) { callbackFn(callbackObj);	}
 | 
			
		||||
		},
 | 
			
		||||
		
 | 
			
		||||
		switchOffAutoHideShow: function() {
 | 
			
		||||
			autoHideShow = false;
 | 
			
		||||
		},
 | 
			
		||||
		
 | 
			
		||||
		ua: ua,
 | 
			
		||||
		
 | 
			
		||||
		getFlashPlayerVersion: function() {
 | 
			
		||||
			return { major:ua.pv[0], minor:ua.pv[1], release:ua.pv[2] };
 | 
			
		||||
		},
 | 
			
		||||
		
 | 
			
		||||
		hasFlashPlayerVersion: hasPlayerVersion,
 | 
			
		||||
		
 | 
			
		||||
		createSWF: function(attObj, parObj, replaceElemIdStr) {
 | 
			
		||||
			if (ua.w3) {
 | 
			
		||||
				return createSWF(attObj, parObj, replaceElemIdStr);
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				return undefined;
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		
 | 
			
		||||
		showExpressInstall: function(att, par, replaceElemIdStr, callbackFn) {
 | 
			
		||||
			if (ua.w3 && canExpressInstall()) {
 | 
			
		||||
				showExpressInstall(att, par, replaceElemIdStr, callbackFn);
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		
 | 
			
		||||
		removeSWF: function(objElemIdStr) {
 | 
			
		||||
			if (ua.w3) {
 | 
			
		||||
				removeSWF(objElemIdStr);
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		
 | 
			
		||||
		createCSS: function(selStr, declStr, mediaStr, newStyleBoolean) {
 | 
			
		||||
			if (ua.w3) {
 | 
			
		||||
				createCSS(selStr, declStr, mediaStr, newStyleBoolean);
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		
 | 
			
		||||
		addDomLoadEvent: addDomLoadEvent,
 | 
			
		||||
		
 | 
			
		||||
		addLoadEvent: addLoadEvent,
 | 
			
		||||
		
 | 
			
		||||
		getQueryParamValue: function(param) {
 | 
			
		||||
			var q = doc.location.search || doc.location.hash;
 | 
			
		||||
			if (q) {
 | 
			
		||||
				if (/\?/.test(q)) { q = q.split("?")[1]; } // strip question mark
 | 
			
		||||
				if (param == null) {
 | 
			
		||||
					return urlEncodeIfNecessary(q);
 | 
			
		||||
				}
 | 
			
		||||
				var pairs = q.split("&");
 | 
			
		||||
				for (var i = 0; i < pairs.length; i++) {
 | 
			
		||||
					if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) {
 | 
			
		||||
						return urlEncodeIfNecessary(pairs[i].substring((pairs[i].indexOf("=") + 1)));
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return "";
 | 
			
		||||
		},
 | 
			
		||||
		
 | 
			
		||||
		// For internal usage only
 | 
			
		||||
		expressInstallCallback: function() {
 | 
			
		||||
			if (isExpressInstallActive) {
 | 
			
		||||
				var obj = getElementById(EXPRESS_INSTALL_ID);
 | 
			
		||||
				if (obj && storedAltContent) {
 | 
			
		||||
					obj.parentNode.replaceChild(storedAltContent, obj);
 | 
			
		||||
					if (storedAltContentId) {
 | 
			
		||||
						setVisibility(storedAltContentId, true);
 | 
			
		||||
						if (ua.ie && ua.win) { storedAltContent.style.display = "block"; }
 | 
			
		||||
					}
 | 
			
		||||
					if (storedCallbackFn) { storedCallbackFn(storedCallbackObj); }
 | 
			
		||||
				}
 | 
			
		||||
				isExpressInstallActive = false;
 | 
			
		||||
			} 
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
}();
 | 
			
		||||
							
								
								
									
										47
									
								
								trunk/research/players/srs_bwt.html
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										47
									
								
								trunk/research/players/srs_bwt.html
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,47 @@
 | 
			
		|||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
    <title>SRS</title>   
 | 
			
		||||
    <meta charset="utf-8">
 | 
			
		||||
    <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
 | 
			
		||||
    <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/bootstrap.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/swfobject.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/srs.js"></script>
 | 
			
		||||
    <style>
 | 
			
		||||
        body{
 | 
			
		||||
            padding-top: 55px;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
    <script type="text/javascript">
 | 
			
		||||
        $(function(){
 | 
			
		||||
            update_nav();
 | 
			
		||||
        });
 | 
			
		||||
    </script>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<div class="navbar navbar-fixed-top">
 | 
			
		||||
    <div class="navbar-inner">
 | 
			
		||||
        <div class="container">
 | 
			
		||||
        <a class="brand" href="index.html">SRS</a>
 | 
			
		||||
            <div class="nav-collapse collapse">
 | 
			
		||||
                <ul class="nav">
 | 
			
		||||
                    <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
 | 
			
		||||
                    <li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
 | 
			
		||||
                    <li class="active"><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
 | 
			
		||||
                    <li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>
 | 
			
		||||
                    <li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>
 | 
			
		||||
                    <li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
<div class="container">
 | 
			
		||||
    <hr>
 | 
			
		||||
    <footer>
 | 
			
		||||
        <p><a href="https://github.com/winlinvip/simple-rtmp-server">SRS Team © 2013</a></p>
 | 
			
		||||
    </footer>
 | 
			
		||||
</div>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										523
									
								
								trunk/research/players/srs_player.html
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										523
									
								
								trunk/research/players/srs_player.html
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,523 @@
 | 
			
		|||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
    <title>SRS</title>   
 | 
			
		||||
    <meta charset="utf-8">
 | 
			
		||||
    <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
 | 
			
		||||
    <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/bootstrap.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/swfobject.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/srs.js"></script>
 | 
			
		||||
    <style>
 | 
			
		||||
        body{
 | 
			
		||||
            padding-top: 55px;
 | 
			
		||||
        }
 | 
			
		||||
        #my_modal_footer {
 | 
			
		||||
            margin-top: -20px;
 | 
			
		||||
            padding-top: 3px;
 | 
			
		||||
        }
 | 
			
		||||
        #div_play_time {
 | 
			
		||||
            margin-top: 10px;
 | 
			
		||||
        }
 | 
			
		||||
        #pb_buffer_bg {
 | 
			
		||||
            margin-top: -4px;
 | 
			
		||||
            margin-bottom: 10px;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
    <script type="text/javascript">
 | 
			
		||||
        var srs_player = null;
 | 
			
		||||
        var url = null;
 | 
			
		||||
        
 | 
			
		||||
        var __active_dar = null;
 | 
			
		||||
        function select_dar(dar_id, num, den) {
 | 
			
		||||
            srs_player.dar(num, den);
 | 
			
		||||
            
 | 
			
		||||
            if (__active_dar) {
 | 
			
		||||
                __active_dar.removeClass("active");
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            __active_dar = $(dar_id).parent();
 | 
			
		||||
            __active_dar.addClass("active");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        var __active_size = null;
 | 
			
		||||
        function select_fs_size(size_id, refer, percent) {
 | 
			
		||||
            srs_player.set_fs(refer, percent);
 | 
			
		||||
            
 | 
			
		||||
            if (__active_size) {
 | 
			
		||||
                __active_size.removeClass("active");
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            __active_size = $(size_id).parent();
 | 
			
		||||
            __active_size.addClass("active");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        var __active_bt = null;
 | 
			
		||||
        function select_buffer_time(bt_id, buffer_time) {
 | 
			
		||||
            srs_player.set_bt(buffer_time);
 | 
			
		||||
            
 | 
			
		||||
            if (__active_bt) {
 | 
			
		||||
                __active_bt.removeClass("active");
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            __active_bt = $(bt_id).parent();
 | 
			
		||||
            __active_bt.addClass("active");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $(function(){
 | 
			
		||||
            // get the vhost and port to set the default url.
 | 
			
		||||
            // for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo
 | 
			
		||||
            // url set to: rtmp://demo:1935/live/livestream
 | 
			
		||||
            srs_init("#txt_url", null, "#main_modal");
 | 
			
		||||
            
 | 
			
		||||
            $("#fs_tips").tooltip({
 | 
			
		||||
                title: "点击视频进入或退出全屏"
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            $("#main_modal").on("show", function(){
 | 
			
		||||
                if (srs_player) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                $("#div_container").remove();
 | 
			
		||||
                
 | 
			
		||||
                var div_container = $("<div/>");
 | 
			
		||||
                $(div_container).attr("id", "div_container");
 | 
			
		||||
                $("#player").append(div_container);
 | 
			
		||||
                
 | 
			
		||||
                var player = $("<div/>");
 | 
			
		||||
                $(player).attr("id", "player_id");
 | 
			
		||||
                $(div_container).append(player);
 | 
			
		||||
                
 | 
			
		||||
                srs_player = new SrsPlayer("player_id", srs_get_player_width(), srs_get_player_height());
 | 
			
		||||
                srs_player.on_player_ready = function() {
 | 
			
		||||
                    select_buffer_time("#btn_bt_0_8", 0.8);
 | 
			
		||||
                    srs_player.play(url);
 | 
			
		||||
                };
 | 
			
		||||
                srs_player.on_player_metadata = function(metadata) {
 | 
			
		||||
                    $("#btn_dar_original").text("视频原始比例" + "(" + metadata.width + ":" + metadata.height + ")");
 | 
			
		||||
                    select_dar("#btn_dar_original", 0, 0);
 | 
			
		||||
                    select_fs_size("#btn_fs_size_screen_100", "screen", 100);
 | 
			
		||||
                };
 | 
			
		||||
                srs_player.on_player_timer = function(time, buffer_length) {
 | 
			
		||||
                    var buffer = buffer_length / srs_player.buffer_time * 100;
 | 
			
		||||
                    $("#pb_buffer").width(Number(buffer).toFixed(1) + "%");
 | 
			
		||||
                    
 | 
			
		||||
                    $("#pb_buffer_bg").attr("title", 
 | 
			
		||||
                        "缓冲区长度:" + Number(buffer_length).toFixed(1) + "秒(" 
 | 
			
		||||
                        + Number(buffer).toFixed(1) + "%)");
 | 
			
		||||
                    
 | 
			
		||||
                    var time_str = "";
 | 
			
		||||
                    // day
 | 
			
		||||
                    time_str = padding(parseInt(time / 24 / 3600), 2, '0') + " ";
 | 
			
		||||
                    // hour
 | 
			
		||||
                    time = time % (24 * 3600);
 | 
			
		||||
                    time_str += padding(parseInt(time / 3600), 2, '0') + ":";
 | 
			
		||||
                    // minute
 | 
			
		||||
                    time = time % (3600);
 | 
			
		||||
                    time_str += padding(parseInt(time / 60), 2, '0') + ":";
 | 
			
		||||
                    // seconds
 | 
			
		||||
                    time = time % (60);
 | 
			
		||||
                    time_str += padding(parseInt(time), 2, '0');
 | 
			
		||||
                    // show
 | 
			
		||||
                    $("#txt_time").val(time_str);
 | 
			
		||||
                };
 | 
			
		||||
                srs_player.start();
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            $("#main_modal").on("hide", function(){
 | 
			
		||||
                if ($("#main_modal").is(":visible")) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                if (srs_player) {
 | 
			
		||||
                    srs_player.stop();
 | 
			
		||||
                    srs_player = null;
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            $("#btn_play").click(function(){
 | 
			
		||||
                url = $("#txt_url").val();
 | 
			
		||||
                $("#main_modal").modal({show:true, keyboard:false});
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            $("#btn_pause").click(function(){
 | 
			
		||||
                if ($("#btn_pause").text() == "暂停") {
 | 
			
		||||
                    $("#btn_pause").text("继续");
 | 
			
		||||
                    srs_player.pause();
 | 
			
		||||
                } else {
 | 
			
		||||
                    $("#btn_pause").text("暂停");
 | 
			
		||||
                    srs_player.resume();
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            $("#srs_publish").click(function(){
 | 
			
		||||
                url = $("#srs_publish").text();
 | 
			
		||||
                $("#main_modal").modal({show:true, keyboard:false});
 | 
			
		||||
            });
 | 
			
		||||
            $("#srs_publish_ld").click(function(){
 | 
			
		||||
                url = $("#srs_publish_ld").text();
 | 
			
		||||
                $("#main_modal").modal({show:true, keyboard:false});
 | 
			
		||||
            });
 | 
			
		||||
            $("#srs_publish_sd").click(function(){
 | 
			
		||||
                url = $("#srs_publish_sd").text();
 | 
			
		||||
                $("#main_modal").modal({show:true, keyboard:false});
 | 
			
		||||
            });
 | 
			
		||||
            $("#srs_publish_fw").click(function(){
 | 
			
		||||
                url = $("#srs_publish_fw").text();
 | 
			
		||||
                $("#main_modal").modal({show:true, keyboard:false});
 | 
			
		||||
            });
 | 
			
		||||
            $("#srs_publish_fw_ld").click(function(){
 | 
			
		||||
                url = $("#srs_publish_fw_ld").text();
 | 
			
		||||
                $("#main_modal").modal({show:true, keyboard:false});
 | 
			
		||||
            });
 | 
			
		||||
            $("#srs_publish_fw_sd").click(function(){
 | 
			
		||||
                url = $("#srs_publish_fw_sd").text();
 | 
			
		||||
                $("#main_modal").modal({show:true, keyboard:false});
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            var query = parse_query_string();
 | 
			
		||||
            var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?vhost=demo.srs.com&app=live&hls_autostart=true";
 | 
			
		||||
            $("#srs_publish_hls").attr("href", jwplayer_url + "&stream=livestream");
 | 
			
		||||
            $("#srs_publish_ld_hls").attr("href", jwplayer_url + "&stream=livestream_ld");
 | 
			
		||||
            $("#srs_publish_sd_hls").attr("href", jwplayer_url + "&stream=livestream_sd");
 | 
			
		||||
            var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?vhost=demo.srs.com&app=forward/live&hls_autostart=true";
 | 
			
		||||
            $("#srs_publish_fw_hls").attr("href", jwplayer_url + "&stream=livestream");
 | 
			
		||||
            $("#srs_publish_fw_ld_hls").attr("href", jwplayer_url + "&stream=livestream_ld");
 | 
			
		||||
            $("#srs_publish_fw_sd_hls").attr("href", jwplayer_url + "&stream=livestream_sd");
 | 
			
		||||
            
 | 
			
		||||
            if (true) {
 | 
			
		||||
                $("#btn_dar_original").click(function(){
 | 
			
		||||
                    select_dar("#btn_dar_original", 0, 0);
 | 
			
		||||
                });
 | 
			
		||||
                $("#btn_dar_21_9").click(function(){
 | 
			
		||||
                    select_dar("#btn_dar_21_9", 9, 21);
 | 
			
		||||
                });
 | 
			
		||||
                $("#btn_dar_16_9").click(function(){
 | 
			
		||||
                    select_dar("#btn_dar_16_9", 9, 16);
 | 
			
		||||
                });
 | 
			
		||||
                $("#btn_dar_4_3").click(function(){
 | 
			
		||||
                    select_dar("#btn_dar_4_3", 3, 4);
 | 
			
		||||
                });
 | 
			
		||||
                $("#btn_dar_fill").click(function(){
 | 
			
		||||
                    select_dar("#btn_dar_fill", -1, -1);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if (true) {
 | 
			
		||||
                $("#btn_fs_size_video_100").click(function(){
 | 
			
		||||
                    select_fs_size("#btn_fs_size_video_100", "video", 100);
 | 
			
		||||
                });
 | 
			
		||||
                $("#btn_fs_size_video_75").click(function(){
 | 
			
		||||
                    select_fs_size("#btn_fs_size_video_75", "video", 75);
 | 
			
		||||
                });
 | 
			
		||||
                $("#btn_fs_size_video_50").click(function(){
 | 
			
		||||
                    select_fs_size("#btn_fs_size_video_50", "video", 50);
 | 
			
		||||
                });
 | 
			
		||||
                $("#btn_fs_size_screen_100").click(function(){
 | 
			
		||||
                    select_fs_size("#btn_fs_size_screen_100", "screen", 100);
 | 
			
		||||
                });
 | 
			
		||||
                $("#btn_fs_size_screen_75").click(function(){
 | 
			
		||||
                    select_fs_size("#btn_fs_size_screen_75", "screen", 75);
 | 
			
		||||
                });
 | 
			
		||||
                $("#btn_fs_size_screen_50").click(function(){
 | 
			
		||||
                    select_fs_size("#btn_fs_size_screen_50", "screen", 50);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if (true) {
 | 
			
		||||
                $("#btn_bt_0_5").click(function(){
 | 
			
		||||
                    select_buffer_time("#btn_bt_0_5", 0.5);
 | 
			
		||||
                });
 | 
			
		||||
                $("#btn_bt_0_8").click(function(){
 | 
			
		||||
                    select_buffer_time("#btn_bt_0_8", 0.8);
 | 
			
		||||
                });
 | 
			
		||||
                $("#btn_bt_1").click(function(){
 | 
			
		||||
                    select_buffer_time("#btn_bt_1", 1);
 | 
			
		||||
                });
 | 
			
		||||
                $("#btn_bt_2").click(function(){
 | 
			
		||||
                    select_buffer_time("#btn_bt_2", 2);
 | 
			
		||||
                });
 | 
			
		||||
                $("#btn_bt_3").click(function(){
 | 
			
		||||
                    select_buffer_time("#btn_bt_3", 3);
 | 
			
		||||
                });
 | 
			
		||||
                $("#btn_bt_5").click(function(){
 | 
			
		||||
                    select_buffer_time("#btn_bt_5", 5);
 | 
			
		||||
                });
 | 
			
		||||
                $("#btn_bt_10").click(function(){
 | 
			
		||||
                    select_buffer_time("#btn_bt_10", 10);
 | 
			
		||||
                });
 | 
			
		||||
                $("#btn_bt_30").click(function(){
 | 
			
		||||
                    select_buffer_time("#btn_bt_30", 30);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            var query = parse_query_string();
 | 
			
		||||
            if (query.autostart == "true") {
 | 
			
		||||
                url = $("#txt_url").val();
 | 
			
		||||
                $("#main_modal").modal({show:true, keyboard:false});
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    </script>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<div class="navbar navbar-fixed-top">
 | 
			
		||||
    <div class="navbar-inner">
 | 
			
		||||
        <div class="container">
 | 
			
		||||
        <a class="brand" href="index.html">SRS</a>
 | 
			
		||||
            <div class="nav-collapse collapse">
 | 
			
		||||
                <ul class="nav">
 | 
			
		||||
                    <li class="active"><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
 | 
			
		||||
                    <li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
 | 
			
		||||
                    <li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
 | 
			
		||||
                    <li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>
 | 
			
		||||
                    <li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>
 | 
			
		||||
                    <li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
<div class="container">
 | 
			
		||||
    <div class="alert alert-info fade in">
 | 
			
		||||
        <button type="button" class="close" data-dismiss="alert">×</button>
 | 
			
		||||
        <strong><span>Usage:</span></strong> <span>输入RTMP/HTTP地址后点击“播放视频”即可播放视频</span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="form-inline">
 | 
			
		||||
        URL:
 | 
			
		||||
        <input type="text" id="txt_url" class="input-xxlarge" value=""></input>
 | 
			
		||||
        <button class="btn btn-primary" id="btn_play">播放视频</button>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="container">
 | 
			
		||||
        <hr/>
 | 
			
		||||
        <span>
 | 
			
		||||
            注意:必须按照<a href="https://github.com/winlinvip/simple-rtmp-server/blob/master/README.md">SRS README.md</a>
 | 
			
		||||
            中的11个Step做完,下面所有的链接才能观看。
 | 
			
		||||
        </span>
 | 
			
		||||
        <div class="accordion" id="main_accordion">
 | 
			
		||||
            <div class="accordion-group">
 | 
			
		||||
                <div class="accordion-heading">
 | 
			
		||||
                    <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse1">
 | 
			
		||||
                        <strong>[1] SRS示例播放流: 原始流</strong>
 | 
			
		||||
                    </span>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div id="collapse1" class="accordion-body collapse">
 | 
			
		||||
                    <div class="accordion-inner">
 | 
			
		||||
                        <a href="#" id="srs_publish">rtmp://demo.srs.com/live/livestream</a> <br/>
 | 
			
		||||
                        <span>用户推送过来的唯一一路流,经过服务器的多种变换和再转发。</span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="accordion-group">
 | 
			
		||||
                <div class="accordion-heading">
 | 
			
		||||
                    <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse10">
 | 
			
		||||
                        <strong>[2] SRS示例播放流: 原始流HLS</strong>
 | 
			
		||||
                    </span>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div id="collapse10" class="accordion-body collapse">
 | 
			
		||||
                    <div class="accordion-inner">
 | 
			
		||||
                        <a href="#" id="srs_publish_hls">http://demo.srs.com/live/livestream.m3u8</a> <br/>
 | 
			
		||||
                        <span>对用户的流进行HLS切片(若编码为非H264/AAC,HLS流会自动禁用)。</span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="accordion-group">
 | 
			
		||||
                <div class="accordion-heading">
 | 
			
		||||
                    <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse2">
 | 
			
		||||
                        <strong>[3] SRS示例播放流: 转码配置LD流</strong>
 | 
			
		||||
                    </span>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div id="collapse2" class="accordion-body collapse">
 | 
			
		||||
                    <div class="accordion-inner">
 | 
			
		||||
                        <a href="#" id="srs_publish_ld">rtmp://demo.srs.com/live/livestream_ld</a> <br/>
 | 
			
		||||
                        <span>对原始流加了<a href="http://ffmpeg.org/ffmpeg-filters.html#drawtext-1">FFMPEG文字水印</a></span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="accordion-group">
 | 
			
		||||
                <div class="accordion-heading">
 | 
			
		||||
                    <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse11">
 | 
			
		||||
                        <strong>[4] SRS示例播放流: 转码配置LD流HLS</strong>
 | 
			
		||||
                    </span>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div id="collapse11" class="accordion-body collapse">
 | 
			
		||||
                    <div class="accordion-inner">
 | 
			
		||||
                        <a href="#" id="srs_publish_ld_hls">http://demo.srs.com/live/livestream_ld.m3u8</a> <br/>
 | 
			
		||||
                        <span>对转码配置LD流进行HLS切片。</span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="accordion-group">
 | 
			
		||||
                <div class="accordion-heading">
 | 
			
		||||
                    <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse3">
 | 
			
		||||
                        <strong>[5] SRS示例播放流: 转码配置SD流</strong>
 | 
			
		||||
                    </span>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div id="collapse3" class="accordion-body collapse">
 | 
			
		||||
                    <div class="accordion-inner">
 | 
			
		||||
                        <a href="#" id="srs_publish_sd">rtmp://demo.srs.com/live/livestream_sd</a> <br/>
 | 
			
		||||
                        <span>对原始流应用了<a href="http://ffmpeg.org/ffmpeg-filters.html#Filtering-Introduction">FFMPEG翻转滤镜</a></span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="accordion-group">
 | 
			
		||||
                <div class="accordion-heading">
 | 
			
		||||
                    <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse12">
 | 
			
		||||
                        <strong>[6] SRS示例播放流: 转码配置SD流HLS</strong>
 | 
			
		||||
                    </span>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div id="collapse12" class="accordion-body collapse">
 | 
			
		||||
                    <div class="accordion-inner">
 | 
			
		||||
                        <a href="#" id="srs_publish_sd_hls">http://demo.srs.com/live/livestream_sd.m3u8</a> <br/>
 | 
			
		||||
                        <span>对转码配置SD流进行HLS切片。</span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="accordion-group">
 | 
			
		||||
                <div class="accordion-heading">
 | 
			
		||||
                    <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse4">
 | 
			
		||||
                        <strong>[7] SRS示例播放流: 转发原始流</strong>
 | 
			
		||||
                    </span>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div id="collapse4" class="accordion-body collapse">
 | 
			
		||||
                    <div class="accordion-inner">
 | 
			
		||||
                        <a href="#" id="srs_publish_fw">rtmp://demo.srs.com:19350/live/livestream</a> <br/>
 | 
			
		||||
                        <span>将用户推送的流转发到另外的vhost或服务器,做热备用。</span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="accordion-group">
 | 
			
		||||
                <div class="accordion-heading">
 | 
			
		||||
                    <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse13">
 | 
			
		||||
                        <strong>[8] SRS示例播放流: 转发原始流HLS</strong>
 | 
			
		||||
                    </span>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div id="collapse13" class="accordion-body collapse">
 | 
			
		||||
                    <div class="accordion-inner">
 | 
			
		||||
                        <a href="#" id="srs_publish_fw_hls">http://demo.srs.com/forward/live/livestream.m3u8</a> <br/>
 | 
			
		||||
                        <span>对转发原始流进行HLS切片(若编码为非H264/AAC,HLS流会自动禁用)。</span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="accordion-group">
 | 
			
		||||
                <div class="accordion-heading">
 | 
			
		||||
                    <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse5">
 | 
			
		||||
                        <strong>[9] SRS示例播放流: 转发转码配置LD流</strong>
 | 
			
		||||
                    </span>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div id="collapse5" class="accordion-body collapse">
 | 
			
		||||
                    <div class="accordion-inner">
 | 
			
		||||
                        <a href="#" id="srs_publish_fw_ld">rtmp://demo.srs.com:19350/live/livestream_ld</a> <br/>
 | 
			
		||||
                        <span>FFMPEG加水印后的流也会自动转发。</span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="accordion-group">
 | 
			
		||||
                <div class="accordion-heading">
 | 
			
		||||
                    <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse14">
 | 
			
		||||
                        <strong>[10] SRS示例播放流: 转发转码配置LD流HLS</strong>
 | 
			
		||||
                    </span>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div id="collapse14" class="accordion-body collapse">
 | 
			
		||||
                    <div class="accordion-inner">
 | 
			
		||||
                        <a href="#" id="srs_publish_fw_ld_hls">http://demo.srs.com/forward/live/livestream_ld.m3u8</a> <br/>
 | 
			
		||||
                        <span>对转发转码配置LD流进行HLS切片,所有转发的流会自动支持HLS。</span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="accordion-group">
 | 
			
		||||
                <div class="accordion-heading">
 | 
			
		||||
                    <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse6">
 | 
			
		||||
                        <strong>[11] SRS示例播放流: 转发转码配置SD流</strong>
 | 
			
		||||
                    </span>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div id="collapse6" class="accordion-body collapse">
 | 
			
		||||
                    <div class="accordion-inner">
 | 
			
		||||
                        <a href="#" id="srs_publish_fw_sd">rtmp://demo.srs.com:19350/live/livestream_sd</a> <br/>
 | 
			
		||||
                        <span>FFMPEG翻转后的流也会自动转发。</span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="accordion-group">
 | 
			
		||||
                <div class="accordion-heading">
 | 
			
		||||
                    <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse15">
 | 
			
		||||
                        <strong>[12] SRS示例播放流: 转发转码配置SD流HLS</strong>
 | 
			
		||||
                    </span>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div id="collapse15" class="accordion-body collapse">
 | 
			
		||||
                    <div class="accordion-inner">
 | 
			
		||||
                        <a href="#" id="srs_publish_fw_sd_hls">http://demo.srs.com/forward/live/livestream_sd.m3u8</a> <br/>
 | 
			
		||||
                        <span>对转发转码配置SD流进行HLS切片,所有转发的流会自动支持HLS。</span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div id="main_modal" class="modal hide fade">
 | 
			
		||||
        <div class="modal-header">
 | 
			
		||||
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
 | 
			
		||||
            <h3><a href="https://github.com/winlinvip/simple-rtmp-server">SrsPlayer</a></h3>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="modal-body">
 | 
			
		||||
            <div id="player"></div>
 | 
			
		||||
            <div class="progress progress-striped active" id="pb_buffer_bg">
 | 
			
		||||
                <div class="bar" style="width: 0%;" id="pb_buffer"></div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="modal-footer" id="my_modal_footer">
 | 
			
		||||
            <div class="input-prepend" id="div_play_time">
 | 
			
		||||
              <span class="add-on" title="播放时长">@T</span>
 | 
			
		||||
              <input class="span2" style="width:85px" id="txt_time" type="text" placeholder="天 时:分:秒">
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="btn-group dropup">
 | 
			
		||||
                <button class="btn dropdown-toggle" data-toggle="dropdown">
 | 
			
		||||
                    <a id="fs_tips" href="#" data-toggle="tooltip" data-placement="top" title="">
 | 
			
		||||
                        <img src="img/tooltip.png"/>
 | 
			
		||||
                    </a>
 | 
			
		||||
                    全屏大小<span class="caret"></span>
 | 
			
		||||
                </button>
 | 
			
		||||
                <ul class="dropdown-menu">
 | 
			
		||||
                    <li><a id="btn_fs_size_screen_100" href="#">屏幕大小(100%)</a></li>
 | 
			
		||||
                    <li><a id="btn_fs_size_screen_75" href="#">屏幕大小(75%)</a></li>
 | 
			
		||||
                    <li><a id="btn_fs_size_screen_50" href="#">屏幕大小(50%)</a></li>
 | 
			
		||||
                    <li><a id="btn_fs_size_video_100" href="#">视频大小(100%)</a></li>
 | 
			
		||||
                    <li><a id="btn_fs_size_video_75" href="#">视频大小(75%)</a></li>
 | 
			
		||||
                    <li><a id="btn_fs_size_video_50" href="#">视频大小(50%)</a></li>
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="btn-group dropup">
 | 
			
		||||
                <button class="btn dropdown-toggle" data-toggle="dropdown">显示比例<span class="caret"></span></button>
 | 
			
		||||
                <ul class="dropdown-menu">
 | 
			
		||||
                    <li><a id="btn_dar_original" href="#">视频原始比例</a></li>
 | 
			
		||||
                    <li><a id="btn_dar_21_9" href="#">宽屏影院(21:9)</a></li>
 | 
			
		||||
                    <li><a id="btn_dar_16_9" href="#">宽屏电视(16:9)</a></li>
 | 
			
		||||
                    <li><a id="btn_dar_4_3" href="#">窄屏(4:3)</a></li>
 | 
			
		||||
                    <li><a id="btn_dar_fill" href="#">填充(容器比例)</a></li>
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="btn-group dropup">
 | 
			
		||||
                <button class="btn dropdown-toggle" data-toggle="dropdown">缓冲区<span class="caret"></span></button>
 | 
			
		||||
                <ul class="dropdown-menu">
 | 
			
		||||
                    <li><a id="btn_bt_0_5" href="#">0.5秒(实时)</a></li>
 | 
			
		||||
                    <li><a id="btn_bt_0_8" href="#">0.8秒(会议)</a></li>
 | 
			
		||||
                    <li><a id="btn_bt_1" href="#">1秒(低延迟)</a></li>
 | 
			
		||||
                    <li><a id="btn_bt_2" href="#">2秒(较低延时)</a></li>
 | 
			
		||||
                    <li><a id="btn_bt_3" href="#">3秒(流畅播放)</a></li>
 | 
			
		||||
                    <li><a id="btn_bt_5" href="#">5秒(网速较低)</a></li>
 | 
			
		||||
                    <li><a id="btn_bt_10" href="#">10秒(无所谓延迟)</a></li>
 | 
			
		||||
                    <li><a id="btn_bt_30" href="#">30秒(流畅第一)</a></li>
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="btn-group dropup">
 | 
			
		||||
                <button id="btn_pause" class="btn">暂停</button>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="btn-group dropup">
 | 
			
		||||
                <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">关闭</button>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <footer>
 | 
			
		||||
        <p><a href="https://github.com/winlinvip/simple-rtmp-server">SRS Team © 2013</a></p>
 | 
			
		||||
    </footer>
 | 
			
		||||
</div>
 | 
			
		||||
</body>
 | 
			
		||||
							
								
								
									
										40
									
								
								trunk/research/players/srs_player/.actionScriptProperties
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										40
									
								
								trunk/research/players/srs_player/.actionScriptProperties
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,40 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<actionScriptProperties analytics="false" mainApplicationPath="srs_player.as" projectUUID="1bb41a0e-6b1f-49b5-8603-219442f9f9b3" version="10">
 | 
			
		||||
  <compiler additionalCompilerArguments="-locale en_US" autoRSLOrdering="true" copyDependentFiles="false" fteInMXComponents="false" generateAccessible="true" htmlExpressInstall="true" htmlGenerate="false" htmlHistoryManagement="true" htmlPlayerVersionCheck="true" includeNetmonSwc="false" outputFolderPath="release" removeUnusedRSL="true" sourceFolderPath="src" strict="true" targetPlayerVersion="0.0.0" useApolloConfig="false" useDebugRSLSwfs="true" verifyDigests="true" warn="true">
 | 
			
		||||
    <compilerSourcePath/>
 | 
			
		||||
    <libraryPath defaultLinkType="0">
 | 
			
		||||
      <libraryPathEntry kind="4" path="">
 | 
			
		||||
        <excludedEntries>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_charts.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="1" linkType="1" path="${PROJECT_FRAMEWORKS}/locale/{locale}"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/advancedgrids.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/qtp.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_air.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/charts.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/framework.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/mx/mx.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/netmon.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/spark.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/sparkskins.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/rpc.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/videoPlayer.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/qtp_air.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/datavisualization.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/spark_dmv.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/flash-integration.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_dmv.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_flashflexkit.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_agent.swc" useDefaultLinkType="false"/>
 | 
			
		||||
        </excludedEntries>
 | 
			
		||||
      </libraryPathEntry>
 | 
			
		||||
    </libraryPath>
 | 
			
		||||
    <sourceAttachmentPath/>
 | 
			
		||||
  </compiler>
 | 
			
		||||
  <applications>
 | 
			
		||||
    <application path="srs_player.as"/>
 | 
			
		||||
  </applications>
 | 
			
		||||
  <modules/>
 | 
			
		||||
  <buildCSSFiles/>
 | 
			
		||||
  <flashCatalyst validateFlashCatalystCompatibility="false"/>
 | 
			
		||||
</actionScriptProperties>
 | 
			
		||||
							
								
								
									
										17
									
								
								trunk/research/players/srs_player/.project
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										17
									
								
								trunk/research/players/srs_player/.project
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<projectDescription>
 | 
			
		||||
	<name>srs_player</name>
 | 
			
		||||
	<comment></comment>
 | 
			
		||||
	<projects>
 | 
			
		||||
	</projects>
 | 
			
		||||
	<buildSpec>
 | 
			
		||||
		<buildCommand>
 | 
			
		||||
			<name>com.adobe.flexbuilder.project.flexbuilder</name>
 | 
			
		||||
			<arguments>
 | 
			
		||||
			</arguments>
 | 
			
		||||
		</buildCommand>
 | 
			
		||||
	</buildSpec>
 | 
			
		||||
	<natures>
 | 
			
		||||
		<nature>com.adobe.flexbuilder.project.actionscriptnature</nature>
 | 
			
		||||
	</natures>
 | 
			
		||||
</projectDescription>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
#Wed Dec 18 10:07:19 CST 2013
 | 
			
		||||
eclipse.preferences.version=1
 | 
			
		||||
encoding/<project>=utf-8
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								trunk/research/players/srs_player/release/srs_player.swf
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								trunk/research/players/srs_player/release/srs_player.swf
									
										
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										506
									
								
								trunk/research/players/srs_player/src/srs_player.as
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										506
									
								
								trunk/research/players/srs_player/src/srs_player.as
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,506 @@
 | 
			
		|||
package
 | 
			
		||||
{
 | 
			
		||||
    import flash.display.Sprite;
 | 
			
		||||
    import flash.display.StageAlign;
 | 
			
		||||
    import flash.display.StageDisplayState;
 | 
			
		||||
    import flash.display.StageScaleMode;
 | 
			
		||||
    import flash.events.Event;
 | 
			
		||||
    import flash.events.FullScreenEvent;
 | 
			
		||||
    import flash.events.MouseEvent;
 | 
			
		||||
    import flash.events.NetStatusEvent;
 | 
			
		||||
    import flash.events.TimerEvent;
 | 
			
		||||
    import flash.external.ExternalInterface;
 | 
			
		||||
    import flash.media.Video;
 | 
			
		||||
    import flash.net.NetConnection;
 | 
			
		||||
    import flash.net.NetStream;
 | 
			
		||||
    import flash.system.Security;
 | 
			
		||||
    import flash.ui.ContextMenu;
 | 
			
		||||
    import flash.ui.ContextMenuItem;
 | 
			
		||||
    import flash.utils.Timer;
 | 
			
		||||
    import flash.utils.setTimeout;
 | 
			
		||||
    
 | 
			
		||||
    public class srs_player extends Sprite
 | 
			
		||||
    {
 | 
			
		||||
        // user set id.
 | 
			
		||||
        private var js_id:String = null;
 | 
			
		||||
        // user set callback
 | 
			
		||||
        private var js_on_player_ready:String = null;
 | 
			
		||||
        private var js_on_player_metadata:String = null;
 | 
			
		||||
        private var js_on_player_timer:String = null;
 | 
			
		||||
        
 | 
			
		||||
        // play param url.
 | 
			
		||||
        private var user_url:String = null;
 | 
			
		||||
        // play param, user set width and height
 | 
			
		||||
        private var user_w:int = 0;
 | 
			
		||||
        private var user_h:int = 0;
 | 
			
		||||
        // user set dar den:num
 | 
			
		||||
        private var user_dar_num:int = 0;
 | 
			
		||||
        private var user_dar_den:int = 0;
 | 
			
		||||
        // user set fs(fullscreen) refer and percent.
 | 
			
		||||
        private var user_fs_refer:String = null;
 | 
			
		||||
        private var user_fs_percent:int = 0;
 | 
			
		||||
        
 | 
			
		||||
        // media specified.
 | 
			
		||||
        private var media_conn:NetConnection = null;
 | 
			
		||||
        private var media_stream:NetStream = null;
 | 
			
		||||
        private var media_video:Video = null;
 | 
			
		||||
        private var media_metadata:Object = {};
 | 
			
		||||
        private var media_timer:Timer = new Timer(300);
 | 
			
		||||
        
 | 
			
		||||
        // controls.
 | 
			
		||||
        // flash donot allow js to set to fullscreen,
 | 
			
		||||
        // only allow user click to enter fullscreen.
 | 
			
		||||
        private var control_fs_mask:Sprite = new Sprite();
 | 
			
		||||
        
 | 
			
		||||
        public function srs_player()
 | 
			
		||||
        {
 | 
			
		||||
            if (!this.stage) {
 | 
			
		||||
                this.addEventListener(Event.ADDED_TO_STAGE, this.system_on_add_to_stage);
 | 
			
		||||
            } else {
 | 
			
		||||
                this.system_on_add_to_stage(null);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
        * system event callback, when this control added to stage.
 | 
			
		||||
        * the main function.
 | 
			
		||||
        */
 | 
			
		||||
        private function system_on_add_to_stage(evt:Event):void {
 | 
			
		||||
            this.removeEventListener(Event.ADDED_TO_STAGE, this.system_on_add_to_stage);
 | 
			
		||||
            
 | 
			
		||||
            this.stage.align = StageAlign.TOP_LEFT;
 | 
			
		||||
            this.stage.scaleMode = StageScaleMode.NO_SCALE;
 | 
			
		||||
            
 | 
			
		||||
            this.stage.addEventListener(FullScreenEvent.FULL_SCREEN, this.user_on_stage_fullscreen);
 | 
			
		||||
            
 | 
			
		||||
            this.addChild(this.control_fs_mask);
 | 
			
		||||
            this.control_fs_mask.buttonMode = true;
 | 
			
		||||
            this.control_fs_mask.addEventListener(MouseEvent.CLICK, user_on_click_video);
 | 
			
		||||
            
 | 
			
		||||
            this.contextMenu = new ContextMenu();
 | 
			
		||||
            this.contextMenu.hideBuiltInItems();
 | 
			
		||||
            
 | 
			
		||||
            var flashvars:Object = this.root.loaderInfo.parameters;
 | 
			
		||||
            
 | 
			
		||||
            if (!flashvars.hasOwnProperty("id")) {
 | 
			
		||||
                throw new Error("must specifies the id");
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            this.js_id = flashvars.id;
 | 
			
		||||
            this.js_on_player_ready = flashvars.on_player_ready;
 | 
			
		||||
            this.js_on_player_metadata = flashvars.on_player_metadata;
 | 
			
		||||
            this.js_on_player_timer = flashvars.on_player_timer;
 | 
			
		||||
            
 | 
			
		||||
            this.media_timer.addEventListener(TimerEvent.TIMER, this.system_on_timer);
 | 
			
		||||
            this.media_timer.start();
 | 
			
		||||
            
 | 
			
		||||
            flash.utils.setTimeout(this.system_on_js_ready, 0);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
         * system callack event, when js ready, register callback for js.
 | 
			
		||||
         * the actual main function.
 | 
			
		||||
         */
 | 
			
		||||
        private function system_on_js_ready():void {
 | 
			
		||||
            if (!flash.external.ExternalInterface.available) {
 | 
			
		||||
                trace("js not ready, try later.");
 | 
			
		||||
                flash.utils.setTimeout(this.system_on_js_ready, 100);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            flash.external.ExternalInterface.addCallback("__play", this.js_call_play);
 | 
			
		||||
            flash.external.ExternalInterface.addCallback("__stop", this.js_call_stop);
 | 
			
		||||
            flash.external.ExternalInterface.addCallback("__pause", this.js_call_pause);
 | 
			
		||||
            flash.external.ExternalInterface.addCallback("__resume", this.js_call_resume);
 | 
			
		||||
            flash.external.ExternalInterface.addCallback("__dar", this.js_call_dar);
 | 
			
		||||
            flash.external.ExternalInterface.addCallback("__set_fs", this.js_call_set_fs_size);
 | 
			
		||||
            flash.external.ExternalInterface.addCallback("__set_bt", this.js_call_set_bt);
 | 
			
		||||
            
 | 
			
		||||
            flash.external.ExternalInterface.call(this.js_on_player_ready, this.js_id);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
        * system callack event, timer to do some regular tasks.
 | 
			
		||||
        */
 | 
			
		||||
        private function system_on_timer(evt:TimerEvent):void {
 | 
			
		||||
            if (!this.media_stream) {
 | 
			
		||||
                trace("stream is null, ignore timer event.");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            trace("notify js the timer event.");
 | 
			
		||||
            flash.external.ExternalInterface.call(
 | 
			
		||||
                this.js_on_player_timer, this.js_id, this.media_stream.time, this.media_stream.bufferLength);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
         * system callack event, when got metadata from stream.
 | 
			
		||||
         * or got video dimension change event(the DAR notification), to update the metadata manually.
 | 
			
		||||
         */
 | 
			
		||||
        private function system_on_metadata(metadata:Object):void {
 | 
			
		||||
            this.media_metadata = metadata;
 | 
			
		||||
            
 | 
			
		||||
            if (metadata.hasOwnProperty("server")) {
 | 
			
		||||
                // for context menu
 | 
			
		||||
                var customItems:Array = [new ContextMenuItem("SrsPlayer")];
 | 
			
		||||
                if (metadata.hasOwnProperty("server")) {
 | 
			
		||||
                    customItems.push(new ContextMenuItem("Server: " + metadata.server));
 | 
			
		||||
                }
 | 
			
		||||
                if (metadata.hasOwnProperty("contributor")) {
 | 
			
		||||
                    customItems.push(new ContextMenuItem("Contributor: " + metadata.contributor));
 | 
			
		||||
                }
 | 
			
		||||
                contextMenu.customItems = customItems;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // for js.
 | 
			
		||||
            var obj:Object = __get_video_size_object();
 | 
			
		||||
            
 | 
			
		||||
            obj.server = 'srs';
 | 
			
		||||
            obj.contributor = 'winlin';
 | 
			
		||||
            
 | 
			
		||||
            if (metadata.hasOwnProperty("server")) {
 | 
			
		||||
                obj.server = metadata.server;
 | 
			
		||||
            }
 | 
			
		||||
            if (metadata.hasOwnProperty("contributor")) {
 | 
			
		||||
                obj.contributor = metadata.contributor;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            var code:int = flash.external.ExternalInterface.call(js_on_player_metadata, js_id, obj);
 | 
			
		||||
            if (code != 0) {
 | 
			
		||||
                throw new Error("callback on_player_metadata failed. code=" + code);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
         * player callack event, when user click video to enter or leave fullscreen.
 | 
			
		||||
         */
 | 
			
		||||
        private function user_on_stage_fullscreen(evt:FullScreenEvent):void {
 | 
			
		||||
            if (!evt.fullScreen) {
 | 
			
		||||
                __execute_user_set_dar();
 | 
			
		||||
            } else {
 | 
			
		||||
                __execute_user_enter_fullscreen();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
         * user event callback, js cannot enter the fullscreen mode, user must click to.
 | 
			
		||||
         */
 | 
			
		||||
        private function user_on_click_video(evt:MouseEvent):void {
 | 
			
		||||
            if (!this.stage.allowsFullScreen) {
 | 
			
		||||
                trace("donot allow fullscreen.");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // enter fullscreen to get the fullscreen size correctly.
 | 
			
		||||
            if (this.stage.displayState == StageDisplayState.FULL_SCREEN) {
 | 
			
		||||
                this.stage.displayState = StageDisplayState.NORMAL;
 | 
			
		||||
            } else {
 | 
			
		||||
                this.stage.displayState = StageDisplayState.FULL_SCREEN;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
         * function for js to call: to pause the stream. ignore if not play.
 | 
			
		||||
         */
 | 
			
		||||
        private function js_call_pause():void {
 | 
			
		||||
            if (this.media_stream) {
 | 
			
		||||
                this.media_stream.pause();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
         * function for js to call: to resume the stream. ignore if not play.
 | 
			
		||||
         */
 | 
			
		||||
        private function js_call_resume():void {
 | 
			
		||||
            if (this.media_stream) {
 | 
			
		||||
                this.media_stream.resume();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
         * to set the DAR, for example, DAR=16:9
 | 
			
		||||
         * @param num, for example, 9. 
 | 
			
		||||
         *       use metadata height if 0.
 | 
			
		||||
         *       use user specified height if -1.
 | 
			
		||||
         * @param den, for example, 16. 
 | 
			
		||||
         *       use metadata width if 0.
 | 
			
		||||
         *       use user specified width if -1.
 | 
			
		||||
         */
 | 
			
		||||
        private function js_call_dar(num:int, den:int):void {
 | 
			
		||||
            user_dar_num = num;
 | 
			
		||||
            user_dar_den = den;
 | 
			
		||||
            
 | 
			
		||||
            flash.utils.setTimeout(__execute_user_set_dar, 0);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
         * set the fullscreen size data.
 | 
			
		||||
         * @refer the refer fullscreen mode. it can be:
 | 
			
		||||
         *       video: use video orignal size.
 | 
			
		||||
         *       screen: use screen size to rescale video.
 | 
			
		||||
         * @param percent, the rescale percent, where
 | 
			
		||||
         *       100 means 100%.
 | 
			
		||||
         */
 | 
			
		||||
        private function js_call_set_fs_size(refer:String, percent:int):void {
 | 
			
		||||
            user_fs_refer = refer;
 | 
			
		||||
            user_fs_percent = percent;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
         * set the stream buffer time in seconds.
 | 
			
		||||
         * @buffer_time the buffer time in seconds.
 | 
			
		||||
         */
 | 
			
		||||
        private function js_call_set_bt(buffer_time:Number):void {
 | 
			
		||||
            if (this.media_stream) {
 | 
			
		||||
                this.media_stream.bufferTime = buffer_time;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
         * function for js to call: to stop the stream. ignore if not play.
 | 
			
		||||
         */
 | 
			
		||||
        private function js_call_stop():void {
 | 
			
		||||
            if (this.media_video) {
 | 
			
		||||
                this.removeChild(this.media_video);
 | 
			
		||||
                this.media_video = null;
 | 
			
		||||
            }
 | 
			
		||||
            if (this.media_stream) {
 | 
			
		||||
                this.media_stream.close();
 | 
			
		||||
                this.media_stream = null;
 | 
			
		||||
            }
 | 
			
		||||
            if (this.media_conn) {
 | 
			
		||||
                this.media_conn.close();
 | 
			
		||||
                this.media_conn = null;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
         * function for js to call: to play the stream. stop then play.
 | 
			
		||||
         * @param url, the rtmp/http url to play.
 | 
			
		||||
         * @param _width, the player width.
 | 
			
		||||
         * @param _height, the player height.
 | 
			
		||||
         * @param buffer_time, the buffer time in seconds. recommend to >=0.5
 | 
			
		||||
         */
 | 
			
		||||
        private function js_call_play(url:String, _width:int, _height:int, buffer_time:Number):void {
 | 
			
		||||
            this.user_url = url;
 | 
			
		||||
            this.user_w = _width;
 | 
			
		||||
            this.user_h = _height;
 | 
			
		||||
            trace("start to play url: " + this.user_url + ", w=" + this.user_w + ", h=" + this.user_h);
 | 
			
		||||
            
 | 
			
		||||
            js_call_stop();
 | 
			
		||||
            
 | 
			
		||||
            this.media_conn = new NetConnection();
 | 
			
		||||
            this.media_conn.client = {};
 | 
			
		||||
            this.media_conn.client.onBWDone = function():void {};
 | 
			
		||||
            this.media_conn.addEventListener(NetStatusEvent.NET_STATUS, function(evt:NetStatusEvent):void {
 | 
			
		||||
                trace ("NetConnection: code=" + evt.info.code);
 | 
			
		||||
                
 | 
			
		||||
                if (evt.info.hasOwnProperty("data") && evt.info.data) {
 | 
			
		||||
                    // for context menu
 | 
			
		||||
                    var customItems:Array = [new ContextMenuItem("SrsPlayer")];
 | 
			
		||||
                    if (evt.info.data.hasOwnProperty("srs_server")) {
 | 
			
		||||
                        customItems.push(new ContextMenuItem("Server: " + evt.info.data.srs_server));
 | 
			
		||||
                    }
 | 
			
		||||
                    if (evt.info.data.hasOwnProperty("srs_contributor")) {
 | 
			
		||||
                        customItems.push(new ContextMenuItem("Contributor: " + evt.info.data.srs_contributor));
 | 
			
		||||
                    }
 | 
			
		||||
                    contextMenu.customItems = customItems;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                // TODO: FIXME: failed event.
 | 
			
		||||
                if (evt.info.code != "NetConnection.Connect.Success") {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                media_stream = new NetStream(media_conn);
 | 
			
		||||
                media_stream.bufferTime = buffer_time;
 | 
			
		||||
                media_stream.client = {};
 | 
			
		||||
                media_stream.client.onMetaData = system_on_metadata;
 | 
			
		||||
                media_stream.addEventListener(NetStatusEvent.NET_STATUS, function(evt:NetStatusEvent):void {
 | 
			
		||||
                    trace ("NetStream: code=" + evt.info.code);
 | 
			
		||||
                    
 | 
			
		||||
                    if (evt.info.code == "NetStream.Video.DimensionChange") {
 | 
			
		||||
                        system_on_metadata(media_metadata);
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    // TODO: FIXME: failed event.
 | 
			
		||||
                });
 | 
			
		||||
                
 | 
			
		||||
                if (url.indexOf("http") == 0) {
 | 
			
		||||
                    media_stream.play(url);
 | 
			
		||||
                } else {
 | 
			
		||||
                    var streamName:String = url.substr(url.lastIndexOf("/"));
 | 
			
		||||
                    media_stream.play(streamName);
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                media_video = new Video();
 | 
			
		||||
                media_video.width = _width;
 | 
			
		||||
                media_video.height = _height;
 | 
			
		||||
                media_video.attachNetStream(media_stream);
 | 
			
		||||
                media_video.smoothing = true;
 | 
			
		||||
                addChild(media_video);
 | 
			
		||||
                
 | 
			
		||||
                __draw_black_background(_width, _height);
 | 
			
		||||
                
 | 
			
		||||
                // lowest layer, for mask to cover it.
 | 
			
		||||
                setChildIndex(media_video, 0);
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            if (url.indexOf("http") == 0) {
 | 
			
		||||
                this.media_conn.connect(null);
 | 
			
		||||
            } else {
 | 
			
		||||
                var tcUrl:String = this.user_url.substr(0, this.user_url.lastIndexOf("/"));
 | 
			
		||||
                this.media_conn.connect(tcUrl);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
        * get the "right" size of video,
 | 
			
		||||
        * 1. initialize with the original video object size.
 | 
			
		||||
        * 2. override with metadata size if specified.
 | 
			
		||||
        * 3. override with codec size if specified.
 | 
			
		||||
        */
 | 
			
		||||
        private function __get_video_size_object():Object {
 | 
			
		||||
            var obj:Object = {
 | 
			
		||||
                width: media_video.width,
 | 
			
		||||
                height: media_video.height
 | 
			
		||||
            };
 | 
			
		||||
            
 | 
			
		||||
            // override with metadata size.
 | 
			
		||||
            if (this.media_metadata.hasOwnProperty("width")) {
 | 
			
		||||
                obj.width = this.media_metadata.width;
 | 
			
		||||
            }
 | 
			
		||||
            if (this.media_metadata.hasOwnProperty("height")) {
 | 
			
		||||
                obj.height = this.media_metadata.height;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // override with codec size.
 | 
			
		||||
            if (media_video.videoWidth > 0) {
 | 
			
		||||
                obj.width = media_video.videoWidth;
 | 
			
		||||
            }
 | 
			
		||||
            if (media_video.videoHeight > 0) {
 | 
			
		||||
                obj.height = media_video.videoHeight;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            return obj;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
        * execute the enter fullscreen action.
 | 
			
		||||
        */
 | 
			
		||||
        private function __execute_user_enter_fullscreen():void {
 | 
			
		||||
            if (!user_fs_refer || user_fs_percent <= 0) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // change to video size if refer to video.
 | 
			
		||||
            var obj:Object = __get_video_size_object();
 | 
			
		||||
            
 | 
			
		||||
            // get the DAR
 | 
			
		||||
            var num:int = user_dar_num;
 | 
			
		||||
            var den:int = user_dar_den;
 | 
			
		||||
            
 | 
			
		||||
            if (num == 0) {
 | 
			
		||||
                num = obj.height;
 | 
			
		||||
            }
 | 
			
		||||
            if (num == -1) {
 | 
			
		||||
                num = this.stage.fullScreenHeight;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if (den == 0) {
 | 
			
		||||
                den = obj.width;
 | 
			
		||||
            }
 | 
			
		||||
            if (den == -1) {
 | 
			
		||||
                den = this.stage.fullScreenWidth;
 | 
			
		||||
            }
 | 
			
		||||
                
 | 
			
		||||
            // for refer is screen.
 | 
			
		||||
            if (user_fs_refer == "screen") {
 | 
			
		||||
                obj = {
 | 
			
		||||
                    width: this.stage.fullScreenWidth,
 | 
			
		||||
                    height: this.stage.fullScreenHeight
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // rescale to fs
 | 
			
		||||
            __update_video_size(num, den, obj.width * user_fs_percent / 100, obj.height * user_fs_percent / 100, this.stage.fullScreenWidth, this.stage.fullScreenHeight);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
         * for user set dar, or leave fullscreen to recover the dar.
 | 
			
		||||
         */
 | 
			
		||||
        private function __execute_user_set_dar():void {
 | 
			
		||||
            // get the DAR
 | 
			
		||||
            var num:int = user_dar_num;
 | 
			
		||||
            var den:int = user_dar_den;
 | 
			
		||||
            
 | 
			
		||||
            var obj:Object = __get_video_size_object();
 | 
			
		||||
            
 | 
			
		||||
            if (num == 0) {
 | 
			
		||||
                num = obj.height;
 | 
			
		||||
            }
 | 
			
		||||
            if (num == -1) {
 | 
			
		||||
                num = this.user_h;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if (den == 0) {
 | 
			
		||||
                den = obj.width;
 | 
			
		||||
            }
 | 
			
		||||
            if (den == -1) {
 | 
			
		||||
                den = this.user_w;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            __update_video_size(num, den, this.user_w, this.user_h, this.user_w, this.user_h);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
        * update the video width and height, 
 | 
			
		||||
        * according to the specifies DAR(den:num) and max size(w:h).
 | 
			
		||||
        * set the position of video(x,y) specifies by size(sw:sh),
 | 
			
		||||
        * and update the bg to size(sw:sh).
 | 
			
		||||
        * @param _num/_den the DAR. use to rescale the player together with paper size.
 | 
			
		||||
        * @param _w/_h the video draw paper size. used to rescale the player together with DAR.
 | 
			
		||||
        * @param _sw/_wh the stage size, >= paper size. used to center the player.
 | 
			
		||||
        */
 | 
			
		||||
        private function __update_video_size(_num:int, _den:int, _w:int, _h:int, _sw:int, _sh:int):void {
 | 
			
		||||
            if (!this.media_video || _num <= 0 || _den <= 0) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // set DAR.
 | 
			
		||||
            // calc the height by DAR
 | 
			
		||||
            var _height:int = _w * _num / _den;
 | 
			
		||||
            if (_height <= _h) {
 | 
			
		||||
                this.media_video.width = _w;
 | 
			
		||||
                this.media_video.height = _height;
 | 
			
		||||
            } else {
 | 
			
		||||
                // height overflow, calc the width by DAR
 | 
			
		||||
                var _width:int = _h * _den / _num;
 | 
			
		||||
                
 | 
			
		||||
                this.media_video.width = _width;
 | 
			
		||||
                this.media_video.height = _h;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // align center.
 | 
			
		||||
            this.media_video.x = (_sw - this.media_video.width) / 2;
 | 
			
		||||
            this.media_video.y = (_sh - this.media_video.height) / 2;
 | 
			
		||||
            
 | 
			
		||||
            __draw_black_background(_sw, _sh);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
        * draw black background and draw the fullscreen mask.
 | 
			
		||||
        */
 | 
			
		||||
        private function __draw_black_background(_width:int, _height:int):void {
 | 
			
		||||
            // draw black bg.
 | 
			
		||||
            this.graphics.beginFill(0x00, 1.0);
 | 
			
		||||
            this.graphics.drawRect(0, 0, _width, _height);
 | 
			
		||||
            this.graphics.endFill();
 | 
			
		||||
            
 | 
			
		||||
            // draw the fs mask.
 | 
			
		||||
            this.control_fs_mask.graphics.beginFill(0xff0000, 0);
 | 
			
		||||
            this.control_fs_mask.graphics.drawRect(0, 0, _width, _height);
 | 
			
		||||
            this.control_fs_mask.graphics.endFill();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										485
									
								
								trunk/research/players/srs_publisher.html
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										485
									
								
								trunk/research/players/srs_publisher.html
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,485 @@
 | 
			
		|||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
    <title>SRS</title>   
 | 
			
		||||
    <meta charset="utf-8">
 | 
			
		||||
    <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
 | 
			
		||||
    <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/bootstrap.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/swfobject.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/srs.js"></script>
 | 
			
		||||
    <style>
 | 
			
		||||
        body{
 | 
			
		||||
            padding-top: 55px;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
    <script type="text/javascript">
 | 
			
		||||
        var srs_publisher = null;
 | 
			
		||||
        var remote_player = null;
 | 
			
		||||
        var realtime_player = null;
 | 
			
		||||
        
 | 
			
		||||
        $(function(){
 | 
			
		||||
            // get the vhost and port to set the default url.
 | 
			
		||||
            // for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo
 | 
			
		||||
            // url set to: rtmp://demo:1935/live/livestream
 | 
			
		||||
            srs_init("#txt_url", null, null);
 | 
			
		||||
            
 | 
			
		||||
            $("#btn_video_settings").click(function(){
 | 
			
		||||
                $("#video_modal").modal({show:true});
 | 
			
		||||
            });
 | 
			
		||||
            $("#btn_audio_settings").click(function(){
 | 
			
		||||
                $("#audio_modal").modal({show:true});
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            $("#remote_tips").tooltip({
 | 
			
		||||
                title: "为了支持HLS输出,FLASH编码器输出的流需要经过转码(VP6=>H264,MP3=>aac),所以会黑屏较长时间,请耐心等待"
 | 
			
		||||
            });
 | 
			
		||||
            $("#low_latecy_tips").tooltip({
 | 
			
		||||
                title: "服务器不转码直接转发FLASH编码器的流,所以延迟比支持HLS的流要低很多"
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            $("#btn_publish").click(on_user_publish);
 | 
			
		||||
            
 | 
			
		||||
            // for publish, we use randome stream name.
 | 
			
		||||
            $("#txt_url").val($("#txt_url").val() + "." + new Date().getTime());
 | 
			
		||||
            
 | 
			
		||||
            // start the publisher.
 | 
			
		||||
            srs_publisher = new SrsPublisher("local_publisher", 430, 185);
 | 
			
		||||
            srs_publisher.on_publisher_ready = function(cameras, microphones) {
 | 
			
		||||
                $("#sl_cameras").empty();
 | 
			
		||||
                for (var i = 0; i < cameras.length; i++) {
 | 
			
		||||
                    $("#sl_cameras").append("<option value='" + i + "'>" + cameras[i] + "</option");
 | 
			
		||||
                }
 | 
			
		||||
                // optional: select the first no "virtual" signed.
 | 
			
		||||
                for (var i = 0; i < cameras.length; i++) {
 | 
			
		||||
                    if (cameras[i].toLowerCase().indexOf("virtual") == -1) {
 | 
			
		||||
                        $("#sl_cameras option[value='" + i + "']").attr("selected", true);
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                $("#sl_microphones").empty();
 | 
			
		||||
                for (var i = 0; i < microphones.length; i++) {
 | 
			
		||||
                    $("#sl_microphones").append("<option value='" + i + "'>" + microphones[i] + "</option");
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                $("#sl_vcodec").empty();
 | 
			
		||||
                var vcodecs = ["h264", "vp6"];
 | 
			
		||||
                for (var i = 0; i < vcodecs.length; i++) {
 | 
			
		||||
                    $("#sl_vcodec").append("<option value='" + vcodecs[i] + "'>" + vcodecs[i] + "</option");
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                $("#sl_profile").empty();
 | 
			
		||||
                var profiles = ["baseline", "main"];
 | 
			
		||||
                for (var i = 0; i < profiles.length; i++) {
 | 
			
		||||
                    $("#sl_profile").append("<option value='" + profiles[i] + "'>" + profiles[i] + "</option");
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                $("#sl_level").empty();
 | 
			
		||||
                var levels = ["1", "1b", "1.1", "1.2", "1.3", 
 | 
			
		||||
                    "2", "2.1", "2.2", "3", "3.1", "3.2", "4", "4.1", "4.2", "5", "5.1"];
 | 
			
		||||
                for (var i = 0; i < levels.length; i++) {
 | 
			
		||||
                    $("#sl_level").append("<option value='" + levels[i] + "'>" + levels[i] + "</option");
 | 
			
		||||
                }
 | 
			
		||||
                $("#sl_level option[value='4.1']").attr("selected", true);
 | 
			
		||||
                
 | 
			
		||||
                $("#sl_gop").empty();
 | 
			
		||||
                var gops = ["0.3", "0.5", "1", "2", "3", "4", 
 | 
			
		||||
                    "5", "6", "7", "8", "9", "10", "15", "20"];
 | 
			
		||||
                for (var i = 0; i < gops.length; i++) {
 | 
			
		||||
                    $("#sl_gop").append("<option value='" + gops[i] + "'>" + gops[i] + "秒</option");
 | 
			
		||||
                }
 | 
			
		||||
                $("#sl_gop option[value='5']").attr("selected", true);
 | 
			
		||||
                
 | 
			
		||||
                $("#sl_size").empty();
 | 
			
		||||
                var sizes = ["176x144", "320x240", "352x240", 
 | 
			
		||||
                    "352x288", "460x240", "640x480", "720x480", "720x576", "800x600", 
 | 
			
		||||
                    "1024x768", "1280x720", "1360x768", "1920x1080"];
 | 
			
		||||
                for (i = 0; i < sizes.length; i++) {
 | 
			
		||||
                    $("#sl_size").append("<option value='" + sizes[i] + "'>" + sizes[i] + "</option");
 | 
			
		||||
                }
 | 
			
		||||
                $("#sl_size option[value='460x240']").attr("selected", true);
 | 
			
		||||
                
 | 
			
		||||
                $("#sl_fps").empty();
 | 
			
		||||
                var fpses = ["5", "10", "15", "20", "24", "25", "29.97", "30"];
 | 
			
		||||
                for (i = 0; i < fpses.length; i++) {
 | 
			
		||||
                    $("#sl_fps").append("<option value='" + fpses[i] + "'>" + Number(fpses[i]).toFixed(2) + " 帧/秒</option");
 | 
			
		||||
                }
 | 
			
		||||
                $("#sl_fps option[value='15']").attr("selected", true);
 | 
			
		||||
                
 | 
			
		||||
                $("#sl_bitrate").empty();
 | 
			
		||||
                var bitrates = ["50", "200", "350", "500", "650", "800", 
 | 
			
		||||
                    "950", "1000", "1200", "1500", "1800", "2000", "3000", "5000"];
 | 
			
		||||
                for (i = 0; i < bitrates.length; i++) {
 | 
			
		||||
                    $("#sl_bitrate").append("<option value='" + bitrates[i] + "'>" + bitrates[i] + " kbps</option");
 | 
			
		||||
                }
 | 
			
		||||
                $("#sl_bitrate option[value='350']").attr("selected", true);
 | 
			
		||||
            };
 | 
			
		||||
            srs_publisher.on_publisher_error = function(code, desc) {
 | 
			
		||||
                error(code, desc);
 | 
			
		||||
            };
 | 
			
		||||
            srs_publisher.on_publisher_warn = function(code, desc) {
 | 
			
		||||
                warn(code, desc);
 | 
			
		||||
            };
 | 
			
		||||
            srs_publisher.start();
 | 
			
		||||
            
 | 
			
		||||
            // if no play specified, donot show the player, for debug the publisher.
 | 
			
		||||
            var query = parse_query_string();
 | 
			
		||||
            if (query.no_play != "true") {
 | 
			
		||||
                // start the normal player with HLS supported.
 | 
			
		||||
                remote_player = new SrsPlayer("remote_player", 430, 185);
 | 
			
		||||
                remote_player.on_player_ready = function() {
 | 
			
		||||
                    remote_player.set_bt(0.8);
 | 
			
		||||
                    remote_player.set_fs("screen", 100);
 | 
			
		||||
                };
 | 
			
		||||
                remote_player.start();
 | 
			
		||||
                
 | 
			
		||||
                // start the realtime player.
 | 
			
		||||
                realtime_player = new SrsPlayer("realtime_player", 430, 185);
 | 
			
		||||
                realtime_player.on_player_ready = function() {
 | 
			
		||||
                    realtime_player.set_bt(0.8);
 | 
			
		||||
                    realtime_player.set_fs("screen", 100);
 | 
			
		||||
                };
 | 
			
		||||
                realtime_player.start();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
        * we generate the transcoded stream url for flash publish donot support HLS
 | 
			
		||||
        * which requires aac, so the publish vhost maybe players for example, we
 | 
			
		||||
        * use players_pub vhost(transcoded stream to which) for all clients,
 | 
			
		||||
        * both players and players_pub are write HLS to the sample dir, 
 | 
			
		||||
        * it's ok for the players vhost disabled the HLS, only the 
 | 
			
		||||
        * players_pub enalbed HLS.
 | 
			
		||||
        */
 | 
			
		||||
        function update_play_url() {
 | 
			
		||||
            var url = $("#txt_url").val();
 | 
			
		||||
            var ret = srs_parse_rtmp_url(url);
 | 
			
		||||
            var query = parse_query_string();
 | 
			
		||||
            
 | 
			
		||||
            var srs_player_url = "http://" + query.host + query.dir + "/srs_player.html?";
 | 
			
		||||
            srs_player_url += "vhost=" + srs_get_player_publish_vhost(ret.vhost) + "&port=" + ret.port + "&app=" + ret.app + "&stream=" + ret.stream;
 | 
			
		||||
            srs_player_url += "&autostart=true";
 | 
			
		||||
            
 | 
			
		||||
            var srs_player_rt_url = "http://" + query.host + query.dir + "/srs_player.html?";
 | 
			
		||||
            srs_player_rt_url += "vhost=" + ret.vhost + "&port=" + ret.port + "&app=" + ret.app + "&stream=" + ret.stream;
 | 
			
		||||
            srs_player_rt_url += "&autostart=true";
 | 
			
		||||
            
 | 
			
		||||
            var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?";
 | 
			
		||||
            jwplayer_url += "vhost=" + srs_get_player_publish_vhost(ret.vhost) + "&port=" + ret.port + "&app=" + ret.app + "&stream=" + ret.stream;
 | 
			
		||||
            jwplayer_url += "&hls_autostart=true";
 | 
			
		||||
            
 | 
			
		||||
            var hls_url = "http://" + ret.server + ":" + query.http_port + "/" + ret.app + "/" + ret.stream + ".m3u8";
 | 
			
		||||
            
 | 
			
		||||
            $("#txt_play_realtime").text("RTMP低延时(点击打开)").attr("href", srs_player_rt_url).attr("target", "_blank");
 | 
			
		||||
            $("#txt_play_url").text("RTMP已转码(点击打开)").attr("href", srs_player_url).attr("target", "_blank");
 | 
			
		||||
            $("#txt_play_hls").text("HLS-m3u8(点击打开或右键复制)").attr("href", hls_url).attr("target", "_blank");
 | 
			
		||||
            $("#txt_play_jwplayer").text("HLS-JWPlayer(点击打开)").attr("href", jwplayer_url).attr("target", "_blank");
 | 
			
		||||
        }
 | 
			
		||||
        function on_user_publish() {
 | 
			
		||||
            if ($("#btn_publish").text() == "停止发布") {
 | 
			
		||||
                srs_publisher.stop();
 | 
			
		||||
                $("#btn_publish").text("发布视频");
 | 
			
		||||
                $("#txt_play_realtime").text("RTMP低延时(请发布视频)").attr("href", "#").attr("target", "_self");
 | 
			
		||||
                $("#txt_play_url").text("RTMP已转码(请发布视频)").attr("href", "#").attr("target", "_self");
 | 
			
		||||
                $("#txt_play_hls").text("HLS-m3u8(请发布视频)").attr("href", "#").attr("target", "_self");
 | 
			
		||||
                $("#txt_play_jwplayer").text("HLS-JWPlayer(请发布视频)").attr("href", "#").attr("target", "_self");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            $("#btn_publish").text("停止发布");
 | 
			
		||||
            
 | 
			
		||||
            update_play_url();
 | 
			
		||||
            
 | 
			
		||||
            var url = $("#txt_url").val();
 | 
			
		||||
            var vcodec = {};
 | 
			
		||||
            var acodec = {};
 | 
			
		||||
            
 | 
			
		||||
            acodec.device_code = $("#sl_microphones").val();
 | 
			
		||||
            acodec.device_name = $("#sl_microphones").text();
 | 
			
		||||
            
 | 
			
		||||
            vcodec.device_code = $("#sl_cameras").find("option:selected").val();
 | 
			
		||||
            vcodec.device_name = $("#sl_cameras").find("option:selected").text();
 | 
			
		||||
            
 | 
			
		||||
            vcodec.codec = $("#sl_vcodec").find("option:selected").val();
 | 
			
		||||
            vcodec.profile = $("#sl_profile").find("option:selected").val();
 | 
			
		||||
            vcodec.level = $("#sl_level").find("option:selected").val();
 | 
			
		||||
            vcodec.fps = $("#sl_fps").find("option:selected").val();
 | 
			
		||||
            vcodec.gop = $("#sl_gop").find("option:selected").val();
 | 
			
		||||
            vcodec.size = $("#sl_size").find("option:selected").val();
 | 
			
		||||
            vcodec.bitrate = $("#sl_bitrate").find("option:selected").val();
 | 
			
		||||
            
 | 
			
		||||
            info("开始推流到服务器");
 | 
			
		||||
            srs_publisher.publish(url, vcodec, acodec);
 | 
			
		||||
            
 | 
			
		||||
            if (realtime_player) {
 | 
			
		||||
                // directly play the url for the realtime player.
 | 
			
		||||
                realtime_player.stop();
 | 
			
		||||
                realtime_player.play(url);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if (remote_player) {
 | 
			
		||||
                // the normal player should play the transcoded stream in another vhost.
 | 
			
		||||
                // for example, publish stream to vhost players,
 | 
			
		||||
                // the realtime player play the vhost players, which may donot support HLS,
 | 
			
		||||
                // the normal player play the vhost players_pub, which transcoded to h264/aac with HLS.
 | 
			
		||||
                var ret = srs_parse_rtmp_url(url);
 | 
			
		||||
                var pub_url = "rtmp://" + ret.server + ":" + ret.port + "/" + ret.app;
 | 
			
		||||
                pub_url += "?vhost=" + srs_get_player_publish_vhost(ret.vhost) + "/" + ret.stream;
 | 
			
		||||
                remote_player.stop();
 | 
			
		||||
                remote_player.play(pub_url);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function info(desc) {
 | 
			
		||||
            $("#txt_log").addClass("alert-info").removeClass("alert-error").removeClass("alert-warn");
 | 
			
		||||
            $("#txt_log_title").text("Info:");
 | 
			
		||||
            $("#txt_log_msg").text(desc);
 | 
			
		||||
        }
 | 
			
		||||
        function warn(code, desc) {
 | 
			
		||||
            $("#txt_log").removeClass("alert-info").removeClass("alert-error").addClass("alert-warn");
 | 
			
		||||
            $("#txt_log_title").text("Warn:");
 | 
			
		||||
            $("#txt_log_msg").text("code: " + code + ", " + desc);
 | 
			
		||||
        }
 | 
			
		||||
        function error(code, desc) {
 | 
			
		||||
            $("#txt_log").removeClass("alert-info").addClass("alert-error").removeClass("alert-warn");
 | 
			
		||||
            $("#txt_log_title").text("Error:");
 | 
			
		||||
            $("#txt_log_msg").text("code: " + code + ", " + desc);
 | 
			
		||||
        }
 | 
			
		||||
    </script>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<div class="navbar navbar-fixed-top">
 | 
			
		||||
    <div class="navbar-inner">
 | 
			
		||||
        <div class="container">
 | 
			
		||||
        <a class="brand" href="index.html">SRS</a>
 | 
			
		||||
            <div class="nav-collapse collapse">
 | 
			
		||||
                <ul class="nav">
 | 
			
		||||
                    <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
 | 
			
		||||
                    <li class="active"><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
 | 
			
		||||
                    <li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
 | 
			
		||||
                    <li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>
 | 
			
		||||
                    <li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>
 | 
			
		||||
                    <li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
<div class="container">
 | 
			
		||||
    <div class="alert alert-info fade in" id="txt_log">
 | 
			
		||||
        <button type="button" class="close" data-dismiss="alert">×</button>
 | 
			
		||||
        <strong><span id="txt_log_title">Usage:</span></strong>
 | 
			
		||||
        <span id="txt_log_msg">设置编码参数,点“发布视频”,允许Flash访问摄像头即可推流</span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="control-group">
 | 
			
		||||
        <div class="form-inline">
 | 
			
		||||
            <button class="btn" id="btn_video_settings">视频编码配置</button>
 | 
			
		||||
            <button class="btn" id="btn_audio_settings">音频编码配置</button>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="control-group">
 | 
			
		||||
        <div class="form-inline">
 | 
			
		||||
            发布地址:
 | 
			
		||||
            <input type="text" id="txt_url" class="input-xxlarge" value=""></input>
 | 
			
		||||
            <button class="btn btn-primary" id="btn_publish">发布视频</button>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="control-group">
 | 
			
		||||
        <div class="form-inline">
 | 
			
		||||
            播放地址
 | 
			
		||||
            1.<a id="txt_play_realtime" class="input-xxlarge" href="#">RTMP低延时(请发布视频)</a>
 | 
			
		||||
            2.<a id="txt_play_url" class="input-xxlarge" href="#">RTMP已转码(请发布视频)</a>
 | 
			
		||||
            3.<a id="txt_play_hls" class="input-xxlarge" href="#">HLS-m3u8(请发布视频)</a>
 | 
			
		||||
            4.<a id="txt_play_jwplayer" class="input-xxlarge" href="#">HLS-JWPlayer(请发布视频)</a>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div id="video_modal" class="modal hide fade">
 | 
			
		||||
        <div class="modal-header">
 | 
			
		||||
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
 | 
			
		||||
            <h3>视频编码</h3>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="modal-body">
 | 
			
		||||
            <div class="form-horizontal">
 | 
			
		||||
                <div class="control-group">
 | 
			
		||||
                    <label class="control-label" for="sl_cameras">
 | 
			
		||||
                        摄像头
 | 
			
		||||
                        <a id="sl_cameras_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
 | 
			
		||||
                            <img src="img/tooltip.png"/>
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <div class="controls">
 | 
			
		||||
                        <select class="span4" id="sl_cameras"></select>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="control-group">
 | 
			
		||||
                    <label class="control-label" for="sl_vcodec">
 | 
			
		||||
                        Codec
 | 
			
		||||
                        <a id="sl_cameras_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
 | 
			
		||||
                            <img src="img/tooltip.png"/>
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <div class="controls">
 | 
			
		||||
                        <select class="span2" id="sl_vcodec"></select>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="control-group">
 | 
			
		||||
                    <label class="control-label" for="sl_profile">
 | 
			
		||||
                        Profile
 | 
			
		||||
                        <a id="sl_profile_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
 | 
			
		||||
                            <img src="img/tooltip.png"/>
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <div class="controls">
 | 
			
		||||
                        <select class="span2" id="sl_profile"></select>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="control-group">
 | 
			
		||||
                    <label class="control-label" for="sl_level">
 | 
			
		||||
                        Level
 | 
			
		||||
                        <a id="sl_level_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
 | 
			
		||||
                            <img src="img/tooltip.png"/>
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <div class="controls">
 | 
			
		||||
                        <select class="span2" id="sl_level"></select>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="control-group">
 | 
			
		||||
                    <label class="control-label" for="sl_gop">
 | 
			
		||||
                        GOP
 | 
			
		||||
                        <a id="sl_gop_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
 | 
			
		||||
                            <img src="img/tooltip.png"/>
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <div class="controls">
 | 
			
		||||
                        <select class="span2" id="sl_gop"></select>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="control-group">
 | 
			
		||||
                    <label class="control-label" for="sl_size">
 | 
			
		||||
                        尺寸
 | 
			
		||||
                        <a id="sl_size_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
 | 
			
		||||
                            <img src="img/tooltip.png"/>
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <div class="controls">
 | 
			
		||||
                        <select class="span2" id="sl_size"></select>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="control-group">
 | 
			
		||||
                    <label class="control-label" for="sl_fps">
 | 
			
		||||
                        帧率
 | 
			
		||||
                        <a id="sl_fps_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
 | 
			
		||||
                            <img src="img/tooltip.png"/>
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <div class="controls">
 | 
			
		||||
                        <select class="span2" id="sl_fps"></select>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="control-group">
 | 
			
		||||
                    <label class="control-label" for="sl_bitrate">
 | 
			
		||||
                        码率
 | 
			
		||||
                        <a id="sl_bitrate_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
 | 
			
		||||
                            <img src="img/tooltip.png"/>
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <div class="controls">
 | 
			
		||||
                        <select class="span2" id="sl_bitrate"></select>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="modal-footer">
 | 
			
		||||
            <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">设置</button>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div id="audio_modal" class="modal hide fade">
 | 
			
		||||
        <div class="modal-header">
 | 
			
		||||
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
 | 
			
		||||
            <h3>音频编码</h3>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="modal-body">
 | 
			
		||||
            <div class="form-horizontal">
 | 
			
		||||
                <div class="control-group">
 | 
			
		||||
                    <label class="control-label" for="sl_microphones">
 | 
			
		||||
                        麦克风
 | 
			
		||||
                        <a id="worker_id_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
 | 
			
		||||
                            <img src="img/tooltip.png"/>
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <div class="controls">
 | 
			
		||||
                        <select class="span4" id="sl_microphones"></select>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="modal-footer">
 | 
			
		||||
            <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">设置</button>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="container">
 | 
			
		||||
        <div class="row-fluid">
 | 
			
		||||
            <div class="span6">
 | 
			
		||||
                <div class="accordion-group">
 | 
			
		||||
                    <div class="accordion-heading">
 | 
			
		||||
                        <span class="accordion-toggle" data-toggle="collapse" href="#collapse1">
 | 
			
		||||
                            <strong>本地摄像头</strong>
 | 
			
		||||
                        </span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div id="collapse1" class="accordion-body collapse in">
 | 
			
		||||
                        <div class="accordion-inner">
 | 
			
		||||
                            <div id="local_publisher"></div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="span6">
 | 
			
		||||
                <div class="accordion-group">
 | 
			
		||||
                    <div class="accordion-heading">
 | 
			
		||||
                        <span class="accordion-toggle" data-toggle="collapse" href="#collapse2">
 | 
			
		||||
                            <strong>远程服务器</strong>
 | 
			
		||||
                            <a id="remote_tips" href="#" data-toggle="tooltip" data-placement="top" title="">
 | 
			
		||||
                                黑屏<img src="img/tooltip.png"/>
 | 
			
		||||
                            </a>
 | 
			
		||||
                        </span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div id="collapse2" class="accordion-body collapse in">
 | 
			
		||||
                        <div class="accordion-inner">
 | 
			
		||||
                            <div id="remote_player"></div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="container">
 | 
			
		||||
        <div class="row-fluid">
 | 
			
		||||
            <div class="span6">
 | 
			
		||||
                <div class="accordion-group">
 | 
			
		||||
                    <div class="accordion-heading">
 | 
			
		||||
                        <span class="accordion-toggle" data-toggle="collapse" href="#collapse3">
 | 
			
		||||
                            <strong>远程服务器</strong>
 | 
			
		||||
                            <a id="low_latecy_tips" href="#" data-toggle="tooltip" data-placement="top" title="">
 | 
			
		||||
                                低延时<img src="img/tooltip.png"/>
 | 
			
		||||
                            </a>
 | 
			
		||||
                        </span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div id="collapse3" class="accordion-body collapse in">
 | 
			
		||||
                        <div class="accordion-inner">
 | 
			
		||||
                            <div id="realtime_player"></div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="span6">
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <footer>
 | 
			
		||||
        <p><a href="https://github.com/winlinvip/simple-rtmp-server">SRS Team © 2013</a></p>
 | 
			
		||||
    </footer>
 | 
			
		||||
</div>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										40
									
								
								trunk/research/players/srs_publisher/.actionScriptProperties
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										40
									
								
								trunk/research/players/srs_publisher/.actionScriptProperties
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,40 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<actionScriptProperties analytics="false" mainApplicationPath="srs_publisher.as" projectUUID="f002791f-ee2e-41b7-aa3a-a7af6c65aa58" version="10">
 | 
			
		||||
  <compiler additionalCompilerArguments="-locale en_US" autoRSLOrdering="true" copyDependentFiles="false" fteInMXComponents="false" generateAccessible="true" htmlExpressInstall="true" htmlGenerate="false" htmlHistoryManagement="true" htmlPlayerVersionCheck="true" includeNetmonSwc="false" outputFolderPath="release" removeUnusedRSL="true" sourceFolderPath="src" strict="true" targetPlayerVersion="0.0.0" useApolloConfig="false" useDebugRSLSwfs="true" verifyDigests="true" warn="true">
 | 
			
		||||
    <compilerSourcePath/>
 | 
			
		||||
    <libraryPath defaultLinkType="0">
 | 
			
		||||
      <libraryPathEntry kind="4" path="">
 | 
			
		||||
        <excludedEntries>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_charts.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="1" linkType="1" path="${PROJECT_FRAMEWORKS}/locale/{locale}"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/advancedgrids.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/qtp.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_air.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/charts.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/framework.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/mx/mx.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/netmon.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/spark.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/sparkskins.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/rpc.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/videoPlayer.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/qtp_air.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/datavisualization.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/spark_dmv.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/flash-integration.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_dmv.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_flashflexkit.swc" useDefaultLinkType="false"/>
 | 
			
		||||
          <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_agent.swc" useDefaultLinkType="false"/>
 | 
			
		||||
        </excludedEntries>
 | 
			
		||||
      </libraryPathEntry>
 | 
			
		||||
    </libraryPath>
 | 
			
		||||
    <sourceAttachmentPath/>
 | 
			
		||||
  </compiler>
 | 
			
		||||
  <applications>
 | 
			
		||||
    <application path="srs_publisher.as"/>
 | 
			
		||||
  </applications>
 | 
			
		||||
  <modules/>
 | 
			
		||||
  <buildCSSFiles/>
 | 
			
		||||
  <flashCatalyst validateFlashCatalystCompatibility="false"/>
 | 
			
		||||
</actionScriptProperties>
 | 
			
		||||
							
								
								
									
										17
									
								
								trunk/research/players/srs_publisher/.project
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										17
									
								
								trunk/research/players/srs_publisher/.project
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<projectDescription>
 | 
			
		||||
	<name>srs_publisher</name>
 | 
			
		||||
	<comment></comment>
 | 
			
		||||
	<projects>
 | 
			
		||||
	</projects>
 | 
			
		||||
	<buildSpec>
 | 
			
		||||
		<buildCommand>
 | 
			
		||||
			<name>com.adobe.flexbuilder.project.flexbuilder</name>
 | 
			
		||||
			<arguments>
 | 
			
		||||
			</arguments>
 | 
			
		||||
		</buildCommand>
 | 
			
		||||
	</buildSpec>
 | 
			
		||||
	<natures>
 | 
			
		||||
		<nature>com.adobe.flexbuilder.project.actionscriptnature</nature>
 | 
			
		||||
	</natures>
 | 
			
		||||
</projectDescription>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
#Wed Dec 18 10:10:45 CST 2013
 | 
			
		||||
eclipse.preferences.version=1
 | 
			
		||||
encoding/<project>=utf-8
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								trunk/research/players/srs_publisher/release/srs_publisher.swf
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								trunk/research/players/srs_publisher/release/srs_publisher.swf
									
										
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										340
									
								
								trunk/research/players/srs_publisher/src/srs_publisher.as
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										340
									
								
								trunk/research/players/srs_publisher/src/srs_publisher.as
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,340 @@
 | 
			
		|||
package
 | 
			
		||||
{
 | 
			
		||||
    import flash.display.Sprite;
 | 
			
		||||
    import flash.display.StageAlign;
 | 
			
		||||
    import flash.display.StageScaleMode;
 | 
			
		||||
    import flash.events.Event;
 | 
			
		||||
    import flash.events.NetStatusEvent;
 | 
			
		||||
    import flash.external.ExternalInterface;
 | 
			
		||||
    import flash.media.Camera;
 | 
			
		||||
    import flash.media.H264Profile;
 | 
			
		||||
    import flash.media.H264VideoStreamSettings;
 | 
			
		||||
    import flash.media.Microphone;
 | 
			
		||||
    import flash.media.Video;
 | 
			
		||||
    import flash.net.NetConnection;
 | 
			
		||||
    import flash.net.NetStream;
 | 
			
		||||
    import flash.ui.ContextMenu;
 | 
			
		||||
    import flash.ui.ContextMenuItem;
 | 
			
		||||
    import flash.utils.setTimeout;
 | 
			
		||||
    
 | 
			
		||||
    public class srs_publisher extends Sprite
 | 
			
		||||
    {
 | 
			
		||||
        // user set id.
 | 
			
		||||
        private var js_id:String = null;
 | 
			
		||||
        // user set callback
 | 
			
		||||
        private var js_on_publisher_ready:String = null;
 | 
			
		||||
        private var js_on_publisher_error:String = null;
 | 
			
		||||
        private var js_on_publisher_warn:String = null;
 | 
			
		||||
        
 | 
			
		||||
        // publish param url.
 | 
			
		||||
        private var user_url:String = null;
 | 
			
		||||
        // play param, user set width and height
 | 
			
		||||
        private var user_w:int = 0;
 | 
			
		||||
        private var user_h:int = 0;
 | 
			
		||||
        private var user_vcodec:Object = {};
 | 
			
		||||
        private var user_acodec:Object = {};
 | 
			
		||||
        
 | 
			
		||||
        // media specified.
 | 
			
		||||
        private var media_conn:NetConnection = null;
 | 
			
		||||
        private var media_stream:NetStream = null;
 | 
			
		||||
        private var media_video:Video = null;
 | 
			
		||||
        private var media_camera:Camera = null;
 | 
			
		||||
        private var media_microphone:Microphone = null;
 | 
			
		||||
        
 | 
			
		||||
        // error code.
 | 
			
		||||
        private const error_camera_get:int = 100;
 | 
			
		||||
        private const error_microphone_get:int = 101;
 | 
			
		||||
        private const error_camera_muted:int = 102;
 | 
			
		||||
        
 | 
			
		||||
        public function srs_publisher()
 | 
			
		||||
        {
 | 
			
		||||
            if (!this.stage) {
 | 
			
		||||
                this.addEventListener(Event.ADDED_TO_STAGE, this.system_on_add_to_stage);
 | 
			
		||||
            } else {
 | 
			
		||||
                this.system_on_add_to_stage(null);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
         * system event callback, when this control added to stage.
 | 
			
		||||
         * the main function.
 | 
			
		||||
         */
 | 
			
		||||
        private function system_on_add_to_stage(evt:Event):void {
 | 
			
		||||
            this.removeEventListener(Event.ADDED_TO_STAGE, this.system_on_add_to_stage);
 | 
			
		||||
            
 | 
			
		||||
            this.stage.align = StageAlign.TOP_LEFT;
 | 
			
		||||
            this.stage.scaleMode = StageScaleMode.NO_SCALE;
 | 
			
		||||
            
 | 
			
		||||
            this.contextMenu = new ContextMenu();
 | 
			
		||||
            this.contextMenu.hideBuiltInItems();
 | 
			
		||||
            
 | 
			
		||||
            var flashvars:Object = this.root.loaderInfo.parameters;
 | 
			
		||||
            
 | 
			
		||||
            if (!flashvars.hasOwnProperty("id")) {
 | 
			
		||||
                throw new Error("must specifies the id");
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            this.js_id = flashvars.id;
 | 
			
		||||
            this.js_on_publisher_ready = flashvars.on_publisher_ready;
 | 
			
		||||
            this.js_on_publisher_error = flashvars.on_publisher_error;
 | 
			
		||||
            this.js_on_publisher_warn = flashvars.on_publisher_warn;
 | 
			
		||||
            
 | 
			
		||||
            flash.utils.setTimeout(this.system_on_js_ready, 0);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
         * system callack event, when js ready, register callback for js.
 | 
			
		||||
         * the actual main function.
 | 
			
		||||
         */
 | 
			
		||||
        private function system_on_js_ready():void {
 | 
			
		||||
            if (!flash.external.ExternalInterface.available) {
 | 
			
		||||
                trace("js not ready, try later.");
 | 
			
		||||
                flash.utils.setTimeout(this.system_on_js_ready, 100);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            flash.external.ExternalInterface.addCallback("__publish", this.js_call_publish);
 | 
			
		||||
            flash.external.ExternalInterface.addCallback("__stop", this.js_call_stop);
 | 
			
		||||
            
 | 
			
		||||
            var cameras:Array = Camera.names;
 | 
			
		||||
            var microphones:Array = Microphone.names;
 | 
			
		||||
            trace("retrieve system cameras(" + cameras + ") and microphones(" + microphones + ")");
 | 
			
		||||
            
 | 
			
		||||
            flash.external.ExternalInterface.call(this.js_on_publisher_ready, this.js_id, cameras, microphones);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
        * notify the js an error occur.
 | 
			
		||||
        */
 | 
			
		||||
        private function system_error(code:int, desc:String):void {
 | 
			
		||||
            trace("system error, code=" + code + ", error=" + desc);
 | 
			
		||||
            flash.external.ExternalInterface.call(this.js_on_publisher_error, this.js_id, code);
 | 
			
		||||
        }
 | 
			
		||||
        private function system_warn(code:int, desc:String):void {
 | 
			
		||||
            trace("system warn, code=" + code + ", error=" + desc);
 | 
			
		||||
            flash.external.ExternalInterface.call(this.js_on_publisher_warn, this.js_id, code);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
         * publish stream to server.
 | 
			
		||||
         * @param url a string indicates the rtmp url to publish.
 | 
			
		||||
         * @param _width, the player width.
 | 
			
		||||
         * @param _height, the player height.
 | 
			
		||||
         * @param vcodec an object contains the video codec info.
 | 
			
		||||
         * @param acodec an object contains the audio codec info.
 | 
			
		||||
         */
 | 
			
		||||
        private function js_call_publish(url:String, _width:int, _height:int, vcodec:Object, acodec:Object):void {
 | 
			
		||||
            trace("start to publish to " + url + ", vcodec " + JSON.stringify(vcodec) + ", acodec " + JSON.stringify(acodec));
 | 
			
		||||
            
 | 
			
		||||
            this.user_url = url;
 | 
			
		||||
            this.user_w = _width;
 | 
			
		||||
            this.user_h = _height;
 | 
			
		||||
            this.user_vcodec = vcodec;
 | 
			
		||||
            this.user_acodec = acodec;
 | 
			
		||||
            
 | 
			
		||||
            this.js_call_stop();
 | 
			
		||||
            
 | 
			
		||||
            // microphone and camera
 | 
			
		||||
            var m:Microphone = Microphone.getMicrophone(acodec.device_code);
 | 
			
		||||
            if(m == null){
 | 
			
		||||
                this.system_error(this.error_microphone_get, "failed to open microphone " + acodec.device_code + "(" + acodec.device_name + ")");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            // ignore muted, for flash will require user to access it.
 | 
			
		||||
            
 | 
			
		||||
            // Remark: the name is the index!
 | 
			
		||||
            var c:Camera = Camera.getCamera(vcodec.device_code);
 | 
			
		||||
            if(c == null){
 | 
			
		||||
                this.system_error(this.error_camera_get, "failed to open camera " + vcodec.device_code + "(" + vcodec.device_name + ")");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            // ignore muted, for flash will require user to access it.
 | 
			
		||||
            // but we still warn user.
 | 
			
		||||
            if(c && c.muted){
 | 
			
		||||
                this.system_warn(this.error_camera_muted, "Access Denied, camera " + vcodec.device_code + "(" + vcodec.device_name + ") is muted");
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            this.media_camera = c;
 | 
			
		||||
            this.media_microphone = m;
 | 
			
		||||
            
 | 
			
		||||
            this.media_conn = new NetConnection();
 | 
			
		||||
            this.media_conn.client = {};
 | 
			
		||||
            this.media_conn.client.onBWDone = function():void {};
 | 
			
		||||
            this.media_conn.addEventListener(NetStatusEvent.NET_STATUS, function(evt:NetStatusEvent):void {
 | 
			
		||||
                trace ("NetConnection: code=" + evt.info.code);
 | 
			
		||||
                
 | 
			
		||||
                if (evt.info.hasOwnProperty("data") && evt.info.data) {
 | 
			
		||||
                    // for context menu
 | 
			
		||||
                    var customItems:Array = [new ContextMenuItem("SrsPlayer")];
 | 
			
		||||
                    if (evt.info.data.hasOwnProperty("srs_server")) {
 | 
			
		||||
                        customItems.push(new ContextMenuItem("Server: " + evt.info.data.srs_server));
 | 
			
		||||
                    }
 | 
			
		||||
                    if (evt.info.data.hasOwnProperty("srs_contributor")) {
 | 
			
		||||
                        customItems.push(new ContextMenuItem("Contributor: " + evt.info.data.srs_contributor));
 | 
			
		||||
                    }
 | 
			
		||||
                    contextMenu.customItems = customItems;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                // TODO: FIXME: failed event.
 | 
			
		||||
                if (evt.info.code != "NetConnection.Connect.Success") {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                media_stream = new NetStream(media_conn);
 | 
			
		||||
                media_stream.client = {};
 | 
			
		||||
                media_stream.addEventListener(NetStatusEvent.NET_STATUS, function(evt:NetStatusEvent):void {
 | 
			
		||||
                    trace ("NetStream: code=" + evt.info.code);
 | 
			
		||||
                    
 | 
			
		||||
                    // TODO: FIXME: failed event.
 | 
			
		||||
                });
 | 
			
		||||
                
 | 
			
		||||
                __build_video_codec(media_stream, c, vcodec);
 | 
			
		||||
                __build_audio_codec(media_stream, m, acodec);
 | 
			
		||||
                
 | 
			
		||||
                if (media_microphone) {
 | 
			
		||||
                    media_stream.attachAudio(m);
 | 
			
		||||
                }
 | 
			
		||||
                if (media_camera) {
 | 
			
		||||
                    media_stream.attachCamera(c);
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                var streamName:String = url.substr(url.lastIndexOf("/"));
 | 
			
		||||
                media_stream.publish(streamName);
 | 
			
		||||
                
 | 
			
		||||
                media_video = new Video();
 | 
			
		||||
                media_video.width = _width;
 | 
			
		||||
                media_video.height = _height;
 | 
			
		||||
                media_video.attachCamera(media_camera);
 | 
			
		||||
                media_video.smoothing = true;
 | 
			
		||||
                addChild(media_video);
 | 
			
		||||
                
 | 
			
		||||
                //__draw_black_background(_width, _height);
 | 
			
		||||
                
 | 
			
		||||
                // lowest layer, for mask to cover it.
 | 
			
		||||
                setChildIndex(media_video, 0);
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            var tcUrl:String = this.user_url.substr(0, this.user_url.lastIndexOf("/"));
 | 
			
		||||
            this.media_conn.connect(tcUrl);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
         * function for js to call: to stop the stream. ignore if not publish.
 | 
			
		||||
         */
 | 
			
		||||
        private function js_call_stop():void {
 | 
			
		||||
            if (this.media_video) {
 | 
			
		||||
                this.removeChild(this.media_video);
 | 
			
		||||
                this.media_video = null;
 | 
			
		||||
            }
 | 
			
		||||
            if (this.media_stream) {
 | 
			
		||||
                this.media_stream.close();
 | 
			
		||||
                this.media_stream = null;
 | 
			
		||||
            }
 | 
			
		||||
            if (this.media_conn) {
 | 
			
		||||
                this.media_conn.close();
 | 
			
		||||
                this.media_conn = null;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        private function __build_audio_codec(stream:NetStream, m:Microphone, acodec:Object):void {
 | 
			
		||||
            if (!m) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // if no microphone, donot set the params.
 | 
			
		||||
            if(m == null){
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // use default values.
 | 
			
		||||
            var microEncodeQuality:int = 8;
 | 
			
		||||
            var microRate:int = 22; // 22 === 22050 Hz
 | 
			
		||||
            
 | 
			
		||||
            trace("[Publish] audio encoding parameters: " 
 | 
			
		||||
                + "audio(microphone) encodeQuality=" + microEncodeQuality
 | 
			
		||||
                + ", rate=" + microRate + "(22050Hz)"
 | 
			
		||||
            );
 | 
			
		||||
            
 | 
			
		||||
            // The encoded speech quality when using the Speex codec. Possible values are from 0 to 10. The default value is 6. Higher numbers 
 | 
			
		||||
            // represent higher quality but require more bandwidth, as shown in the following table. The bit rate values that are listed represent 
 | 
			
		||||
            // net bit rates and do not include packetization overhead.
 | 
			
		||||
            m.encodeQuality = microEncodeQuality;
 | 
			
		||||
            
 | 
			
		||||
            // The rate at which the microphone is capturing sound, in kHz. Acceptable values are 5, 8, 11, 22, and 44. The default value is 8 kHz 
 | 
			
		||||
            // if your sound capture device supports this value. Otherwise, the default value is the next available capture level above 8 kHz that 
 | 
			
		||||
            // your sound capture device supports, usually 11 kHz.
 | 
			
		||||
            m.rate = microRate;
 | 
			
		||||
        }
 | 
			
		||||
        private function __build_video_codec(stream:NetStream, c:Camera, vcodec:Object):void {
 | 
			
		||||
            if (!c) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if(vcodec.codec == "vp6"){
 | 
			
		||||
                trace("use VP6, donot use H.264 publish encoding.");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var x264profile:String = (vcodec.profile == "main") ? H264Profile.MAIN : H264Profile.BASELINE;
 | 
			
		||||
            var x264level:String = vcodec.level;
 | 
			
		||||
            var cameraFps:Number = Number(vcodec.fps);
 | 
			
		||||
            var x264KeyFrameInterval:int = int(vcodec.gop * cameraFps);
 | 
			
		||||
            var cameraWidth:int = String(vcodec.size).split("x")[0];
 | 
			
		||||
            var cameraHeight:int = String(vcodec.size).split("x")[1];
 | 
			
		||||
            var cameraBitrate:int = int(vcodec.bitrate);
 | 
			
		||||
            
 | 
			
		||||
            // use default values.
 | 
			
		||||
            var cameraQuality:int = 85;
 | 
			
		||||
            
 | 
			
		||||
            trace("[Publish] video h.264(x264) encoding parameters: " 
 | 
			
		||||
                + "profile=" + x264profile 
 | 
			
		||||
                + ", level=" + x264level
 | 
			
		||||
                + ", keyFrameInterval(gop)=" + x264KeyFrameInterval
 | 
			
		||||
                + "; video(camera) width=" + cameraWidth
 | 
			
		||||
                + ", height=" + cameraHeight
 | 
			
		||||
                + ", fps=" + cameraFps
 | 
			
		||||
                + ", bitrate=" + cameraBitrate
 | 
			
		||||
                + ", quality=" + cameraQuality
 | 
			
		||||
            );
 | 
			
		||||
            
 | 
			
		||||
            var h264Settings:H264VideoStreamSettings = new H264VideoStreamSettings();
 | 
			
		||||
            // we MUST set its values first, then set the NetStream.videoStreamSettings, or it will keep the origin values.
 | 
			
		||||
            h264Settings.setProfileLevel(x264profile, x264level); 
 | 
			
		||||
            stream.videoStreamSettings = h264Settings;
 | 
			
		||||
            // the setKeyFrameInterval/setMode/setQuality use the camera settings.
 | 
			
		||||
            // http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/VideoStreamSettings.html
 | 
			
		||||
            // Note This feature will be supported in future releases of Flash Player and AIR, for now, Camera parameters are used.
 | 
			
		||||
            //
 | 
			
		||||
            //h264Settings.setKeyFrameInterval(4);
 | 
			
		||||
            //h264Settings.setMode(800, 600, 15);
 | 
			
		||||
            //h264Settings.setQuality(500, 0);
 | 
			
		||||
            
 | 
			
		||||
            // set the camera and microphone.
 | 
			
		||||
            
 | 
			
		||||
            // setKeyFrameInterval(keyFrameInterval:int):void
 | 
			
		||||
            // 	keyFrameInterval:int — A value that specifies which video frames are transmitted in full (as keyframes) instead of being 
 | 
			
		||||
            //		interpolated by the video compression algorithm. A value of 1 means that every frame is a keyframe, a value of 3 means 
 | 
			
		||||
            //		that every third frame is a keyframe, and so on. Acceptable values are 1 through 48.
 | 
			
		||||
            c.setKeyFrameInterval(x264KeyFrameInterval);
 | 
			
		||||
            
 | 
			
		||||
            // setMode(width:int, height:int, fps:Number, favorArea:Boolean = true):void
 | 
			
		||||
            //  width:int — The requested capture width, in pixels. The default value is 160.
 | 
			
		||||
            //  height:int — The requested capture height, in pixels. The default value is 120.
 | 
			
		||||
            //  fps:Number — The requested rate at which the camera should capture data, in frames per second. The default value is 15.
 | 
			
		||||
            c.setMode(cameraWidth, cameraHeight, cameraFps);
 | 
			
		||||
            
 | 
			
		||||
            // setQuality(bandwidth:int, quality:int):void
 | 
			
		||||
            //  bandwidth:int — Specifies the maximum amount of bandwidth that the current outgoing video feed can use, in bytes per second. 
 | 
			
		||||
            //		To specify that the video can use as much bandwidth as needed to maintain the value of quality, pass 0 for bandwidth. 
 | 
			
		||||
            //		The default value is 16384.
 | 
			
		||||
            //  quality:int — An integer that specifies the required level of picture quality, as determined by the amount of compression 
 | 
			
		||||
            // 		being applied to each video frame. Acceptable values range from 1 (lowest quality, maximum compression) to 100 
 | 
			
		||||
            //		(highest quality, no compression). To specify that picture quality can vary as needed to avoid exceeding bandwidth, 
 | 
			
		||||
            //		pass 0 for quality.
 | 
			
		||||
            //  winlin:
 | 
			
		||||
            //		bandwidth is in bps not kbps. 500*1000 = 500kbps.
 | 
			
		||||
            //		quality=1 is lowest quality, 100 is highest quality.
 | 
			
		||||
            c.setQuality(cameraBitrate * 1000, cameraQuality);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								trunk/research/players/vlc.html
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										51
									
								
								trunk/research/players/vlc.html
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,51 @@
 | 
			
		|||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
    <title>SRS</title>   
 | 
			
		||||
    <meta charset="utf-8">
 | 
			
		||||
    <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
 | 
			
		||||
    <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/bootstrap.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/swfobject.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="js/srs.js"></script>
 | 
			
		||||
    <style>
 | 
			
		||||
        body{
 | 
			
		||||
            padding-top: 55px;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
    <script type="text/javascript">
 | 
			
		||||
        $(function(){
 | 
			
		||||
            update_nav();
 | 
			
		||||
            $("#main_frame").attr("src", "http://www.videolan.org/vlc/");
 | 
			
		||||
        });
 | 
			
		||||
    </script>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<div class="navbar navbar-fixed-top">
 | 
			
		||||
    <div class="navbar-inner">
 | 
			
		||||
        <div class="container">
 | 
			
		||||
        <a class="brand" href="index.html">SRS</a>
 | 
			
		||||
            <div class="nav-collapse collapse">
 | 
			
		||||
                <ul class="nav">
 | 
			
		||||
                    <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
 | 
			
		||||
                    <li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
 | 
			
		||||
                    <li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
 | 
			
		||||
                    <li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>
 | 
			
		||||
                    <li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>
 | 
			
		||||
                    <li class="active"><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
<div class="container">
 | 
			
		||||
    <iframe id="main_frame" width="100%" height="800" frameBorder="0"></iframe>
 | 
			
		||||
</div>
 | 
			
		||||
<div class="container">
 | 
			
		||||
    <hr>
 | 
			
		||||
    <footer>
 | 
			
		||||
        <p><a href="https://github.com/winlinvip/simple-rtmp-server">SRS Team © 2013</a></p>
 | 
			
		||||
    </footer>
 | 
			
		||||
</div>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -139,6 +139,8 @@ int SrsRequest::discovery_app()
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	strip();
 | 
			
		||||
 | 
			
		||||
	// resolve the vhost from config
 | 
			
		||||
	SrsConfDirective* parsed_vhost = config->get_vhost(vhost);
 | 
			
		||||
	if (parsed_vhost) {
 | 
			
		||||
| 
						 | 
				
			
			@ -611,7 +613,7 @@ int SrsRtmp::response_connect_app(SrsRequest *req, const char *ip)
 | 
			
		|||
	pkt->info->set("data", data);
 | 
			
		||||
	
 | 
			
		||||
	data->set("srs_version", new SrsAmf0String(RTMP_SIG_FMS_VER));
 | 
			
		||||
	data->set("srs_server", new SrsAmf0String(RTMP_SIG_SRS_NAME));
 | 
			
		||||
	data->set("srs_server", new SrsAmf0String(RTMP_SIG_SRS_KEY" "RTMP_SIG_SRS_VERSION" ("RTMP_SIG_SRS_URL_SHORT")"));
 | 
			
		||||
	data->set("srs_license", new SrsAmf0String(RTMP_SIG_SRS_LICENSE));
 | 
			
		||||
	data->set("srs_role", new SrsAmf0String(RTMP_SIG_SRS_ROLE));
 | 
			
		||||
	data->set("srs_url", new SrsAmf0String(RTMP_SIG_SRS_URL));
 | 
			
		||||
| 
						 | 
				
			
			@ -620,8 +622,11 @@ int SrsRtmp::response_connect_app(SrsRequest *req, const char *ip)
 | 
			
		|||
	data->set("srs_email", new SrsAmf0String(RTMP_SIG_SRS_EMAIL));
 | 
			
		||||
	data->set("srs_copyright", new SrsAmf0String(RTMP_SIG_SRS_COPYRIGHT));
 | 
			
		||||
 | 
			
		||||
    if(ip)
 | 
			
		||||
    if (ip) {
 | 
			
		||||
        data->set("srs_server_ip", new SrsAmf0String(ip));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    data->set("srs_contributor", new SrsAmf0String(RTMP_SIG_SRS_CONTRIBUTOR));
 | 
			
		||||
 | 
			
		||||
	msg->set_packet(pkt, 0);
 | 
			
		||||
	
 | 
			
		||||
| 
						 | 
				
			
			@ -1297,11 +1302,13 @@ int SrsRtmp::bandwidth_check_play(int duration_ms, int interval_ms, int &actual_
 | 
			
		|||
        SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket;
 | 
			
		||||
        pkt->command_name = SRS_BW_CHECK_PLAYING;
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < 100; ++i) {
 | 
			
		||||
        int object_num = 1;
 | 
			
		||||
        for (int i = 0; i < object_num; ++i) {
 | 
			
		||||
            char buf[32];
 | 
			
		||||
            sprintf(buf, "%d", i);
 | 
			
		||||
            pkt->data->set(buf, new SrsAmf0String(random_data));
 | 
			
		||||
        }
 | 
			
		||||
        object_num += 1;
 | 
			
		||||
        msg->set_packet(pkt, 0);
 | 
			
		||||
 | 
			
		||||
        play_bytes += pkt->get_payload_length();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue