胡斌

V2.0.3

1.没有老师,但是有两个学生时,默认使用一对多布局
2.一对一时,老师和学生的视频尺寸不同时,合成的视频高度取老师视频高度加上学生视频高度(之前版本假定老师和学生视频大小一致,使用的是最大高度的二倍)
3.一对多时,支持学生的视频尺寸不一致的情况(之前版本假定只有一种视频尺寸,其它尺寸视为异常)
4.一对多时,最多只在老师视频下部排4个学生,多于4个学生的情况,扩大合成视频的高度,把学生视频排列在老师视频下方,保证老师视频部分最多只有一排学生视频,避免老师视频被过度遮挡
1 #include "AVDecoder.h" 1 #include "AVDecoder.h"
2 - 2 +extern "C" {
  3 +#include <libswscale/swscale.h>
  4 +}
3 5
4 CAVDecoder::CAVDecoder() : 6 CAVDecoder::CAVDecoder() :
5 _a_start_time_ms(INT64_MAX), 7 _a_start_time_ms(INT64_MAX),
@@ -9,7 +11,12 @@ _cur_v_ts_ms(INT64_MAX), @@ -9,7 +11,12 @@ _cur_v_ts_ms(INT64_MAX),
9 _end_time_ms(0), 11 _end_time_ms(0),
10 _cur_a_frame(NULL), 12 _cur_a_frame(NULL),
11 _cur_v_frame(NULL), 13 _cur_v_frame(NULL),
12 -_media_role(mr_student) 14 +_media_role(mr_student),
  15 +_scaled_width(0),
  16 +_scaled_height(0),
  17 +_src_width(0),
  18 +_src_height(0),
  19 +_sws_ctx(NULL)
13 { 20 {
14 } 21 }
15 22
@@ -18,6 +25,10 @@ CAVDecoder::~CAVDecoder() @@ -18,6 +25,10 @@ CAVDecoder::~CAVDecoder()
18 { 25 {
19 free_cur_v_frame(); 26 free_cur_v_frame();
20 free_cur_a_frame(); 27 free_cur_a_frame();
  28 + if (_sws_ctx) {
  29 + sws_freeContext(_sws_ctx);
  30 + _sws_ctx = NULL;
  31 + }
21 } 32 }
22 33
23 int CAVDecoder::add(media_info &info) 34 int CAVDecoder::add(media_info &info)
@@ -116,6 +127,32 @@ void CAVDecoder::free_cur_a_frame() @@ -116,6 +127,32 @@ void CAVDecoder::free_cur_a_frame()
116 } 127 }
117 } 128 }
118 129
  130 +int CAVDecoder::scale_frame(AVFrame * pFrame, AVFrame * pScaledFrame, int scaled_width, int scaled_height)
  131 +{
  132 + if (pFrame->width == _src_width && pFrame->height == _src_height && scaled_width == _scaled_width && scaled_height == _scaled_height) {
  133 + return sws_scale(_sws_ctx, pFrame->data, pFrame->linesize, 0, pFrame->height,
  134 + pScaledFrame->data, pScaledFrame->linesize);
  135 + }
  136 + else {
  137 + if (_sws_ctx) {
  138 + sws_freeContext(_sws_ctx);
  139 + _sws_ctx = NULL;
  140 + }
  141 + _sws_ctx = sws_getContext(pFrame->width, pFrame->height, AV_PIX_FMT_YUV420P,
  142 + scaled_width, scaled_height, AV_PIX_FMT_YUV420P, SWS_BILINEAR,
  143 + NULL, NULL, NULL);
  144 + if (!_sws_ctx) {
  145 + return -1;
  146 + }
  147 + _src_width = pFrame->width;
  148 + _src_height = pFrame->height;
  149 + _scaled_width = scaled_width;
  150 + _scaled_height = scaled_height;
  151 + return sws_scale(_sws_ctx, pFrame->data, pFrame->linesize, 0, pFrame->height,
  152 + pScaledFrame->data, pScaledFrame->linesize);
  153 + }
  154 +}
  155 +
119 void CAVDecoder::free_cur_v_frame() 156 void CAVDecoder::free_cur_v_frame()
120 { 157 {
121 if (_cur_v_frame) { 158 if (_cur_v_frame) {
@@ -37,5 +37,15 @@ protected: @@ -37,5 +37,15 @@ protected:
37 protected: 37 protected:
38 void free_cur_v_frame(); 38 void free_cur_v_frame();
39 void free_cur_a_frame(); 39 void free_cur_a_frame();
  40 +public:
  41 + int scale_frame(AVFrame * pFrame, AVFrame * pScaledFrame, int scaled_width, int scaled_height);
  42 +
  43 +protected:
  44 + int _scaled_width;
  45 + int _scaled_height;
  46 + int _src_width;
  47 + int _src_height;
  48 + struct SwsContext * _sws_ctx;
  49 +
40 }; 50 };
41 51
@@ -13,8 +13,13 @@ extern "C" { @@ -13,8 +13,13 @@ extern "C" {
13 uint8_t blank_r = 0x16; 13 uint8_t blank_r = 0x16;
14 uint8_t blank_g = 0x5a; 14 uint8_t blank_g = 0x5a;
15 uint8_t blank_b = 0x82; 15 uint8_t blank_b = 0x82;
  16 +int pip_x_gap = 8;
  17 +int pip_y_gap = 4;
  18 +int pip_x_reduce = 3;
  19 +int pip_y_reduce = 3;
  20 +int pip_x_border = 4;
16 21
17 -CAVTranscoder::CAVTranscoder(bool bOne2One, int width_teacher, int height_teacher, int width_student, int height_student) : 22 +CAVTranscoder::CAVTranscoder(bool bOne2One, int width_teacher, int height_teacher, int width_student, int height_student, bool has_teacher, int max_audio) :
18 _start_time(INT64_MAX), 23 _start_time(INT64_MAX),
19 _all_processed(true), 24 _all_processed(true),
20 _nOutputWidth(320), 25 _nOutputWidth(320),
@@ -29,7 +34,9 @@ _scaled_frame_h_w(NULL), @@ -29,7 +34,9 @@ _scaled_frame_h_w(NULL),
29 _scaled_frame_h_h(NULL), 34 _scaled_frame_h_h(NULL),
30 _last_videos_got(-1), 35 _last_videos_got(-1),
31 _teacherFrame(NULL), 36 _teacherFrame(NULL),
32 -_studentFrame(NULL) 37 +_studentFrame(NULL),
  38 +_pip_width(0),
  39 +_pip_height(0)
33 { 40 {
34 _teacher_width = width_teacher; 41 _teacher_width = width_teacher;
35 _teacher_height = height_teacher; 42 _teacher_height = height_teacher;
@@ -38,6 +45,7 @@ _studentFrame(NULL) @@ -38,6 +45,7 @@ _studentFrame(NULL)
38 45
39 _scaled_width = _teacher_width * 10 / 32; 46 _scaled_width = _teacher_width * 10 / 32;
40 _scaled_height = _teacher_height * 10 / 32; 47 _scaled_height = _teacher_height * 10 / 32;
  48 +
41 _one2one = bOne2One; 49 _one2one = bOne2One;
42 if (_one2one) { 50 if (_one2one) {
43 _nOutputWidth = max(_teacher_width, _student_width); 51 _nOutputWidth = max(_teacher_width, _student_width);
@@ -45,7 +53,23 @@ _studentFrame(NULL) @@ -45,7 +53,23 @@ _studentFrame(NULL)
45 } 53 }
46 else { 54 else {
47 _nOutputWidth = _teacher_width; 55 _nOutputWidth = _teacher_width;
48 - _nOutputHeight = _teacher_height; 56 + int n_students = (max_audio - (has_teacher ? 1 : 0));
  57 + int extent_student_lines = n_students / 4;
  58 + int part_student = n_students % 4;
  59 +
  60 + _pip_width = _scaled_height - pip_x_reduce; //use the scaled height,not the scaled width as pip_width
  61 + _pip_height = _scaled_height - pip_y_reduce;
  62 +
  63 + _nOutputHeight = _teacher_height + extent_student_lines * (_pip_height + pip_y_gap) - (part_student == 0 ? (pip_y_gap) : 0);
  64 + _nOutputHeight = ((_nOutputHeight + 1) / 2) * 2;
  65 +
  66 + int student_line_width = 4 * (_pip_width)+3 * pip_x_gap + 2 * pip_x_border;
  67 + if (student_line_width > _nOutputWidth) {
  68 + pip_x_gap -= (student_line_width - _nOutputWidth) / 3;
  69 + }
  70 + student_line_width = 4 * (_pip_width) + 3 * pip_x_gap + 2 * pip_x_border;
  71 + pip_x_border -= (student_line_width - _nOutputWidth) / 2;
  72 +
49 73
50 init_scale_context(&_sws_ctx_w_h, &_scaled_frame_w_h, _student_width, _student_height, _scaled_width, _scaled_height); 74 init_scale_context(&_sws_ctx_w_h, &_scaled_frame_w_h, _student_width, _student_height, _scaled_width, _scaled_height);
51 init_scale_context(&_sws_ctx_h_w, &_scaled_frame_h_w, _student_height, _student_width, _scaled_height, _scaled_width); 75 init_scale_context(&_sws_ctx_h_w, &_scaled_frame_h_w, _student_height, _student_width, _scaled_height, _scaled_width);
@@ -356,12 +380,17 @@ int CAVTranscoder::open_output_file(const char *filename) @@ -356,12 +380,17 @@ int CAVTranscoder::open_output_file(const char *filename)
356 } 380 }
357 if (_teacherFrame) { 381 if (_teacherFrame) {
358 fillDestFrame(pDstFrame, _teacherFrame, 0, 0); 382 fillDestFrame(pDstFrame, _teacherFrame, 0, 0);
  383 + if (_nOutputHeight > _teacherFrame->height) {
  384 + memset(pDstFrame->data[0] + _teacher_height * pDstFrame->linesize[0], _blank_y, pDstFrame->linesize[0] * (_nOutputHeight - _teacherFrame->height));
  385 + memset(pDstFrame->data[1] + _teacher_height / 2 * pDstFrame->linesize[1], _blank_u, pDstFrame->linesize[1] * (_nOutputHeight - _teacherFrame->height) / 2);
  386 + memset(pDstFrame->data[2] + _teacher_height / 2 * pDstFrame->linesize[2], _blank_v, pDstFrame->linesize[2] * (_nOutputHeight - _teacherFrame->height) / 2);
  387 + }
359 } 388 }
360 else 389 else
361 {//fill with pure color 390 {//fill with pure color
362 - memset(pDstFrame->data[0], _blank_y, _nOutputWidth * _nOutputHeight);  
363 - memset(pDstFrame->data[1], _blank_u, _nOutputWidth *_nOutputHeight / 4);  
364 - memset(pDstFrame->data[2], _blank_v, _nOutputWidth * _nOutputHeight / 4); 391 + memset(pDstFrame->data[0], _blank_y, pDstFrame->linesize[0] * _nOutputHeight);
  392 + memset(pDstFrame->data[1], _blank_u, pDstFrame->linesize[1] * _nOutputHeight / 2);
  393 + memset(pDstFrame->data[2], _blank_v, pDstFrame->linesize[2] * _nOutputHeight / 2);
365 } 394 }
366 395
367 int imageIdx = 0; 396 int imageIdx = 0;
@@ -382,7 +411,7 @@ int CAVTranscoder::open_output_file(const char *filename) @@ -382,7 +411,7 @@ int CAVTranscoder::open_output_file(const char *filename)
382 continue; 411 continue;
383 } 412 }
384 _scaled_frame_w_h->pkt_dts = pFrame->pkt_dts;//pass rotation 413 _scaled_frame_w_h->pkt_dts = pFrame->pkt_dts;//pass rotation
385 - fillDestFrame(pDstFrame, _scaled_frame_w_h, _teacher_width - (imageIdx % 4 + 1) * (_scaled_height + 5) + 4, _teacher_height - _scaled_height + 3 - (_scaled_height + 1)*(imageIdx / 4), (_scaled_width - _scaled_height) / 2, 0, _scaled_height - 3, _scaled_height - 3); 414 + fillDestFrame(pDstFrame, _scaled_frame_w_h, _teacher_width - (imageIdx % 4 + 1) * (_pip_width + pip_x_gap) - pip_x_border + pip_x_gap, _nOutputHeight - _scaled_height + pip_y_reduce - (_pip_height + pip_y_gap)*(imageIdx / 4), (_scaled_width - _scaled_height) / 2, 0, _pip_width, _pip_height);
386 } 415 }
387 else if (pFrame->width == _student_height && pFrame->height == _student_width) { 416 else if (pFrame->width == _student_height && pFrame->height == _student_width) {
388 h = sws_scale(_sws_ctx_h_w, pFrame->data, pFrame->linesize, 0, pFrame->height, 417 h = sws_scale(_sws_ctx_h_w, pFrame->data, pFrame->linesize, 0, pFrame->height,
@@ -392,7 +421,7 @@ int CAVTranscoder::open_output_file(const char *filename) @@ -392,7 +421,7 @@ int CAVTranscoder::open_output_file(const char *filename)
392 continue; 421 continue;
393 } 422 }
394 _scaled_frame_h_w->pkt_dts = pFrame->pkt_dts;//pass rotation 423 _scaled_frame_h_w->pkt_dts = pFrame->pkt_dts;//pass rotation
395 - fillDestFrame(pDstFrame, _scaled_frame_h_w, _teacher_width - (imageIdx % 4 + 1) * (_scaled_height + 5) + 4, _teacher_height - _scaled_height + 3 - (_scaled_height + 1)*(imageIdx / 4), 0, (_scaled_width - _scaled_height) / 2, _scaled_height - 3, _scaled_height - 3); 424 + fillDestFrame(pDstFrame, _scaled_frame_h_w, _teacher_width - (imageIdx % 4 + 1) * (_pip_width + pip_x_gap) - pip_x_border + pip_x_gap, _nOutputHeight - _scaled_height + pip_y_reduce - (_pip_height + pip_y_gap)*(imageIdx / 4), 0, (_scaled_width - _scaled_height) / 2, _pip_width, _pip_height);
396 425
397 } 426 }
398 else if (pFrame->width == _student_height && pFrame->height == _student_height) { 427 else if (pFrame->width == _student_height && pFrame->height == _student_height) {
@@ -403,11 +432,37 @@ int CAVTranscoder::open_output_file(const char *filename) @@ -403,11 +432,37 @@ int CAVTranscoder::open_output_file(const char *filename)
403 continue; 432 continue;
404 } 433 }
405 _scaled_frame_h_h->pkt_dts = pFrame->pkt_dts;//pass rotation 434 _scaled_frame_h_h->pkt_dts = pFrame->pkt_dts;//pass rotation
406 - fillDestFrame(pDstFrame, _scaled_frame_h_h, _teacher_width - (imageIdx % 4 + 1) * (_scaled_height + 5) + 4, _teacher_height - _scaled_height + 3 - (_scaled_height + 1)*(imageIdx / 4), 0, 0, _scaled_height - 3, _scaled_height - 3); 435 + fillDestFrame(pDstFrame, _scaled_frame_h_h, _teacher_width - (imageIdx % 4 + 1) * (_pip_width + pip_x_gap) - pip_x_border + pip_x_gap, _nOutputHeight - _scaled_height + pip_y_reduce - (_pip_height + pip_y_gap)*(imageIdx / 4), 0, 0, _pip_width, _pip_height);
407 } 436 }
408 else { 437 else {
409 - printf("\nthe frame resolution %dx%d is unexpected! ignored!", pFrame->width, pFrame->height);  
410 - continue; 438 + if (pFrame->width > pFrame->height) {
  439 + h = pDecoder->scale_frame(pFrame, _scaled_frame_w_h, _scaled_width, _scaled_height);
  440 + if (h <= 0){
  441 + printf("\nscale output result:%d?,ignored", h);
  442 + continue;
  443 + }
  444 + _scaled_frame_w_h->pkt_dts = pFrame->pkt_dts;//pass rotation
  445 + fillDestFrame(pDstFrame, _scaled_frame_w_h, _teacher_width - (imageIdx % 4 + 1) * (_pip_width + pip_x_gap) - pip_x_border + pip_x_gap, _nOutputHeight - _scaled_height + pip_y_reduce - (_pip_height + pip_y_gap)*(imageIdx / 4), (_scaled_width - _scaled_height) / 2, 0, _pip_width, _pip_height);
  446 + }
  447 + else if (pFrame->width == pFrame->height)
  448 + {
  449 + h = pDecoder->scale_frame(pFrame, _scaled_frame_h_h, _scaled_height, _scaled_height);
  450 + if (h <= 0){
  451 + printf("\nscale output result:%d?,ignored", h);
  452 + continue;
  453 + }
  454 + _scaled_frame_h_h->pkt_dts = pFrame->pkt_dts;//pass rotation
  455 + fillDestFrame(pDstFrame, _scaled_frame_h_h, _teacher_width - (imageIdx % 4 + 1) * (_pip_width + pip_x_gap) - pip_x_border + pip_x_gap, _nOutputHeight - _scaled_height + pip_y_reduce - (_pip_height + pip_y_gap)*(imageIdx / 4), 0, 0, _pip_width, _pip_height);
  456 + }
  457 + else {
  458 + h = pDecoder->scale_frame(pFrame, _scaled_frame_h_w, _scaled_height, _scaled_width);
  459 + if (h <= 0){
  460 + printf("\nscale output result:%d?,ignored", h);
  461 + continue;
  462 + }
  463 + _scaled_frame_h_w->pkt_dts = pFrame->pkt_dts;//pass rotation
  464 + fillDestFrame(pDstFrame, _scaled_frame_h_w, _teacher_width - (imageIdx % 4 + 1) * (_pip_width + pip_x_gap) - pip_x_border + pip_x_gap, _nOutputHeight - _scaled_height + pip_y_reduce - (_pip_height + pip_y_gap)*(imageIdx / 4), 0, (_scaled_width - _scaled_height) / 2, _pip_width, _pip_height);
  465 + }
411 } 466 }
412 467
413 imageIdx++; 468 imageIdx++;
@@ -508,9 +563,9 @@ int CAVTranscoder::open_output_file(const char *filename) @@ -508,9 +563,9 @@ int CAVTranscoder::open_output_file(const char *filename)
508 memcpy(pDstFrame->data[0] + (y + i)*pDstFrame->linesize[0] + x, pSrcFrame->data[0] + (i + srcy) * pSrcFrame->linesize[0] + srcx, w); 563 memcpy(pDstFrame->data[0] + (y + i)*pDstFrame->linesize[0] + x, pSrcFrame->data[0] + (i + srcy) * pSrcFrame->linesize[0] + srcx, w);
509 } 564 }
510 565
511 - for (int i = 0; i < h / 2; i++){  
512 - memcpy(pDstFrame->data[1] + (y / 2 + i)*pDstFrame->linesize[1] + x / 2, pSrcFrame->data[1] + (i + srcy / 2) * pSrcFrame->linesize[1] + srcx/2, w / 2);  
513 - memcpy(pDstFrame->data[2] + (y / 2 + i)*pDstFrame->linesize[2] + x / 2, pSrcFrame->data[2] + (i + srcy / 2) * pSrcFrame->linesize[2] + srcx/2, w / 2); 566 + for (int i = 0; i < (h +1) / 2; i++){
  567 + memcpy(pDstFrame->data[1] + (y / 2 + i)*pDstFrame->linesize[1] + x / 2, pSrcFrame->data[1] + (i + srcy / 2) * pSrcFrame->linesize[1] + srcx/2, (w +1)/ 2);
  568 + memcpy(pDstFrame->data[2] + (y / 2 + i)*pDstFrame->linesize[2] + x / 2, pSrcFrame->data[2] + (i + srcy / 2) * pSrcFrame->linesize[2] + srcx/2, (w +1)/ 2);
514 } 569 }
515 } 570 }
516 else if (pSrcFrame->pkt_dts == 180) { 571 else if (pSrcFrame->pkt_dts == 180) {
@@ -525,16 +580,16 @@ int CAVTranscoder::open_output_file(const char *filename) @@ -525,16 +580,16 @@ int CAVTranscoder::open_output_file(const char *filename)
525 } 580 }
526 unsigned char * startSrcU = pSrcFrame->data[1] + pSrcFrame->width / 2 + ((pSrcFrame->height - srcy -1)/ 2) * pSrcFrame->linesize[1] - srcx / 2 - 1; 581 unsigned char * startSrcU = pSrcFrame->data[1] + pSrcFrame->width / 2 + ((pSrcFrame->height - srcy -1)/ 2) * pSrcFrame->linesize[1] - srcx / 2 - 1;
527 unsigned char * startSrcV = pSrcFrame->data[2] + pSrcFrame->width / 2 + ((pSrcFrame->height - srcy -1)/ 2) * pSrcFrame->linesize[2] - srcx / 2 - 1; 582 unsigned char * startSrcV = pSrcFrame->data[2] + pSrcFrame->width / 2 + ((pSrcFrame->height - srcy -1)/ 2) * pSrcFrame->linesize[2] - srcx / 2 - 1;
528 - for (int i = 0; i < h / 2; i++){ 583 + for (int i = 0; i < (h + 1) / 2; i++){
529 unsigned char * psrc = startSrcU - i * pSrcFrame->linesize[1]; 584 unsigned char * psrc = startSrcU - i * pSrcFrame->linesize[1];
530 unsigned char * pdst = pDstFrame->data[1] + (y / 2 + i)*pDstFrame->linesize[1] + x / 2; 585 unsigned char * pdst = pDstFrame->data[1] + (y / 2 + i)*pDstFrame->linesize[1] + x / 2;
531 - unsigned char * pdst_end = pdst + w/2; 586 + unsigned char * pdst_end = pdst + (w + 1)/2;
532 for (; pdst < pdst_end; psrc--, pdst++) { 587 for (; pdst < pdst_end; psrc--, pdst++) {
533 *pdst = *psrc; 588 *pdst = *psrc;
534 } 589 }
535 psrc = startSrcV - i * pSrcFrame->linesize[2]; 590 psrc = startSrcV - i * pSrcFrame->linesize[2];
536 pdst = pDstFrame->data[2] + (y / 2 + i)*pDstFrame->linesize[2] + x / 2; 591 pdst = pDstFrame->data[2] + (y / 2 + i)*pDstFrame->linesize[2] + x / 2;
537 - pdst_end = pdst + w/2; 592 + pdst_end = pdst + (w +1)/2;
538 for (; pdst < pdst_end; psrc--, pdst++) { 593 for (; pdst < pdst_end; psrc--, pdst++) {
539 *pdst = *psrc; 594 *pdst = *psrc;
540 } 595 }
@@ -552,9 +607,9 @@ int CAVTranscoder::open_output_file(const char *filename) @@ -552,9 +607,9 @@ int CAVTranscoder::open_output_file(const char *filename)
552 } 607 }
553 608
554 unsigned char * startSrcU = pSrcFrame->data[1] + srcy/2 * pSrcFrame->linesize[1] + srcx/2; 609 unsigned char * startSrcU = pSrcFrame->data[1] + srcy/2 * pSrcFrame->linesize[1] + srcx/2;
555 - for (int i = 0; i < h/2; i++) { 610 + for (int i = 0; i < (h + 1)/2; i++) {
556 unsigned char * psrc = startSrcU + i* pSrcFrame->linesize[1]; 611 unsigned char * psrc = startSrcU + i* pSrcFrame->linesize[1];
557 - unsigned char * psrc_end = psrc + w/2; 612 + unsigned char * psrc_end = psrc + (w +1)/2;
558 unsigned char * pdst = pDstFrame->data[1] + y/2*pDstFrame->linesize[1] + h/2 -1 - i +x/2; 613 unsigned char * pdst = pDstFrame->data[1] + y/2*pDstFrame->linesize[1] + h/2 -1 - i +x/2;
559 for (; psrc < psrc_end; psrc++, pdst += pDstFrame->linesize[1]) { 614 for (; psrc < psrc_end; psrc++, pdst += pDstFrame->linesize[1]) {
560 *pdst = *psrc; 615 *pdst = *psrc;
@@ -562,9 +617,9 @@ int CAVTranscoder::open_output_file(const char *filename) @@ -562,9 +617,9 @@ int CAVTranscoder::open_output_file(const char *filename)
562 } 617 }
563 618
564 unsigned char * startSrcV= pSrcFrame->data[2] + srcy / 2 * pSrcFrame->linesize[2] + srcx / 2; 619 unsigned char * startSrcV= pSrcFrame->data[2] + srcy / 2 * pSrcFrame->linesize[2] + srcx / 2;
565 - for (int i = 0; i < h / 2; i++) { 620 + for (int i = 0; i < (h + 1) / 2; i++) {
566 unsigned char * psrc = startSrcV + i* pSrcFrame->linesize[2]; 621 unsigned char * psrc = startSrcV + i* pSrcFrame->linesize[2];
567 - unsigned char * psrc_end = psrc + w / 2; 622 + unsigned char * psrc_end = psrc + (w + 1) / 2;
568 unsigned char * pdst = pDstFrame->data[2] + y / 2 * pDstFrame->linesize[2] + h / 2 -1 - i + x/2; 623 unsigned char * pdst = pDstFrame->data[2] + y / 2 * pDstFrame->linesize[2] + h / 2 -1 - i + x/2;
569 for (; psrc < psrc_end; psrc++, pdst += pDstFrame->linesize[2]) { 624 for (; psrc < psrc_end; psrc++, pdst += pDstFrame->linesize[2]) {
570 *pdst = *psrc; 625 *pdst = *psrc;
@@ -607,55 +662,55 @@ int CAVTranscoder::open_output_file(const char *filename) @@ -607,55 +662,55 @@ int CAVTranscoder::open_output_file(const char *filename)
607 } 662 }
608 663
609 if (!_teacherFrame || !_studentFrame) { 664 if (!_teacherFrame || !_studentFrame) {
610 - memset(pDstFrame->data[0], _blank_y, _nOutputWidth * _nOutputHeight);  
611 - memset(pDstFrame->data[1], _blank_u, _nOutputWidth * _nOutputHeight / 4);  
612 - memset(pDstFrame->data[2], _blank_v, _nOutputWidth * _nOutputHeight / 4); 665 + memset(pDstFrame->data[0], _blank_y, pDstFrame->linesize[0] * _nOutputHeight);
  666 + memset(pDstFrame->data[1], _blank_u, pDstFrame->linesize[1] * _nOutputHeight / 2);
  667 + memset(pDstFrame->data[2], _blank_v, pDstFrame->linesize[2] * _nOutputHeight / 2);
613 } 668 }
614 669
615 if (_teacherFrame) { 670 if (_teacherFrame) {
616 if (_teacherFrame->width == _teacher_width && _teacherFrame->height == _teacher_height) { 671 if (_teacherFrame->width == _teacher_width && _teacherFrame->height == _teacher_height) {
617 if (_teacherFrame->pkt_dts != 90){ 672 if (_teacherFrame->pkt_dts != 90){
618 if (_teacher_width < _nOutputWidth) { 673 if (_teacher_width < _nOutputWidth) {
619 - memset(pDstFrame->data[0], _blank_y, _nOutputWidth * _teacher_height);  
620 - memset(pDstFrame->data[1], _blank_u, _nOutputWidth * _teacher_height / 4);  
621 - memset(pDstFrame->data[2], _blank_v, _nOutputWidth * _teacher_height / 4); 674 + memset(pDstFrame->data[0], _blank_y, pDstFrame->linesize[0] * _teacher_height);
  675 + memset(pDstFrame->data[1], _blank_u, pDstFrame->linesize[1] * _teacher_height / 2);
  676 + memset(pDstFrame->data[2], _blank_v, pDstFrame->linesize[2] * _teacher_height / 2);
622 } 677 }
623 fillDestFrame(pDstFrame, _teacherFrame, 0, 0); 678 fillDestFrame(pDstFrame, _teacherFrame, 0, 0);
624 } 679 }
625 else { 680 else {
626 memset(pDstFrame->data[0], _blank_y, _nOutputWidth * _teacher_height); 681 memset(pDstFrame->data[0], _blank_y, _nOutputWidth * _teacher_height);
627 - memset(pDstFrame->data[1], _blank_u, _nOutputWidth * _teacher_height / 4);  
628 - memset(pDstFrame->data[2], _blank_v, _nOutputWidth * _teacher_height / 4); 682 + memset(pDstFrame->data[1], _blank_u, _nOutputWidth * _teacher_height / 2);
  683 + memset(pDstFrame->data[2], _blank_v, _nOutputWidth * _teacher_height / 2);
629 fillDestFrame(pDstFrame, _teacherFrame, (_nOutputWidth - _teacher_height) / 2, 0, (_teacher_width - _teacher_height) / 2, 0, _teacher_height, _teacher_height); 684 fillDestFrame(pDstFrame, _teacherFrame, (_nOutputWidth - _teacher_height) / 2, 0, (_teacher_width - _teacher_height) / 2, 0, _teacher_height, _teacher_height);
630 } 685 }
631 } 686 }
632 else if (_teacherFrame->width == _teacher_height && _teacherFrame->height == _teacher_width) { 687 else if (_teacherFrame->width == _teacher_height && _teacherFrame->height == _teacher_width) {
633 if (_teacherFrame->pkt_dts == 90){ 688 if (_teacherFrame->pkt_dts == 90){
634 if (_teacher_width < _nOutputWidth) { 689 if (_teacher_width < _nOutputWidth) {
635 - memset(pDstFrame->data[0], _blank_y, _nOutputWidth * _teacher_height);  
636 - memset(pDstFrame->data[1], _blank_u, _nOutputWidth * _teacher_height / 4);  
637 - memset(pDstFrame->data[2], _blank_v, _nOutputWidth * _teacher_height / 4); 690 + memset(pDstFrame->data[0], _blank_y, pDstFrame->linesize[0] * _teacher_height);
  691 + memset(pDstFrame->data[1], _blank_u, pDstFrame->linesize[1] * _teacher_height / 2);
  692 + memset(pDstFrame->data[2], _blank_v, pDstFrame->linesize[2] * _teacher_height / 2);
638 } 693 }
639 fillDestFrame(pDstFrame, _teacherFrame, 0, 0); 694 fillDestFrame(pDstFrame, _teacherFrame, 0, 0);
640 } 695 }
641 else { 696 else {
642 - memset(pDstFrame->data[0], _blank_y, _nOutputWidth * _teacher_height);  
643 - memset(pDstFrame->data[1], _blank_u, _nOutputWidth * _teacher_height / 4);  
644 - memset(pDstFrame->data[2], _blank_v, _nOutputWidth * _teacher_height / 4); 697 + memset(pDstFrame->data[0], _blank_y, pDstFrame->linesize[0] * _teacher_height);
  698 + memset(pDstFrame->data[1], _blank_u, pDstFrame->linesize[1] * _teacher_height / 2);
  699 + memset(pDstFrame->data[2], _blank_v, pDstFrame->linesize[2] * _teacher_height / 2);
645 fillDestFrame(pDstFrame, _teacherFrame, (_nOutputWidth - _teacher_height) / 2, 0, 0, (_teacher_width - _teacher_height) / 2, _teacher_height, _teacher_height); 700 fillDestFrame(pDstFrame, _teacherFrame, (_nOutputWidth - _teacher_height) / 2, 0, 0, (_teacher_width - _teacher_height) / 2, _teacher_height, _teacher_height);
646 } 701 }
647 } 702 }
648 else if (_teacherFrame->width == _teacher_height && _teacherFrame->height == _teacher_height) { 703 else if (_teacherFrame->width == _teacher_height && _teacherFrame->height == _teacher_height) {
649 - memset(pDstFrame->data[0], _blank_y, _nOutputWidth * _teacher_height);  
650 - memset(pDstFrame->data[1], _blank_u, _nOutputWidth * _teacher_height / 4);  
651 - memset(pDstFrame->data[2], _blank_v, _nOutputWidth * _teacher_height / 4); 704 + memset(pDstFrame->data[0], _blank_y, pDstFrame->linesize[0] * _teacher_height);
  705 + memset(pDstFrame->data[1], _blank_u, pDstFrame->linesize[1] * _teacher_height / 2);
  706 + memset(pDstFrame->data[2], _blank_v, pDstFrame->linesize[2] * _teacher_height / 2);
652 fillDestFrame(pDstFrame, _teacherFrame, (_nOutputWidth - _teacher_height) / 2, 0); 707 fillDestFrame(pDstFrame, _teacherFrame, (_nOutputWidth - _teacher_height) / 2, 0);
653 } 708 }
654 else { 709 else {
655 //printf("\nresolution: %dx%d unexpected!", _teacherFrame->width, _teacherFrame->height); 710 //printf("\nresolution: %dx%d unexpected!", _teacherFrame->width, _teacherFrame->height);
656 - memset(pDstFrame->data[0], _blank_y, _nOutputWidth * _teacher_height);  
657 - memset(pDstFrame->data[1], _blank_u, _nOutputWidth * _teacher_height / 4);  
658 - memset(pDstFrame->data[2], _blank_v, _nOutputWidth * _teacher_height / 4); 711 + memset(pDstFrame->data[0], _blank_y, pDstFrame->linesize[0] * _teacher_height);
  712 + memset(pDstFrame->data[1], _blank_u, pDstFrame->linesize[1] * _teacher_height / 2);
  713 + memset(pDstFrame->data[2], _blank_v, pDstFrame->linesize[2] * _teacher_height / 2);
659 714
660 fillDestFrame(pDstFrame, _teacherFrame, 0, 0); 715 fillDestFrame(pDstFrame, _teacherFrame, 0, 0);
661 } 716 }
@@ -663,31 +718,31 @@ int CAVTranscoder::open_output_file(const char *filename) @@ -663,31 +718,31 @@ int CAVTranscoder::open_output_file(const char *filename)
663 if (_studentFrame->width == _student_width) { 718 if (_studentFrame->width == _student_width) {
664 if (_studentFrame->pkt_dts != 90){ 719 if (_studentFrame->pkt_dts != 90){
665 if (_student_width < _nOutputWidth) { 720 if (_student_width < _nOutputWidth) {
666 - memset(pDstFrame->data[0] + _teacher_height * pDstFrame->linesize[0], _blank_y, _nOutputWidth * _student_height);  
667 - memset(pDstFrame->data[1] + _teacher_height / 2 * pDstFrame->linesize[1], _blank_u, _nOutputWidth * _student_height / 4);  
668 - memset(pDstFrame->data[2] + _teacher_height / 2 * pDstFrame->linesize[2], _blank_v, _nOutputWidth * _student_height / 4); 721 + memset(pDstFrame->data[0] + _teacher_height * pDstFrame->linesize[0], _blank_y, pDstFrame->linesize[0] * _student_height);
  722 + memset(pDstFrame->data[1] + _teacher_height / 2 * pDstFrame->linesize[1], _blank_u, pDstFrame->linesize[1] * _student_height / 2);
  723 + memset(pDstFrame->data[2] + _teacher_height / 2 * pDstFrame->linesize[2], _blank_v, pDstFrame->linesize[2] * _student_height / 2);
669 } 724 }
670 fillDestFrame(pDstFrame, _studentFrame, 0, _teacher_height); 725 fillDestFrame(pDstFrame, _studentFrame, 0, _teacher_height);
671 } 726 }
672 else { 727 else {
673 - memset(pDstFrame->data[0] + _teacher_height * pDstFrame->linesize[0], _blank_y, _nOutputWidth * _student_height);  
674 - memset(pDstFrame->data[1] + _teacher_height / 2 * pDstFrame->linesize[1], _blank_u, _nOutputWidth * _student_height / 4);  
675 - memset(pDstFrame->data[2] + _teacher_height / 2 * pDstFrame->linesize[2], _blank_v, _nOutputWidth * _student_height / 4); 728 + memset(pDstFrame->data[0] + _teacher_height * pDstFrame->linesize[0], _blank_y, pDstFrame->linesize[0] * _student_height);
  729 + memset(pDstFrame->data[1] + _teacher_height / 2 * pDstFrame->linesize[1], _blank_u, pDstFrame->linesize[1] * _student_height / 2);
  730 + memset(pDstFrame->data[2] + _teacher_height / 2 * pDstFrame->linesize[2], _blank_v, pDstFrame->linesize[2] * _student_height / 2);
676 fillDestFrame(pDstFrame, _studentFrame, (_nOutputWidth - _student_height) / 2, _teacher_height, (_student_width - _student_height) / 2, 0, _student_height, _student_height); 731 fillDestFrame(pDstFrame, _studentFrame, (_nOutputWidth - _student_height) / 2, _teacher_height, (_student_width - _student_height) / 2, 0, _student_height, _student_height);
677 } 732 }
678 } 733 }
679 else if (_studentFrame->pkt_dts == 90){ 734 else if (_studentFrame->pkt_dts == 90){
680 if (_student_width < _nOutputWidth) { 735 if (_student_width < _nOutputWidth) {
681 - memset(pDstFrame->data[0] + _teacher_height * pDstFrame->linesize[0], _blank_y, _nOutputWidth * _student_height);  
682 - memset(pDstFrame->data[1] + _teacher_height / 2 * pDstFrame->linesize[1], _blank_u, _nOutputWidth * _student_height / 4);  
683 - memset(pDstFrame->data[2] + _teacher_height / 2 * pDstFrame->linesize[2], _blank_v, _nOutputWidth * _student_height / 4); 736 + memset(pDstFrame->data[0] + _teacher_height * pDstFrame->linesize[0], _blank_y, pDstFrame->linesize[0] * _student_height);
  737 + memset(pDstFrame->data[1] + _teacher_height / 2 * pDstFrame->linesize[1], _blank_u, pDstFrame->linesize[1] * _student_height / 2);
  738 + memset(pDstFrame->data[2] + _teacher_height / 2 * pDstFrame->linesize[2], _blank_v, pDstFrame->linesize[2] * _student_height / 2);
684 } 739 }
685 fillDestFrame(pDstFrame, _studentFrame, 0, _teacher_height); 740 fillDestFrame(pDstFrame, _studentFrame, 0, _teacher_height);
686 } 741 }
687 else { 742 else {
688 - memset(pDstFrame->data[0] + _teacher_height * pDstFrame->linesize[0], _blank_y, _nOutputWidth * _student_height);  
689 - memset(pDstFrame->data[1] + _teacher_height / 2 * pDstFrame->linesize[1], _blank_u, _nOutputWidth * _student_height / 4);  
690 - memset(pDstFrame->data[2] + _teacher_height / 2 * pDstFrame->linesize[2], _blank_v, _nOutputWidth * _student_height / 4); 743 + memset(pDstFrame->data[0] + _teacher_height * pDstFrame->linesize[0], _blank_y, pDstFrame->linesize[0] * _student_height);
  744 + memset(pDstFrame->data[1] + _teacher_height / 2 * pDstFrame->linesize[1], _blank_u, pDstFrame->linesize[1] * _student_height / 2);
  745 + memset(pDstFrame->data[2] + _teacher_height / 2 * pDstFrame->linesize[2], _blank_v, pDstFrame->linesize[2] * _student_height / 2);
691 fillDestFrame(pDstFrame, _studentFrame, (_nOutputWidth - _student_height) / 2, _teacher_height, 0, (_student_width - _student_height) / 2, _student_height, _student_height); 746 fillDestFrame(pDstFrame, _studentFrame, (_nOutputWidth - _student_height) / 2, _teacher_height, 0, (_student_width - _student_height) / 2, _student_height, _student_height);
692 } 747 }
693 } 748 }
@@ -714,9 +769,9 @@ int CAVTranscoder::open_output_file(const char *filename) @@ -714,9 +769,9 @@ int CAVTranscoder::open_output_file(const char *filename)
714 } 769 }
715 else { 770 else {
716 //printf("\nresolution: %dx%d unexpected!", _studentFrame->width, _studentFrame->height); 771 //printf("\nresolution: %dx%d unexpected!", _studentFrame->width, _studentFrame->height);
717 - memset(pDstFrame->data[0], _blank_y, _nOutputWidth * _student_height);  
718 - memset(pDstFrame->data[1], _blank_u, _nOutputWidth * _student_height / 4);  
719 - memset(pDstFrame->data[2], _blank_v, _nOutputWidth * _student_height / 4); 772 + memset(pDstFrame->data[0], _blank_y, pDstFrame->linesize[0] * _teacher_height);
  773 + memset(pDstFrame->data[1], _blank_u, pDstFrame->linesize[1] * _teacher_height / 2);
  774 + memset(pDstFrame->data[2], _blank_v, pDstFrame->linesize[2] * _teacher_height / 2);
720 fillDestFrame(pDstFrame, _studentFrame, 0, 0); 775 fillDestFrame(pDstFrame, _studentFrame, 0, 0);
721 } 776 }
722 } 777 }
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 class CAVTranscoder 5 class CAVTranscoder
6 { 6 {
7 public: 7 public:
8 - CAVTranscoder(bool bOne2One, int width_teacher, int height_teacher, int student_width,int student_height); 8 + CAVTranscoder(bool bOne2One, int width_teacher, int height_teacher, int student_width,int student_height, bool has_teacher, int max_audio);
9 virtual ~CAVTranscoder(); 9 virtual ~CAVTranscoder();
10 10
11 int add(media_info & info); 11 int add(media_info & info);
@@ -46,6 +46,8 @@ private: @@ -46,6 +46,8 @@ private:
46 int _max_audio; 46 int _max_audio;
47 int _scaled_width; 47 int _scaled_width;
48 int _scaled_height; 48 int _scaled_height;
  49 + int _pip_width;
  50 + int _pip_height;
49 int _teacher_width; 51 int _teacher_width;
50 int _teacher_height; 52 int _teacher_height;
51 int _student_width; 53 int _student_width;
@@ -42,5 +42,11 @@ V2.0.1 @@ -42,5 +42,11 @@ V2.0.1
42 42
43 V2.0.2 43 V2.0.2
44 1.修改学生视频为320x240,老师的视频为240x180时,老师背景有花屏 44 1.修改学生视频为320x240,老师的视频为240x180时,老师背景有花屏
45 -2.修改老师和学生视频都为240x180视频时,视频宽度仍为240, 且有花屏  
46 -3.只有一路视频时,默认合成为上下布局  
  45 +2.修改老师和学生视频都为240x180视频时,视频宽度仍为240(由于之前假定只有320x240的视频尺寸), 且有花屏
  46 +3.只有一路视频时,默认合成为上下布局
  47 +
  48 +V2.0.3
  49 +1.没有老师,但是有两个学生时,默认使用一对多布局
  50 +2.一对一时,老师和学生的视频尺寸不同时,合成的视频高度取老师视频高度加上学生视频高度(之前版本假定老师和学生视频大小一致,使用的是最大高度的二倍)
  51 +3.一对多时,支持学生的视频尺寸不一致的情况(之前版本假定只有一种视频尺寸,其它尺寸视为异常)
  52 +4.一对多时,最多只在老师视频下部排4个学生,多于4个学生的情况,扩大合成视频的高度,把学生视频排列在老师视频下方,保证老师视频部分最多只有一排学生视频,避免老师视频被过度遮挡
@@ -1123,7 +1123,7 @@ int process_av_files(char * record_info, int piptype) @@ -1123,7 +1123,7 @@ int process_av_files(char * record_info, int piptype)
1123 } 1123 }
1124 } 1124 }
1125 1125
1126 - CAVTranscoder videoTranscoder(one2one, width_teacher, height_teacher,width_student, height_student); 1126 + CAVTranscoder videoTranscoder(one2one, width_teacher, height_teacher,width_student, height_student, has_teacher, max_audio);
1127 videoTranscoder.set_max_audio(max_audio); 1127 videoTranscoder.set_max_audio(max_audio);
1128 1128
1129 int64_t cur_time = 0; 1129 int64_t cur_time = 0;