Toggle navigation
Toggle navigation
此项目
正在载入...
Sign in
胡斌
/
merge_av
转到一个项目
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
胡斌
2019-05-15 08:08:53 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
dfceaff2df2a05a4b6ba29e574668fb854de1645
dfceaff2
1 parent
c160aaa9
V2.0.4 支持读取编码配置文件,用于改变编码配置
隐藏空白字符变更
内嵌
并排对比
正在显示
7 个修改的文件
包含
266 行增加
和
60 行删除
pip/AVTranscoder.cpp
pip/ConfigFile.cpp
pip/ConfigFile.h
pip/ReadMe.txt
pip/merge_pip.cpp
pip/pip.vcxproj
pip/pip.vcxproj.filters
pip/AVTranscoder.cpp
查看文件 @
dfceaff
#include "AVTranscoder.h"
#include "tools.h"
#include "ConfigFile.h"
extern
CConfigFile
_codec_config
;
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
...
...
@@ -227,9 +230,8 @@ int CAVTranscoder::open_output_file(const char *filename)
return
AVERROR_INVALIDDATA
;
}
/* In this example, we transcode to same properties (picture size,
* sample rate etc.). These properties can be changed for output
* streams easily using filters */
printf
(
"
\n
video parameters:"
);
enc_ctx
->
height
=
_nOutputHeight
;
enc_ctx
->
width
=
_nOutputWidth
;
enc_ctx
->
sample_aspect_ratio
.
den
=
1
;
...
...
@@ -238,21 +240,58 @@ int CAVTranscoder::open_output_file(const char *filename)
enc_ctx
->
pix_fmt
=
AV_PIX_FMT_YUV420P
;
/* video time_base can be set to whatever is handy and supported by encoder */
enc_ctx
->
time_base
.
num
=
1
;
enc_ctx
->
time_base
.
den
=
20
;
enc_ctx
->
gop_size
=
20
;
enc_ctx
->
time_base
.
den
=
_codec_config
.
get_int
(
"fps"
,
20
);
printf
(
"
\n
fps: %d"
,
enc_ctx
->
time_base
.
den
);
enc_ctx
->
gop_size
=
_codec_config
.
get_int
(
"gop_size"
,
enc_ctx
->
time_base
.
den
);
printf
(
"
\n
gop_size: %d"
,
enc_ctx
->
gop_size
);
enc_ctx
->
me_range
=
16
;
enc_ctx
->
max_qdiff
=
4
;
enc_ctx
->
qmin
=
10
;
enc_ctx
->
qmax
=
30
;
enc_ctx
->
qcompress
=
0.6
f
;
enc_ctx
->
me_range
=
_codec_config
.
get_int
(
"me_range"
,
16
);
printf
(
"
\n
me_range: %d"
,
enc_ctx
->
me_range
);
enc_ctx
->
max_qdiff
=
_codec_config
.
get_int
(
"max_qdiff"
,
4
);
printf
(
"
\n
max_qdiff: %d"
,
enc_ctx
->
max_qdiff
);
enc_ctx
->
qmin
=
_codec_config
.
get_int
(
"qmin"
,
10
);
printf
(
"
\n
qmin: %d"
,
enc_ctx
->
qmin
);
enc_ctx
->
qmax
=
_codec_config
.
get_int
(
"qmax"
,
30
);
printf
(
"
\n
qmax: %d"
,
enc_ctx
->
qmax
);
enc_ctx
->
qcompress
=
_codec_config
.
get_float
(
"qcompress"
,
0.6
f
);
printf
(
"
\n
qcompress: %.2f"
,
enc_ctx
->
qcompress
);
enc_ctx
->
framerate
.
den
=
20
;
enc_ctx
->
framerate
.
den
=
enc_ctx
->
time_base
.
den
;
enc_ctx
->
framerate
.
num
=
1
;
enc_ctx
->
max_b_frames
=
0
;
enc_ctx
->
max_b_frames
=
_codec_config
.
get_int
(
"max_b_frames"
,
0
);
printf
(
"
\n
max_b_frames: %d"
,
enc_ctx
->
max_b_frames
);
enc_ctx
->
bit_rate
=
_codec_config
.
get_int
(
"bit_rate"
,
256000
);
printf
(
"
\n
bit_rate: %d"
,
enc_ctx
->
bit_rate
);
enc_ctx
->
rc_max_rate
=
_codec_config
.
get_int
(
"rc_max_rate"
,
0
);
printf
(
"
\n
rc_max_rate: %d"
,
enc_ctx
->
rc_max_rate
);
enc_ctx
->
rc_min_rate
=
_codec_config
.
get_int
(
"rc_min_rate"
,
0
);
printf
(
"
\n
rc_min_rate: %d"
,
enc_ctx
->
rc_min_rate
);
enc_ctx
->
rc_buffer_size
=
_codec_config
.
get_int
(
"rc_buffer_size"
,
enc_ctx
->
rc_max_rate
);
printf
(
"
\n
rc_buffer_size: %d"
,
enc_ctx
->
rc_buffer_size
);
AVDictionary
*
d
=
NULL
;
av_dict_set
(
&
d
,
"preset"
,
"ultrafast"
,
0
);
std
::
string
preset
=
_codec_config
.
get_string
(
"preset"
,
"ultrafast"
);
if
(
preset
!=
"none"
)
{
printf
(
"
\n
preset: %s"
,
preset
.
c_str
());
av_dict_set
(
&
d
,
"preset"
,
preset
.
c_str
(),
0
);
}
std
::
string
tune
=
_codec_config
.
get_string
(
"tune"
,
"none"
);
if
(
tune
!=
"none"
)
{
printf
(
"
\n
tune: %s"
,
tune
.
c_str
());
av_dict_set
(
&
d
,
"tune"
,
tune
.
c_str
(),
0
);
}
std
::
string
profile
=
_codec_config
.
get_string
(
"profile"
,
"none"
);
if
(
profile
!=
"none"
)
{
printf
(
"
\n
profile: %s"
,
profile
.
c_str
());
av_dict_set
(
&
d
,
"profile"
,
profile
.
c_str
(),
0
);
}
printf
(
"
\n
-----------------------------------"
);
/* Third parameter can be used to pass settings to encoder */
ret
=
avcodec_open2
(
enc_ctx
,
encoder
,
&
d
);
if
(
ret
<
0
)
{
...
...
@@ -261,20 +300,24 @@ int CAVTranscoder::open_output_file(const char *filename)
}
}
else
{
printf
(
"
\n
audio parameters:"
);
encoder
=
avcodec_find_encoder
(
AV_CODEC_ID_AAC
);;
if
(
!
encoder
)
{
av_log
(
NULL
,
AV_LOG_FATAL
,
"Necessary encoder not found
\n
"
);
return
AVERROR_INVALIDDATA
;
}
enc_ctx
->
sample_rate
=
48000
;
enc_ctx
->
sample_rate
=
_codec_config
.
get_int
(
"a_sample_rate"
,
48000
);
printf
(
"
\n
sample_rate: %d"
,
enc_ctx
->
sample_rate
);
enc_ctx
->
channel_layout
=
AV_CH_LAYOUT_MONO
;
enc_ctx
->
channels
=
av_get_channel_layout_nb_channels
(
AV_CH_LAYOUT_MONO
);
/* take first format from list of supported formats */
enc_ctx
->
sample_fmt
=
PCM_FORMAT_FOR_AAC_ENCODE
;
//AV_SAMPLE_FMT_FLTP;
enc_ctx
->
time_base
.
num
=
1
;
enc_ctx
->
time_base
.
den
=
enc_ctx
->
sample_rate
;
enc_ctx
->
bit_rate
=
64000
;
printf
(
"
\n
bit_rate: %d"
,
enc_ctx
->
bit_rate
);
enc_ctx
->
bit_rate
=
_codec_config
.
get_int
(
"a_bit_rate"
,
64000
);
/* Third parameter can be used to pass settings to encoder */
printf
(
"
\n
-----------------------------------"
);
ret
=
avcodec_open2
(
enc_ctx
,
encoder
,
NULL
);
if
(
ret
<
0
)
{
av_log
(
NULL
,
AV_LOG_ERROR
,
"Cannot open audio encoder for stream #%u
\n
"
,
i
);
...
...
pip/ConfigFile.cpp
0 → 100644
查看文件 @
dfceaff
#include "ConfigFile.h"
#include <iostream>
#include <fstream>
using
namespace
std
;
CConfigFile
::
CConfigFile
()
{
}
CConfigFile
::~
CConfigFile
()
{
}
std
::
string
&
trim
(
std
::
string
&
s
)
{
if
(
s
.
empty
())
{
return
s
;
}
s
.
erase
(
0
,
s
.
find_first_not_of
(
" "
));
s
.
erase
(
s
.
find_last_not_of
(
" "
)
+
1
);
return
s
;
}
int
CConfigFile
::
load
(
const
char
*
filename
)
{
ifstream
fin
(
filename
);
if
(
!
fin
)
{
return
-
1
;
}
const
int
LINE_LENGTH
=
1000
;
char
str
[
LINE_LENGTH
];
while
(
fin
.
getline
(
str
,
LINE_LENGTH
))
{
char
*
p
=
str
;
while
(
*
p
==
0x20
||
*
p
==
0x9
){
p
++
;
//bypass space and tab
}
if
(
*
p
==
';'
||
*
p
==
'#'
){
continue
;
//bypass the comment line
}
std
::
string
linestr
=
p
;
string
::
size_type
position
=
linestr
.
find
(
'='
);
if
(
position
!=
linestr
.
npos
)
{
string
item
=
linestr
.
substr
(
0
,
position
);
int
value_len
=
linestr
.
length
()
-
position
;
if
(
value_len
>
0
)
{
string
value
=
linestr
.
substr
(
position
+
1
,
value_len
);
trim
(
item
);
trim
(
value
);
_configs
[
item
]
=
value
;
}
}
}
return
0
;
}
std
::
string
CConfigFile
::
lookup
(
const
char
*
item
)
{
map
<
string
,
string
>::
iterator
it
=
_configs
.
find
(
item
);
if
(
it
!=
_configs
.
end
())
{
return
(
*
it
).
second
;
}
return
""
;
}
int
CConfigFile
::
get_int
(
const
char
*
item
,
int
def
)
{
std
::
string
value
=
lookup
(
item
);
if
(
value
.
length
()
>
0
)
{
return
atoi
(
value
.
c_str
());
}
else
{
return
def
;
}
}
float
CConfigFile
::
get_float
(
const
char
*
item
,
float
def
)
{
std
::
string
value
=
lookup
(
item
);
if
(
value
.
length
()
>
0
)
{
return
atof
(
value
.
c_str
());
}
else
{
return
def
;
}
}
std
::
string
CConfigFile
::
get_string
(
const
char
*
item
,
const
char
*
def
)
{
std
::
string
value
=
lookup
(
item
);
if
(
value
.
length
()
>
0
)
{
return
value
;
}
else
{
return
def
;
}
}
...
...
pip/ConfigFile.h
0 → 100644
查看文件 @
dfceaff
#pragma once
#include <string>
#include <map>
class
CConfigFile
{
public
:
CConfigFile
();
~
CConfigFile
();
int
load
(
const
char
*
filename
);
std
::
string
lookup
(
const
char
*
item
);
int
get_int
(
const
char
*
item
,
int
def
);
float
get_float
(
const
char
*
item
,
float
def
);
std
::
string
get_string
(
const
char
*
item
,
const
char
*
def
);
protected
:
std
::
map
<
std
::
string
,
std
::
string
>
_configs
;
};
...
...
pip/ReadMe.txt
查看文件 @
dfceaff
...
...
@@ -3,7 +3,7 @@
读入合屏信息文件,合成画中画视频。
使用方法:
merge_pip merge_info.txt [-t {0,1,2}]
merge_pip merge_info.txt [-t {0,1,2}]
[-c codec.cfg]
其中merge_info.txt为合屏信息文件,格式如下:
teacher:
...
...
@@ -31,6 +31,22 @@ student:下面是学生的录像信息文件,一个文件名一行
2 为使用一对多布局
如果不加-t,则为程序自动选择合屏布局
-c 为可选参数,后面为编码配置文件名。缺省的编码配置文件名为merge_pip_codec.cfg。在windows系统里,与merge_av.exe放在同一目录。在linux下,放在HOME目录下的merge_av目录。
merge_pip_codec.cfg主要编码参数:
#帧率
fps = 20
#关键帧间隔,默认与fps一致,即每秒一个关键帧
gop_size = 20
#视频码率
bit_rate = 256000
;视频预设值编码参数: ultrafast、superfast、veryfast、faster、fast、medium、slow、slower、veryslow、placebo
preset = ultrafast
#音频采样率
a_sample_rate = 48000
#音频码率
a_bit_rate = 64000
合屏后生成完成信息文件,文件名为"m_" + 输入文件名" + ".txt",合成的mp4文件名为"m_" + 输入文件名" + ".mp4"
如merge_pip 1.txt
生成的完成信息文件是m_1.txt,m_1.txt只有一行,记录输出的mp4文件名(m_1.mp4)、参与合成m_1.mp4的第一个媒体文件名(用于帮助确认m_1.mp4的开始时间)及mp4的时长。下面是一个实际的m_1.txt内容:
...
...
@@ -49,4 +65,7 @@ V2.0.3
1.没有老师,但是有两个学生时,默认使用一对多布局
2.一对一时,老师和学生的视频尺寸不同时,合成的视频高度取老师视频高度加上学生视频高度(之前版本假定老师和学生视频大小一致,使用的是最大高度的二倍)
3.一对多时,支持学生的视频尺寸不一致的情况(之前版本假定只有一种视频尺寸,其它尺寸视为异常)
4.一对多时,最多只在老师视频下部排4个学生,多于4个学生的情况,扩大合成视频的高度,把学生视频排列在老师视频下方,保证老师视频部分最多只有一排学生视频,避免老师视频被过度遮挡
\ No newline at end of file
4.一对多时,最多只在老师视频下部排4个学生,多于4个学生的情况,扩大合成视频的高度,把学生视频排列在老师视频下方,保证老师视频部分最多只有一排学生视频,避免老师视频被过度遮挡
V2.0.4
1.支持读取编码配置文件,用于改变编码配置
\ No newline at end of file
...
...
pip/merge_pip.cpp
查看文件 @
dfceaff
...
...
@@ -9,6 +9,7 @@
#include <deque>
#include "tools.h"
#include "AVTranscoder.h"
#include "ConfigFile.h"
bool
only_print
=
false
;
bool
keep_tmp_files
=
false
;
...
...
@@ -50,11 +51,11 @@ void run_shell_cmd(const char * cmd)
}
}
char
exe_path
[
1024
]
=
{
0
};
#ifdef WIN32
#include <Windows.h>
char
exe_path
[
MAX_PATH
]
=
{
0
};
int
GetExePath
()
{
char
path_buffer
[
MAX_PATH
]
=
""
;
...
...
@@ -70,15 +71,37 @@ int GetExePath()
strcat
(
exe_path
,
dir
);
return
0
;
}
#else
int
GetExePath
()
{
char
path
[
1024
];
int
cnt
=
readlink
(
"/proc/self/exe"
,
path
,
1024
);
if
(
cnt
<
0
||
cnt
>=
1024
)
{
return
-
1
;
}
for
(
int
i
=
cnt
;
i
>=
0
;
--
i
)
{
if
(
path
[
i
]
==
'/'
)
{
path
[
i
+
1
]
=
'\0'
;
break
;
}
}
strcpy
(
exe_path
,
path
);
return
0
;
}
#endif
char
cfg_path
[
1024
];
void
get_config_path
(){
#ifdef WIN32
GetExePath
();
strcpy
(
cfg_path
,
exe_path
);
#else
#if 0
strcpy(cfg_path, getenv("HOME"));
strcat(cfg_path, "/merge_av/");
#endif
...
...
@@ -957,6 +980,10 @@ int readfile(const char * filename, media_role role)
vector
<
string
>
all_input_files_for_pip
;
CConfigFile
_codec_config
;
char
user_codec_cfg
[
1024
]
=
{
0
};
void
load_codec_param
()
{
strcpy
(
acodec_param
,
default_acodec_param
);
...
...
@@ -968,43 +995,19 @@ void load_codec_param()
char
cfgfile
[
1024
];
strcpy
(
cfgfile
,
cfg_path
);
strcat
(
cfgfile
,
"merge_pip.cfg"
);
ifstream
fin
(
cfgfile
);
if
(
!
fin
)
{
return
;
}
const
int
LINE_LENGTH
=
1000
;
char
str
[
LINE_LENGTH
];
str
[
0
]
=
0
;
if
(
fin
.
getline
(
str
,
LINE_LENGTH
))
{
printf
(
"
\n
load video codec from %s: %s
\n
"
,
cfgfile
,
str
);
strcpy
(
vcodec_param
,
str
);
}
str
[
0
]
=
0
;
if
(
fin
.
getline
(
str
,
LINE_LENGTH
))
{
printf
(
"load audio codec from %s: %s
\n
"
,
cfgfile
,
str
);
strcpy
(
acodec_param
,
str
);
if
(
user_codec_cfg
[
0
])
{
strcat
(
cfgfile
,
user_codec_cfg
);
}
str
[
0
]
=
0
;
if
(
fin
.
getline
(
str
,
LINE_LENGTH
))
{
printf
(
"load av codec from %s: %s
\n
"
,
cfgfile
,
str
);
strcpy
(
av_codec_param
,
str
);
else
{
strcat
(
cfgfile
,
"merge_pip_codec.cfg"
);
}
str
[
0
]
=
0
;
if
(
fin
.
getline
(
str
,
LINE_LENGTH
))
{
printf
(
"load pip codec from %s: %s
\n
"
,
cfgfile
,
str
);
strcpy
(
pip_param
,
str
);
if
(
_codec_config
.
load
(
cfgfile
)
<
0
)
{
printf
(
"open codec config file fail: %s"
,
cfgfile
);
}
str
[
0
]
=
0
;
if
(
fin
.
getline
(
str
,
LINE_LENGTH
))
{
printf
(
"load pip1 codec from %s: %s
\n
"
,
cfgfile
,
str
);
strcpy
(
pip1_param
,
str
);
else
{
printf
(
"open codec config file success: %s"
,
cfgfile
);
}
}
...
...
@@ -1198,17 +1201,13 @@ int process_av_files(char * record_info, int piptype)
int
main
(
int
argc
,
char
*
argv
[])
{
if
(
argc
<
2
)
{
printf
(
" merge_pip 2.0.
3
\n
"
);
printf
(
" merge_pip 2.0.
4
\n
"
);
printf
(
" merge video files to one pip video according to record info file,
\n
usage:"
);
printf
(
"
\n
%s record_info_filename [-t {0,1,2}]"
,
argv
[
0
]);
printf
(
"
\n
%s record_info_filename [-t {0,1,2}]
[-c codec.cfg]
"
,
argv
[
0
]);
printf
(
"
\n\n
"
);
return
-
1
;
}
//get_config_path();
//load_codec_param();
int
piptype
=
0
;
for
(
int
i
=
2
;
i
<
argc
;
i
++
){
if
(
!
strcmp
(
argv
[
i
],
"-t"
)){
...
...
@@ -1219,7 +1218,20 @@ int main(int argc, char * argv[])
}
piptype
=
atoi
(
argv
[
i
]);
}
else
if
(
!
strcmp
(
argv
[
i
],
"-c"
)){
i
++
;
if
(
i
>
argc
)
{
printf
(
"error,should have codec config file name after -c"
);
return
-
2
;
}
strcpy
(
user_codec_cfg
,
argv
[
i
]);
}
}
get_config_path
();
load_codec_param
();
return
process_av_files
(
argv
[
1
],
piptype
);
}
...
...
pip/pip.vcxproj
查看文件 @
dfceaff
...
...
@@ -86,6 +86,7 @@
<ItemGroup>
<ClCompile Include="AudioDecoder.cpp" />
<ClCompile Include="AVDecoder.cpp" />
<ClCompile Include="ConfigFile.cpp" />
<ClCompile Include="merge_pip.cpp" />
<ClCompile Include="tools.cpp" />
<ClCompile Include="VideoDecoder.cpp" />
...
...
@@ -94,6 +95,7 @@
<ItemGroup>
<ClInclude Include="AudioDecoder.h" />
<ClInclude Include="AVDecoder.h" />
<ClInclude Include="ConfigFile.h" />
<ClInclude Include="media_info.h" />
<ClInclude Include="tools.h" />
<ClInclude Include="VideoDecoder.h" />
...
...
pip/pip.vcxproj.filters
查看文件 @
dfceaff
...
...
@@ -36,6 +36,9 @@
<ClCompile Include="merge_pip.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="ConfigFile.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="VideoDecoder.h">
...
...
@@ -56,5 +59,8 @@
<ClInclude Include="tools.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="ConfigFile.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
</Project>
\ No newline at end of file
...
...
请
注册
或
登录
后发表评论