胡斌

V2.0.13

1.命令行增加可选参数-r {0|1},控制视频缩放后是否裁剪以适应目标区域
2.命令行增加可选参数-k {0|1},控制一对多时合成的视频是否保持4:3宽高比
... ... @@ -34,7 +34,7 @@ int g_fps;
#define ensure_no_zero(x, v) if(!x) x = v
CAVTranscoder::CAVTranscoder(bool bOne2One, bool one2one_same_size, bool one2many_inflat, int width_teacher, int height_teacher, int width_student, int height_student, bool has_teacher, int max_audio, int max_video, int keep_4_3) :
CAVTranscoder::CAVTranscoder(bool bOne2One, bool one2one_same_size, bool one2many_inflat, int width_teacher, int height_teacher, int width_student, int height_student, bool has_teacher, int max_audio, int max_video, bool crop, bool keep_4_3) :
_start_time(INT64_MAX),
_all_processed(true),
_nOutputWidth(320),
... ... @@ -61,7 +61,8 @@ _src_width_teacher(0),
_src_height_teacher(0),
_src_width_student(0),
_src_height_student(0),
_one2one_same_size(one2one_same_size)
_one2one_same_size(one2one_same_size),
_crop(crop)
{
ensure_no_zero(width_teacher, 320);
ensure_no_zero(height_teacher, 240);
... ... @@ -120,6 +121,15 @@ _one2one_same_size(one2one_same_size)
_nOutputHeight = _nOutputHeight - (part_student == 0 ? (pip_y_gap) : 0);
}
_nOutputHeight = ((_nOutputHeight + 1) / 2) * 2;
if (keep_4_3){
int nOutputHeight = _nOutputWidth * 3 / 4;
if (_nOutputHeight < nOutputHeight) {
_nOutputHeight = nOutputHeight;
}
}
if (_crop){
_teacher_height = _nOutputHeight;
}
int student_line_width = 4 * (_pip_width)+3 * pip_x_gap + 2 * pip_x_border;
if (student_line_width > _nOutputWidth) {
... ... @@ -785,7 +795,12 @@ int CAVTranscoder::open_output_file(const char *filename)
memset(pDstFrame->data[0], _blank_y, pDstFrame->linesize[0] * _teacher_height);
memset(pDstFrame->data[1], _blank_u, pDstFrame->linesize[1] * _teacher_height / 2);
memset(pDstFrame->data[2], _blank_v, pDstFrame->linesize[2] * _teacher_height / 2);
fillDestFrame(pDstFrame, _teacherFrame, (_nOutputWidth - _teacherFrame->width) / 2, (_teacher_height - _teacherFrame->height) / 2);
if (_crop){
fillDestFrame(pDstFrame, _teacherFrame, 0, 0, (_teacherFrame->width - _teacher_width) / 2, (_teacherFrame->height - _teacher_height) / 2, _teacher_width, _teacher_height);
}
else {
fillDestFrame(pDstFrame, _teacherFrame, (_nOutputWidth - _teacherFrame->width) / 2, (_teacher_height - _teacherFrame->height) / 2);
}
}
else {
fillDestFrame(pDstFrame, _teacherFrame, 0, 0);
... ... @@ -835,7 +850,12 @@ int CAVTranscoder::open_output_file(const char *filename)
memset(pDstFrame->data[0] + y * pDstFrame->linesize[0], _blank_y, pDstFrame->linesize[0] * _student_height);
memset(pDstFrame->data[1] + y * pDstFrame->linesize[1] / 2, _blank_u, pDstFrame->linesize[1] * _student_height / 2);
memset(pDstFrame->data[2] + y * pDstFrame->linesize[2] / 2, _blank_v, pDstFrame->linesize[2] * _student_height / 2);
fillDestFrame(pDstFrame, _studentFrame, (_nOutputWidth - _studentFrame->width) / 2, (_student_height - _studentFrame->height) / 2 + y);
if (_crop){
fillDestFrame(pDstFrame, _studentFrame, 0, y, (_studentFrame->width - _student_width) / 2, (_studentFrame->height - _student_height) / 2,_student_width,_student_height);
}
else{
fillDestFrame(pDstFrame, _studentFrame, (_nOutputWidth - _studentFrame->width) / 2, (_student_height - _studentFrame->height) / 2 + y);
}
}
else {
fillDestFrame(pDstFrame, _studentFrame, 0, y);
... ... @@ -911,13 +931,25 @@ int CAVTranscoder::open_output_file(const char *filename)
if (pFrame->pkt_dts == 0 || pFrame->pkt_dts == 180) {
double src_wh_ratio = pFrame->width / (double)pFrame->height;
double dest_wh_ratio = dest_width / (double)dest_height;
if (src_wh_ratio > dest_wh_ratio) {
*scaled_width = dest_width;
*scaled_height =(int)( dest_width / src_wh_ratio + 0.5);
if (_crop){
if (src_wh_ratio > dest_wh_ratio) {
*scaled_width = (int)(dest_width*src_wh_ratio + 0.5);
*scaled_height = dest_height;
}
else {
*scaled_width = dest_width;
*scaled_height = (int)(dest_width / src_wh_ratio + 0.5);
}
}
else {
*scaled_height = dest_height;
*scaled_width = (int)(dest_height * src_wh_ratio);
if (src_wh_ratio > dest_wh_ratio) {
*scaled_width = dest_width;
*scaled_height = (int)(dest_width / src_wh_ratio + 0.5);
}
else {
*scaled_height = dest_height;
*scaled_width = (int)(dest_height * src_wh_ratio);
}
}
}
else {
... ... @@ -943,7 +975,12 @@ int CAVTranscoder::open_output_file(const char *filename)
free_scale_context(&_sws_ctx_teacher, &_scaled_frame_teacher);
int scaled_width, scaled_height;
get_scaled_dest_size(_teacherFrame, _teacher_width, _teacher_height, &scaled_width, &scaled_height);
if (_crop){
get_scaled_dest_size(_teacherFrame, _nOutputWidth, _nOutputHeight, &scaled_width, &scaled_height);
}
else {
get_scaled_dest_size(_teacherFrame, _teacher_width, _teacher_height, &scaled_width, &scaled_height);
}
init_scale_context(&_sws_ctx_teacher, &_scaled_frame_teacher, _teacherFrame->width, _teacherFrame->height, scaled_width, scaled_height);
_src_width_teacher = _teacherFrame->width;
... ... @@ -965,7 +1002,12 @@ int CAVTranscoder::open_output_file(const char *filename)
memset(pDstFrame->data[1], _blank_u, pDstFrame->linesize[1] * (_teacherFrame->height) / 2);
memset(pDstFrame->data[2], _blank_v, pDstFrame->linesize[2] * (_teacherFrame->height) / 2);
}
fillDestFrame(pDstFrame, _teacherFrame, 0, 0);
if (_crop){
fillDestFrame(pDstFrame, _teacherFrame, 0, 0, (_teacherFrame->width - _nOutputWidth) / 2, (_teacherFrame->height - _nOutputHeight) / 2, _nOutputWidth, _nOutputHeight);
}
else {
fillDestFrame(pDstFrame, _teacherFrame, 0, 0);
}
return 0;
}
... ...
... ... @@ -5,7 +5,7 @@
class CAVTranscoder
{
public:
CAVTranscoder(bool bOne2One, bool one2one_same_size, bool one2many_inflat, int width_teacher, int height_teacher, int student_width, int student_height, bool has_teacher, int max_audio, int max_video, int keep_4_3= true);
CAVTranscoder(bool bOne2One, bool one2one_same_size, bool one2many_inflat, int width_teacher, int height_teacher, int student_width, int student_height, bool has_teacher, int max_audio, int max_video, bool crop = false, bool keep_4_3= true);
virtual ~CAVTranscoder();
int add(media_info & info);
... ... @@ -56,6 +56,7 @@ private:
int _student_width;
int _student_height;
bool _one2one_same_size;//top and bottom are same size ,if not ,scale the smaller to the larger
bool _crop;//
struct SwsContext * _sws_ctx_w_h; //for one2many student frame
struct SwsContext * _sws_ctx_h_w;
struct SwsContext * _sws_ctx_h_h;
... ...
... ... @@ -51,12 +51,23 @@ merge_pip_codec.cfg主要编码参数:
1 在一对一时, 如果老师和学生的视频大小不一致,会放大较小的视频使得老师和学生视频大小相同。在一对多时,如果老师视频由多段不同分辨率视频组成,会对老师视频进行缩放统一
0 保持原有视频大小
-r 为可选参数。缺省为0
0 视频保持原有宽高比缩放后,宽或高与目标区域相同,完整视频放置在目标区域,上下或左右填充背景色
1 视频保持原有宽高比缩放后,宽或高与目标区域相同,裁剪上下或左右,铺满目标区域
-k 为可选参数。缺省为1
0 1对多时,合成的视频大小为老师原始视频大小
1 1对多时,合成的视频保持4:3的宽高比
合屏后生成完成信息文件,文件名为"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内容:
m_1.mp4 859282931_20181112133025316.mp4 3397.150
V2.0.1
1.修改bug: 复制缩小后的视频时,U、V分量x偏移不正确
... ... @@ -101,4 +112,8 @@ V2.0.11
1.修改1对多布局时,缺省不扩大合成视频大小,-t 3参数时才根据学生数量扩大合成视频大小
V2.0.12
1.在一对一时,强制老师和学生的视频大小一致,且宽高比均为4:3,当不为4:3时,保持视频原始宽高比,水平或垂直居中
\ No newline at end of file
1.在一对一时,强制老师和学生的视频大小一致,且宽高比均为4:3,当不为4:3时,保持视频原始宽高比,水平或垂直居中
V2.0.13
1.命令行增加可选参数-r {0|1},控制视频缩放后是否裁剪以适应目标区域
2.命令行增加可选参数-k {0|1},控制一对多时合成的视频是否保持4:3宽高比
\ No newline at end of file
... ...
... ... @@ -14,6 +14,8 @@
bool only_print = false;
bool keep_tmp_files = false;
bool out_one_video = true;
bool crop = false;
bool keep_4_3 = false;
class fileinfo {
... ... @@ -683,6 +685,7 @@ int height_teacher = 0;
int width_student = 0;
int height_student = 0;
bool has_teacher = false;
bool has_student = false;
void add_media_infos()
{
... ... @@ -780,6 +783,7 @@ void add_media_infos()
}
}
else {
has_student = true;
if (it->rotate == 0 || it->rotate == 180) {
if (width_student < it->width) {
width_student = it->width;
... ... @@ -942,7 +946,7 @@ float get_uid_start_time_from_filename(const char * filename, unsigned int &uid)
const char * end = strstr(start + 1, "_");
if (end) {//get the next
*(char *)end = 0;
uid = atoi(start + 1);
uid = atoi(start);
*(char *)end = '_';
start = end;
... ... @@ -1173,6 +1177,10 @@ int process_av_files(char * record_info, int piptype, bool one2one_same_size, in
one2one = false;
}
if (has_student == false){
one2one = false;
}
bool one_to_many_inflat = false;
if (1 == piptype) {
... ... @@ -1202,7 +1210,11 @@ int process_av_files(char * record_info, int piptype, bool one2one_same_size, in
}
}
CAVTranscoder videoTranscoder(one2one, one2one_same_size, one_to_many_inflat, width_teacher, height_teacher, width_student, height_student, has_teacher, max_audio, max_video);
bool k = keep_4_3;
if (one2one){
k = true;
}
CAVTranscoder videoTranscoder(one2one, one2one_same_size, one_to_many_inflat, width_teacher, height_teacher, width_student, height_student, has_teacher, max_audio, max_video, crop, k);
int64_t cur_time = 0;
bool has_file = sorted_media.size()!=0;
... ... @@ -1285,9 +1297,9 @@ int process_av_files(char * record_info, int piptype, bool one2one_same_size, in
int main(int argc, char * argv[])
{
if (argc < 2) {
printf(" merge_pip 2.0.12\n");
printf(" merge_pip 2.0.13\n");
printf(" merge video files to one pip video according to record info file,\nusage:");
printf("\n %s record_info_filename [-t {0,1,2,3}] [-c codec.cfg] [-s {1,0}]", argv[0]);
printf("\n %s record_info_filename [-t {0,1,2,3}] [-c codec.cfg] [-s {1,0}] [-r {0,1}] [-k {0,1}]", argv[0]);
printf("\n\n");
return -1;
}
... ... @@ -1328,6 +1340,22 @@ int main(int argc, char * argv[])
}
max_duration = atoi(argv[i]);
}
else if (!strcmp(argv[i], "-r")){
i++;
if (i > argc) {
printf("error,should be 0 or 1 after -r");
return -2;
}
crop = atoi(argv[i]);
}
else if (!strcmp(argv[i], "-k")){
i++;
if (i > argc) {
printf("error,should be 1 or 0 after -k");
return -2;
}
keep_4_3 = atoi(argv[i]);
}
}
... ...