Toggle navigation
Toggle navigation
此项目
正在载入...
Sign in
胡斌
/
srs
转到一个项目
Toggle navigation
项目
群组
代码片段
帮助
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
winlin
2013-12-21 19:25:43 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
a6e2f19a0fe90027bab5edbd8c5f27106e171300
a6e2f19a
1 parent
85515f05
support publish
隐藏空白字符变更
内嵌
并排对比
正在显示
9 个修改的文件
包含
825 行增加
和
35 行删除
trunk/research/players/js/srs.js
trunk/research/players/jwplayer6.html
trunk/research/players/osmf.html
trunk/research/players/srs_player.html
trunk/research/players/srs_player/release/srs_player.swf
trunk/research/players/srs_player/src/srs_player.as
trunk/research/players/srs_publisher.html
trunk/research/players/srs_publisher/release/srs_publisher.swf
trunk/research/players/srs_publisher/src/srs_publisher.as
trunk/research/players/js/srs.js
查看文件 @
a6e2f19
...
...
@@ -116,11 +116,10 @@ function srs_init(rtmp_url, hls_url, modal_player) {
/**
* the SrsPlayer object.
* @param container the html container id.
* @param stream_url the url of stream, rtmp or http.
* @param width a float value specifies the width of player.
* @param height a float value specifies the height of player.
*/
function
SrsPlayer
(
container
,
stream_url
,
width
,
height
)
{
function
SrsPlayer
(
container
,
width
,
height
)
{
if
(
!
SrsPlayer
.
__id
)
{
SrsPlayer
.
__id
=
100
;
}
...
...
@@ -131,12 +130,12 @@ function SrsPlayer(container, stream_url, width, height) {
SrsPlayer
.
__players
.
push
(
this
);
this
.
container
=
container
;
this
.
stream_url
=
stream_url
;
this
.
width
=
width
;
this
.
height
=
height
;
this
.
id
=
SrsPlayer
.
__id
++
;
this
.
callbackObj
=
null
;
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
...
...
@@ -178,7 +177,12 @@ SrsPlayer.prototype.start = function() {
return
this
;
}
SrsPlayer
.
prototype
.
play
=
function
()
{
/**
* 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
()
{
...
...
@@ -233,7 +237,6 @@ SrsPlayer.prototype.set_bt = function(buffer_time) {
this
.
callbackObj
.
ref
.
__set_bt
(
buffer_time
);
}
SrsPlayer
.
prototype
.
on_player_ready
=
function
()
{
this
.
play
();
}
SrsPlayer
.
prototype
.
on_player_metadata
=
function
(
metadata
)
{
// ignore.
...
...
@@ -286,4 +289,131 @@ function __srs_on_player_timer(id, 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
.
error_device_muted
=
100
;
}
/**
* 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):int, when srs publisher error, 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"
;
var
params
=
{};
params
.
wmode
=
"opaque"
;
params
.
allowFullScreen
=
"true"
;
params
.
allowScriptAccess
=
"always"
;
var
attributes
=
{};
var
self
=
this
;
swfobject
.
embedSWF
(
"srs_publisher/release/srs_publisher.swf"
,
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.
*/
SrsPublisher
.
prototype
.
on_publisher_error
=
function
(
code
)
{
throw
new
Error
(
"publisher error. code="
+
code
);
}
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
);
}
...
...
trunk/research/players/jwplayer6.html
查看文件 @
a6e2f19
...
...
@@ -35,14 +35,13 @@
$
(
"#main_modal"
).
on
(
"show"
,
function
(){
$
(
"#div_container"
).
remove
();
var
obj
=
$
(
"<div/>"
);
$
(
obj
).
attr
(
"id"
,
"div_container"
);
var
div_container
=
$
(
"<div/>"
);
$
(
div_container
).
attr
(
"id"
,
"div_container"
);
$
(
"#player"
).
append
(
div_container
);
var
player
=
$
(
"<div/>"
);
$
(
obj
).
append
(
player
);
$
(
obj
).
attr
(
"id"
,
"player_id"
);
$
(
"#player"
).
append
(
obj
);
$
(
player
).
attr
(
"id"
,
"player_id"
);
$
(
div_container
).
append
(
player
);
var
conf
=
{
file
:
_url
,
...
...
trunk/research/players/osmf.html
查看文件 @
a6e2f19
...
...
@@ -21,14 +21,13 @@
function
osmf_play
(
url
)
{
$
(
"#div_container"
).
remove
();
var
obj
=
$
(
"<div/>"
);
$
(
obj
).
attr
(
"id"
,
"div_container"
);
var
div_container
=
$
(
"<div/>"
);
$
(
div_container
).
attr
(
"id"
,
"div_container"
);
$
(
"#player"
).
append
(
div_container
);
var
player
=
$
(
"<div/>"
);
$
(
obj
).
append
(
player
);
$
(
obj
).
attr
(
"id"
,
"player_id"
);
$
(
"#player"
).
append
(
obj
);
$
(
player
).
attr
(
"id"
,
"player_id"
);
$
(
div_container
).
append
(
player
);
var
flashvars
=
{};
flashvars
.
src
=
url
;
...
...
trunk/research/players/srs_player.html
查看文件 @
a6e2f19
...
...
@@ -80,28 +80,26 @@
$
(
"#div_container"
).
remove
();
var
obj
=
$
(
"<div/>"
);
$
(
obj
).
attr
(
"id"
,
"div_container"
);
var
div_container
=
$
(
"<div/>"
);
$
(
div_container
).
attr
(
"id"
,
"div_container"
);
$
(
"#player"
).
append
(
div_container
);
var
player
=
$
(
"<div/>"
);
$
(
obj
).
append
(
player
);
$
(
obj
).
attr
(
"id"
,
"player_id"
);
$
(
"#player"
).
append
(
obj
);
$
(
player
).
attr
(
"id"
,
"player_id"
);
$
(
div_container
).
append
(
player
);
var
url
=
$
(
"#txt_url"
).
val
();
srs_player
=
new
SrsPlayer
(
"player_id"
,
url
,
srs_get_player_width
(),
srs_get_player_height
());
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
();
}
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
)
+
"%"
);
...
...
@@ -124,7 +122,7 @@
time_str
+=
padding
(
parseInt
(
time
),
2
,
'0'
);
// show
$
(
"#txt_time"
).
val
(
time_str
);
}
}
;
srs_player
.
start
();
});
...
...
@@ -218,6 +216,11 @@
select_buffer_time
(
"#btn_bt_30"
,
30
);
});
}
var
query
=
parse_query_string
();
if
(
query
.
autostart
==
"true"
)
{
$
(
"#main_modal"
).
modal
({
show
:
true
,
keyboard
:
false
});
}
});
</script>
</head>
...
...
trunk/research/players/srs_player/release/srs_player.swf
查看文件 @
a6e2f19
不能预览此文件类型
trunk/research/players/srs_player/src/srs_player.as
查看文件 @
a6e2f19
...
...
@@ -258,6 +258,10 @@ package
* 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
;
...
...
@@ -266,10 +270,6 @@ package
this
.
media_conn
.
close
()
;
this
.
media_conn
=
null
;
}
if
(
this
.
media_video
)
{
this
.
removeChild
(
this
.
media_video
)
;
this
.
media_video
=
null
;
}
}
/**
...
...
trunk/research/players/srs_publisher.html
查看文件 @
a6e2f19
...
...
@@ -14,9 +14,174 @@
}
</style>
<script
type=
"text/javascript"
>
var
srs_publisher
=
null
;
var
remote_player
=
null
;
$
(
function
(){
update_nav
();
// 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
});
});
$
(
"#btn_publish"
).
click
(
on_user_publish
);
update_play_url
();
// 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"
);
}
$
(
"#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
)
{
if
(
code
==
srs_publisher
.
error_device_muted
)
{
error
(
code
,
"摄像头和麦克风被禁用,请右键flash播放器启用。"
);
}
else
{
error
(
code
,
"未知系统错误"
);
}
};
srs_publisher
.
start
();
// start the player.
remote_player
=
new
SrsPlayer
(
"remote_player"
,
430
,
185
);
remote_player
.
on_player_ready
=
function
()
{
};
remote_player
.
start
();
});
function
update_play_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
=
$
(
"#txt_url"
).
val
().
replace
(
"rtmp://"
,
"http://"
);
var
url
=
"http://"
+
window
.
location
.
host
;
url
+=
window
.
location
.
pathname
.
substr
(
0
,
window
.
location
.
pathname
.
lastIndexOf
(
"/"
));
url
+=
"/srs_player.html?"
;
url
+=
"vhost="
+
a
.
hostname
;
url
+=
"&port="
+
a
.
port
;
url
+=
"&app="
+
a
.
pathname
.
substr
(
1
,
a
.
pathname
.
lastIndexOf
(
"/"
)
-
1
);
url
+=
"&stream="
+
a
.
pathname
.
substr
(
a
.
pathname
.
lastIndexOf
(
"/"
)
+
1
);
// autostart
url
+=
"&autostart=true"
;
$
(
"#txt_play_url"
).
text
(
url
);
$
(
"#txt_play_url"
).
attr
(
"href"
,
url
);
}
function
on_user_publish
()
{
if
(
$
(
"#btn_publish"
).
text
()
==
"停止发布"
)
{
srs_publisher
.
stop
();
$
(
"#btn_publish"
).
text
(
"发布视频"
);
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
);
// replay the url.
remote_player
.
stop
();
remote_player
.
play
(
url
);
}
function
info
(
desc
)
{
$
(
"#txt_log"
).
removeClass
(
"alert-error"
).
addClass
(
"alert-info"
);
$
(
"#txt_log_title"
).
text
(
"Info:"
);
$
(
"#txt_log_msg"
).
text
(
desc
);
}
function
error
(
code
,
desc
)
{
$
(
"#txt_log"
).
removeClass
(
"alert-info"
).
addClass
(
"alert-error"
);
$
(
"#txt_log_title"
).
text
(
"Error:"
);
$
(
"#txt_log_msg"
).
text
(
"code: "
+
code
+
", "
+
desc
);
}
</script>
</head>
<body>
...
...
@@ -38,6 +203,187 @@
</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"
>
输入地址后点击发布按钮
</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"
id=
"btn_publish"
>
发布视频
</button>
</div>
</div>
<div
class=
"control-group"
>
<div
class=
"form-inline"
>
观看地址:
<a
id=
"txt_play_url"
class=
"input-xxlarge"
href=
"srs_player.html"
>
srs_player.html
</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=
"#collapseOne"
>
<strong>
本地摄像头
</strong>
</span>
</div>
<div
id=
"collapseOne"
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=
"#collapseTwo"
>
<strong>
远程服务器
</strong>
</span>
</div>
<div
id=
"collapseTwo"
class=
"accordion-body collapse in"
>
<div
class=
"accordion-inner"
>
<div
id=
"remote_player"
></div>
</div>
</div>
</div>
</div>
</div>
</div>
<hr>
<footer>
<p><a
href=
"https://github.com/winlinvip/simple-rtmp-server"
>
SRS Team
©
2013
</a></p>
...
...
trunk/research/players/srs_publisher/release/srs_publisher.swf
查看文件 @
a6e2f19
不能预览此文件类型
trunk/research/players/srs_publisher/src/srs_publisher.as
查看文件 @
a6e2f19
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
.
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
;
// 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_device_muted
:
int
=
100
;
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
;
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
)
;
}
/**
* 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
){
trace
(
"failed to open microphone "
+
acodec
.
device_code
+
"("
+
acodec
.
device_name
+
")"
)
;
}
if
(
m
.
muted
){
trace
(
"Access Denied, microphone "
+
acodec
.
device_code
+
"("
+
acodec
.
device_name
+
") is muted"
)
;
m
=
null
;
}
// Remark: the name is the index!
var
c
:
Camera
=
Camera
.
getCamera
(
vcodec
.
device_code
)
;
if
(
c
==
null
){
trace
(
"failed to open camera "
+
vcodec
.
device_code
+
"("
+
vcodec
.
device_name
+
")"
)
;
}
if
(
c
.
muted
){
trace
(
"Access Denied, camera "
+
vcodec
.
device_code
+
"("
+
vcodec
.
device_name
+
") is muted"
)
;
c
=
null
;
}
if
(
m
==
null
&&
c
==
null
)
{
system_error
(
error_device_muted
,
"failed to publish, for neither camera or microphone is ok."
)
;
return
;
}
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
)
;
// 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
)
;
}
}
}
\ No newline at end of file
...
...
请
注册
或
登录
后发表评论