Введение:
OWT — это ** «Открытый набор инструментов WebRTC»Аббревиатура для видеоконференций Intel с открытым исходным кодом.«SFU + MCU» ** Система, заимствованная из официального Git Readme Описание:
❝
The media server for OWT provides an efficient video conference and streaming service that is based on WebRTC. It scales a single WebRTC stream out to many endpoints. At the same time, it enables media analytics capabilities for media streams. It features:
Distributed, scalable, and reliable SFU + MCU server Высокопроизводительное транскодирование VP8, VP9, H.264 и HEVC в реальном времени на процессорах Intel® Core™ и Intel® Xeon® Wide streaming protocols support including WebRTC, RTSP, RTMP, HLS, MPEG-DASH Efficient mixing of HD video streams to save bandwidth and power on mobile devices Intelligent Quality of Service (QoS) control mechanisms that adapt to different network environments Customer defined media analytics plugins to perform analytics on streams from MCU The usage scenarios for real-time media stream analytics including but not limited to movement/object detection❞
Настройка среды и работа
Пожалуйста, обратитесь кOWT-Server User GuideиБыстрый старт на сервере OWT,Ван Ли объяснил конструкцию, отладку и анализ среды сервера OWT.
Часто задаваемые вопросы и примечания
-
Версия узла должна использовать v8.15.0.
-
Текущая основная ветка будет использовать webrtc-m79.Синхронизация и компиляция кода занимает много времени.Необходимо использовать стабильную VPN, а общий код занимает около 17G, что требует большой емкости жесткого диска.Рекомендуется использовать и отлаживать ветку 4.3.x напрямую.Используемый коммит: ec770323d387c6e63c609712481d9d2b0beebd52.
-
При упаковке убедитесь в отсутствии ошибок в процессе проверки. Динамические библиотеки, от которых зависят video_agent, audio_agent и webrtc_agent, необходимо скопировать в соответствующие каталоги lib, особенно если включен fdk-aac для ffmpeg, libfdk-aac.so.1 необходимо вручную скопировать в соответствующий каталог lib. При отсутствии зависимых динамических библиотек не видно явного сообщения об ошибке, и вам необходимо проверить журнал работы соответствующего агента.
-
В процессе упаковки ветки 4.3.x необходимо вручную скопировать sipLib.so из каталога source/agent/sip/sipIn/build/Release/lib.target/ в каталог верхнего уровня Release.
-
init-all.sh Запустить ошибку сервера rabbitmq возникает в виртуальной машине, работающей LAN в 192:
Job for rabbitmq-server.service failed because the control process exited with error code. See "systemctl status rabbitmq-server.service" and "journalctl -xe" for details.
Глядя на журнал, сообщение об ошибке:
ERROR: epmd error for host 192: badarg (unknown POSIX error)
Решение:
❝
vim /etc/rabbitmq/rabbitmq-env.conf
❞
Добавьте эту строку в файл: NODENAME=rabbit@localhost, сохраните
(Примечание: если файл rabbitmq-env.conf не существует, он будет создан автоматически после открытия)
Общий анализ структуры и кода
ПРИМЕЧАНИЕ. Это среда путем фокусировки средств и для сигнализации на последующем RE-API.
Чтобы узнать о структуре программы OWT, используйте Nodejs для вызова кода C++, см. Wangli Dashen.CodeNodejs
Для анализа кода OWT см.Дизайн Intel owt-server VideoMixerиЗабудьте о заборе CodeVideo
Анализ принципа VideoMix
Источник данных YUV изменяет размер декодированного изображения в соответствии с п. Размер макета макета целевого изображения, затем изображение копируется в область памяти текстуры, соответствующую синтезированному выходу. Как показано ниже[1]: Синтезированное изображение слева от цели, справа исходное изображение.Сначала требуется выборка и масштабирование, а источник s1 в середине рисунка ниже необходимо масштабировать до целевого размера справа.
Затем текстура, принцип текстуры:
Компонент Y дискретизированного изображения напрямую связан с соответствующей областью составного изображения, и необходимо отметить компонент U/V: по горизонтали и вертикали U/V имеют 1/2 дискретизацию, чересстрочную копию, w/ 2 длины после каждой выборки копии. После синтеза данные U/V целевого изображения также чересстрочно - и хранение также непрерывно, поэтому при копировании UV выборка длины w/2 непрерывно копируется и затем вводится в данные U/V следующей строки. синтезированного изображения, а затем скопировано, высота копии h/2 высоты после дискретизации.
Вышеупомянутый процесс может быть выполнен функцией I420Scale libyuv с открытым исходным кодом Google, Код выглядит следующим образом:
void SoftFrameGenerator::layout_regions(SoftFrameGenerator *t, rtc::scoped_refptr<webrtc::I420Buffer> compositeBuffer, const LayoutSolution ®ions)
{
uint32_t composite_width = compositeBuffer->width();
uint32_t composite_height = compositeBuffer->height();
for (LayoutSolution::const_iterator it = regions.begin(); it != regions.end(); ++it) {
boost::shared_ptr<webrtc::VideoFrame> inputFrame = t->m_owner->getInputFrame(it->input);
if (inputFrame == NULL) {
continue;
}
rtc::scoped_refptr<webrtc::VideoFrameBuffer> inputBuffer = inputFrame->video_frame_buffer();
Region region = it->region;
uint32_t dst_x = (uint64_t)composite_width * region.area.rect.left.numerator / region.area.rect.left.denominator;
uint32_t dst_y = (uint64_t)composite_height * region.area.rect.top.numerator / region.area.rect.top.denominator;
uint32_t dst_width = (uint64_t)composite_width * region.area.rect.width.numerator / region.area.rect.width.denominator;
uint32_t dst_height = (uint64_t)composite_height * region.area.rect.height.numerator / region.area.rect.height.denominator;
if (dst_x + dst_width > composite_width)
dst_width = composite_width - dst_x;
if (dst_y + dst_height > composite_height)
dst_height = composite_height - dst_y;
uint32_t cropped_dst_width;
uint32_t cropped_dst_height;
uint32_t src_x;
uint32_t src_y;
uint32_t src_width;
uint32_t src_height;
if (t->m_crop) {
src_width = std::min((uint32_t)inputBuffer->width(), dst_width * inputBuffer->height() / dst_height);
src_height = std::min((uint32_t)inputBuffer->height(), dst_height * inputBuffer->width() / dst_width);
src_x = (inputBuffer->width() - src_width) / 2;
src_y = (inputBuffer->height() - src_height) / 2;
cropped_dst_width = dst_width;
cropped_dst_height = dst_height;
} else {
src_width = inputBuffer->width();
src_height = inputBuffer->height();
src_x = 0;
src_y = 0;
cropped_dst_width = std::min(dst_width, inputBuffer->width() * dst_height / inputBuffer->height());
cropped_dst_height = std::min(dst_height, inputBuffer->height() * dst_width / inputBuffer->width());
}
dst_x += (dst_width - cropped_dst_width) / 2;
dst_y += (dst_height - cropped_dst_height) / 2;
src_x &= ~1;
src_y &= ~1;
src_width &= ~1;
src_height &= ~1;
dst_x &= ~1;
dst_y &= ~1;
cropped_dst_width &= ~1;
cropped_dst_height &= ~1;
int ret = libyuv::I420Scale(
inputBuffer->DataY() + src_y * inputBuffer->StrideY() + src_x, inputBuffer->StrideY(),
inputBuffer->DataU() + (src_y * inputBuffer->StrideU() + src_x) / 2, inputBuffer->StrideU(),
inputBuffer->DataV() + (src_y * inputBuffer->StrideV() + src_x) / 2, inputBuffer->StrideV(),
src_width, src_height,
compositeBuffer->MutableDataY() + dst_y * compositeBuffer->StrideY() + dst_x, compositeBuffer->StrideY(),
compositeBuffer->MutableDataU() + (dst_y * compositeBuffer->StrideU() + dst_x) / 2, compositeBuffer->StrideU(),
compositeBuffer->MutableDataV() + (dst_y * compositeBuffer->StrideV() + dst_x) / 2, compositeBuffer->StrideV(),
cropped_dst_width, cropped_dst_height,
libyuv::kFilterBox);
if (ret != 0)
ELOG_ERROR("I420Scale failed, ret %d", ret);
}
}
Вы можете видеть, что в приведенном выше коде ** «шаг» появляется много раз.,Тот"Что такое шаг"**[2]Шерстяная ткань?
Когда видеоизображение хранится в памяти, буфер памяти может иметь дополнительные байты заполнения после каждой строки пикселей.Байты заполнения влияют на то, как изображение хранится в памяти, но не на то, как оно отображается. шаг — это количество байтов от начала строки пикселей в памяти до следующей строки пикселей в памяти.Его также можно назвать шагом.Если есть заполняющие байты, шаг будет больше, чем ширина изображения, как показано на следующем рисунке:
Два буфера, содержащие изображения одинакового размера, могут иметь разные шаги, поэтому при обработке видеоизображений необходимо учитывать шаги.
Кроме того, изображения располагаются в памяти двумя способами. **"низходящий"Первый пиксель первой строки изображения сохраняется в памяти первым.Последняя строка изображения «снизу вверх»** сохраняется в памяти первой. На рисунке ниже показана разница между ними:
bottom-upИзображение имеет отрицательный шаг, потому что шаг определяется как расстояние, на которое необходимо переместиться назад от первой строки пикселей до второй строки пикселей. Изображения YUV обычно располагаются сверху вниз, поверхности Direct3D должны располагаться сверху вниз. Изображения RGB в памяти обычно располагаются снизу вверх. При преобразовании видео особенно необходимо иметь дело с буферами, которые не соответствуют шагу.
Подводя итог, для MCU видеоконференции координаты расположения потокового сервера обычно определяются следующим образом:
Для каждого входного потока службы смешанных потоков необходимо установить разумное значение координат относительно левого верхнего угла**(слева, сверху)"и"(справа, снизу)**, то вы можете использовать значение координаты, чтобы определить смещение для выполнения описанной выше операции копирования пикселей.
Используя приведенные выше координаты и дизайн макета в качестве основы, мы можем заранее установить часто используемые шаблоны макета макета для пользователей.Следующие макеты и изображения взяты изFreeswitch.
1up_top_left+9
2up_bottom+8
2up_middle+8
2up_top+8
3up+4
3up+9
3x3
4x4
5x5
6x6
8x8
overlaps
картинка в картинке
С тех пор были введены основные принципы микширования и синтеза видео.
Приглашаем всех оставить сообщение и поделиться интересующими вас темами! Приглашаю всех обратить внимание на мой личный публичный номер!
Reference
Принцип синтеза изображения YUV:
[2]
Image Stride:
В этой статье используетсяmdniceнабор текста