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-11-30 23:04:47 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
525af4599f49b96b6621d6eaf3fef4992a6dca29
525af459
1 parent
ee18b9f5
support live stream transcoding by ffmpeg.
隐藏空白字符变更
内嵌
并排对比
正在显示
6 个修改的文件
包含
145 行增加
和
26 行删除
trunk/auto/depends.sh
trunk/conf/srs.conf
trunk/research/ffempty/ffempty.cc
trunk/src/core/srs_core_encoder.cpp
trunk/src/core/srs_core_encoder.hpp
trunk/src/core/srs_core_error.hpp
trunk/auto/depends.sh
100644 → 100755
查看文件 @
525af45
...
...
@@ -109,3 +109,12 @@ if [ $SRS_FFMPEG = YES ]; then
else
echo
"#undef SRS_FFMPEG"
>>
$SRS_AUTO_HEADERS_H
fi
#####################################################################################
# build research code
#####################################################################################
(
cd
research/hls
&&
make
)
ret
=
$?
;
if
[[
$ret
-ne 0
]]
;
then
echo
"build research/hls failed, ret=
$ret
"
;
exit
$ret
;
fi
(
cd
research/ffempty
&&
make
)
ret
=
$?
;
if
[[
$ret
-ne 0
]]
;
then
echo
"build research/ffempty failed, ret=
$ret
"
;
exit
$ret
;
fi
...
...
trunk/conf/srs.conf
查看文件 @
525af45
...
...
@@ -18,7 +18,8 @@ vhost __defaultVhost__ {
#forward 127.0.0.1:1936;
transcode
{
enabled
on
;
ffmpeg
/
home
/
winlin
/
srs
/
objs
/
ffmpeg
/
bin
/
ffmpeg
;
ffmpeg
./
objs
/
ffmpeg
/
bin
/
ffmpeg
;
#ffmpeg ./research/ffempty/ffempty;
engine
fd
{
enabled
on
;
vcodec
libx264
;
...
...
@@ -29,12 +30,14 @@ vhost __defaultVhost__ {
vthreads
2
;
vprofile
baseline
;
vpreset
superfast
;
vparams
{}
vparams
{
}
acodec
libaacplus
;
abitrate
30
;
asample_rate
2205
0
;
asample_rate
4410
0
;
achannels
2
;
aparams
{}
aparams
{
}
output
rtmp
://[
vhost
]:[
port
]/[
app
]/[
stream
]
_
fast
;
}
}
...
...
@@ -151,7 +154,34 @@ vhost all.transcode.vhost.com {
}
acodec
libaacplus
;
abitrate
30
;
asample_rate
22050
;
asample_rate
44100
;
achannels
2
;
aparams
{
}
output
rtmp
://[
vhost
]:[
port
]/[
app
]/[
stream
]
_
fast
;
}
}
}
# transcode all stream using the empty ffmpeg demo, donothing.
vhost
ffempty
.
transcode
.
vhost
.
com
{
transcode
{
enabled
on
;
ffmpeg
./
research
/
ffempty
/
ffempty
;
engine
fd
{
enabled
on
;
vcodec
libx264
;
vbitrate
300
;
vfps
20
;
vwidth
480
;
vheight
320
;
vthreads
2
;
vprofile
baseline
;
vpreset
superfast
;
vparams
{
}
acodec
libaacplus
;
abitrate
30
;
asample_rate
44100
;
achannels
2
;
aparams
{
}
...
...
trunk/research/ffempty/ffempty.cc
查看文件 @
525af45
...
...
@@ -31,6 +31,12 @@ int main(int argc, char** argv)
for
(
int
i
=
0
;
i
<
argc
;
i
++
)
{
fprintf
(
stderr
,
"argv[%d]=%s
\n
"
,
i
,
argv
[
i
]);
}
fprintf
(
stderr
,
"summary:
\n
"
);
for
(
int
i
=
0
;
i
<
argc
;
i
++
)
{
fprintf
(
stderr
,
"%s "
,
argv
[
i
]);
}
fprintf
(
stderr
,
"
\n
"
);
return
0
;
}
...
...
trunk/src/core/srs_core_encoder.cpp
查看文件 @
525af45
...
...
@@ -81,6 +81,7 @@ int SrsFFMPEG::initialize(std::string vhost, std::string port, std::string app,
vheight
-=
vheight
%
2
;
// input stream, from local.
// ie. rtmp://127.0.0.1:1935/live/livestream
input
=
"rtmp://127.0.0.1:"
;
input
+=
port
;
input
+=
"/"
;
...
...
@@ -88,6 +89,8 @@ int SrsFFMPEG::initialize(std::string vhost, std::string port, std::string app,
input
+=
"/"
;
input
+=
stream
;
// output stream, to other/self server
// ie. rtmp://127.0.0.1:1935/live/livestream_sd
if
(
vhost
==
RTMP_VHOST_DEFAULT
)
{
output
=
srs_replace
(
output
,
"[vhost]"
,
"127.0.0.1"
);
}
else
{
...
...
@@ -96,6 +99,22 @@ int SrsFFMPEG::initialize(std::string vhost, std::string port, std::string app,
output
=
srs_replace
(
output
,
"[port]"
,
port
);
output
=
srs_replace
(
output
,
"[app]"
,
app
);
output
=
srs_replace
(
output
,
"[stream]"
,
stream
);
// important: loop check, donot transcode again.
// we think the following is loop circle:
// input: rtmp://127.0.0.1:1935/live/livestream_sd
// output: rtmp://127.0.0.1:1935/live/livestream_sd_sd
std
::
string
tail
=
""
;
// tail="_sd"
if
(
output
.
length
()
>
input
.
length
())
{
tail
=
output
.
substr
(
input
.
length
());
}
// if input also endwiths the tail, loop detected.
if
(
!
tail
.
empty
()
&&
input
.
rfind
(
tail
)
==
input
.
length
()
-
tail
.
length
())
{
ret
=
ERROR_ENCODER_LOOP
;
srs_info
(
"detect a loop cycle, input=%s, output=%s, ignore it. ret=%d"
,
input
.
c_str
(),
output
.
c_str
(),
ret
);
return
ret
;
}
if
(
vcodec
!=
SRS_ENCODER_VCODEC
)
{
ret
=
ERROR_ENCODER_VCODEC
;
...
...
@@ -184,9 +203,32 @@ int SrsFFMPEG::start()
snprintf
(
vsize
,
sizeof
(
vsize
),
"%dx%d"
,
vwidth
,
vheight
);
char
vaspect
[
22
];
snprintf
(
vaspect
,
sizeof
(
vaspect
),
"%d:%d"
,
vwidth
,
vheight
);
char
s_vbitrate
[
10
];
snprintf
(
s_vbitrate
,
sizeof
(
s_vbitrate
),
"%d"
,
vbitrate
*
1000
);
char
s_vfps
[
10
];
snprintf
(
s_vfps
,
sizeof
(
s_vfps
),
"%.2f"
,
vfps
);
char
s_vthreads
[
10
];
snprintf
(
s_vthreads
,
sizeof
(
s_vthreads
),
"%d"
,
vthreads
);
char
s_abitrate
[
10
];
snprintf
(
s_abitrate
,
sizeof
(
s_abitrate
),
"%d"
,
abitrate
*
1000
);
char
s_asample_rate
[
10
];
snprintf
(
s_asample_rate
,
sizeof
(
s_asample_rate
),
"%d"
,
asample_rate
);
char
s_achannels
[
10
];
snprintf
(
s_achannels
,
sizeof
(
s_achannels
),
"%d"
,
achannels
);
// video params
std
::
string
s_vpreset
=
vpreset
;
if
(
!
vparams
.
empty
())
{
s_vpreset
+=
" "
;
s_vpreset
+=
vparams
;
}
// audio params
std
::
string
s_aparams
=
s_achannels
;
if
(
!
aparams
.
empty
())
{
s_aparams
+=
" "
;
s_aparams
+=
aparams
;
}
// we use vfork, for we use fored process
// to start ffmpeg, that is, exec after vfork.
if
((
pid
=
fork
())
<
0
)
{
ret
=
ERROR_ENCODER_FORK
;
srs_error
(
"vfork process failed. ret=%d"
,
ret
);
...
...
@@ -195,25 +237,24 @@ int SrsFFMPEG::start()
// child process: ffmpeg encoder engine.
if
(
pid
==
0
)
{
// must exec immediately, or may introduce bug.
ret
=
execl
(
ffmpeg
.
c_str
(),
ffmpeg
.
c_str
(),
"-f"
,
"flv"
,
"-i"
,
input
.
c_str
(),
// video specified.
"-vcodec"
,
vcodec
.
c_str
(),
"-b:v"
,
vbitrate
*
1000
,
"-r"
,
vfps
,
"-size"
,
vsize
,
"-b:v"
,
s_vbitrate
,
"-r"
,
s_vfps
,
"-s"
,
vsize
,
"-aspect"
,
vaspect
,
// TODO: add aspect if needed.
"-threads"
,
vthreads
,
"-profile"
,
vprofile
.
c_str
(),
"-preset"
,
vpreset
.
c_str
(),
vparams
.
c_str
(),
"-threads"
,
s_vthreads
,
"-profile:v"
,
vprofile
.
c_str
(),
"-preset"
,
s_vpreset
.
c_str
(),
// audio specified.
"-acodec"
,
acodec
.
c_str
(),
"-b:a"
,
abitrate
*
1000
,
"-ar"
,
asample_rate
,
"-ac"
,
achannels
,
aparams
.
c_str
(),
"-b:a"
,
s_abitrate
,
"-ar"
,
s_asample_rate
,
"-ac"
,
s_aparams
.
c_str
(),
"-f"
,
"flv"
,
"-y"
,
output
.
c_str
(),
NULL
...
...
@@ -253,14 +294,9 @@ SrsEncoder::~SrsEncoder()
on_unpublish
();
}
int
SrsEncoder
::
on_publish
(
std
::
string
_vhost
,
std
::
string
_port
,
std
::
string
_app
,
std
::
string
_stream
)
int
SrsEncoder
::
parse_scope_engines
(
)
{
int
ret
=
ERROR_SUCCESS
;
vhost
=
_vhost
;
port
=
_port
;
app
=
_app
;
stream
=
_stream
;
// parse all transcode engines.
SrsConfDirective
*
conf
=
NULL
;
...
...
@@ -293,6 +329,30 @@ int SrsEncoder::on_publish(std::string _vhost, std::string _port, std::string _a
return
ret
;
}
}
return
ret
;
}
int
SrsEncoder
::
on_publish
(
std
::
string
_vhost
,
std
::
string
_port
,
std
::
string
_app
,
std
::
string
_stream
)
{
int
ret
=
ERROR_SUCCESS
;
vhost
=
_vhost
;
port
=
_port
;
app
=
_app
;
stream
=
_stream
;
ret
=
parse_scope_engines
();
// ignore the loop encoder
if
(
ret
=
ERROR_ENCODER_LOOP
)
{
ret
=
ERROR_SUCCESS
;
}
// return for error or no engine.
if
(
ret
!=
ERROR_SUCCESS
||
ffmpegs
.
empty
())
{
return
ret
;
}
// start thread to run all encoding engines.
srs_assert
(
!
tid
);
...
...
@@ -313,7 +373,12 @@ void SrsEncoder::on_unpublish()
st_thread_join
(
tid
,
NULL
);
tid
=
NULL
;
}
clear_engines
();
}
void
SrsEncoder
::
clear_engines
()
{
std
::
vector
<
SrsFFMPEG
*>::
iterator
it
;
for
(
it
=
ffmpegs
.
begin
();
it
!=
ffmpegs
.
end
();
++
it
)
{
SrsFFMPEG
*
ffmpeg
=
*
it
;
...
...
@@ -371,6 +436,12 @@ int SrsEncoder::parse_transcode(SrsConfDirective* conf)
if
((
ret
=
ffmpeg
->
initialize
(
vhost
,
port
,
app
,
stream
,
engine
))
!=
ERROR_SUCCESS
)
{
srs_freep
(
ffmpeg
);
// if got a loop, donot transcode the whole stream.
if
(
ret
==
ERROR_ENCODER_LOOP
)
{
clear_engines
();
break
;
}
srs_error
(
"invalid transcode engine: %s %s"
,
conf
->
arg0
().
c_str
(),
engine
->
arg0
().
c_str
());
return
ret
;
...
...
trunk/src/core/srs_core_encoder.hpp
查看文件 @
525af45
...
...
@@ -95,6 +95,8 @@ public:
virtual
int
on_publish
(
std
::
string
vhost
,
std
::
string
port
,
std
::
string
app
,
std
::
string
stream
);
virtual
void
on_unpublish
();
private
:
virtual
int
parse_scope_engines
();
virtual
void
clear_engines
();
virtual
SrsFFMPEG
*
at
(
int
index
);
virtual
int
parse_transcode
(
SrsConfDirective
*
conf
);
virtual
int
cycle
();
...
...
trunk/src/core/srs_core_error.hpp
查看文件 @
525af45
...
...
@@ -136,5 +136,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define ERROR_ENCODER_VFPS 711
#define ERROR_ENCODER_VBITRATE 712
#define ERROR_ENCODER_FORK 713
#define ERROR_ENCODER_LOOP 714
#endif
\ No newline at end of file
...
...
请
注册
或
登录
后发表评论