Я проектирую конвейер для кодирования видеокадра из приложения opencv (полученного с веб-камеры) в формат video / x-h264, отправки его по сети и декодирования на другом устройстве другого типа (возможно, в raspberry pi) на правильный RGB поток для моего проекта.
Для этого я должен использовать Encoder и Decoder с аппаратным ускорением.
Поскольку весь сценарий огромен, текущая разработка выполняется на машине Intel с использованием плагинов VAAPI gstreamer (vaapiencode_h264 & vaapidecode). А также тот факт, что нам НЕ нужно использовать какие-либо сетевые плагины, такие как TCPServer или UDPServer.
Для этого я использовал приведенный ниже конвейер для своих целей:
На конце кодера:
appsrc name=applicationSource ! videoconvert ! video/x-raw, format=I420, width=640, height=480,framerate=30/1, pixel-aspect-ratio=1/1,interlace-mode=progressive ! vaapiencode_h264 bitrate=600 tune=high-compression ! h264parse config-interval=1 ! appsink name=applicationSink sync=false
Часть Appsrc работает отлично, в то время как часть appsink имеет некоторые проблемы с ней.
Часть appsink этого конвейера была установлена с помощью следующих заглавных букв:
«video / x-h264, format = (string) {avc, avc3, byte-stream}, выравнивание = (string) {au, nal}; video / mpeg, mpegversion = (int) 2, profile = (string) simple «
Код для извлечения данных моей appsink является
bool HWEncoder::grabData()
{
// initial checks..
if (!cameraPipeline)
{
GST_ERROR("ERROR AS TO NO PIPE FOUND ... Stopping FRAME GRAB HERE !! ");
return false;
}if (gst_app_sink_is_eos (GST_APP_SINK(applicationSink)))
{
GST_WARNING("APP SINK GAVE US AN EOS! BAILING OUT ");
return false;
}
if (sample)
{
cout << "sample available ... unrefing it ! "<< endl;
gst_sample_unref(sample);
}sample = gst_app_sink_pull_sample (GST_APP_SINK(applicationSink));
if (!sample)
{
GST_WARNING("No valid sample");
return false; // no valid sample pulled !
}
sink_buffer = gst_sample_get_buffer(sample);
if (!sink_buffer)
{
GST_ERROR("No Valid Buffer ");return false;
}
return true;
}
После запуска конвейера и проверки заполнения буфера в моем appinkink я застрял в указанных ниже строках моего кода на неопределенное время:
sample = gst_app_sink_pull_sample (GST_APP_SINK(applicationSink));
У меня есть следующие вопросы:
1) Правильны ли мои шапки для appsink? Если нет, как я могу определить колпачки для них?
2) Что-то не так в моем конвейере выше?
Как я могу исправить эту проблему с Appsink ??
Любая помощь будет полезна!
Спасибо !!
Просто предположение (у меня были похожие проблемы) проблема, связанная с наличием appsink и appsrc в одном конвейере, может заключаться в том, что когда вы заполняете / опускаете одно из них, оно блокирует другое (подробнее об этом ниже).
appsink и appsrc блокируются, когда они заполнены / пусты — это нормальное желаемое поведение. Есть вариант drop
для appsink или для appsrc есть опция block
— но с их помощью это может быть просто обходной путь, и вы получите глюки в своем потоке. Правильное решение заключается в улучшении синхронизации между appsrc и appsink.
Вы можете реагировать на сигналы приложения enough-data
а также need-data
— это наш путь. Также мы поиграли со свойствами appsrc: is-live
, do-timestamp
и размер буфера (это может или не может помочь вам):
g_object_set(src->appsrc,
"stream-type", GST_APP_STREAM_TYPE_STREAM,
"format", GST_FORMAT_TIME,
"do-timestamp", TRUE,
"is-live", TRUE,
"block", TRUE,
NULL);
Почему они блокируют друг друга?
Потому что (я думаю) вы обрабатываете appsink и одновременно appsrc в главном потоке приложений. Когда один из appsink / appsrc блокирует поток, нет никого, кто мог бы обработать обработку для другого. Поэтому, когда appsink заблокирован из-за отсутствия данных, нет никого, кто мог бы снабдить appsrc новыми данными — таким образом, бесконечный тупик.
Мы также внедрили ноблочную версию метода appsink * pull_sample, но это был просто обходной путь, который привел к большему количеству проблем, чем к решениям.
Если вы хотите отладить происходящее, вы можете добавить запись GST_DEBUG для appsrc / appsink (я не помню, что это было), вы можете добавить обратный вызов для упомянутых enough-data
а также need-data
или вы можете добавить очереди и включить GST_DEBUG = queue_dataflow: 5, чтобы увидеть, какая очередь заполняется первой и т. д., это всегда полезно при отладке «тупика данных».
Других решений пока нет …