Ник:
Пароль:

Контакты

E-mail: info@starterkit.ru
тел.: +7 922 680-21-73
тел.: +7 922 680-21-74
Телеграм: t.me/starterkit_ru

Способы оплаты

User Info


Добро пожаловать,
Guest

Регистрация или входРегистрация или вход
Потеряли пароль?Потеряли пароль?

Ник:
Пароль:

ПользователейПользователей:3
Поисковых ботовПоисковых ботов:3
ГостейГостей:1

ОбновитьПодробнееВсегоВсего:7
Форум » starterkit.ru » Embedded Linux
Работа с кодеками IMX-GPU
geostart
Добавлено 13.11.2024 14:12
5
Сообщение: 1
geostart
0

Пункты: 180
Регистрация: 05.11.2024
Здравствуйте! Ипользую Вашу платформу
http://starterkit.ru/html/index.php?name=shop&op=view&id=97

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

Использовал как базу образ, найденный у Вас на форуме. ССылка ниже:
http://starterkit.ru/html/index.php?name=forum&op=view&id=29909

В сборке я использую gstreamer1,
ниже приведены установленные пакеты.
\\\\\\\\\\\\\\\\\\\\\\\
--- gst1-imx
[ ] imxeglvivsink
[*] imxg2d
[*] imxipu
[ ] mp3encoder
[ ] imxpxp
[*] uniaudiodec
[*] imxvpu
[*] imxv4l2videosrc
[*] imxv4l2videosink
\\\\\\\\\\\\\\\\\\\\\\\\\\

...............................................................................
[ ] gmrender-resurrect
[ ] gstreamer 0.10
[*] gstreamer 1.x
[*] enable command-line parser
[*] enable tracing subsystem
[*] enable gst-debug trace support
[*] enable plugin registry
[*] install gst-launch & gst-inspect
[ ] gstreamer1-mm
-*- gst1-plugins-base --->
[*] gst1-plugins-good --->
-*- gst1-plugins-bad --->
[*] gst1-plugins-ugly --->
[*] gst1-imx --->
[ ] gst1-interpipe
[*] gst1-libav
[ ] gst1-rtsp-server
[ ] gst1-shark
*** gst1-validate depends on python ***
[ ] gst1-vaapi
*** gst-omx requires a OpenMAX implementation ***
[ ] gstreamer1-editing-services
......................................................................................

Мне необходимо производить конверсию кадров, я хочу произвести это с максимальной скоростью.
Вот ссылка , на gstreamer
https://github.com/Freescale/gstreamer-imx?tab=readme-ov-file

Я написал класс, для обработки кадров, которые передаются через QByteArray (у меня проприетарный протокол, кадры в h264), на gstreamer. Могу предоставить класс который делает эту конверсию. Проблемма в том , что кадры не всегда обрабатываются гстримером (какое-то время в стриме пишет что проблемма в nal заголовке, потом какое-то время - что во временной метке). Эта же функциональность на компьютере работает.

Так же в сборке не нашел
libimxdmabuffer - необходимый для imx плагинов.

Есть еще вариант без использования gstreamer, c прямым использованием libimxdmabuffer и libimxvpuapi.
Но я не нашел примеров использования в интеренете, прошу подсказать где можно посмотреть, или предоставить пример.

Класс для обработки кадров:
---------------------------------------------------------------------
#pragma once

#include <QObject>
#include <QImage>
#include <QByteArray>
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/app/gstappsink.h>
#include <memory>

class H264FrameDecoder : public QObject
{
Q_OBJECT

public:
H264FrameDecoder(QObject *parent = nullptr);
~H264FrameDecoder();

public slots:
void processFrame(const QByteArray &frame, int width, int height, int isIFrame);
void emitFrameProcessed();

signals:
void frameProcessed(const QImage &image);

private:
GstElement *pipeline;
GstElement *appsrc;
GstElement *h264parse;
GstElement *decoder;
GstElement *conv;
GstElement *sink;
GstBus *bus;
GstMessage *msg;
GstStateChangeReturn ret;
QImage m_rgbImage;
std::unique_ptr<uint8_t[]> m_rgb32Data = NULL;
bool initialized;

void initializeGStreamer();
void cleanupGStreamer();

static GstFlowReturn onNewSample(GstAppSink *sink, gpointer user_data);
void i420ToRgb32(const uint8_t *yuvData, int width, int height);
void NV12toRgb32(const uint8_t* nv12Data, int width, int height);
};

-----------------------------------------------------------------------------
#include "H264FrameDecoder.h"
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/app/gstappsink.h>
#include <libyuv.h>
#include <memory>
#include <QDebug>
#include <QCoreApplication>
#include <QProcessEnvironment>

H264FrameDecoder::H264FrameDecoder(QObject *parent)
: QObject(parent), initialized(false) {
initializeGStreamer();
}

H264FrameDecoder::~H264FrameDecoder() {
cleanupGStreamer();
}

void H264FrameDecoder::initializeGStreamer() {
gst_init(nullptr, nullptr);
pipeline = gst_pipeline_new("video-pipeline");
appsrc = gst_element_factory_make("appsrc", "source");
h264parse = gst_element_factory_make("h264parse", "h264-parser");
#ifdef IS_IMX6
decoder = gst_element_factory_make("imxvpudec", "decoder");
conv = gst_element_factory_make("imxg2dvideotransform", "converter");
sink = gst_element_factory_make("imxg2dvideosink", "sink");
#else
decoder = gst_element_factory_make("avdec_h264", "decoder");
conv = gst_element_factory_make("videoconvert", "converter");
sink = gst_element_factory_make("appsink", "sink");
#endif

if (!pipeline || !appsrc || !h264parse || !decoder || !conv || !sink) {
qWarning() << "Not all elements could be created.";
return;
}

gst_bin_add_many(GST_BIN(pipeline), appsrc, h264parse, decoder, conv, sink, nullptr);
if (!gst_element_link_many(appsrc, h264parse, decoder, conv, sink, nullptr)) {
qWarning() << "Elements could not be linked.";
gst_object_unref(pipeline);
return;
}

GstCaps *caps = gst_caps_new_simple("video/x-h264", "stream-format", G_TYPE_STRING, "byte-stream", nullptr);
g_object_set(G_OBJECT(appsrc), "caps", caps, nullptr);
gst_caps_unref(caps);

g_object_set(G_OBJECT(sink), "emit-signals", TRUE, "sync", FALSE, nullptr);
g_object_set(G_OBJECT(sink), "max-buffers", 20, nullptr); // Set max-buffers property
g_signal_connect(sink, "new-sample", G_CALLBACK(onNewSample), this);

ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);
if (ret == GST_STATE_CHANGE_FAILURE) {
qWarning() << "Unable to set the pipeline to the playing state.";
gst_object_unref(pipeline);
return;
}

initialized = true;
}

void H264FrameDecoder::cleanupGStreamer() {
if (initialized) {
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);
}
}

void H264FrameDecoder::processFrame(const QByteArray &frame, int width, int height, int frameRate) {
if (!initialized) {
qWarning() << "GStreamer not initialized.";
return;
}

// Set the caps on the appsrc element to specify the width and height
GstCaps *caps = gst_caps_new_simple("video/x-h264",
"width", G_TYPE_INT, width,
"height", G_TYPE_INT, height,
"framerate", GST_TYPE_FRACTION, frameRate, 1,
"stream-format", G_TYPE_STRING, "byte-stream",
nullptr);

g_object_set(G_OBJECT(appsrc), "caps", caps, nullptr);
gst_caps_unref(caps);

// Create a buffer from the frame data
GstBuffer *buffer = gst_buffer_new_and_alloc(frame.size());
GstMapInfo map;
gst_buffer_map(buffer, &map, GST_MAP_WRITE);
memcpy(map.data, frame.constData(), frame.size());
gst_buffer_unmap(buffer, &map);


// Set buffer timestamp and duration
GstClockTime timestamp = gst_util_get_timestamp();
GstClockTime duration = gst_util_uint64_scale_int(1, GST_SECOND, frameRate);
GST_BUFFER_PTS(buffer) = timestamp;
GST_BUFFER_DTS(buffer) = timestamp;
GST_BUFFER_DURATION(buffer) = duration;

// Push the buffer into the pipeline
GstFlowReturn ret;
g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
gst_buffer_unref(buffer);

if (ret != GST_FLOW_OK) {
qWarning() << "Error pushing buffer to GStreamer pipeline.";
}

// Check the pipeline state
/* It have a side effect - stopping running program process in this function */
#if 0
GstState state;
gst_element_get_state(pipeline, &state, nullptr, GST_CLOCK_TIME_NONE);
qDebug() << "Pipeline state:" << state;
#endif
}

void H264FrameDecoder::emitFrameProcessed()
{
emit frameProcessed(m_rgbImage);
}

GstFlowReturn H264FrameDecoder::onNewSample(GstAppSink *sink, gpointer user_data) {
GstSample *sample;
GstBuffer *buffer;
GstMapInfo map;

sample = gst_app_sink_pull_sample(sink);
buffer = gst_sample_get_buffer(sample);
gst_buffer_map(buffer, &map, GST_MAP_READ);

GstCaps *caps = gst_sample_get_caps(sample);
GstStructure *structure = gst_caps_get_structure(caps, 0);
int width, height;
gst_structure_get_int(structure, "width", &width);
gst_structure_get_int(structure, "height", &height);

H264FrameDecoder *processor = static_cast<H264FrameDecoder *>(user_data);

// Ensure the image format is correct
const gchar *format = gst_structure_get_string(structure, "format");
if (format && strcmp(format, "I420") == 0) {
processor->i420ToRgb32(map.data, width, height);
} else if (format && strcmp(format, "NV12") == 0){
processor->NV12toRgb32(map.data, width, height);
} else {
qWarning() << "Unsupported pixel format:" << format;
}

processor->emitFrameProcessed();
gst_buffer_unmap(buffer, &map);
gst_sample_unref(sample);

return GST_FLOW_OK;
}

void H264FrameDecoder::i420ToRgb32(const uint8_t *yuvData, int width, int height) {
// Calculate the sizes of the Y, U, and V planes
int ySize = width * height;
int uvSize = (width * height) / 4;

// Extract the Y, U, and V planes from the I420 data
const uint8_t *yPlane = yuvData;
const uint8_t *uPlane = yuvData + ySize;
const uint8_t *vPlane = yuvData + ySize + uvSize;

// Allocate memory for the RGB32 data
if (!m_rgb32Data.get())
m_rgb32Data = std::make_unique<uint8_t[]>(width * height * 4);

// Convert I420 to ARGB using libyuv
libyuv::I420ToARGB(yPlane, width,
uPlane, width / 2,
vPlane, width / 2,
m_rgb32Data.get(), width * 4,
width, height);

QImage tmpImg(m_rgb32Data.get(), width, height, QImage::Format_RGB32);
// Create a QImage from the RGB32 data
m_rgbImage.swap(tmpImg);
}

void H264FrameDecoder::NV12toRgb32(const uint8_t *nv12Data, int width, int height) {
int ySize = width * height;
int uvSize = (width * height) / 2;

// Extract the Y and UV planes from the NV12 data
const uint8_t* yPlane = nv12Data;
const uint8_t* uvPlane = nv12Data + ySize;

// Allocate memory for the RGB data if not already allocated
if (!m_rgb32Data) {
m_rgb32Data = std::make_unique<uint8_t[]>(width * height * 4); // ARGB format requires 4 bytes per pixel
}

// Convert NV12 to ARGB using libyuv
libyuv::NV12ToARGB(yPlane, width,
uvPlane, width,
m_rgb32Data.get(), width * 4, // ARGB format requires 4 bytes per pixel
width, height);

// Create a QImage from the ARGB data
QImage rgbImage(m_rgb32Data.get(), width, height, QImage::Format_ARGB32);

// Ensure the QImage does not take ownership of the raw data pointer
// Create a deep copy of the QImage to ensure the data is not deleted prematurely
m_rgbImage = rgbImage.copy();
}
----------------------------------------------------------------------------

Прошу подсказать, что я делаю неправильно.
Спуститься к концу Подняться к началу
Персональная информация
sasamy
Добавлено 13.11.2024 16:29 Редактировалось 13.11.2024 16:33 Сообщение: 2
sasamy
4.71

Пункты: 83777
Регистрация: 14.08.2009
Цитата

Есть еще вариант без использования gstreamer, c прямым использованием libimxdmabuffer и libimxvpuapi.
Но я не нашел примеров использования в интеренете, прошу подсказать где можно посмотреть, или предоставить пример.


примеры прямо в библиотеке есть

https://github.com/Freescale/libimxvpuapi/tree/master/example

и есть поновей версия buildroot

http://starterkit.ru/html/index.php?name=forum&op=view&id=31011
Спуститься к концу Подняться к началу
Персональная информация
geostart
Добавлено 14.11.2024 02:18 Сообщение: 3
geostart
0

Пункты: 180
Регистрация: 05.11.2024
Благодарю, но прошу также уточнить, как в сборку добавить libimxdmabuffer. И привести пример пайпа на гстример, который работал бы спотоковым видео через vpu, у меня есть mp4 файл, чтобы можно было програмным способом проверить работу vpu через гстример. На gstreamer, доков и примеров поболее для простоты програмной реализации.
Спуститься к концу Подняться к началу
Персональная информация
geostart
Добавлено 14.11.2024 02:55 Сообщение: 4
geostart
0

Пункты: 180
Регистрация: 05.11.2024
[quote]Благодарю, но прошу также уточнить, как в сборку добавить libimxdmabuffer. И привести пример пайпа на гстример, который работал бы спотоковым видео через vpu, у меня есть mp4 файл, чтобы можно было програмным способом проверить работу vpu через гстример. На gstreamer, доков и примеров поболее для простоты програмной реализации.[/quote
И касательно билдрута, у меня с нандом контроллер, подскажите что нужно добавить, чтобы сборка на новом билдруте прошла? И контреллер загружался с нанда
Спуститься к концу Подняться к началу
Персональная информация
sasamy
Добавлено 14.11.2024 11:26 Сообщение: 5
sasamy
4.71

Пункты: 83777
Регистрация: 14.08.2009
Цитата
[quote]Благодарю, но прошу также уточнить, как в сборку добавить libimxdmabuffer.


есть две версии библиотеки
libimxvpuapi, в штатных конфигах используется певая версия (v1), если нужна вторая, то её можно включить тут

-> Target packages
-> Hardware handling
-> Freescale i.MX libraries (BR2_PACKAGE_FREESCALE_IMX [=y])
[*] libimxvpuapi-v2

libimxdmabuffer используется во второй версии находится в том же меню и выбудет выбран автоматом

Цитата

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


скрипты с примерами после сборки есть в /root, отличия второй и первой описаны на гитхабе проекта

https://github.com/Freescale/libimxvpuapi

в конфиге с qt собирается пакет qtmultimedia, пример с qml

/usr/lib/qt/examples/multimedia/video/qmlvideo/qmlvideo
Спуститься к концу Подняться к началу
Персональная информация
geostart
Добавлено 16.11.2024 04:04 Сообщение: 6
geostart
0

Пункты: 180
Регистрация: 05.11.2024
Здравствуйте! Вы предоставили новую версию билдрут, там можно собрать сборочку по максимуму, но я хотел бы уточнить. Пропадчили ли вы его для nand памяти, у меня nand контроллер было бы чудно, если бы подсказали, как это сделать.

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

И какие плагини с библиотеками нужно включить, чтобы можно было быть уверенным, что vpu включен на процессоре, и гстример его корректно цепляет.

Вторая часть вопроса,
Не удается натсроит удаленную отладку через gdb-server, на платформе. Коннект я проверил, через qt-creator, удаленные процуссы он мне вывел, а вот ходит внутри по коду не получается.
Спуститься к концу Подняться к началу
Персональная информация
sasamy
Добавлено 16.11.2024 12:12 Сообщение: 7
sasamy
4.71

Пункты: 83777
Регистрация: 14.08.2009
Цитата
у меня nand контроллер было бы чудно, если бы подсказали, как это сделать.


упустил это из вида, нет - последняя публичная версия не работает с nand и планов сделать это нет
Спуститься к концу Подняться к началу
Персональная информация
geostart
Добавлено 17.11.2024 21:17 Редактировалось 17.11.2024 21:19 Сообщение: 8
geostart
0

Пункты: 180
Регистрация: 05.11.2024
Подскажите, а есть ли версия buildroot-2019.02-sk, но которая собирался бы из коробки с конфигурацией imxx6sk_qt5gst_defconfig, а то проблеммы с отладкой через gdbserver, все настроено, а он не подключается. P.S. если поставить libimxvpuapi-v2, не будет ли она конфликтовать с уже выставленной? Собираюсь под убунтой 22.04
Спуститься к концу Подняться к началу
Персональная информация
geostart
Добавлено 17.11.2024 21:45 Редактировалось 17.11.2024 21:46 Сообщение: 9
geostart
0

Пункты: 180
Регистрация: 05.11.2024
Цитата
Подскажите, а есть ли версия buildroot-2019.02-sk, но которая собирался бы из коробки с конфигурацией imxx6sk_qt5gst_defconfig, а то проблеммы с отладкой через gdbserver, все настроено, а он не подключается. P.S. если поставить libimxvpuapi-v2, не будет ли она конфликтовать с уже выставленной? Собираюсь под убунтой 22.04


Так же в версии buildroot-2019.02-sk, отсутвует вторая версия библиотеки и буффер кадров для нее.
--- Freescale i.MX libraries
i.MX platform (imx6q/imx6dl) --->
[*] imx-alsa-plugins
[*] imx-codec
[*] imx-kobs
[*] imx-lib
[ ] imx-m4fwloader
[*] imx-parser
[ ] imx-uuc
[*] imx-vpu
*** imx-vpu-hantro needs an i.MX platform with Hantro VPU ***
[ ] imx-vpuwrap
-*- firmware-imx
[ ] gst-variable-rtsp-server
[*] imx-gpu-g2d
[*] install examples
-*- imx-gpu-viv
Output option (Framebuffer) --->
[*] install examples
[ ] install gmem_info tool
[*] kernel-module-imx-gpu-viv

Предоставьте пжлст патч на включение второй версии библиотеки с буффером.
Так же хочу у Вас удостоверится, у меня плата SK-iMX6S-OEM,
а выбрана секция (imx6q/imx6dl), корректно ли это?
Спуститься к концу Подняться к началу
Персональная информация
Форум » starterkit.ru » Embedded Linux