Русский
Русский
English
Статистика
Реклама

Promwad

Как портировать SDK Flutter на ТВ-приставку для разработки и запуска приложений Android TV

15.04.2021 16:11:54 | Автор: admin

Недавно мы успешно портировали фреймворк Flutter на ТВ-приставку c открытой программной платформой RDK. В этой статье расскажем о трудностях, с которыми пришлось столкнуться, и предложим решения для успешного запуска и повышения производительности.

Учитывая, что программный стек RDK или Reference Design Kit сейчас активно используется для разработки OTT-приложений, голосового управления приставками и других продвинутых функций для видео по запросу (VoD), мы хотели разобраться, сможет ли Flutter работать на ТВ-приставке. Оказалось, что да, но, как это обычно бывает, есть нюансы.

Далее мы по шагам распишем процесс портирования и запуска Flutter на встраиваемых Linux-платформах и разберемся, как этот SDK с открытым исходным кодом от Google чувствует себя на железе с ограниченными ресурсами и ARM-процессорами.

Но прежде чем переходить непосредственно к Flutter и его преимуществам скажем пару слов об исходном решении, которое было задействовано на ТВ-приставке. На плате работала связка набор библиотек EFL + протокол Wayland, а рисование примитивов было реализовано из node.js на основе плагинного нативного модуля. Это решение неплохо себя показало с точки зрения производительности при отображении кадров, однако сам EFL отнюдь не самый новый фреймворк для отрисовки. А в режиме выполнения node.js со своим огромным event-loopом казался уже не самой перспективной идеей. В то же время Flutter мог позволить нам задействовать более производительную связку рендеринга.

Для тех, кто не в теме: первую версию этого SDK с открытым кодом Google представил еще шесть лет назад. Тогда этот набор средств разработки годился только для Android. Сейчас на нем можно писать приложения для веба, iOS, Linux и даже Google Fuchsia. :-) Рабочий язык для разработки приложений на Flutter Dart, в свое время он был предложен в качестве альтернативы JavaScript.

Перед нами стоял вопрос: даст ли переход на Flutter какой-то выигрыш по производительности? Ведь подход там совершенно иной, хоть в конечном счете и имеется та же графическая подсистема Wayland + OpenGL. Ну и как там с поддержкой процессоров с neon-инструкциями? Были и другие вопросы, например, нюансы по переносу UI на dart или то, что поддержка Linux находится в стадии альфы-беты.

Сборка Flutter Engine для ТВ-приставок на базе ARM

Итак, начнем. Вначале Futter нужно запустить на чужеродной платформе с Wayland + OpenGL ES. В основе рендеринга у Flutter лежит библиотека Skia, которая прекрасно поддерживает OpenGL ES, поэтому в теории все выглядело хорошо.

При сборке Flutter под наши целевые устройства (три ТВ-приставки с RDK), к нашему удивлению, проблемы возникли только на одной. Не будем с ней сражаться, т.к. из-за старой архитектуре intel x86 она для нас не является приоритетной. Лучше сосредоточимся на оставшихся двух ARM-платформах.

Вот, с какими опциями мы собирали Flutter Engine:

./flutter/tools/gn \      --embedder-for-target \      --target-os linux \      --linux-cpu arm \      --target-sysroot DEVICE_SYSROOT      --disable-desktop-embeddings \      --arm-float-abi hard      --target-toolchain /usr      --target-triple arm-linux-gnueabihf      --runtime-mode debugninja -C out/linux_debug_unopt_arm

Большинство опций понятны: собираем под 32-битный ARM-процессор и Linux, выключая при этом все лишнее через --embedder-for-target --disable-desktop-embeddings.

Для сборки в системе должен быть установлен clang версии 9 и выше, т.е. это стандартный сборочный механизм Flutter, инструментарий кросс-компиляции gcc не пойдет. Самое важное подать корректный target-sysroot устройства с RDK.

Честно говоря, мы удивились, что при сборке не возникло вообще никаких нюансов. На выходе получаем заветную библиотеку flutter_engine.so и заголовок с необходимыми функциями для эмбеддера.

Теперь можно собрать целевой проект flutter/dart с нашей библиотекой/движком. Это сделать легко:

flutter --local-engine-src-path PATH_TO_BUILDED_ENGINE_src --local-engine=host_debug_unopt build bundle

Важно! Сборка проекта должна происходить не на устройстве с собранной библиотекой, а на хостовой, т.е. x86_64!

Для этого достаточно еще раз пройти путь сборкой gn и ninja только под x86_64! Именно она указывается в параметре host_debug_unopt.

PATH_TO_BUILDED_ENGINE_src это путь, где находится engine/src/out.

За запуск Flutter Engine под системой обычно отвечает embedder, именно он конфигурирует Flutter под целевую систему и дает основные контексты рендеринга библиотеке Skia и Dart-обработчику. Не так давно в состав Flutter добавили linux-embedder, и, в частности, GTK-embedder, так что можно воспользоваться им из коробки. На нашей платформе на момент портирования это был не вариант, нужно было что-то независимое от GTK.

Рассмотрим некоторые особенности реализации, которые пришлось учесть с кастомным эмбеддером (все, кто любит разбирать не нюансы, а исходники целиком, может сразу перейти к проекту нашего форка с доработками на github.com). К тому же по производительности наш вариант немного выигрывал у версии GTK, что было крайне важно для заказчика, и не тянул за собой весь зоопарк GTK-библиотек.

Так что же вообще нужно от эмбеддера для запуска flutter-приложения? Достаточно, чтобы он просто вызывал из библотеки flutter_engine.so

FlutterEngineRun(FLUTTER_ENGINE_VERSION, &config, &args, display /* userdata */, &engine_);

где в качестве параметров идет передача настроек проекта (директория с собранным flutter bundle) FlutterProjectArgs args и аргументов рендеринга FlutterRendererConfig config.

В первой структуре как раз задается путь bundle-пакета, собранного flutter-утилитой, а во второй используются контексты OpenGL .

// пример использования на github.com/DEgITx/flutter_wayland/blob/master/src/flutter_application.cc

Все довольно примитивно, но этого достаточно для запуска приложения.

Проблемы и их решение

Теперь поговорим о нюансах, с которыми мы столкнулись на этапе портирования. А как же без них? Не только ведь библиотеки собирать :-)

1. Краш эмбеддера и замена очередности вызова функций

Первая проблема, с которой мы столкнулись краш эмбеддера под платформой. Казалось бы, инициализация egl-контекста в других приложения происходит нормально, FlutterRendererConfig инициализирован корректно, но нет эмбеддер не заводится. Значит в связке что-то явно не так. Оказалось, eglBindAPI нельзя вызывать перед eglGetDisplay, на котором происходит особая инициализация nexus-драйвера дисплея (у нас платформа базируется на чипе BCM). В обычном Linux это не проблема, но на целевой платформе оказалась иначе.

Корректная инициализация эмбеддера выглядит так:

egl_display_ = eglGetDisplay(display_);if (egl_display_ == EGL_NO_DISPLAY) {  LogLastEGLError();  FL_ERROR("Could not access EGL display.");  return false;}if (eglInitialize(egl_display_, nullptr, nullptr) != EGL_TRUE) {  LogLastEGLError();  FL_ERROR("Could not initialize EGL display.");  return false;}if (eglBindAPI(EGL_OPENGL_ES_API) != EGL_TRUE) {  LogLastEGLError();  FL_ERROR("Could not bind the ES API.");  return false;}

// github.com/DEgITx/flutter_wayland/blob/master/src/wayland_display.cc корректная реализация, т.е. помогла измененная очередность вызова функций.

Теперь, когда нюанс запуска улажен, мы рады увидеть заветное демо-окно приложения на экране :-).

2. Оптимизация производительности

Настало время проверить производительность. И, честно говоря, она нас не сильно порадовала в режиме отладки (debug mode). Что-то работало шустро, что-то наоборот, имело большие просадки по фреймам и тормозило гораздо больше, чем что-то похожее на EFL+Node.js.

Мы немного расстроились и начали копать дальше. В SDK Flutter есть специальный режим компиляции машинного кода AOT, это даже не jit, а именно компиляция в нативный код со всеми сопутствующими оптимизациями, именно это подразумевается под по релиз-версией Flutter. Такой поддержки у нас в эмбеддере пока не было, добавляем.

Необходимы определенные инструкции, поданные аргументами к FlutterEngineRun

// полная реализация github.com/DEgITx/flutter_wayland/blob/master/src/elf.cc

vm_snapshot_instructions_ = dlsym(fd, "_kDartVmSnapshotInstructions");if (vm_snapshot_instructions_ == NULL) {  error_ = strerror(errno);  break;}vm_isolate_snapshot_instructions_ = dlsym(fd, "_kDartIsolateSnapshotInstructions");if (vm_isolate_snapshot_instructions_ == NULL) {  error_ = strerror(errno);  break;}vm_snapshot_data_ = dlsym(fd, "_kDartVmSnapshotData");if (vm_snapshot_data_ == NULL) {  error_ = strerror(errno);  break;}vm_isolate_snapshot_data_ = dlsym(fd, "_kDartIsolateSnapshotData");if (vm_isolate_snapshot_data_ == NULL) {  error_ = strerror(errno);  break;}
if (vm_snapshot_data_ == NULL || vm_snapshot_instructions_ == NULL || vm_isolate_snapshot_data_ == NULL || vm_isolate_snapshot_instructions_ == NULL) {  return false;}*vm_snapshot_data = reinterpret_cast <  const uint8_t * > (vm_snapshot_data_);*vm_snapshot_instructions = reinterpret_cast <  const uint8_t * > (vm_snapshot_instructions_);*vm_isolate_snapshot_data = reinterpret_cast <  const uint8_t * > (vm_isolate_snapshot_data_);*vm_isolate_snapshot_instructions = reinterpret_cast <  const uint8_t * > (vm_isolate_snapshot_instructions_);
FlutterProjectArgs args;// передаем все необходимое в argsargs.vm_snapshot_data = vm_snapshot_data;args.vm_snapshot_instructions = vm_snapshot_instructions;args.isolate_snapshot_data = vm_isolate_snapshot_data;args.isolate_snapshot_instructions = vm_isolate_snapshot_instructions;

Теперь, когда все есть, нужно собрать приложение особым образом, чтобы получить AOT-скомпилированный модуль под целевую платформу. Это можно сделать, выполнив команду из корня dart-проекта:

$HOST_ENGINE/dart-sdk/bin/dart \--disable-dart-dev \$HOST_ENGINE/gen/frontend_server.dart.snapshot \--sdk-root $DEVICE_ENGINE}/flutter_patched_sdk/ \--target=flutter \-Ddart.developer.causal_async_stacks=false \-Ddart.vm.profile=release \-Ddart.vm.product=release \--bytecode-options=source-positions \--aot \--tfa \--packages .packages \--output-dill build/tmp/app.dill \--depfile build/kernel_snapshot.d \package:lib/main.dart$DEVICE_ENGINE/gen_snapshot                               \    --deterministic                                             \    --snapshot_kind=app-aot-elf                                 \    --elf=build/lib/libapp.so                                   \    --no-causal-async-stacks                                    \    --lazy-async-stacks                                         \    build/tmp/app.dill

Не нужно пугаться огромного количества параметров, большинство из них является стандартными. В частности:

-Ddart.vm.profile=release \
-Ddart.vm.product=release \

указывают на то, что нам не нужен профайлер в комплекте и у нас продуктовая версия.

output-dill нужен для построения нативной библитеки libapp.so.

Самыми важными для нас являются пути $DEVICE_ENGINE и $HOST_ENGINE два собранных движка под целевую (ARM) и хост-системы (x86_64) соответственно. Тут важно ничего не перепутать и убедиться, что libapp.so получается именно 32-битной ARM-версией:

$ file libapp.so libapp.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked

Запускаем и-и-и-и... вуаля! все работает!

И работает шустрее значительно! Теперь уже можно говорить о сравнимой производительности и эффективности рендеринга с исходным приложением на базе набора библиотек EFL. Рендеринг работает почти без запинки и почти идеально на простых приложениях.

3. Подключение устройств ввода

В рамках этой статьи мы пропустим то, как подружили Wayland и эмбеддер с пультом, мышкой и другими устройствами ввода. На их реализацию можно посмотреть в исходниках эмбеддера.

4. Интерфейс на ТВ-приставке под Linux и Android и как увеличить производительность в 23 раза

Коснемся еще нескольких нюансов производительности, с которыми столкнулись в продуктовом UI-приложении. Нас очень обрадовала идентичность работы UI как на целевом устройстве, так и на Linux и Android. Уже сейчас Flutter может вполне может похвастаться очень гибкой портируемостью.

Еще отметим интересный опыт оптимизации самого dart-приложения под целевую платформу. Нас разочаровала довольно низкая производительность продуктового приложения (в отличии от демок). Мы взяли в руки профайлер и начали копать идовольно быстро обнаружили активное использование функций __brcm_cpu_dcache_flush и khrn_copy_8888_to_tf32 во время анимаций (на платформе используется чип процессора Broadcom/BCM ). Явно происходило какое-то очень жесткое пиксельное программное трансформирование или копирование во время анимаций. В итоге виновник был найден: в одной из панелей был задействован эффект размытия:

//...filter: new ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),//...

Комментирование одного этого эффекта дало увеличение производительности приложения в дватри раза и вывело приложение на стабильные 50-60 fps. Это хороший пример того, как один специфический эффект может уничтожить производительность во всем приложении на Flutter при том, что он был зайствован всего-лишь в одной панели, которая большую часть времени была скрыта.

Итого

В результате мы получили не просто работающее продуктовое приложение, а работающее приложение с качественным фреймрейтом на Flutter на целевом устройстве. Форк и наша версия эмбеддера под RDK и другие платформы на основе Wayland находится тут: github.com/DEgITx/flutter_wayland

Надеемся, опыт нашей команды в разработке и портировании ПО для ТВ-приставок и Smart TV пригодится вам в своих проектах и послужит отправной точкой для портирования Flutter на других устройствах.

[!?] Вопросы и комментарии приветствуются. На них будет отвечать автор статьи Алексей Касьянчук, наш инженер-программист

Подробнее..

Тестируем плату для 4K Android ТВ-приставок на чипе Realtek RTD1395

27.08.2020 10:09:54 | Автор: admin


Мы недавно получили посылку от партнеров в Тайване компании Realtek. Внутри была плата Hercules OTT 32-битная, с памятью на 2 Гб и предустановленной ОС Android 9. Посмотрим, что она умеет и как ее можно использовать для разработки новых ТВ-приставок.

Плата Hercules OTT представляет собой Android IPTV box, который воспроизводит видео любых форматов с максимальным разрешением 4K. Обеспечена поддержка стриминговых сервисов Youtube, Netflix и др. посредством dash и hls. Будут работать и любые другие приложения для Android, такие как приложения аудио-видеозвонков и конференций. Однако с играми будут проблемы из за неудобства управления (придется подключать геймпад).

Realtek представила платы на базе чипа RTD1395 еще в 2018 году, их задействовали в своих абонентских устройствах операторы IP и кабельного телевидения, а также программисты, которые разрабатывают ПО для ТВ-приставок. Чип RTD1395 с четырьмя ядрами ARM Cortex-A53 и граф. процессором Mali-470 стал тогда более дешевой альтернативой для других моделей RTD1295 и RTD1296, но при этом поддерживал те же возможности работы с видео 4K. Сейчас аналогичные решения есть у Amlogic, Mediatek и других чип-вендоров, но о них мы расскажем в другой раз.

А сейчас сфокусируемся на нашей посылке.

Тестируем железо на плате


Так как плата Hercules ОТТ является отладочной, мы проверяли только физические способности чипа.

Итак, характеристики RTD1395ES:
  • 4-ядерный ARM Cortex-A53
  • Графический процессор ARM Mali-470 MP4
  • Декодер H.265 4K 60 fps, VP9 4K 60 fps, H.264 4K 30 fps
  • Кодировщик H.264 1080P 60 fps
  • HDR10, HLG, TCH Prime, Dolby Vision, HDR10+
  • USB2.0 хост/устройство
  • HDMI Tx v2.0b + CEC
  • 10/100 MAC и PHY + Gigabit Ethernet MAC
  • PCIe 2.0
  • SGMII
  • SDIO 3.0 и SD 3.0
  • I2S ввод/вывод
  • S/PDIF вывод




Результаты тестирования платы:
  • 2 х USB 2.0 оба работают
  • 1 х Ethernet 100 Мбитный порт работает
  • 1 х HDMI работает
  • 1 х S/PDIF работает
  • 1 х 3,5 мм аудиоразъем работает
  • 1 х слот для SD-карт работает
  • 1 х ИК-порт так как родного пульта у нас не было, а пульт от Amlogic не подошёл, то протестировать не смогли
  • 1 х USB Type-C только как питание
  • 1 х WIFI/Bluetooth-модуль: wifi работает, bluetooth не проверяли


Питание платы реализовано по кабелю Type-C на 5 Вольт так как отдельный разъём питания не распаян.

Для навигации в Android мы пробовали использовать пульт Opal с usb-свистком, который прежде работал со всеми IPTV-коробками, но на этой работать он отказался и даже не определялся в lsusb. Из-за этого пришлось пользоваться клавиатурой/мышью, что не очень удобно из-за отсутствия кнопок Back и Menu.

Сам процессор во время работы прилично греется, поэтому мы прилепили радиатор в виде тормозной колодки (см. на фото выше).

Тестируем воспроизведение видео


1. Запускаем 56 тестовых роликов


Проверяем возможности декодирования с помощью тестовых видео с сайта http://jell.yfish.us/

Открыть список из 56 видеофайлов для проверки:
jellyfish-3-mbps-hd-h264.mkv
jellyfish-3-mbps-hd-hevc-10bit.mkv
jellyfish-3-mbps-hd-hevc.mkv
jellyfish-5-mbps-hd-h264.mkv
jellyfish-5-mbps-hd-hevc.mkv
jellyfish-10-mbps-hd-h264.mkv
jellyfish-10-mbps-hd-hevc-10bit.mkv
jellyfish-10-mbps-hd-hevc.mkv
jellyfish-15-mbps-hd-h264.mkv
jellyfish-15-mbps-hd-hevc.mkv
jellyfish-20-mbps-hd-h264.mkv
jellyfish-20-mbps-hd-hevc-10bit.mkv
jellyfish-20-mbps-hd-hevc.mkv
jellyfish-25-mbps-hd-h264.mkv
jellyfish-25-mbps-hd-hevc.mkv
jellyfish-30-mbps-hd-h264.mkv
jellyfish-30-mbps-hd-hevc.mkv
jellyfish-35-mbps-hd-h264.mkv
jellyfish-35-mbps-hd-hevc.mkv
jellyfish-40-mbps-hd-h264.mkv
jellyfish-40-mbps-hd-hevc-10bit.mkv
jellyfish-40-mbps-hd-hevc.mkv
jellyfish-45-mbps-hd-h264.mkv
jellyfish-45-mbps-hd-hevc.mkv
jellyfish-50-mbps-hd-h264.mkv
jellyfish-50-mbps-hd-hevc.mkv
jellyfish-55-mbps-hd-h264.mkv
jellyfish-55-mbps-hd-hevc.mkv
jellyfish-60-mbps-hd-h264.mkv
jellyfish-60-mbps-hd-hevc-10bit.mkv
jellyfish-60-mbps-hd-hevc.mkv
jellyfish-70-mbps-hd-h264.mkv
jellyfish-70-mbps-hd-hevc.mkv
jellyfish-80-mbps-hd-h264.mkv
jellyfish-80-mbps-hd-hevc.mkv
jellyfish-90-mbps-hd-h264.mkv
jellyfish-90-mbps-hd-hevc-10bit.mkv
jellyfish-90-mbps-hd-hevc.mkv
jellyfish-100-mbps-hd-h264.mkv
jellyfish-100-mbps-hd-hevc.mkv
jellyfish-110-mbps-hd-h264.mkv
jellyfish-110-mbps-hd-hevc.mkv
jellyfish-120-mbps-4k-uhd-h264.mkv
jellyfish-120-mbps-4k-uhd-hevc-10bit.mkv
jellyfish-140-mbps-4k-uhd-h264.mkv
jellyfish-140-mbps-4k-uhd-hevc-10bit.mkv
jellyfish-160-mbps-4k-uhd-h264.mkv
jellyfish-160-mbps-4k-uhd-hevc-10bit.mkv
jellyfish-180-mbps-4k-uhd-h264.mkv
jellyfish-180-mbps-4k-uhd-hevc-10bit.mkv
jellyfish-200-mbps-4k-uhd-h264.mkv
jellyfish-200-mbps-4k-uhd-hevc-10bit.mkv
jellyfish-250-mbps-4k-uhd-h264.mkv
jellyfish-250-mbps-4k-uhd-hevc-10bit.mkv
jellyfish-300-mbps-4k-uhd-hevc-10bit.mkv
jellyfish-400-mbps-4k-uhd-hevc-10bit.mkv


Из всех протестированных видео не запустились только 3 файла из-за краша в realtek.rvsd@1.0-service:
jellyfish-250-mbps-4k-uhd-hevc-10bit.mkv
jellyfish-300-mbps-4k-uhd-hevc-10bit.mkv
jellyfish-400-mbps-4k-uhd-hevc-10bit.mkv

Лог ошибки воспроизведения:
DEBUG (4077 4077)  Fpid: 1815, tid: 4069, name: rvsd@1.0-servic  >>> /vendor/bin/hw/vendor.realtek.rvsd@1.0-service <<<            DEBUG (4077 4077)  Fsignal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------                                                    DEBUG (4077 4077)  FAbort message: 'FORTIFY: pthread_mutex_destroy called on a destroyed mutex (0xa7b1b06c)'


В 53 видеофайлах, которые успешно открылись в процессе тестирования, не было замечено подвисаний и пропуска кадров. Возможно, чип способен осилить и более сложные по битрейту видео, но мы этого не узнаем.

Скриншоты работы видеоплеера от Realtek получить не удалось. Вероятно, дело в том что плеер реализован не средствами Android, а имеет доступ напрямую к фреймбуферу, чтобы защитить контент от пиратства. В VLC и ExoPlayer скриншоты делаются без проблем.

При тестировании этих же видео в VLC файлы h264 играет до 180 Мбит/с, дальше уже не успевает подготавливать кадры. HEVC перестаёт воспроизводить на 120 Мбит/с (судя по логам крашей из-за нехватки памяти).

2. Запускаем тест Geekbench3


В тесте Geekbench3 система набрала 523/1656 баллов SingleCore/MultiCore, что примерно равно производительности чипа Amlogic S905 (500/1400) а в multicore даже немного опережает. Но при этом значительно отстаёт от Amlogic S905X2 (700/2200).



3. Проверяем разные fps


Мы тестировали видео с разной кадровой частотой (fps): 23.976, 24, 25, 50, 59.94, 60. С этим проблем не возникло.

Варианты видео с прогрессивной и чересстрочной развёрткой также воспроизводятся успешно.

4. Запускаем стримы HLS и Mpeg-Dash


Также протестировали воспроизведение HLS и Mpeg-Dash-стримов с помощью нескольких способов, а именно:

Способ 1. Воспроизведение стримов через агрегатор фильмов HD VideoBox, в котором при запуске видео можно выбрать плеер, в нашем случае VideoPlayer.




Способ 2. Воспроизведение HLS и Mpeg-Dash- стримов через youtube-приложение. Для тестирования брали ролики 4K 60 fps. Просадок кадров или затормаживания не заметили. На всех скриншотах из youtube получился чёрный экран вместо картинки, вероятно, из-за защиты контента.



На SmartYoutube скриншоты делаются корректно.

Способ 3. Скормить mpd- и m3u8-файлы напрямую плееру через файловый менеджер или браузер никак не удалось, но в некоторых случаях браузер способен воспроизводить видео.

Способ 4. Воспроизведение стримов DASH и HSL через Exoplayer Demo. Все видео, ссылки на которых были живы, воспроизводились успешно. Единственное, что не воспроизводилось защищённые видео Widevine, которые сопровождались надписью Это устройство не поддерживает требуемую DRM-схему (This device does not support the required DRM scheme)

5. Встроенные тесты видео от Realtek


Также на плате Hercules ОТТ есть и собственное предустановленное приложение для тестирования воспроизведения сразу нескольких видео. В ходе тестирования выяснилось, что в режиме, когда экран делится на 2 или в режиме картинка-в-картинке, более-менее сносно воспроизводится видео только с битрейтом до 45 Мбит/с и желательно MPEG4:



Видео с низким битрейтом 360 кбит/с, но 60 fps не осилил даже 2 видео одновременно.

Видео с низким битрейтом 670 кбит/с и 15 fps и разрешением 320x240 пикселей осилил одновременно 8 видео, при 9 и более некоторые могли не запуститься и кадры в видео терялись.



Также на плате Realtek предустановлена программа Encoder, которая позволяет транскодировать до 4 видео одновременно из mp4 в AVC-ts-файлы.





Проверили, что она может транскодировать:
1 видео 1080p60fps (скорость транскодирования около 54 fps)
2 параллельных видео 1080p30fps (скорость транскодирования около 23 fps)

6. Запускаем приложение OpenCamera


Для последней проверки запускаем приложение OpenCamera и подключаем usb-веб-камеру Logitech С920 для тестирования кодирования видеозаписи. Выяснили, что в формате AVC на плате можно записать видео до 1080p27fps. В формате HEVC записать видео не удалось.

Выводы


Тесты показали, что в целом чип RTD1395 соответствует заявленным показателям. Плату Hercules ОТТ можно использовать для разработки и отладки устройств типа Android TV, дисплеев Miracast and Intel Wireless, ТВ-приставок и стриминговых OTT-плееров. Также на ней можно разрабатывать прошивку на основе AOSP для операторов IP-телевидения.

А для полной объективной оценки этого решения можно еще изучить конкурентов с аналогичными характеристиками, таких как Amlogic s905x и более новый S905X2.
Подробнее..

Литье пластика со встроенной электроникой (IME) что это, и почему это новый тренд

24.05.2021 12:21:25 | Автор: admin
Источник фото: TactoTek, финская компания, которая развивает технологию IMSE (In-Mold Structural Electronics).Источник фото: TactoTek, финская компания, которая развивает технологию IMSE (In-Mold Structural Electronics).

Вот уже несколько лет производители электроники говорят о новой прорывной технологии, которая изменит привычные нам устройства и подход к их проектированию: никаких больше механических кнопок и переключателей, сокращение толщины до 2 мм, снижение веса на 70%, а себестоимости на 30%. Причем речь идет не о будущих серийных устройствах типа экрана с двойным сложением, который недавно представила Samsung, а о технологии производства, которая уже сейчас используется в автомобилях, бытовой технике и IoT-гаджетах. Эта технология называется литье с интегрированной / встроенной электроникой или In-Mold Electronics (IME).

На Хабре эту интересную тему еще почему-то не затрагивали. Исправляем это досадное недоразумение.

Начнем со спойлера и сразу отметим, что литье со встроенной электроникой (IME) это не какая-то кардинально новая технология, а эволюция техпроцессов, которые уже использовались ранее. Появились более эластичные материалы и более качественные токопроводящие чернила, которые выдерживают формовку при высокой температуре, поэтому проводники, которые раньше покрывали печатную плату, теперь можно наносить прямо на пластиковый корпус электронного устройства. В результате мы избавляемся от жесткой печатной платы в формате 2D и переключаемся на пленочные платы и 3D-электронику с резисторами, микросхемами, сенсорами, антеннами и светодиодами, которые покрывают изогнутые формы корпусов самых разных устройств.

А теперь давайте обо всем по порядку. Литье с интегрированной электроникой это одно из направлений литья с декорированием в форме, о котором мы уже рассказывали на Хабре. В англоязычных инженерных публикациях такая технология называется In-Mold Decoration (IMD). Напомним, что корпус декорируется под давлением прямо в пресс-форме или в процессе выдувного формования.

В результате получается полностью готовая деталь, которая не требует дополнительной обработки поверхности, маркировки или окрашивания.

Принцип маркировки в форме (In-Mold Labeling, IML) Источник: Maspi S.r.l.

На схеме выше показана суть технологий IMD и IML:

  1. Сначала на тонкопленочный пластик наносят нужный рисунок текст, декор или текстуру (например, лого фирмы-изготовителя или подписи для кнопок). Это делается за счет трафаретной или цифровой печати. Получается так называемая аппликация.

  2. Аппликацию помещают в пресс-форму для литья.

  3. Затем в формовочную машину засыпают сухие гранулы полимера, который в расплавленном виде под давлением подается в пресс-форму за пленкой или перед ней.

  4. Форма заполняется полимером, и печатная этикетка приклеивается к пластику.

  5. На выходе при раскрытии формы мы получаем готовую деталь пластикового корпуса уже со встроенной графикой.

Технология декорирования в форме позволяет качественно реализовать идеи промышленных дизайнеров даже в конструкционно сложных пластмассовых компонентах. Детали получаются долговечными и устойчивыми к царапинам.

На фото выше верхняя панель пульта дистанционного управления, изготовленная с декорированием в форме (IMD). Другие всем знакомые примеры устройств, которые производятся по этой технологии: мультиметры, автомобильные панели, игрушки и мобильные телефоны.

В чем разница между декорированием в форме (IMD) и маркировкой в форме (IML)?

Если графика или текстура внутри пресс-формы наносится не на всю поверхность изделия от края до края, а локально, на отдельный участок, то такой тип декорирования называется маркировка в пресс-форме или In-Mold Labeling (IML). С помощью этой технологии можно добавлять цвет, графические элементы и текстурированные области.

IML часто используют для нанесения логотипов, предупреждающих знаков, иконок сертификатов, номеров деталей или мини-инструкций. Вы наверняка встречали такую маркировку на одноразовой упаковке и пластиковых контейнерах для домашнего использования.

И вот теперь мы возвращаемся литью с электроникой (In-Mold Electronics), которая стала логическим продолжением предыдущих двух технологий. Похоже, что первое коммерческое внедрение IME было реализовано в инновационной подвесной консоли для автомобиля Ford в 2012 году. Сегодня же IME применяется в производстве бытовой техники, автомобильных панелей, медицинского оборудования, аэрокосмической и носимой электроники.

Эта технология объединяет декоративную аппликацию из IMD-процесса с функциональной электроникой. Только в этом случае на пленке печатается не декор или текст, а дорожки проводников из токопроводящих серебряных красок, также на пленку можно добавлять резисторы, микросхемы и светодиоды. В результате в процессе формовки получаются пластиковые компоненты небольшой толщины (до 2 мм) с достаточной прочностью, высокой функциональностью, добавлением света, клавиатуры и декоративных элементов.

На схеме ниже показано, как это работает:

Источник изображения: Functional Ink Systems for In Mold Electronics by DuPont

  1. Трафаретная печать графики и проводящих дорожек из функциональных чернил на тонкой полимерной подложке, такой как полиэстер или поликарбонатная пленка.

  2. Термоформование придает печатным носителям трехмерную форму, которая соответствует форме для литья под давлением.

  3. Литье под давлением.

IME, как правило, термоформованные, но не всегда. В областях с сенсорным интерфейсом поверхность может остаться плоской.

Наметившаяся тенденция использование полиэтилентерефталата (PET), который не очень хорошо поддается формовке, но подходит для конструкций с меньшим радиусом кривизны. Однако ПЭТ не переносит сильного нагрева, поэтому сейчас разрабатываются низкотемпературные припои.

Пока эта технология еще воспринимается потребителями как новаторская, сами дорожки-проводники выглядят как элементы декора. :-) Со временем промдизайнеры и hardware-стартапы наверняка предложат свежие идеи по использованию возможностей такого литься.

Источник фото: аналитический отчет IDTechEx за 2020 год.

На фото выше серийные устройства и прототипы, созданные по технологии In-Mold Electronics.

Пример литой электроники чаще всего можно увидеть в новых автомобилях и бытовой технике, где форма электроники полностью соответствует кривым поверхностям задуманного дизайна.

В приборных панелях больше нет традиционных кнопок, датчиков и других функциональных переключателей. Вместо всего этого сенсорные визуальные интерфейсы. IME позволяет встроить освещение, разъемы, микросхемы или емкостное сенсорное покрытие в практически любую изогнутую деталь.

Формованные таким образом устройства и встроенная электроника выглядят красиво, они функциональны и надежны. Из-за многократного уменьшения деталей и подвижных компонентов сокращается не только риск поломок, но и затраты на производство, сборку и обслуживание.

Емкостное сенсорное управление и пользовательские интерфейсы

Технология емкостного сенсорного управления используется во многих приложениях IME. Такой интерфейс заменяет нажатие физической кнопки на прикосновение пальца. Дорожки на плате находятся под сенсорной точкой на панели и следят за изменением в электростатическом поле. Палец действует как функциональный конденсатор, который участвует в электрической цепи устройства. Например, в автомобиле, такие интерфейсы используются для включения фар, питания или регулировки громкости.

Вот, как американская химическая компания Dupont, один из мировых разработчиков токопроводящих чернил для IME, представляет в своей презентации интерфейсы для автомобилей настоящего и будущего:

Источник изображений: Functional Ink Systems for In Mold Electronics by DuPontИсточник изображений: Functional Ink Systems for In Mold Electronics by DuPontИсточник изображений: Functional Ink Systems for In Mold Electronics by DuPontИсточник изображений: Functional Ink Systems for In Mold Electronics by DuPont

Подводим итоги

Автопром это всего лишь одна из многих сфер применения IME, которые мы уже называли выше. Но давайте на ее примере рассмотрим реальный кейс. Возьмем потолочную консоль в автомобиле, которая была спроектирована с использованием печатной платы и классического пластикового корпуса, состоящего из десятков компонентов и сборных деталей, и сравним ее с консолью финской компании TactoTek, которая сейчас разрабатывает свою технологию in-mold structural electronics (IMSE):

Источник фото: Functional Ink Systems for In Mold Electronics by DuPontИсточник фото: Functional Ink Systems for In Mold Electronics by DuPont

Обычная сборка

Версия IME

Сокращение параметра

Вес

650 г

150 г

77%

Глубина сборки

45 мм

3 мм
(без изгиба)

93%

Механические детали

64 штук

2 штуки

96%

Размер PCBA

10 х 4 см

10 х 3 см

25%

Итого, мы получаем значительное уменьшение веса, габаритов, количества подвижных частей и, как следствие, надежности и себестоимости устройства в целом. Судя по активным разработкам в этой теме и отчетам аналитиков, которые прогнозируют рост внедрений IME, начиная с 20232024 года, на рынке электроники намечается новый тренд переход от печатных плат в коробке к трехмерной структурной электронике. Так что если ваша работа связана hardware, можно присмотреться к этому направлению и успеть попасть на гребень волны. Надеемся, что мы вскоре сможем поделиться с читателями Хабра собственными кейсами по разработкам и запуску производства литой электроники.

Если у вас есть опыт в этой сфере или идеи по внедрению IME в новых устройствах расскажите об этом в комментариях. Будет здорово, если к обсуждению подключатся инженеры, технологи, промдизайнеры и простые юзеры. Мы сейчас горим этой темой, так что с удовольствием пообщаемся.

Подробнее..

Как можно и как нельзя использовать нулевой указатель в С

30.07.2020 16:13:15 | Автор: admin


Некоторым этот банальный вопрос уже набил оскомину, но мы взяли 7 примеров и попытались объяснить их поведение при помощи стандарта:


struct A {    int data_mem;    void non_static_mem_fn() {}    static void static_mem_fn() {}};void foo(int) {}A* p{nullptr};/*1*/ *p;/*2*/ foo((*p, 5));                     /*3*/ A a{*p};/*4*/ p->data_mem;/*5*/ int b{p->data_mem};/*6*/ p->non_static_mem_fn();/*7*/ p->static_mem_fn();

Очевидная, но важная деталь: p, инициализированный нулевым указателем, не может указывать на объект типа А, потому что его значение отлично от значения любого указателя на объект типа А conv.ptr#1.


Disclaimer: статья содержит вольный перевод терминов и выдержек из стандарта на русский язык. Мы рекомендуем английскую версию статьи на dev.to, лишенную неточностей перевода.


Пример 1


Открыть начало кода
struct A {    int data_mem;    void non_static_mem_fn() {}    static void static_mem_fn() {}};void foo(int) {}A* p{nullptr};


*p;

Синтаксически это оператор выражения (expression statement, stmt.expr#1), в котором *p является выражением с отброшенным результатом, который, тем не менее, нужно вычислить. Определение унарного оператора * expr.unary.op#1 гласит, что этот оператор осуществляет косвенное обращение (indirection), и результатом является l-значение, которое обозначает объект или функцию, на которую указывает выражение. Его семантика понятна, чего не скажешь о том, должен ли объект существовать. Нулевой указатель в определении не упоминается ни разу.


Можно попробовать зацепиться за косвенное обращение, потому что есть basic.stc#4, в котором четко написано, что поведение при косвенном обращении через недопустимое значение указателя (indirection through an invalid pointer value) не определено. Но там же дается описание недопустимого значения указателя, под которое нулевой не подходит, и дается ссылка на basic.compound#3.4, где видно, что нулевой указатель и недопустимый это различные значения указателя.


Еще есть примечание в dcl.ref#5, которое гласит, что the only way to create such a reference would be to bind it to the object obtained by indirection through a null pointer, which causes undefined behavior, т.е. единственный способ создать такую ссылку привязать ее к объекту, полученному за счет косвенного обращения через нулевой указатель, что приводит к неопределенному поведению. Но придаточное в конце может относиться не только к косвенному обращению, но и к привязать (to bind), и в этом случае неопределенное поведение вызвано тем, что нулевой указатель не указывает на объект, о чем и говорится в основном тексте пункта dcl.ref#5.


Раз стандарт вместо однозначных формулировок оставляет пространство для интерпретаций в разрезе нашего вопроса, можно обратиться к списку дефектов языковой части стандарта, где Core Working Group среди прочего поясняет текст стандарта. Наш вопрос выделен в отдельный дефект, где CWG довольно давно пришла к неформальному консенсусу (так определен статус drafting), что неопределенное поведение влечет не разыменование само по себе, а конвертация результата разыменования из l-значения в r-значение. Если неформальный консенсус CWG звучит недостаточно весомо, то есть другой дефект, в котором рассматривается пример, аналогичный нашему примеру 7. Такой код назван корректным по этой же причине в официальной аргументации CWG.


В дальнейших рассуждениях мы будем опираться на этот консенсус. Если в будущем стандарт запретит разыменовывать нулевые указатели по примеру Си (N2176, 6.5.3.2 и сноска 104), значит, все примеры содержат неопределенное поведение, и на этом разговор можно закончить.


Пример 2


Открыть начало кода
struct A {    int data_mem;    void non_static_mem_fn() {}    static void static_mem_fn() {}};void foo(int) {}A* p{nullptr};


foo((*p, 5));  

Чтобы вызвать foo, требуется проинициализировать его параметр, для чего нужно вычислить результат оператора запятая. Его операнды вычисляются слева направо, причем все, кроме последнего, являются выражениями с отброшенным значением так же, как и в примере 1 (expr.comma#1). Следовательно, этот пример также корректен.


Пример 3


Открыть начало кода
struct A {    int data_mem;    void non_static_mem_fn() {}    static void static_mem_fn() {}};void foo(int) {}A* p{nullptr};


A a{*p};

Для инициализации a будет выбран неявный конструктор копирования, и для того, чтобы его вызвать, нужно проинициализировать параметр const A& допустимым объектом, в противном случае поведение не определено (dcl.ref#5). В нашем случае допустимого объекта нет.


Пример 4


Открыть начало кода
struct A {    int data_mem;    void non_static_mem_fn() {}    static void static_mem_fn() {}};void foo(int) {}A* p{nullptr};


p->data_mem;

Выражение этого оператора выражения при вычислении будет раскрыто в (*(p)).data_mem согласно expr.ref#2, которое обозначает (designate) соответствующий подобъект объекта, на который указывает выражение до точки (expr.ref#6.2). Параллели с примером 1 становятся особенно явными, если открыть, скажем, basic.lookup.qual#1, и увидеть, как to refer и to designate взаимозаменяемо используются в том же смысле, что и в expr.ref. Из чего мы делаем вывод, что это корректный код, однако некоторые компиляторы не согласны (см. про проверку константными выражениями в конце статьи).


Пример 5


Открыть начало кода
struct A {    int data_mem;    void non_static_mem_fn() {}    static void static_mem_fn() {}};void foo(int) {}A* p{nullptr};


int b{p->data_mem};

В продолжение предыдущего примера не будем отбрасывать результат, а проинициализируем им int. В этом случае результат нужно конвертировать в pr-значение, потому что выражения именно этой категории инициализируют объекты (basic.lval#1.2). Так как речь идет об int, будет осуществлен доступ к объекту результата (conv.lval#3.4), что в нашем случае ведет к неопределенному поведению, потому что ни одно из условий basic.lval#11 не соблюдается.


Пример 6


Открыть начало кода
struct A {    int data_mem;    void non_static_mem_fn() {}    static void static_mem_fn() {}};void foo(int) {}A* p{nullptr};


p->non_static_mem_fn();

class.mfct.non-static#1 гласит, что функции-члены разрешено вызывать для объекта типа, к которому они принадлежат (или унаследованного от него), или напрямую из определений функций-членов класса. Именно разрешено такой смысл вкладывается в глагол may be в директивах ИСО/МЭК, которым следуют все стандарты ИСО. Раз объекта нет, то и поведение при таком вызове не определено.


Пример 7


Открыть начало кода
struct A {    int data_mem;    void non_static_mem_fn() {}    static void static_mem_fn() {}};void foo(int) {}A* p{nullptr};


p->static_mem_fn();

Как говорилось в рассуждениях к примеру 1, Core Working Group считает этот код корректным. Добавить можно лишь то, что согласно сноске 59, выражение слева от оператора -> разыменовывается, даже его результат не требуется.


Проверка с помощью constexpr


Раз константные выражения не могут полагаться на неопределенное поведение (expr.const#5), то можно узнать мнение компиляторов о наших примерах. Пусть они и несовершенны, но как минимум нередко правы. Мы взяли три популярных компилятора, подправили пример под constexpr и для наглядности закомментировали те примеры, которые не компилируются, потому что сообщения об ошибках что у GCC, что у MSVC оставляют желать лучшего на данных примерах: godbolt.


Что получилось в итоге:


#
Код
Предположение
GCC 10.1
Clang 10
MSVC 19.24
1
*p;
+
+
+
+
2
foo((*p, 5));
+
+
+
+
3
A a{*p};
4
p->data_mem;
+
+
5
int b{p->data_mem};
6
p->non_static_mem_fn();
+
+
7
p->static_mem_fn();
+
+
+
+

Результаты заставляют несколько усомниться в выводе из примера 6 и в большей степени из примера 4. Но также интересно, что мы все сходимся во мнении о ключевом примере 1.


Спасибо, что остались с нами до конца, чтобы проследить за приключениями нулевого указателя в С++! :-) Обычно мы делимся на Хабре кусками кода из реальных проектов по разработке встроенного ПО для электроники, но этот раз нас заинтересовали чисто философские вопросы, поэтому примеры синтетические.


Если вы разделяете нашу любовь к противоречиям в С++, делитесь наболевшим в комментариях.

Подробнее..

Трансформация аутсорсинговых компаний в инженерные путь смелых из Беларуси, Украины и России

13.04.2021 14:10:30 | Автор: admin
Аутсорсинг отличная инженерная школа. Но куда мы отправимся дальше?Аутсорсинг отличная инженерная школа. Но куда мы отправимся дальше?

В ИТ-сообществе слово аутсорсинг часто воспринимается как обидное. Руководители компаний и команд, которые занимаются заказной разработкой ПО или электроники, и сами разработчики предпочитают не называть себя аутсорсерами. Даже из моих предыдущих статей об инженерных командах и их пути могло показаться, что я против этой бизнес-модели. Так что давайте разберемся, почему аутсорсинг стал для нас инженеров из Беларуси, Украины и России важной школой, и почему лидеры ИТ-рынка больше не хотят называть себя этим словом.

Сразу отмечу свое отношение к термину аутсорсинг: мне нравится эта бизнес-модель, я много лет строил компанию в сфере заказной разработки электроники и встроенного ПО, а сейчас трансформирую бизнес в этой сфере.

Более того, я уверен, что аутсорсинг сыграл ключевую роль в развитии ИТ-сектора в наших странах. Если аллегорически сравнить его с высшим образованием, то можно сказать, что это отличная бизнес-модель для обучения большого количества специалистов с оплатой в процессе обучения. Сначала надо пройти путь абитуриента и сдать экзамен на первый контракт. Потом побыть студентом, где тебе будут платить небольшую стипендию это период, когда молодая аутсорсинговая компания получает контракты, позволяющие держать на плаву небольшую команду. Затем появляются несколько клиентов и, возможно, один-два ключевых. Ключевой клиент как профессор в магистратуре или аспирантуре. Аспирант обслуживает интересы профессора в обмен на обучение. Профессор, т.е. зарубежный клиент, получает всю славу, результат и вполне солидные деньги за проект, который был создан при поддержке аспирантов.

Студентам дают стипендию. В аутсорсинге примерно также тебе дают деньги на жизнь, пока ты учишься на первых клиентских проектах

Кто и чему учится в рамках аутсорсинговой бизнес-модели:

  • Основатели и менеджеры бизнесу и управлению.

  • Инженеры разработке и инженерной культуре.

  • Продавцы длинным и сложным B2B-продажам, где нужно вырабатывать доверие, продавая воздух.

Представьте, как долго мы выходцы из постсоветских стран проходили бы этот путь, если бы такая бизнес-модель как аутсорсинг в мире не существовала? Ведь она позволила нам получить и накопить интеллектуальный и денежный капитал. В 90-х и нулевых мы только стартовали. В 2010-х те, кто заработал капитал, инвестировали в собственный бизнес. А сегодня предприниматели с 2030 летним опытом готовы инвестировать в сторонние компании и передавать знания новому поколению.

После развала Союза у нас не было опыта в бизнесе, не хватало инженерных знаний всё это мы получили во многом благодаря аутсорсингу!

Заказные разработки позволили нам получить сегодняшних специалистов, часть из которых перешла в продуктовые компании. И теперь вопрос: как быть дальше? Как поднять эффективность своей работы и всей отрасли? Очевидно, что аутсорсинг это одна из ступеней в развитии отрасли. Те игроки рынка, которые уже прошли эту школу, могут отправляться в свободное плавание. Мы это видим на примере компаний, которые занимались аутсорсингом, а сейчас имеют продуктово-сервисные модели.

Тот же EPAM, который некоторые до сих пор по-привычке считают аутсорсинговой компанией, уже давно совершил разворот к сервисно-инжиниринговой модели. Как пишут Ведомости, если до 2005 г. около 80% заказов этой компании приходилось на аутсорсинг в разработке продуктов для технологических компаний, то сейчас на подобные заказы приходится около 20%. Сам Аркадий Добкин, основатель EPAM, так объясняет этот термин в прошлогоднем интервью журналу Большой:

Аутсорсинг это бизнес-практика, когда работа, которая раньше производилась внутри компании ее собственными сотрудниками, отдается внешним компаниям с целью сокращения расходов или высвобождения ресурсов для других более важных функций. Так начиналась офшорная индустрия в Индии. Туда передавалась много работы по поддержанию систем, которые до того выполнялись внутри компаний Нет ничего предосудительного в аутсорсинговой модели, это очень важный компонент глобального бизнеса.

Вполне понятно, почему зрелые компании стремятся уйти от этой модели и переключиться на позиционирование в качестве инжиниринговой компании с уникальной экспертизой. Но для этого требуется время, поэтому часть новых игроков на рынке будут по-прежнему выбирать аутсорсинг, чтобы за несколько лет получить нужный опыт и накопить стартовый капитал я уже писал о таком пути в прошлой статье на Хабре. Но чем более зрелой будет отрасль, чем более сильной и открытой будут экономика нашей страны, в которой работает компания, тем активнее долю аутсорсинговых компаний будут замещать инжиниринговые и продуктовые. Но у нас впереди еще долгий путь в этом направлении. В следующей статье я даже рискну предположить сколько лет займет такой путь.

Посмотрите сами: где была бы Индия со своим ИТ и где был бы Китай со своим производством, если бы не заказные проекты зарубежных заказчиков?

Зрелость индустрии соответствует зрелости государства и общества. Поэтому логично, что на данном этапе мы (IT-компании в Беларуси) занимаемся аутсорсингом, как и наши соседи в Украине, России, Болгарии, Молдове и т.д. Даже Польша, Чехия, Литва и Румыния все еще входят в список стран для ИТ-аутсорсинга, хотя там ситуация постепенно меняется. А в таких странах как Дания и Германия структура бизнес-моделей и компаний уже совсем другая. Это положение дел обусловлено стоимостью оплаты труда, индексом экономического развития и другими параметрами, поэтому не стоит думать, что мы все-еще занимаемся аутсорсингом, потому что кого-то из наших инженеров несправедливо недооценили.

Со временем мы придем другому балансу в ИТ-отрасли: по мере развития отрасли и роста экономического уровня будет все больше продуктовых и инжиниринговых компаний в противовес аутсорсинговым.

Почему в Германии много продуктовых компаний? Потому что там есть не только стартапы, но и инвесторы. Почему у нас рождаются единицы сильных стартапов, а в европеских странах сотни? Это только кажется, что везде есть фонды и везде есть классные инженеры. Бизнес-ангелы у нас в Беларуси только-только появились, они вкладывают скрепя зубами несколько десятков тысяч долларов по небольшой оценке, иногда забирая большую долю в стартапах, демотивируя этим фаундеров. Поэтому инженерные команды, которые делают свой продукт или запускают корпоративный спин-офф, предпочитают воспользоваться зарубежными институтами финансирования и поддержки инноваций, они переезжают в ЕС, чтобы быть ближе к развитым бизнес-экосистемам и быстрее достигать свои цели.

Трансформация аутсорсинга

Но и аутсорсинг как бизнес-модель не стоит на месте, она трансформируется под давлением рынка вместе с прочими моделями. Какие у нас есть варианты для трансформации? Во-первых, важно понять, что на пути между аутсорсер и продуктовая компания есть промежуточные гибридные модели. Во-вторых, мы можем посмотреть на опыт компаний в развитых экономиках Западной Европы, где заказная разработка тоже имеет место в Германии, Дании и Финляндии успешно работают инженерные сервисные компании, которые зарабатывают отнюдь не на ценовых преимуществах. А на чем же?

Давайте рассмотрим, в какие бизнес-модели они используют:

  1. Свой продукт + доп. услуги по разработке. Если компания, к примеру, продает собственные процессорные модули, ее экономика формируется за счет продуктов, но при этом она генерирует дополнительную прибыль за счет дозагрузки инженеров на заказных разработках для своих клиентов.

  2. Сервисная компания + доп. платформы / решения. Когда экономика компании формируется за счет заказных разработок или инженерного сервиса, она не может обеспечить себе высокую маржинальность в странах с развитой экономикой из-за высокой стоимости рабочего времени инженеров. В этом случае компании выгодно обеспечивать дополнительный поток прибыли за счет допродажи собственных готовых решений и платформ для решения задач своих клиентов в конкретных индустриях.

  3. Сервисная компания + аутсорсинг. Компании в Западной Европе, которые занимаются заказной разработкой или инженерным сервисом, позволяют своим клиентам быстро подключить к проекту нужных инженеров, не нанимая их в штат. Заказчик таким образом снимает с себя задачу найма узких специалистов и бремя социальных выплат на штатных работников. При этом часть задач сервисная компания передает на аутсорсинг в Восточную Европу так они снижают затраты.

Как на это смотрят сами руководители компаний из Западной Европы? Мой коллега Зоран Вельковски, основатель датской инжиниринговой компании TekPartner, так прокомментировал перспективы сотрудничества в отрасли:

Для разработки электронных продуктов в эпоху интернета вещей, периферийных вычислений и машинного обучения требуются мультидисциплинарные команды с широким набором навыков.

Только компании с огромным бюджетом на НИОКР, такие как Apple, Tesla, Microsoft и Google, могут позволить себе полную вертикальную интеграцию. Всем остальным нужна внешняя помощь, т.е. аутсорсинг всех видов деятельности, которые не относятся к основной компетенции компании.

Поэтому более дешевые инженеры из Восточной Европы это не главное преимущество аутсорсинга для заказчика. Для него важна ориентация команды на основной бизнес, получение доступа к высококлассным технологиям/компетенциям, сокращение расходов в том числе, более быстрый выход на рынок, снижение рисков, улучшение конкурентных преимуществ.

Те компании, которые это понимают, уже сейчас повышают свою эффективность и работают с гибридными моделями, потому что на одной только разнице в оплате труда инженеров невозможно продержаться в долгосрочной перспективе.

В Беларуси, к примеру, уже была возможность за 1015 лет реализовать свою среднесрочную ИТ-стратегию в Парке высоких технологий (ПВТ), воспользовавшись специальным налоговым режимом и более низким уровнем жизни, чем в ЕС и США. В краткосрочной и среднесрочной перспективе это были правильные действия. Но дальше нужна трансформация и выбор проактивной позиции: мы можем использовать опыт европейских сервисных компаний и заниматься высокооплачиваемым инженерным сервисом, добавляя исследовательскую и интеграционную составляющую, обеспечив свою географическую близость к клиенту и более глубокое понимание его рынка.

Эта трансформация переключит нас с позиции я делаю то, что умею на я делаю то, что нужно клиенту, предлагая множество дополнительных и достаточно дорогих функций по сдаче проекта (delivery).

Ведь что такое сдача проекта delivery? Наш классический проджект-менеджер это не деливери-менеджер, потому что он, как правило, не обеспечивает бесшовную интеграцию проекта в бизнес клиента. Живой пример из нашей компании: мы в Promwad разработали для своего клиента ТВ-приставку в рамках проекта за несколько десятков тысяч долларов, а на этапе delivery ценность наших услуг и бюджет проекта исчислялся уже в сотнях тысяч долларов. Мы интегрировали свою разработку в цепочку поставок клиента: поставили приставку на серийное производство в оптимальной для клиента локации, запускали там автоматизированное тестирование и дописывали ПО. Но это случилось, потому что мы стремились увеличить свое участие в бизнесе клиента, действовали проактивно.

Рецепты

Итого, основываясь на словах своих коллег и опыте компаний с Запада, вот что можно сделать после инженерной школы, которой для нас стал аутсорсинг:

  1. Расти за счет дорогих сервисов и большей маржинальности, но для этого нужно слышать клиента и быть к нему ближе географически за счет локальных офисов в ЕС и США.

  2. Дополнять свои услуги продуктами / платформами / решениями.

  3. Продолжать развивать аутсорсинг, но при этом быть готовым к резкому изменению ландшафта, т.е. условий для ведения подобного бизнеса в наших странах.

При этом, как видите, вы не становитесь продуктовой компанией. Ведь мы тут не обсуждаем жесткий разворот в продуктовую стратегию.

Рынок со временем все расставит на свои места. Даже пассивные компании с устаревшими бизнес-моделями будут вынуждены трансформироваться. Но куда интереснее, хотя, конечно, труднее и рискованнее действовать проактивно и самому пойти в новые бизнес-модели, опередив своих более капиталоемких соседей по отрасли! У аутсорсинга в истории ИТ-сектора в Восточной Европе большая роль и большая история, но уже сейчас пришло время наращивать свою ценность для мира: преобразовать свои знания в мировое признание, обеспечивать бОльшую добавленную стоимость и потянуть вслед за собой за собой тех, кто эту инженерную школу только проходит.

В этой статье я Роман Пахолков, основатель Promwad, поделился ключевыми выводами, которые подтолкнули меня к созданию новой стратегии для собственной компании к специализации на конкретных индустриях и развитию лидеров направлений в нашей инженерной команде. Более того, мы даже запустили целое отраслевое сообщество Hardware Ecosystem для всех, кто работает в сфере электроники. Там есть и подмастерья-студенты, и профессора. Верю, что объединившись, мы сможем достичь большего.

А в какой модели сейчас находитесь вы сами? И как вы видите трансформацию своего бизнеса или компании, в которой работаете? Поделитесь своими мыслями в комментариях, а я буду рад ответить на ваши вопросы и рассказать о собственном опыте.

Подробнее..

Как мы запустили Hardware Ecosystem для проектов в электронике митап по беспилотникам 10.10.2020

02.10.2020 22:23:38 | Автор: admin
Митап Hardware Ecosystem в Минске по теме MedTech в 2019 годуМитап Hardware Ecosystem в Минске по теме MedTech в 2019 году

Два года назад основатель нашей компании Роман Пахолков создал открытое сообщество для всех, что работает в hardware, развивает свои проекты и готов делиться опытом. Всё начиналось с небольшой LinkedIn-группы, а потом переросло серию подкастов и митапов с инженерами и руководителями компаний, которые успешно вышли на рынок электроники со своими продуктами.

В этой статье мы объясним, чем Hardware Ecosystem полезна для участников. А если захотите познакомиться с этим сообществом поближе, это можно сделать на ближайшей неделе утром в субботу, 10 октября. В этот день в Минске состоится митап, посвященный беспилотным технологиям и примерам их внедрения на земле и ввоздухе. Так что если вы не равнодушны к хардверу, дронам и автономным автомобилям, присоединяйтесь онлайн или приходите лично.

В этот раз событие будет международным, с участием докладчиков из Беларуси, России, ЕС и Китая. Запланированы презентации стартапов Aorion и Crop Fleet, совместный доклад корпораций Arrow и Analog Devices, выступления экспертов Solar LS и международной китайской корпорации Интеллектуальные технологии. Также к нам присоединится российская компания Starline, которая занимается разработкой беспилотных автомобилей.

Итак, зачем и для кого было создано сообщество Hardware Ecosystem?

У нас на рынке high-tech и электроники есть отдельные элементы экосистемы: стартапы, инвестиционные компании, ассоциация приборостроителей, университеты, научные организации, где работают инженеры. Но эти элементы работают сами по себе, связи между ними пока слишком слабые или их нет вовсе. Такое случается в незрелой бизнес-экосистеме: участники не сразу объединяются и начинают работать на общие цели.

Конечно, мировой опыт вдохновляет на то, чтобы пробежать эту дорогу быстро. У каждой страны и каждой экосистемы свой путь, и она уникальна. И это хорошо, мы разные и можем дополнять друг друга.

У наших инженеров есть шансы в определенных отраслях, которые связаны с hardware. Например, в медицинской технике, в IoT на стыке software и hardware, в беспилотных технологиях (собственно поэтому предстоящий митап и посвящен этой теме).

Живой пример: инженерная аутсорсинговая прослойка из Парка высоких технологий в Минске дает большой поток крутых разработчиков, которые пользуясь элементами экосистемы, могут создавать свое IP, решать проблемы мировых рынков, соединять решения hardware и software вместе.

За два года к сообществу Hardware Ecosystem присоединилось более 650 участников из разных стран инженеров, владельцев и менеджеров ИТ-компаний, инвесторов, руководителей тех. хабов и акселераторов. Они делились опытом в группе на LinkedIn и встречались на митапах, а в начале 2020 года из-за COVID-19 ушли в онлайн: так и появился новый подкаст и ютуб-канал c видеозаписями прошлогодних митапов про IoT, MedTech и о том, как инженеру вывести свой продукт на рынок.

И вот сейчас, при поддержке hardware-акселератора Bridgio, сообщество возвращается к формату личных встреч: в Минске, на площадке SUP, 10 октября пройдет митап Беспилотники на земле и в воздухе: бизнес-кейсы стартапов и корпораций. Впервые будет организована онлайн-трансляция встречи для русскоязычных инженеров из других городов и стран. Участники митапа из первых уст узнают о бизнес-проблемах, которые решают мировые корпоративные игроки, как проходят R&D мирового уровня. В ходе встречи организаторы постараются определить возможные варианты кооперации между инженерными командами и международными компаниями.

Если вы болеете за hardware и беспилотные технологии присоединяйтесь!

Подробнее..

Сообщество Hardware Ecosystem для проектов в электронике митап по беспилотникам 10.10.2020

03.10.2020 10:21:59 | Автор: admin
Митап Hardware Ecosystem в Минске по теме MedTech в 2019 годуМитап Hardware Ecosystem в Минске по теме MedTech в 2019 году

Два года назад основатель нашей компании Роман Пахолков создал открытое сообщество для всех, что работает в hardware, развивает свои проекты и готов делиться опытом. Всё начиналось с небольшой LinkedIn-группы, а потом переросло серию подкастов и митапов с инженерами и руководителями компаний, которые успешно вышли на рынок электроники со своими продуктами.

В этой статье мы объясним, чем Hardware Ecosystem полезна для участников. А если захотите познакомиться с этим сообществом поближе, это можно сделать на ближайшей неделе утром в субботу, 10 октября. В этот день в Минске состоится митап, посвященный беспилотным технологиям и примерам их внедрения на земле и ввоздухе. Так что если вы не равнодушны к хардверу, дронам и автономным автомобилям, присоединяйтесь онлайн или приходите лично.

В этот раз событие будет международным, с участием докладчиков из Беларуси, России, ЕС и Китая. Запланированы презентации стартапов Aorion и Crop Fleet, совместный доклад корпораций Arrow и Analog Devices, выступления экспертов Solar LS и международной китайской корпорации Интеллектуальные технологии. Также к нам присоединится российская компания Starline, которая занимается разработкой беспилотных автомобилей.

Итак, зачем и для кого было создано сообщество Hardware Ecosystem?

У нас на рынке high-tech и электроники есть отдельные элементы экосистемы: стартапы, инвестиционные компании, ассоциация приборостроителей, университеты, научные организации, где работают инженеры. Но эти элементы работают сами по себе, связи между ними пока слишком слабые или их нет вовсе. Такое случается в незрелой бизнес-экосистеме: участники не сразу объединяются и начинают работать на общие цели.

Конечно, мировой опыт вдохновляет на то, чтобы пробежать эту дорогу быстро. У каждой страны и каждой экосистемы свой путь, и она уникальна. И это хорошо, мы разные и можем дополнять друг друга.

У наших инженеров есть шансы в определенных отраслях, которые связаны с hardware. Например, в медицинской технике, в IoT на стыке software и hardware, в беспилотных технологиях (собственно поэтому предстоящий митап и посвящен этой теме).

Живой пример: инженерная аутсорсинговая прослойка из Парка высоких технологий в Минске дает большой поток крутых разработчиков, которые пользуясь элементами экосистемы, могут создавать свое IP, решать проблемы мировых рынков, соединять решения hardware и software вместе.

За два года к сообществу Hardware Ecosystem присоединилось более 650 участников из разных стран инженеров, владельцев и менеджеров ИТ-компаний, инвесторов, руководителей тех. хабов и акселераторов. Они делились опытом в группе на LinkedIn и встречались на митапах, а в начале 2020 года из-за COVID-19 ушли в онлайн: так и появился новый подкаст и ютуб-канал c видеозаписями прошлогодних митапов про IoT, MedTech и о том, как инженеру вывести свой продукт на рынок.

И вот сейчас, при поддержке hardware-акселератора Bridgio, сообщество возвращается к формату личных встреч: в Минске, на площадке SUP, 10 октября пройдет митап Беспилотники на земле и в воздухе: бизнес-кейсы стартапов и корпораций. Впервые будет организована онлайн-трансляция встречи для русскоязычных инженеров из других городов и стран. Участники митапа из первых уст узнают о бизнес-проблемах, которые решают мировые корпоративные игроки, как проходят R&D мирового уровня. В ходе встречи организаторы постараются определить возможные варианты кооперации между инженерными командами и международными компаниями.

Если вы болеете за hardware и беспилотные технологии присоединяйтесь!

Подробнее..

Как разработать аналог Zoom для ТВ-приставок на RDK и Linux. Разбираемся с фреймворком GStreamer

29.09.2020 16:20:30 | Автор: admin
Сценарии: как использовать приложение для видеоконференций на SmartTV и ТВ-приставкахСценарии: как использовать приложение для видеоконференций на SmartTV и ТВ-приставках

Пандемия COVID-19 стала катализатором для новых полезных сервисов. Например, Zoom стал настолько успешным, что по стоимости обогнал в этом месяце IBM. Нас вдохновил этот пример, и мы решили пойти еще дальше: а что если онлайн-конференции реализовать на приставках и Smart TV, чтобы общаться не только по работе, но устраивать удаленные посиделки на диване с друзьями? Но ведь тогда можно на футболе вместе покричать, и кино посмотреть или спортом заняться под контролем тренера.

Почему-то у операторов цифрового ТВ такой услуги не оказалось, хотя с инженерной точки зрения все эти функции вполне можно реализовать на ТВ-приставках на базе Linux/Android и RDK. Мы это проверили на практике и вот теперь делимся с читателями Хабра своим рецептом создания аналога Zoom и видеоконференций через Smart TV. Разберем архитектуру решения и кодирование видеопотока с использованием GStreamer. Информацию для работы с этим фреймворком мы собирали по крупицам, но оно того стоило.

Разбираемся с архитектурой

При разработке архитектуры приложений для ТВ-приставок важно учитывать потенциальные ограничения программной и аппаратной части этих устройств. Те, кто создает desktop-программы, как правило, не сталкиваются с этими сложностями, а для embedded-разработчиков это обычное дело.

Итак, с чем мы столкнемся на ТВ-приставках:

  1. Ограниченность ресурсов процессоров и самих приставок. Чаще всего в STB-устройствах используются разнообразные ARM-процессоры, они несут в себя ряд ограничений и дополнительных задач, в частности необходимость использования аппаратного кодирования/декодирование видеопотока. Всегда нужно учитывать, что быстродействие одно из узких мест.

  2. Разность архитектур в приставках разных производителей. Некоторые базируются на Android, другие на RDK, третьи на дистрибутивах на базе Linux со своими ограничениями и нюансами. Поэтому на старте разработки лучше выбрать наиболее общие и кроссплатформенные решения в разных модулях программы. Уже не говоря о поддержке desktop-версии. А уже потом переходить к частным случаям.

  3. Сетевые ограничения. Многие приставки работают как по Ethernet так и по wifi. Сжатие и передача видео/аудиопотока еще одно узкое место в приложениях такого рода.

  4. Безопасность передачи потока и др. вопросы безопасности данных.

  5. Поддержка камер и микрофонов на встроенных платформах.

Теперь можно разложить по полочкам и саму архитектуру. Аналог Zoom для ТВ-приставок будет состоять из нескольких больших компонентов и модулей:

  • Захват видеопотока

  • Захват аудиопотока

  • Сетевой модуль

  • Модуль кодирования видео/аудиопотока

  • Модуль декодирования видео/аудиопотока

  • Вывод видеоконференции на экран

  • Вывод звука

  • Цветовые преобразования

  • Несколько других второстепенных компонентов

В упрощенном виде один из вариантов архитектуры можно изобразить так:

Архитектура приложения для видеоконференций через Smart TVАрхитектура приложения для видеоконференций через Smart TV

В рамках статьи мы сфокусируемся на кодировании декодирования видеопотока и на возможной реализации с использованием фреймворка GStreamer, т.к. это один из ключевых моментов в разработке приложений для видеоконференций.

Кодирование/декодирование потока

1) Преимущества GStreamer

Как мы уже отметили, одним из узких мест является передача видеопотока. Предположим у вас есть камера, отдающие кадры на скорости 30 кадров с секунду на небольшом разрешении 640x480. Итого, в RGB24 получается:

640 х 480 х 3 х 30 = 27 648 000 байт в секунду, т.е. более 26 Мбайт в секунду, что по понятным причинам совершенно неприемлемо в рамках сетевой передачи.

Один из вариантов решения реализовать кодирование какой-нибудь библиотекой. И тут, как можно уже было догадаться из названия статьи, выбор пал на фреймворк GStreamer. Почему именно эта библиотека? Вот несколько ее преимуществ на фоне остальных решений:

  1. Хорошая кроссплатформенность и отличная поддержка Linux и Android.

  2. На RDK Gstreamer является стандартом кодирования/декодирования и включен в дистрибутив по-умолчанию.

  3. Поддержках широкого набора модулей, фильтров и кодеков. Тот же FFmpeg, который можно использовать для тех же целей, де-факто является лишь одним из модулей GStreamerа.

  4. Простота построения конвейера (pipeline). Выстроить цепочку кодирования/декодирования не составляет большого труда, а сам подход конвейера позволяет легко заменять кодеки, фильтры и прочее без лишнего переписывания кода.

  5. API для работы С/C++ идет комплекте.

  6. Поддержка аппаратных кодеров/декодеров, в частности OpenMAX API что крайне важно при работе с ТВ-приставками.

2) Знакомимся с GStreamer разбираемся с конвейерами

Прежде чем приступать к рассмотрению кода, давайте разберемся с тем, что можно делать пока и без него. В состав GStreamer входят полезные утилиты для работы, в частности:

gst-inspect-1.0 позволит посмотреть список доступных кодеков и модулей, так что можно сразу увидеть, что будет работать, и выбрать набор фильтров и кодеков.

gst-launch-1.0 позволяет запустить любой конвейер (pipeline).

В GStreamer используется схема декодирования, по которой поток последовательно проходит через разные компоненты, начиная с source, заканчивая sink-выводом. При этом source может быть любым файл, устройство, для вывода (sink) также можно указать нужное файл, экран, сетевые выводы и протоколы (наподобие RTP).

Подробнее про использование утилит и принцип построения конвейера можно почитать в другой статье на Хабре. Классический пример проигрывания mp4-файла:

gst-launch-1.0 filesrc location=file.mp4 ! qtdemux ! h264parse ! avdec_h264 ! videoconvert ! autovideosink

На входе принимается mp4-файл, который проходит через демуксер mp4 qtdemux, парсер h264, затем через декодер, конвертер и, наконец, идет вывод на экран.

Можно заменить autovideosink на filesink с параметром файла и вывести декодированный поток прямиком в файл.

3) Пишем приложение на GStreamer C/C++ API. Попробуем декодировать

Теперь, когда мы разобрались немного с использованием gst-launch-1.0, проделаем все тоже самое, только уже в рамках приложения. Принцип останется тем же: мы встраиваем декодирующий конвейер (pipeline), однако уже с использованием библиотеки GStreamer и glib-событий.

О простейшем примере построения filesrc в filesink с кодом хорошо рассказано в другой хабрастатье GStreamer: элементы и контейнеры. Мы же рассмотрим чуть более реалистичный и сложный живой пример H264-декодирования.

Инициализация GStreamer-приложения происходит один раз при помощи

gstinit (NULL, NULL);

Если вы хотите сразу видеть происходящее в деталях, можно выстроить уровень логирования перед инициализацией

gst_debug_set_active(TRUE);gst_debug_set_default_threshold(GST_LEVEL_LOG);

Учтите: сколько бы у вас не было конвейеров в приложении, инициализировать gstinit достаточно один раз.

Создадим новый event-loop, в котором будут обрабатываться события:

GMainLoop *loop;loop = g_main_loop_new (NULL, FALSE);

И теперь можно начать выстраивать наш конвейер:

Объявим необходимые элементы, в частности сам конвейер как тип GstElement:

GstElement *pipeline, *source, *demuxer, *parser, *decoder, *conv, *sink;pipeline = gst_pipeline_new ("video-decoder");source   = gst_element_factory_make ("filesrc",       "file-source");demuxer  = gst_element_factory_make ("qtdemux",      "h264-demuxer");parser   = gst_element_factory_make ("h264parse",      "h264-parser");decoder  = gst_element_factory_make ("avdec_h264",     "h264-decoder");conv     = gst_element_factory_make ("videoconvert",  "converter");sink     = gst_element_factory_make ("appsink", "video-output");

Каждый элемент конвейера создается через gst_element_factory_make, где первым параметром идет тип, а вторым его условное название для GStreamer, на которое он впоследствии будет опираться, например при выдаче ошибок.

Также не мешало бы проверить, что все компоненты найдены, в противном случае gst_element_factory_make, возвращает NULL.

if (!pipeline || !source || !demuxer || !parser || !decoder || !conv || !sink) {// не инициализирован один элемент - остановкаreturn;}

Установим тот самый параметр location через gob_ject_set:

gob_ject_set (G_OBJECT (source), "location", argv[1], NULL);

Остальные параметры в других элементах можно выставлять аналогичным образом.

Теперь необходим обработчик сообщений GStreamer, создадим соответствующий bus_call:

GstBus *bus;guint bus_watch_id;bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));bus_watch_id = gst_bus_add_watch (bus, bus_call, loop);gst_object_unref (bus);

gst_object_unref и другие подобные вызовы нужны для очищения выделенных объектов.

Затем объявим сам обработчик сообщений:

static gbooleanbus_call (GstBus     *bus,          GstMessage *msg,          gpointer    data){  GMainLoop *loop = (GMainLoop *) data;  switch (GST_MESSAGE_TYPE (msg)) {    case GST_MESSAGE_EOS:      LOGI ("End of stream\n");      g_main_loop_quit (loop);      break;    case GST_MESSAGE_ERROR: {      gchar  *debug;      GError *error;      gst_message_parse_error (msg, &error, &debug);      g_free (debug);      LOGE ("Error: %s\n", error->message);      g_error_free (error);      g_main_loop_quit (loop);      break;    }    default:      break;  }  return TRUE;}

А теперь самое важное: собираем и добавляем все созданные элементы в единый конвейер, тот самый что выстраивали через gst-launch. Очередность добавления, естественно, важна:

gst_bin_add_many (GST_BIN (pipeline), source, demuxer, parser, decoder, conv, sink, NULL);gst_element_link_many (source, demuxer, parser, decoder, conv, sink, NULL);

Стоит также заметить, что такой подход линковки элементов прекрасно работает для потоковых выходов, но в случае именно проигрывания (autovideosink) необходима дополнительная синхронизация и динамическая линковка демуксера и парсера:

  gst_element_link (source, demuxer);  gst_element_link_many (parser, decoder, conv, sink, NULL);  g_signal_connect (demuxer, "pad-added", G_CALLBACK (on_pad_added), parser);static voidon_pad_added (GstElement *element,              GstPad     *pad,              gpointer    data){  GstPad *sinkpad;  GstElement *decoder = (GstElement *) data;  /* We can now link this pad with the sink pad */  g_print ("Dynamic pad created, linking demuxer/decoder\n");  sinkpad = gst_element_get_static_pad (decoder, "sink");  gst_pad_link (pad, sinkpad);  gst_object_unref (sinkpad);}

Динамическое соединение дает возможность определения типа и количества потоков в отличии от статического, и будет работать в некоторых случаях когда это требуется.

Ну и, наконец, переводим состояние конвейера в проигрывание:

gst_element_set_state (pipeline, GST_STATE_PLAYING);

И запускаем event-loop:

g_main_loop_run (loop);

После окончания этой процедуры все нужно почистить:

gst_element_set_state (pipeline, GST_STATE_NULL);  gst_object_unref (GST_OBJECT (pipeline));  g_source_remove (bus_watch_id);  g_main_loop_unref (loop);

4) Выбираем энкодеры и декодеры. Фоллбэки

Стоит еще рассказать о полезных, но не особо упомянутых вещах в документации о том, как можно легко организовать фоллбэк декодеров или энкодеров.

Поможет нам в этом функция gst_element_factory_find, которая проверяет, есть ли у нас кодек в factory элементов:

if(gst_element_factory_find("omxh264dec"))decoder  = gst_element_factory_make ("omxh264dec",     "h264-decoder");elsedecoder  = gst_element_factory_make ("avdec_h264",     "h264-decoder");

В данном примере мы приоритезировали выбор аппаратного декорера OMX на платформе RDK, и в случае его отсутствия будем выбирать программную реализацию.

Другой крайне полезной, но еще более редко используемой функцией является проверка того, что же мы на самом деле инициализировали в GstElement (какой кодек):

gst_plugin_feature_get_name(gst_element_get_factory(encoder))

Можно проделать это таким незамысловатым способом и вернуть название инициализированного кодека.

5) Цветовые модели видео

Не стоит оставлять без внимания и цветовые модели, раз уж мы заговорили о кодировании видео с камер. И тут чаще подразумевается YUV, нежели RGB.

Камеры просто обожают цветовую модель YUYV. Но это то, с чем любит работать GStreamer, для него более привычна модель I420. На выходе, если речь не идет о выводе в gl-фрейм, у нас также будут выходить I420-кадры. Будьте готовы подставить необходимые фильтры и выполнить преобразования. Некоторые энкодеры умеют работать и с другими цветовыми моделями, но чаще это исключения из правил.

Еще стоит заметить что у GStreamerа есть свой модуль получения видеопотока с камеры, и его можно использовать для построения конвейера, но об этом расскажем как-нибудь в другой раз.

Разбираемся с буферами и берем данные на лету

1) Буфер ввода

Пришло время разобраться с потоками данных. До этого момента мы просто кодировали то, что есть в файле, через filesrc и выводили все в тот же filesink или на экран.

Теперь будем работать с буферами и входами и выходами appsrc / appsink. Почему-то этому вопросу почти не уделиливнимания в официальной документации.

Как же организовать постоянный поток данных в созданных конвейерах, а точнее подать буфер на выход и получить кодированный или декодированный буфер выхода? Допустим мы получили картинку с камеры, и нам нужно ее закодировать. Мы уже определились с тем, что нам потребуется фрейм в I420. Допустим он у нас есть, что дальше? Как пропустить картинку через весь поток конвейера?

Вначале установим обработчик события need-data, который будет запускаться при необходимости подачи данных в конвейер и начнем подавать входной буфер:

g_signal_connect (source, "need-data", G_CALLBACK (encoder_cb_need_data), NULL);

Сам обработчик имеет следующий вид:

encoder_cb_need_data (GstElement *appsrc,          guint       unused_size,          gpointer    user_data){  GstBuffer *buffer;  GstFlowReturn ret;  GstMapInfo map;   int size;   uint8_t* image;  // get image  buffer = gst_buffer_new_allocate (NULL, size, NULL);  gst_buffer_map (buffer, &map, GST_MAP_WRITE);    memcpy((guchar *)map.data, image,  gst_buffer_get_size( buffer ) );  gst_buffer_unmap(buffer, &map);  g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret);  gst_buffer_unref(buffer);}

image это, условно говоря, псевдокод буфера картинки в I420.

Далее мы создаем через gst_buffer_new_allocate буфер необходимого размера, который будет соответствовать размеру буфера картинки.

При помощи gst_buffer_map устанавливаем буфер в режим записи и, используя memcpy, копируем нашу картинку в созданный буфер.

И, наконец, сигнализируем GStreamу о том, что буфер готов.

Ремарка: очень важно после записи использовать gst_buffer_unmap, а также очищать буфер после использования при помощи gst_buffer_unref. Иначе будет утечка памяти. В скудном количестве доступных примеров никто особо насчет вопроса освобождения памяти не заморачивался, а он, понятное дело, важный.

Теперь, когда мы закончили с обработчиком, нужно проделать еще одну вещь: настроить caps на поступление ожидаемого формата.

Делается это перед установкой обработчика сигнала need-data:

g_object_set (G_OBJECT (source),        "stream-type", 0,        "format", GST_FORMAT_TIME, NULL);g_object_set (G_OBJECT (source), "caps",gst_caps_new_simple ("video/x-raw","format", G_TYPE_STRING, "I420","width", G_TYPE_INT, 640,"height", G_TYPE_INT, 480,"framerate", GST_TYPE_FRACTION, 30, 1,NULL), NULL);

Как и все параметры GstElement, установка параметров осуществляется через g_object_set.

В данном случае мы задали тип потока, и его caps формат данных. Указав, что на выход appsrc будет поступать данные I420 c разрешением 640x480 и частотой 30 кадров в секунду.

Частота в нашем случае, да в целом, не играет роли. На практике мы не замечали, чтобы GStreamer как-то ограничивал вызовы need-data по частоте.

Готово, теперь наши кадры поступают в энкодер.

2) Буфер вывода

А теперь разберемся, как получить кодированный поток на выходе.

Подключаем обработчик к sink pad:

GstPad *pad = gst_element_get_static_pad (sink, "sink");  gst_pad_add_probe  (pad, GST_PAD_PROBE_TYPE_BUFFER, encoder_cb_have_data, NULL, NULL);  gst_object_unref (pad);

Похожим образом мы подключились к другому событию sink pad GST_PAD_PROBE_TYPE_BUFFER, которое будет вызываться по мере поступления буфера данных в sink pad.

static GstPadProbeReturnencoder_cb_have_data (GstPad * pad,                        GstPadProbeInfo * info,                        gpointer user_data) {  GstBuffer *buf = gst_pad_probe_info_get_buffer (info);  GstMemory *bufMem = gst_buffer_get_memory(buf, 0);  GstMapInfo bufInfo;  gst_memory_map(bufMem, &bufInfo, GST_MAP_READ);  // bufInfo.data, bufInfo.size  gst_memory_unmap(bufMem, &bufInfo);  return GST_PAD_PROBE_OK;}

Колбэк имеет похожую структуру. Теперь нужно достучаться до памяти буфера. Вначале получаем GstBuffer, затем указатель его памяти, используя gst_buffer_get_memory по индексу 0 (как правило задействован только он). И, наконец, используя gst_memory_map, получаем адрес буфера данных bufInfo.data и его размер bufInfo.size.

Фактически мы добились цели получили буфер с кодированными данными и его размер.

Итак, мы рассмотрели ключевые и самые интересные компоненты из приложения для Smart TV аналога Zoom для ТВ-приставок: архитектуру, модули кодирования / декодирования через GStreamer, буферы ввода / вывода и используемые цветовые преобразования.

Для операторов цифрового ТВ такая программная платформа может стать новым абонентским сервисом. Для нас инженеров новым интересным embedded-проектом для реализации на разных приставках на базе RDK, Linux и Android. А для всех остальных возможностью приятно проводить время за совместным просмотром фильмов и спортивных матчей, занятий спортом и посиделок с близкими в период карантина или удаленной работы.

Эту идею с сервисом видеоконференций по Smart TV можно развивать и дальше, как с точки зрения инженерных решений, так и по сценариям их использования. Так что делитесь мыслями в комментариях.

Подробнее..

Генератор трафика Cisco TRex запускаем нагрузочное тестирование сетевых устройств

13.07.2020 10:06:40 | Автор: admin


При разработке очередного роутера мы тестировали производительность сети с помощью полезной open-source-штуки генератора трафика Cisco TRex. Что это за инструмент? Как им пользоваться? И чем он может пригодится инженерам-разработчикам? Под катом ответы на эти вопросы.

1. Что такое Cisco TRex


Это программный генератор трафика с открытым исходным кодом, работает на стандартных процессорах Intel на базе DPDK, поддерживает режимы с контролем состояния потока и без (stateful / stateless modes). Сравнительно простой и полностью масштабируемый.

Англоязычная документация для этого инструмента доступна на сайте https://trex-tgn.cisco.com/trex/doc

Trex позволяет генерировать разные типы трафика и анализировать данные при их получении. Поддерживается работа на уровне MAC и IP. Можно задавать размер пакетов и их количество, контролировать скорость передачи данных.

Работа с генератором организована в среде Linux.

Одно из важных отличий генератора Trex использование технологии DPDK, которая позволяет обойти узкие места в производительности сетевого стека Linux. DPDK или Data Plane Development Kit это целый набор библиотек и драйверов для быстрой обработки пакетов, который позволяет исключить сетевой стек Linux из процесса обработки пакетов и взаимодействовать с сетевым устройством напрямую.

DPDK превращает процессор общего назначения в сервер пересылки пакетов. Благодаря этой трансформации отпадает необходимость в дорогостоящих коммутаторах и маршрутизаторах. Однако DPDK накладывает ограничения на использование конкретных сетевых адаптеров, список поддерживаемого железа указан на http://core.dpdk.org/supported тут самая популярная платформа от Intel, т.е. обеспечена поддердка железа, которое работает с linux-драйверами e1000, ixgbe, i40e, ice, fm10k, ipn3ke, ifc, igc.

Также важно понимать, что для работы TRex-сервера на скоростях 10 Гбит/с необходим многоядерный процессор от 4 ядер и выше, желательно CPU семейства Intel c поддержкой одновременной многопоточности (hyper-threading).

2. Как получить и попробовать TRex


1) Загружаем архив с сервера trex-tgn.cisco.com:
https://trex-tgn.cisco.com/trex/release/

Распаковываем архив в домашней директории пользователя /home/user, где user имя пользователя.
[bash]>wget --no-cache https://trex-tgn.cisco.com/trex/release/latest[bash]>tar -xzvf latest

2) Настраиваем интерфейсы отправки и приема данных

Выполним настройку с помощью утилиты dpdk_setup_ports.py, которая идет в архиве с TRex. Конфигурировать сетевые интерфейсы, которые использует TRex, можно на уровне MAC или IP. Для старта необходимо запустить данную утилиту с ключом интерактивной настройки sudo ./dpdk_setup_ports.py i.

Первым шагом откажемся от конфигурации на MAC-уровне (Do you want to use MAC based config? (y/N) n).

Вторым шагом необходимо выбрать пару сетевых интерфейсов, с которыми будем работать, в нашем случае сетевая карта Intel X710 работает с 4 сетевыми интерфейсами, будем использовать 1-е и 4-е гнездо сетевой карты.



Третьим шагом система предложит автоматически создать замкнутую конфигурацию когда данные уходят с порта 1 и приходят в порт 2 (и обратно), все на одном ПК. Нам пришлось отказаться от данной схемы и настроить схему маршрутизации на 2 ПК.

Четвертым и пятым шагом даем согласие на сохранение конфигурации в файл /etc/trex_cfg.yaml.

Для примера рассмотрим конфигурацию на IP-уровне для следующей схемы подключения:



Файл конфигурации находится тут: /etc/trex_cfg.yaml. Простой конфигурационный файл показан ниже для сетевой карты с 2 портами и CPU, поддерживающем 8 потоков:

### Config file generated by dpdk_setup_ports.py ###- version: 2  interfaces: ['01:00.0', '01:00.3']  port_info:      - ip: 192.168.253.106        default_gw: 192.168.253.107      - ip: 192.168.254.106        default_gw: 192.168.254.107   platform:      master_thread_id: 0      latency_thread_id: 1      dual_if:    - socket: 0      threads: [2,3,4,5,6,7]


В конфигурации:
  • '01:00.0', '01:00.3' наименование Eth-интерфейсов в используемой системе Linux.
  • ip: 192.168.253.106 адрес порта ПК Server TRex, с которого генерируется трафик.
  • default_gw: 192.168.253.107 адрес 1 порта ПК DUT (Device under test).
  • ip: 192.168.254.106 адрес порта ПК Server TRex, с которого возвращается трафик после прохождения через правила QOS.
  • default_gw: 192.168.253.107 адрес 2 порта ПК DUT.

Внимание! Система TRex запрещает использование той же подсети при генерации потоков, что используются системой, для этого при генерации пакетов используются подсети 16.0.0.0 и 48.0.0.0.

3) Настраиваем интерфейсы на удаленной машине

Необходимо настроить пересылку (forwarding) и маршруты, чтобы система (DUT), через которую будем пропускать трафик, знала, откуда принимать и куда отправлять пакеты.

Настраиваем на ПК DUT правила маршрутизации потоков:
sudo echo 1 > /proc/sys/net/ipv4/ip_forwardsudo route add -net 16.0.0.0 netmask 255.0.0.0 gw 192.168.253.106sudo route add -net 48.0.0.0 netmask 255.0.0.0 gw 192.168.254.106

4) Запускаем TRex-сервер в режиме astf:
cd v2.XXsudo ./t-rex-64 -i --astf

При успешном запуске TRex-сервера, увидим информацию о Ethernet-портах, занятых под тестирование:

The ports are bound/configured.port : 0 ------------link         :  link : Link Up - speed 10000 Mbps - full-duplexpromiscuous  : 0 port : 1 ------------link         :  link : Link Up - speed 10000 Mbps - full-duplexpromiscuous  : 0 number of ports         : 2 max cores for 2 ports   : 1 tx queues per port      : 3

5) Запускаем консоль TRex

С помощью консоли в отдельном окне запускаем генерацию потока из готовых примеров (папка с примерами astf есть в архиве к TRex):

cd v2.XX./trex-consolestart -f astf/http_simple.py -m 1 start (options):-a (all ports)-port 1 2 3 (ports 1 2 3)-d duration (-d 100 -d 10m -d 1h)-m stream strength (-m 1 -m 1gb -m 40%)-f load from disk the streams file

При успешном запуске увидим статистику по прохождению трафика в консоли TRex-сервера:
Global stats enabledCpu Utilization : 0.3  %  0.6 Gb/core Platform_factor : 1.0  Total-Tx        :     759.81 Kbps  Total-Rx        :     759.81 Kbps  Total-PPS       :      82.81  pps  Total-CPS       :       2.69  cps   Expected-PPS    :       0.00  pps  Expected-CPS    :       0.00  cps  Expected-L7-BPS :       0.00  bps   Active-flows    :        2  Clients :        0   Socket-util : 0.0000 %    Open-flows      :      641


3. Автоматизация разработки и тестирования с помощью TRex


В процессе разработки сетевого роутера мы написали много тестов для TRex, соответственно встал вопрос по их прогону в автоматическом режиме с помощью python. Как мы это организовали:

Запустили TRex-сервер в режиме stl:
cd v2.XXsudo ./t-rex-64 -i --stl

Задали переменную окружения для python, так как TRex работает в связке с python.
export PYTHONPATH=/home/!!!user!!!/v2.XX/automation/trex_control_plane/interactive,
где, !!!user!!! имя пользователя и домашняя директория, v2.XX версия ПО TRex, загруженная и распакованная в данную папку.

Запустили генератор трафика с помощью python, листинг примера конфигурации приведен ниже.

python example_test_2bidirectstream.py

Ожидаемый результат:

Transmit: 10000.24576MByte/s Receive: 10000.272384MByte/sStream 1 TX: 4487179200 Bit/s RX: 4487179200 Bit/sStream 2 TX: 2492873600 Bit/s RX: 2492873600 Bit/sStream 3 TX: 1994294400 Bit/s RX: 1994294400 Bit/sStream 4 TX: 997147200 Bit/s RX: 997147200 Bit/s


Разберем данный пример:
c = STLClient(server = '127.0.0.1')

Создаем подключение к TRex-серверу, в данном случае подключение создается к той же машине, где и сервер.

  • base_pkt_dir_a, base_pkt_dir_b, base_pkt_dir_c, base_pkt_dir_d шаблоны пакетов, в которых указаны адреса источника и получателя, и порты источника и получателя. В данном примере создается 4 потока, 2 в одну сторону и 2 в обратную.
  • s1, s2, s3, s4 у класса STLStream запрашиваем параметры генерируемого потока, такие как ID потока и bitrate, в нашем случае ID1=4.5 Гбит/с, ID2=2.5 Гбит/с, ID3=2 Гбит/с, ID4=1 Гбит/с.


Листинг файла конфигурации потоков example_test_2bidirectstream.py
# get TRex APIsfrom trex_stl_lib.api import * c = STLClient(server = '127.0.0.1')c.connect() try:    # create a base packet with scapy    base_pkt_dir_a = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=5001,sport=50001)    base_pkt_dir_b = Ether()/IP(src="48.0.0.1",dst="16.0.0.1")/UDP(dport=50001,sport=5001)     base_pkt_dir_c = Ether()/IP(src="16.0.0.2",dst="48.0.0.2")/UDP(dport=5002,sport=50002)    base_pkt_dir_d = Ether()/IP(src="48.0.0.2",dst="16.0.0.2")/UDP(dport=50002,sport=5002)     # pps : float    # Packets per second    #    # bps_L1 : float    # Bits per second L1 (with IPG)    #    # bps_L2 : float    # Bits per second L2 (Ethernet-FCS)    packet_size = 1400     def pad(base_pkt):        pad = (packet_size - len(base_pkt)) * 'x'        return pad     s1 = STLStream(packet=STLPktBuilder(base_pkt_dir_a/pad(base_pkt_dir_a)), mode=STLTXCont(bps_L2=4500000000), flow_stats=STLFlowStats(pg_id=1))    s2 = STLStream(packet=STLPktBuilder(base_pkt_dir_b/pad(base_pkt_dir_b)), mode=STLTXCont(bps_L2=2500000000), flow_stats=STLFlowStats(pg_id=2))    s3 = STLStream(packet=STLPktBuilder(base_pkt_dir_c/pad(base_pkt_dir_c)), mode=STLTXCont(bps_L2=2000000000), flow_stats=STLFlowStats(pg_id=3))    s4 = STLStream(packet=STLPktBuilder(base_pkt_dir_d/pad(base_pkt_dir_d)), mode=STLTXCont(bps_L2=1000000000), flow_stats=STLFlowStats(pg_id=4))     my_ports = [0, 1]     c.reset(ports = [my_ports[0], my_ports[1]])     # add the streams    c.add_streams(s1, ports = my_ports[0])    c.add_streams(s2, ports = my_ports[1])    c.add_streams(s3, ports = my_ports[0])    c.add_streams(s4, ports = my_ports[1])     # start traffic with limit of 10 seconds (otherwise it will continue forever)    # bi direction    testduration = 10    c.start(ports=[my_ports[0], my_ports[1]], duration=testduration)    # hold until traffic ends    c.wait_on_traffic()     # check out the stats    stats = c.get_stats()     # get global stats    totalstats = stats['global']    totaltx = round(totalstats.get('tx_bps'))    totalrx = round(totalstats.get('rx_bps'))    print('Transmit: {}MByte/s Receive: {}MByte/s'.format((totaltx / 1000000), (totalrx / 1000000)))    c.clear_stats(ports = [my_ports[0], my_ports[1]])     # get flow stats    totalstats = stats['flow_stats']    stream1 = totalstats[1]     stream2 = totalstats[2]    stream3 = totalstats[3]    stream4 = totalstats[4]    totaltx_1 = stream1.get('tx_pkts')    totalrx_1 = stream1.get('rx_pkts')    print('Stream 1 TX: {} Bit/s RX: {} Bit/s'.format((totaltx_1['total'] / testduration * packet_size * 8),                                                               (totalrx_1['total'] / testduration * packet_size * 8)))    totaltx_2 = stream2.get('tx_pkts')    totalrx_2 = stream2.get('rx_pkts')    print('Stream 2 TX: {} Bit/s RX: {} Bit/s'.format((totaltx_2['total'] / testduration * packet_size * 8),                                                               (totalrx_2['total'] / testduration * packet_size * 8)))    totaltx_3 = stream3.get('tx_pkts')    totalrx_3 = stream3.get('rx_pkts')    print('Stream 3 TX: {} Bit/s RX: {} Bit/s'.format((totaltx_3['total'] / testduration * packet_size * 8),                                                               (totalrx_3['total'] / testduration * packet_size * 8)))    totaltx_4 = stream4.get('tx_pkts')    totalrx_4 = stream4.get('rx_pkts')    print('Stream 4 TX: {} Bit/s RX: {} Bit/s'.format((totaltx_4['total'] / testduration * packet_size * 8),                                                               (totalrx_4['total'] / testduration * packet_size * 8)))except STLError as e:    print(e) finally:    c.disconnect()


Заключение


При подготовке этого руководства для Хабра мы запустили и проверили работу системы DUT с 4 потоками, собрали информацию по потокам и глобальную статистику.

Описанная выше операция запускается с помощью python, значит с помощью TRex можно автоматизировать тестирование и отладку сетевых устройств и программных продуктов в цикле или при последовательном запуске тестов на python.

Так чем же TRex компании Cisco лучше или хуже других аналогичных генераторов трафика? Например, популярной клиент-серверной программы iperf? В сценарии использования TRex мы видим описание настройки и работы с потоками. Оба средства тестирования и отладки хороши: iperf для быстрой проверки функциональности на ходу, а TRex отлично справляется с автоматизацией тестирования и разработки сложных сетевых устройств и систем, где важна возможность настройки многопоточных стримов, чтобы каждый поток конфигурировать под конкретную задачу и анализировать результаты на выходе.

TRex позволяет создавать шаблоны практически любого вида трафика и усиливать их для генерации крупномасштабных DDoS-атак, в том числе TCP-SYN, UDP и ICMP-потоков. Возможность генерации массивных потоков трафика позволяет моделировать атаки от различных клиентов на множество целевых серверов.

Так что если вы еще не пробовали этот инструмент можно взять на заметку. А если пробовали поделитесь своими примерами и отзывами в комментариях. Интересно узнать, что о TRex думают и как используют коллеги-инженеры.
Подробнее..

Эволюция системы обновления Android

17.12.2020 06:12:58 | Автор: admin
Индиана устанавливает новый активный раздел: меняет золотого идола на мешок с песком в легендарной сцене из фильма Индиана Джонс: В поисках утраченного ковчегаИндиана устанавливает новый активный раздел: меняет золотого идола на мешок с песком в легендарной сцене из фильма Индиана Джонс: В поисках утраченного ковчега

В этой статье мы рассмотрим все возможные варианты обновления прошивки на устройствах под управлением Fuchsia Android. Особое внимание уделим самому популярному способу обновлению по воздуху или OTA (over-the-air) и расскажем об этапах его развития.

Итак, как можно обновить Android на мобильных устройствах? Занимаясь разработкой ТВ-приставок под управлением этой ОС, мы определили для себя 4 способа, отбросив совсем уж экзотические варианты:

  1. перепрошивка flash-памяти через аппаратный интерфейс JTAG (если есть);

  2. перепрошивка flash-памяти с использованием загрузчика (bootloader);

  3. обновление через Recovery Mode;

  4. OTA (over-the-air).

Рассмотрим подробнее каждый из вариантов.

1. Обновление Android через JTAG-интерфейс

Вариант с JTAG позволяет обновлять устройство только локально и требует подключения девайса с Android к хосту, например, по USB-интерфейсу. Так как перепрошивается flash-память, новую версию Android можно поставить на прошивку с другими ключами безопасности, да и в целом не сильно стесняться в выборе версий самой Android, версии собранной прошивки или переконфигурации разделов flash-памяти.

Однако обычно JTAG-интерфейс присутствует только на отладочных платах, что сильно сужает область применения этого варианта обновится.

2. Обновление Android через Recovery Mode

Обычно загрузчик является проприетарным, его разрабатывает производитель чипа. Именно bootloader инициализирует доверенную среду выполнения (TEE, trusted execution environment) и проверяет целостность разделов boot и recovery перед переносом выполнения в ядро Linux. Сам загрузчик часто является составным, часть его уровней может быть открытой (например, на базе U-boot), а часть проприетарной.

Bootloader Android позволяет перепрошивать flash-память устройства подготовленными образами разделов. Для этого используется протокол fastboot либо его аналог (в случае Amlogic это будет протокол WorldCup Device). Fastboot,как и его аналог WorldCup Device, это протокол взаимодействия с bootloader через USB-интерфейс или локальную сеть Ethernet.

Для перепрошивки необходимо подключить устройство через USB к хосту (есть вариант использовать LAN Ethernet), перевести загрузчик (bootloader) в специальный update-режим и в этом режиме перепрошить flash-память устройства.

Плюсы и минусы данного метода всё те же, что и для JTAG: так как обновление проходит без участия самой системы Android, при перепрошивке нет ограничений, связанных с версией системы/сборки или ключами безопасности.

Но, как всегда, есть одно НО. :-) Bootloader должен быть разблокирован, а это значит, что мы можем перепрошить сам загрузчик или разделы устройства. Блокировка/разблокировка производится командой fastboot flashing lock/unlock, но для выполнения этой команды может понадобится пароль, установленный тем, кто добрался до этого устройства раньше вас (обычно это производитель).

3. Обновление Android через Recovery Mode и OTA

Если первые два варианта обновления оставались неизменными на протяжении всего времени развития Android, то следующие два варианта обновление через Recovery Mode и OTA реализуются средствами самой Android и эволюционировали вместе со всей ОС.

Стоит упомянуть, что Recovery Mode и OTA это два различных варианта вызова движка обновления Android.

Recovery или non-A/B System Updates

Recovery и движок обновления updater (bootable/recovery/updater) это как раз то, с чего началась система обновления Android (располагается в bootable/recovery в дереве исходников AOSP).

Схема обновления Recovery (или non-A/B System Updates) задействует специальный раздел восстановления (Recovery), где содержится специальная ОС на основе ядра Linux. Эта ОС на базе Linux содержит программное обеспечение для распаковки загруженного образа обновления и его применения к другим разделам. Так и проходит обновление Android.

Пример разметки flash-памяти на устройстве с Android 6.0:

Карта разделов Android 6.0.1

[mmcblk0p01] bootloader offset 0x000000000000, size 0x000000400000

[mmcblk0p02] reserved offset 0x000002400000, size 0x000004000000

[mmcblk0p03] cache offset 0x000006c00000, size 0x000020000000

[mmcblk0p04] env offset 0x000027400000, size 0x000000800000

[mmcblk0p05] logo offset 0x000028400000, size 0x000002000000

[mmcblk0p06] recovery offset 0x00002ac00000, size 0x000002000000

[mmcblk0p07] rsv offset 0x00002d400000, size 0x000000800000

[mmcblk0p08] tee offset 0x00002e400000, size 0x000000800000

[mmcblk0p09] crypt offset 0x00002f400000, size 0x000002000000

[mmcblk0p10] misc offset 0x000031c00000, size 0x000002000000

[mmcblk0p11] instaboot offset 0x000034400000, size 0x000020000000

[mmcblk0p12] boot offset 0x000054c00000, size 0x000002000000

[mmcblk0p13] system offset 0x000057400000, size 0x000060000000

[mmcblk0p14] data offset 0x0000b7c00000, size 0x0002ec200000

Сам процесс обновления происходит в два этапа:

  1. после загрузки с раздела Recovery происходит обновления всех остальных разделов Android;

  2. и уже после перезагрузки и запуска новой версии Android происходит обновление раздела Recovery.

При обновлении с использованием движка updater на первом этапе проверяется версия и цифровая подпись образа, поэтому откатить на старую версию ОС уже не получится.

Обновиться по схеме Recovery можно как локально, выбрав в bootloader режим Recovery Mode и запустив движок обновления updater через меню Recovery Mode, либо удаленно, через OTA, когда приложение, работающее в Android, вызывает тот же updater из Java. И как раз при таком удаленном запуске можно организовать массовое обновление целой серии устройств. Этот вариант используют операторы цифрового ТВ при обновлении своих абонентских ТВ-приставок.

Сам раздел Recovery при non-A/B-схеме обновления является физическим разделом во flash-памяти. С появлением A/B-схемы раздел Recovery переместился на RAM-диск в оперативной памяти устройства, но возможность сделать его отдельным физическим разделом так же осталась.

Нужно сказать, что в системе Android нет четкого разделения на старое и новое, скорее добавляются дополнительные возможности в конфигурации сборки Android с сохранением по возможности совместимости со старыми решениями. Однако не все варианты конфигураций работают.

Одним из важных недостатков схемы Recovery или non-A/B System Updates является то, что при любом сбое во время обновления или битой прошивке мы получаем пусть и не кирпич (с раздела Recovery всё еще можно запустить устройство в Recovery Mode), но всё же не полнофункциональное и требующее восстановления устройство.

С этим, видимо, решено было что-то делать, потому что следующим этапом эволюции системы обновления стало бесшовное обновление (seamless updates) или A/B-схема обновления.

Бесшовное обновление или A/B-схема

Эта возможность появилась в Android 7.0, она реализована в новом движке update_engine, который располагается в system/update_engine в дереве исходников AOSP.

Главной особенностью A/B-схемы стало то, что в случае сбоев при обновлении можно загрузится с предыдущей рабочей версии системы Android. Flash-память устройства содержит дублирующиеся системные разделы или слоты (slot A и B), отсюда и название A/B system updates (вечная проблема с выбором названий). За выбор слота для загрузки (A или B) отвечает bootloader, анализируя состояние слотов.

Принцип бесшовного обновления Android по A/B-схеме (активный раздел отмечен птичкой)Принцип бесшовного обновления Android по A/B-схеме (активный раздел отмечен птичкой)

Итак, как же происходит обновление:

1) Загружая систему, например, со слотов A, мы скачиваем и прошиваем обновления на слоты B.

2) После перезагрузки со слотов B мы проверяем работоспособность системы, и, если все ОК, сообщаем bootloader, что обновление прошло успешно.

В случае проблем с обновлением bootloader вернется на старую версию прошивки после нескольких неудачных попыток загрузиться с новой системы.

На официальном сайте для разработчиков Android Source этот процесс расписан более детально в 9 шагах, также там объясняется, как все работает после перезагрузки.

Особенность бесшовной A/B-схемы обновление это съедение большего объема flash- памяти. Насколько большего? Это можно оценить по приведенным ниже схемам разделов для Android 9.0. Как уже упоминалось ранее, разработчик может выбирать, какую из схем A/B или non-A/B применять в конфигурации системы.

Карта разделов Android P (recovery)

[mmcblk0p01] bootloader offset 0x000000000000, size 0x000000400000

[mmcblk0p02] reserved offset 0x000002400000, size 0x000004000000

[mmcblk0p03] cache offset 0x000006c00000, size 0x000046000000

[mmcblk0p04] env offset 0x00004d400000, size 0x000000800000

[mmcblk0p05] logo offset 0x00004e400000, size 0x000000800000

[mmcblk0p06] recovery offset 0x00004f400000, size 0x000001800000

[mmcblk0p07] misc offset 0x000051400000, size 0x000000800000

[mmcblk0p08] dtbo offset 0x000052400000, size 0x000000800000

[mmcblk0p09] cri_data offset 0x000053400000, size 0x000000800000

[mmcblk0p10] param offset 0x000054400000, size 0x000001000000

[mmcblk0p11] boot offset 0x000055c00000, size 0x000001000000

[mmcblk0p12] rsv offset 0x000057400000, size 0x000001000000

[mmcblk0p13] metadata offset 0x000058c00000, size 0x000001000000

[mmcblk0p14] vbmeta offset 0x00005a400000, size 0x000000200000

[mmcblk0p15] tee offset 0x00005ae00000, size 0x000002000000

[mmcblk0p16] vendor offset 0x00005d600000, size 0x000040000000

[mmcblk0p17] odm offset 0x00009de00000, size 0x000008000000

[mmcblk0p18] system offset 0x0000a6600000, size 0x000050000000

[mmcblk0p19] product offset 0x0000f6e00000, size 0x00000800000

Карта разделов Android P (A/B-схема)

[mmcblk0p01] bootloader offset 0x000000000000, size 0x000000400000

[mmcblk0p02] reserved offset 0x000002400000, size 0x000004000000

[mmcblk0p03] cache offset 0x000006c00000, size 0x000000000000

[mmcblk0p04] env offset 0x000007400000, size 0x000000800000

[mmcblk0p05] logo offset 0x000008400000, size 0x000000800000

[mmcblk0p06] boot_a offset 0x000009400000, size 0x000001000000

[mmcblk0p07] misc offset 0x00000ac00000, size 0x000000800000

[mmcblk0p08] dtbo_a offset 0x00000bc00000, size 0x000000800000

[mmcblk0p09] dtbo_b offset 0x00000cc00000, size 0x000000800000

[mmcblk0p10] cri_data offset 0x00000dc00000, size 0x000000800000

[mmcblk0p11] param offset 0x00000ec00000, size 0x000001000000

[mmcblk0p12] boot_b offset 0x000010400000, size 0x000001000000

[mmcblk0p13] rsv offset 0x000011c00000, size 0x000001000000

[mmcblk0p14] metadata_a offset 0x000013400000, size 0x000001000000

[mmcblk0p15] metadata_b offset 0x000014c00000, size 0x000001000000

[mmcblk0p16] vbmeta_a offset 0x000016400000, size 0x000000200000

[mmcblk0p17] vbmeta_b offset 0x000016e00000, size 0x000000200000

[mmcblk0p18] tee offset 0x000017800000, size 0x000002000000

[mmcblk0p19] vendor_a offset 0x00001a000000, size 0x000040000000

[mmcblk0p20] vendor_b offset 0x00005a800000, size 0x000040000000

[mmcblk0p21] odm_a offset 0x00009b000000, size 0x000008000000

[mmcblk0p22] odm_b offset 0x0000a3800000, size 0x000008000000

[mmcblk0p23] system_a offset 0x0000ac000000, size 0x000050000000

[mmcblk0p24] system_b offset 0x0000fc800000, size 0x000050000000

[mmcblk0p25] product_a offset 0x00014d000000, size 0x000008000000

[mmcblk0p26] product_b offset 0x000155800000, size 0x000008000000

[mmcblk0p27] data offset 0x00015e000000, size 0x000245e00000

Если сравнить эти две конфигурации, то можно заметить, что раздел data при A/B-схеме меньше на 1,6 ГБ, и это цена дублирующихся системных разделов. Много это или мало каждый решает сам, ориентируясь на характеристики своего устройства/проекта.

Проект Treble

Следующие изменения в системе обновления произошли в Android 8.0. Начиная с Android O (8.0) и продолжая в Android P (9.0), Google реализует свой проект Treble. Идея проекта состоит в том, чтобы упростить технологический процесс создания обновления для андроид-устройства. Google предложил разделить с помощью неизменных интерфейсов части прошивки, созданием которых занимаются разные компании. Процесс разработки прошивки для конкретного девайса можно упрощенно разделить на следующие шаги:

  1. команда Android создает новую версию своей OC;

  2. разработчик чипа или системы на кристалле (Silicon Manufacturer) создает аппаратно-зависимые патчи для запуска этой версии Android на своих платах;

  3. и уже разработчики конечного устройства (Vendors) делают свою часть для реализации всех функций конкретного продукта для рынка электроники.

Проект Treble разделяет ОС Android с дополнениями от производителей чипов/СнК и код разработчика конечного устройства, так что теперь операционная система может получать обновления без реализации изменений от производителя устройства.

Разделение происходит как с помощью программного интерфейса (переход с Hardware Abstraction Layer 1.0 на HAL2.0), так и за счет выделения отдельных разделов на flash-памяти для Silicon Manufacturer и Vendor (выше в карте разделов Android 9.0 можно увидеть разделы odm, vendor, product).

Переход с HAL1.0 на HAL2.0 заключается в отказе от прямого связывания с системными библиотеками. Вместо этого, используя IPC Binder, можно подключаться к системным сервисам.

И еще одно небольшое, но полезное изменение: начиная с Android 8.0, в update_engine добавлена поддержка потоковых обновлений по A/B-схеме, в ходе которых идет прямая запись в слот B без необходимости промежуточного хранения данных в /data. Для таких потоковых обновлений практически не требуется временное хранилище, достаточно всего лишь 100 килобайт для сохранения метаданных.

При этом необходимо, чтобы http-сервер, используемый для скачивания обновления, поддерживал HTTP range requests или другими словами докачку.

Проект Mainline

Следующим серьезным этапом в развитии системы обновления Android стал проект Mainline. Реализация этого проекта началась с Android 10.0 и продолжилась в текущем Android 11.0.

Проект Mainline позволяет обновлять отдельные системные компоненты без обновления ОС целиком. Нужные данные загружаются через Google Play отдельно от OTA-обновления прошивки от производителя. Предполагается, что прямая доставка обновлений, не привязанных к оборудованию частей Android, позволит существенно сократить время получения обновлений, увеличить оперативность исправления уязвимостей и снизить зависимость от производителей устройств в поддержке безопасности ОС.

Для реализации проекта Mainline выбранные компонентов системы Android преобразуется в модули. Часть этих модулей имеет старый формат APK, а часть конвертируется в новый APEX-формат, который отличается от APK возможностью применения на раннем этапе загрузки системы. На случай возможных сбоев предусмотрен режим отката изменений.

С APEX-пакетами работает системный сервис APEX manager (apexd). Это нативный сервис, который после проверки распаковывает APEX-пакет в пользовательское пространство на диске и добавляет запись о нем в свою базу данных. При следующей загрузке системы APEX manager проверяет все пакеты из базы данных, создает loop-устройство для ext4-образа каждого APEX-пакета и монтирует его по пути /apex/name@ver.

Модули с обновлениями изначально будут поставляться с открытым кодом, они будут сразу доступны в репозиториях AOSP (Android Open Source Project) и смогут включать улучшения и исправления, подготовленные сторонними участниками.

В рамках проекта Mainline в Android 10 было добавлено 13 обновляемых модулей, а в Android 11 в дополнение к уже существующим прибавилось еще 11 модулей.

Схема Virtual A/B

Также в Android 11 к схемам non-A/B и A/B была добавлена схема Virtual A/B. Этот новый механизм обновления сочетает преимущества обоих предшественников, он обеспечивает устойчивое к сбоям обновление устройства, задействуя при этом минимальный объем flash-памяти. Это стало возможным благодаря созданию снимков файловой системы (snapshot) с использованием технологии Device-mapper (подсистема ядра Linux, позволяющая создавать виртуальные блочные устройства) и Dynamic Partitions.

Dynamic Partitions это система организации динамических разделов для Android. С ее помощью можно создавать, изменять размер или уничтожать разделы прямо в процессе обновления по воздуху (OTA). При использовании динамических разделов разработчикам больше не нужно беспокоиться о размере отдельных разделов, таких как system, vendor и product. Вместо них на устройстве выделяется суперраздел, внутри которого можно динамически изменять размер подразделов. Больше нет необходимости оставлять свободное пространство для будущих OTA-обновлений внутри отдельных образов разделов. Оставшееся свободное место в суперразделе теперь доступно для всех динамических подразделов.

И в заключении последние слухи конца 2020 года вишенка на торте. Google конвертирует Android Runtime в модуль Mainline. Android Runtime или ART это среда выполнения Android-приложений, включающая компиляцию байт-кода приложения в машинные инструкции. Так что есть вероятность, что уже в Android 12 можно будет обновить ART через GooglePlay, установив APEX-пакет.

Также, вероятно, система обновления Android мигрирует в Fuchsia, новую ОС Google, которая сейчас находится в процессе разработки. Они традиционно копируют удачные решения в своих программных продуктах. Так, например, update_engine для A/B-схемы, который применяется сейчас в Android, используется в еще одной ОC Google Chrome OS. Или еще один пример: в Fuchsia предлагается библиотека Machina, которая позволяет запускать Linux-программы в специальной изолированной виртуальной машине по аналогии с тем, как организован запуск Linux-приложений в той же Chrome OS.

Желаем всем успешных обновлений!

P.S. Как там было в Индиане Джонсе?
Как вы меня узнали?
У вас глаза вашего отца.
И уши моей матери. Но все остальное принадлежит вам.

Подробнее..

О чем думает промдизайнер при разработке корпуса для электроники

06.11.2020 16:10:59 | Автор: admin

Делимся очередной порцией заметок из жизни промышленных дизайнеров и конструкторов, которые проектируют корпус для новых электронных устройств. Этим летом мы уже делали обзор всех этапов разработки от эскизов до запуска серийного производства. А в этот раз остановимся на типичных ошибках, тонкостях и примерах из практики, которые тогда остались за кадром.

Заметка 1. Делайте дизайн для пользователей, а не для себя

Прежде начать разбор технических аспектов в работе дизайнера важно понимать главное: проблемы большинства новых продуктов для рынка электроники связаны не с техническими ограничениями, а с недостаточным пониманием целевых клиентов и рынка.

На Хабре опубликованы сотни статей о разработке под клиента (Customer Development), проверке гипотез в поле и тестировании прототипов продукта, однако практика показывает, что часть команд все еще отталкивается от своих личных ощущений, а не потребностей целевой аудитории.

Если не забывать о том, что решение задач пользователя это основа любого дизайн-проекта, то технические ограничения не помешают вам добиться цели. Вы сможете с ними справиться. Вам помогут проблемные интервью, на которых вы узнаете о реальных, а не предполагаемых проблемах своих потребителей: дорого, устарело, неудобно, мало/много функций, быстро выходит из строя, неприветливый дизайн, раздражающие цвета, не работает при нужных условиях.

Заметка 2. Учитывайте класс защиты корпуса

При разработке корпуса нужно учитывать климатические условия и интенсивность использования устройства. В некоторых проектах нужно обеспечивать виброзащиту и противоударные свойства корпуса, на других будет достаточно стандартной пыле- и влагозащиты.

Один из важных факторов для промдизайнера IP (International Protection) или степень защиты от пыли и влаги. От этого показателя зависит не только материал, но и конструкция:

Возьмем IP68 и IP30: IP68 можно топить в воде, в нем не будет открытых разъемов; в в устройстве с А IP30 вообще не будет защиты от воды, даже от легких брызг.

Фото: Donald Trung Quoc Don (Ch Hn: ) - Wikimedia Commons - CC BY-SA 4.0 International. Фото: Donald Trung Quoc Don (Ch Hn: ) - Wikimedia Commons - CC BY-SA 4.0 International.

На фото слева телефон с классом защиты IP68, выдерживает свободное падение с высоты 1,8 метра. Справа типовая модель смартфона с защитой от пыли и легких брызг.

Заметка 3. Не забывайте об условиях эксплуатации при нанесении графики и выборе материалов

Еще один важный вопрос: устойчив ли материал к морозу или солнечным лучам? Не будет ли он осветляться? Так, при выборе наклейки для устройства важна не только графика, которую мы печатаем сверху, но также выбор материала наклейки и сам клей. Будет ли он держаться в той температуре, при которой используется устройство?

Простой пример для всех: клавиатура ноутбука. В старых бюджетных моделять спустя какое-то время буквы стирались, и на помощь приходили наклейки. В новых моделях используют более износостойкую краску и специальные защитные покрытия.

При выборе материала для кнопок нужно учесть температуру эксплуатации. Так, эластичные материалы крайне чувствительны к изменению температуры и резко теряют свою эластичность при отрицательных температурах.

Фото: 3D-модель и серийный образец корпуса глубинометраФото: 3D-модель и серийный образец корпуса глубинометра

На фото выше глубиномер для зимней рыбалки с эластичной кнопкой из материала TPU, легко нажимается на морозе.

Заметка 4. У серийного производства свои требования к форме и материалам корпуса

Бывает, заказчик приходит с готовым дизайном корпуса, который отлично смотрится на эскизах и 3D-моделях, но не годится для серийного производства по методу литья под давлением в пресс-форме. Мы уже подробно разбирали этот вопрос в статье про литьевые уклоны и другие тонкости работы с пластмассами.

Если корпус нетехнологичен, т.е. не адаптирован к требованиям производства, тогда дизайнер в паре с конструктором вынуждены предложить иную форму для отливки или найти иной метод изготовления корпуса.

Также у серийного производства свои требования к материалам. Хотя сегодня в ход могут пойти такие нестандартные материалы и технологии как кварцевое стекло, алюминий, древесина и даже обжиг керамики. Да-да, всё это можно использовать в производстве корпусов для электронных устройств. Один из кейсов о серийном производстве корпусов с применением металлов и древесины мы уже публиковали на Хабре, а со стеклом и алюминием мы экспериментировали при при производстве опытных образцов.

Фото: Qoobi Audio Innovations CompanyФото: Qoobi Audio Innovations Company

На фото беспроводной предусилитель на радиолампах, изготовлен из анодированного алюминия с ручной полировкой, внешняя форма это призма из тонкого кварцевого стекла.

Фото: прототипы части корпуса для вставки радиолампФото: прототипы части корпуса для вставки радиоламп

На фото выше предварительные заготовки из металла и пластика (3D-печать), на которых мы проверяли дизайн и конструкцию будущего устройства.

Заметка 5. Ощущения веса и поверхности корпуса нужно проверять на практике

Сам материал это только половина дела, потому что ощущения от материала определяются технологией его обработки. Например, на рельефных выступающих элементах корпуса не всегда возможно получить нужную шероховатость или глянец, и тогда приходится по согласованию с заказчиком менять саму форму, чтобы глянец получился качественный.

А в некоторых проектах глянец, к которому так стремились дизайнеры, может сыграть с ними злую шутку. Например, на устройстве, которое часто держат в руках: мобильные телефоны, ручка или дверца СВЧ, глянцевые кнопки на передней панели любых электронных устройств.

Фото: глянцевый корпус смартфона и матовый прототип рацииФото: глянцевый корпус смартфона и матовый прототип рации

Глянцевый корпус при постоянном контакте с пальцами будет выглядеть грязным, такое решение проигрывает моделям с матовыми покрытиями.

Заметка 6. Размер корпуса может измениться из-за печатной платы и теплового моделирования

Еще один интересный квест, с которым может столкнуться дизайнер при разработке нового устройства необходимость изменить габариты. Такое может случиться из-за теплового моделирования или анализа электромагнитной совместимости, когда компоненты на плате нужно расположить иначе (разнести подальше друг от друга). Плата становится больше и уже не влазит в исходный корпус. Бывают и обратные ситуации, когда при замене компонентов на более новые миниатюрные модели дизайнер может уменьшить всё устройство в целом.

Заметка 7. Себестоимость: крупнее серия дешевле продукт

На этапе эскизирования и моделирования можно предложить самые смелые решения различные материалы и формы, но по факту при расчете стоимости производства могут получиться неподъемные цены для заказчика, и, как следствие, для конечного потребителя. Тогда в ход идут различные методы удешевления. Например, замена металлических вставок на их имитацию металлизированный пластик. Или уход от компонентного литья (это дорого) и использование раздельного литься с последующей склейкой.

Еще один метод оптимизации бюджета на производство сокращение количество частей в корпусе. Чем меньше, тем дешевле.

Также экономить можно при увеличении серийности производства. Например, стоимость прототипов устройства может достигать нескольких тысяч долларов за штуку, а при крупносерийном производстве снизится до нескольких десятков долларов за единицу.

Заметка 8. Эргономика: форма и функция продукта должны соответствовать его целям

Перцентильная криваяПерцентильная кривая

При разработке серийного коммерческого продукта невозмозможно учесть абсолютно всех потенциальных пользователей. Нас людей много, и мы разные. В эргономике используется понятие перцентиля: производители ориентируются на среднее большинство, составляющее 90% популяции, а 5% в начале и в конце графика параметров отсекаются. Например, в магазине обуви редкие обладатели очень маленькой или очень большой стопы не смогут найти себе новую пару.

Тот же принцип действует и на рынке электроники. Руководства по эргономике мобильных устройств рассчитаны на правшей со средними размерами ладоней и пальцев:

UCLA Safety Department: Mobile & Tablet TipsUCLA Safety Department: Mobile & Tablet Tips

И в заключении скажем о функции продукта. Классический пример пульт дистанционного управления для ТВ, большая часть которого покрыта кнопками, которые никто не использует (и редко кто знает для чего они).

Старые модели пультов для ТВ и новая усовершенствованная версияСтарые модели пультов для ТВ и новая усовершенствованная версия

Цель дизайнера довести продукт до такого уровня, когда в нем нет ни одного лишнего элемента.

На сегодня на этом всё. Делитесь в комментариях собственными наблюдениями и фотографиями из сферы промдизайна и разработки конструкции. Будем вместе дополнять этот список заметок.

Подробнее..

Стоит ли инженерной команде с продуктовыми амбициями заниматься аутсорсингом?

25.02.2021 12:15:55 | Автор: admin
Делегируйте и доверяйте инженерам, не мешайте им творить!Делегируйте и доверяйте инженерам, не мешайте им творить!

Если бы я основатель дизайн-центра электроники Promwad начинал свой бизнес сейчас, то не выбрал бы аутсорсинговую бизнес-модель. Это не значит, что всем командам с продуктовыми амбициями нужно обходить ее стороной. Временная работа в таком формате может стать отличным инструментом для достижения своих целей. Важно только действовать осознанно и понимать, как это работает.

Когда я только начинал работать в отрасли электроники в начале 2000-х и мечтал создавать серийные устройства на острие технологий, то мог рассчитывать только на собственные ресурсы. Не было доступа к западным рынкам свободного капитала, менторов, хабов и акселераторов всего того, что сейчас формирует hardware-экосистему, да и доступ в интернет в те времена только недавно заработал без Dial-Up :-).

Самым логичным выходом из ситуации для меня было такое решение: разрабатывать и производить устройства на заказ, работая с клиентами, у которых был бюджет и конкретные требования к решению для целевого рынка. Так мои амбиции по созданию собственного продукта трансформировались в работу по сервисной модели вместе с инженерной командой Promwad. Хотя на самом старте мы создали аппаратную платформу на базе новейшего процессора по тем временам, но все равно это не было полноценным продуктом. Где-то в далеком видении я отмечал про себя, что когда мы научимся круто разрабатывать, а затем производить серийную электронику, можно будет использовать эти навыки для трансформации в продуктовую бизнес-модель. Но это оказалось не совсем так

Теперь, оглядываясь назад, я вижу весь наш маршрут и понимаю, на каком этапе можно было свернуть к своей исходной цели. Хочу поделиться этими выводами с теми, кто и сегодня сталкиваются с такими же препятствиями отсутствием стартовых инвестиций, команды, четкого понимания рынка и бизнес-навыков, но при этом горит желанием делать собственный продукт.

Конечно, есть бизнесмены, которые осознанно запускают аутсорсинговые компании: они с самого начала мыслят категориями роста и операционной эффективности, относительно быстро преодолевают планку в 200500 сотрудников и выходят на новые рынки. В этом состоит их цель и самореализация. Но есть и те, кого просто занесло в эту гавань в силу обстоятельств: обычно такие компании работают в составе 50200 сотрудников с несколькими миллионами оборота и годами остаются на этом плато.

На менторских сессиях я вижу, как молодые инженерные команды, которые искренне любят свое дело и хотят работать над собственным продуктом, вынуждены зарабатывать на работе по контракту. Они сомневаются, стоит ли им браться за заказные разработки, не станет ли это отказом от мечты. Но надо сделать свой выбор!

Этапы развития сервисной модели и точки для разворота

Если с самого начала рассматривать сервисную модель как стартовую точку своего бизнеса для получения первых денег, опыта в продажах, поиска идеи/рынка и возможности сработаться с командой, то можно смело становиться на эту ступеньку, удерживать в сознании первоначальную цель по созданию продукта и вовремя свернуть.

Так когда надо сворачивать?!

Первый этап, первые контракты на заказную разработку позволят получить базовые бизнес-навыки. В команде до 1020 человек можно обходиться ролями, не обязательно вводить должности и функции. Под ролью я подразумеваю общее направление работы, которое интересует человека и в котором он проявляет себя лучше других. Обычно складываются такие роли:

  • Предпринимательская: главный по продажам, главный конструктор/инженер/архитектор.

  • Административная роль: главный по проектам, главный по операционной работе.

  • Производственная (речь идет про производство сервисов в этом случае) роль: главный инженер и все инженеры-разработчики с конкретными специализациями, которые вносят в дело результат в виде готовой конструкторской документации и кода.

  • Интеграционная роль: главный менеджер проектов, который в растяжке бюджет/срок/требования добивается от команды результатов через интеграцию клиента и команды разработчиков.

То, что я имею в виду под ролями, очень похоже на то, о чем пишет в своих работах Ицхак Адизес. Вот его код PAEI: P производитель результатов, A администратор, E предприниматель, I интегратор.

Второй этап, по мере роста, условно с 20 до 50 сотрудников, в бизнес-модели аутсорсинга в команде появятся должности со своими четкими функциями генеральный директор, технический директор, менеджеры проектов, инженеры по специализациям и так далее. У ключевых людей в команде останутся роли, о которых я упомянул в описании первого этапа, но функции станут над ними превалировать. Если вы стали распределять функции значит вы дошли до той точки маршрута, после которой начинается системное строительство аутсорсинговой компании. Начнут формироваться бизнес-процессы.

На этом этапе гораздо сложнее повернуть к продуктовой модели, но все еще возможно.

На третьем этапе, когда команда растет выше условной планки 5060 сотрудников, роль жестких бизнес-процессов становится превалирующей, появляются функциональные отделы маркетинга и продаж, финансов, HR и др., они начинают обслуживать выстроенную вами именно аутсорсинговую бизнес-модель, а не какую-то иную.

На этом этапе свернуть обратно к продуктовой модели будет почти нереально без трансформации всего бизнеса.

Что делать?

В случае когда пройден третий этап, вместо разворота разумнее сохранить компанию в неизменном формате и сделать следующее:

  1. Передать управление и предпринимательскую роль кому-то из своих партнеров внутри и позволить им свободно принимать ключевые решения вместо вас.

  2. Очертить свою новую роль в компании. Например: я остаюсь в качестве владельца и обозначаю стратегический вектор развития компании.

  3. Переключиться на продуктовую модель в рамках новой компании, опираясь на весь свой накопленный опыт и хватать за хвост новые идеи. :-)

Но все равно вам придется начать этот бизнес с нуля, потому что придется собирать новую команду и преодолевать возникающие барьеры заново. Но дорогу осилит идущий!

Выводы: триггеры на пути к мечте и что дает аутсорсинг

Вернемся к тем, кто только стартовал, и для создания своего первого капитала и приобретения бизнес-опыта вступил на путь сервисной бизнес-модели. Итак, если вы только начинаете и готовы преодолевать препятствия на пути к своей продуктовой цели, то вполне можно посвятить 1-2-3 года работе по сервисной модели, но помнить о риске застрять в этой модели надолго и обращать внимание на важные триггеры, которые подскажут, что пора поворачивать к своей мечте:

  1. Собралась крепкая команда профессионалов из 1020 сотрудников с высоким уровнем доверия друг к другу. Соответственно, дальнейший рост в текущей бизнес-модели будет только усложнять разворот к продуктовой модели.

  2. Роли стали трансформироваться в функции и должности в компании это знак того, что нужно переключаться на продуктовую модель либо целенаправленно сохранять аутсорсинговую компанию.

  3. Третий триггер, наверное, самый главный удовольствие от своего дела. Если нет драйва и вы не видите смысла в росте и масштабировании, то есть риск остаться в нише середняков в аутсорсинговой модели в будущем.

А тем основателям и владельцам, у кого аутсорсинговая компания надолго застряла на плато в 50200 человек, пора задуматься: Своим ли делом вы занимаетесь?

Как видите, аутсорсинг это тоже по-своему отличная бизнес-модель. Кому-то она позволяет самореализоваться, построить глобальные компании с сотнями, тысячами и даже десятками тысяч сотрудников, достичь успехов в бизнесе. А для команд, которые мечтают о создании собственного продукта, на первом этапе она позволяет:

  • получить нужные компетенции, первый бизнес-опыт и знания об отрасли;

  • собрать и сработаться с командой;

  • развить свой нетворк сеть бизнес-контактов.

Выбор как всегда за нами! А вы в какой лиге сейчас? Давайте вместе решим, что делать дальше!

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru