Disable Weston video playback offset
現在目標與狀況
- Disable Weston video playback
- User hardware decode
- Enable Weston video playback normally
- Disable Weston video playback offset
目標
遇到狀況
gst-launch-1.0 filesrc location=/home/root/demo.mp4 ! \ qtdemux name=d d.video_0 ! queue ! h264parse ! vpudec ! \ queue ! waylandsink
gst-launch-1.0 -v \ filesrc location=/home/root/demo.mp4 ! \ qtdemux name=d d.video_0 ! queue ! h264parse ! \ vpudec ! glimagesink
驗證分析
- 同一支影片、同一個 decoder,在不同video sink,行為不同
- 更換video sink
- glimagesink: 是 OpenGL 視窗/GL render 路徑
- kmssink: 是直接走 DRM/KMS plane 的路徑
- 如果要避開 Weston,又想低 CPU,應該要是decoder → KMS plane
- 簡單測試kmssink
- 用 modetest 去看DRM支援什麼
- 不使用vpudec,指定輸出格式丟到kmssink
- 使用gdb debug
- 確認是strcmp()問題,回到gstreamer1.0-plugins source找尋strcmp()
- 確認是strcmp()問題,回到gstreamer1.0-plugins source找尋strcmp()
- 依造上述 (gdb) info registers 和 (gdb) (gdb) x/16i $pc 的內容
- 所以結合source找尋strcmp() 的結果,像問題點只有
- 查 get_imx_drm_device_name() 的實作
- i.MX 8M Mini Applications Processor Reference Manual
gst-launch-1.0 -v videotestsrc ! kmssink
# 發現顯示 Caught SIGSEGV,所以kmssink有bug
modetest -M imx-drm
# formats: XR24 AR24 RG16 XB24 AB24 RX24 RA24 AR15 XR15 AB15 XB15 BG16
# 沒有 NV12 / NV16
# vpudec 解碼輸出影像格式是 NV12,DRM plane不支援顯示 NV12
videotestsrc ! videoconvert ! video/x-raw,format=BGRx,width=1280,height=800 ! kmssink
# 還是crash
gdb --args gst-launch-1.0 --gst-disable-segtrap -v \ videotestsrc ! videoconvert ! \ video/x-raw,format=BGRx,width=1280,height=800 ! \ kmssink driver-name=imx-drm plane-id=29 # --args : 後續為GStreamer指令 # --gst-disable-segtrap : GStreamer 不攔截 SIGSEGV
(gdb) handle SIGSEGV stop print nopass
# stop:當GStreamer收到 SIGSEGV 時停止執行
# print:收到 SIGSEGV 時 GDB 會打印信號信息
# nopass:GStreamer不會自行處理或崩潰,由 GDB 接管
(gdb) run # 正式啟動GStreamer #其中發現 Thread 2 "videotestsrc0:s" received signal SIGSEGV, Segmentation fault. [Switching to Thread 0xffffbeed91f0 (LWP 4051)] strcmp () at ../sysdeps/aarch64/strcmp.S:64 (gdb) bt #0 strcmp () at ../sysdeps/aarch64/strcmp.S:64 #1 0x0000ffffbef8117c in ?? () from /usr/lib/gstreamer-1.0/libgstkms.so #2 0x0000000000652df0 in ?? () #3 0x657361625f747367 in ?? () # 表示libgstkms.so 裡某個函式呼叫 strcmp() 時出了問題
(gdb) thread apply all bt
# 檢視其他thread是否有問題
# 顯示 :
Thread 2
停在strcmp() → 這就是出事的 thread
Thread 1 / Thread 3
在等待
grep -R "strcmp *(" -n sys/kms
sys/kms/gstkmssink.c:496: if (strcmp (get_imx_drm_device_name(), "DPU") == 0) {
sys/kms/gstkmssink.c:747: if (!strcmp (property->name, prop_name)) {
sys/kms/gstkmssink.c:1446: if (!strcmp(prop->name, "dtrc_table_ofs")) {
sys/kms/gstkmssink.c:1670: if (!strcmp(prop->name, "dtrc_table_ofs") && dtrc_table_ofs) {
sys/kms/gstkmssink.c:1696: if (!strcmp(prop->name, "alpha")) {
sys/kms/gstkmssink.c:1948: if (!strcmp(prop->name, "HDR_SOURCE_METADATA")) {
sys/kms/gstkmssink.c:2020: if (strcmp (get_imx_drm_device_name(), "DPU") == 0) {
grep -R "strcmp *(" -n sys/kms
sys/kms/gstkmssink.c:496: if (strcmp (get_imx_drm_device_name(), "DPU") == 0) {
sys/kms/gstkmssink.c:747: if (!strcmp (property->name, prop_name)) {
sys/kms/gstkmssink.c:1446: if (!strcmp(prop->name, "dtrc_table_ofs")) {
sys/kms/gstkmssink.c:1670: if (!strcmp(prop->name, "dtrc_table_ofs") && dtrc_table_ofs) {
sys/kms/gstkmssink.c:1696: if (!strcmp(prop->name, "alpha")) {
sys/kms/gstkmssink.c:1948: if (!strcmp(prop->name, "HDR_SOURCE_METADATA")) {
sys/kms/gstkmssink.c:2020: if (strcmp (get_imx_drm_device_name(), "DPU") == 0) {
(gdb) info registers # 顯示目前 CPU register的內容 x0 0xdf8475800 60000000000 x1 0xffffbef86390 281473885692816 x2 0xffffb8000080 281473768751232 x3 0xffffb80008d0 281473768753360 ... ... ...
(gdb) x/16i $pc # 反組譯(disassemble)目前程式執行machine Code 0xffffbf326d18 <strcmp+24>: ldr x2, [x0], #8 0xffffbf326d1c <strcmp+28>: ldr x3, [x1], #8 ... ... ...
strcmp(a, b); x0 = a x1 = b call strcmp 所以實際上執行strcmp(x0, x1) x0 = 0xdf8475800 (60000000000) 看起來很不像合法字串位址
sys/kms/gstkmssink.c:496: if (strcmp (get_imx_drm_device_name(), "DPU") == 0) {
sys/kms/gstkmssink.c:2020: if (strcmp (get_imx_drm_device_name(), "DPU") == 0) {
get_imx_drm_device_name (void){
const gchar * device;
...
if (strstr (entry->d_name, "dpu@")) {
device = "DPU";
break;
}
if (strstr (entry->d_name, "dcss@")) {
device = "DCSS";
break;
}
...
return device;
}
1.4.11 Display Interfaces
-
The chip has the following display support:
-
• LCDIF Display Controller:
• Supports one layer
• Supports up to 1920x1200p60 display through MIPI DSI
• MIPI Interface:
• 4-lane MIPI CSI interface
• 4-lane MIPI DSI interface
• CSI Interface:
• CSI is a simple camera interface which is used to capture the MIPI CSI input and
-
save the pixels into memory
解決方式
- 修正初始化
- 補上LCDIF
- 避免 crash
const gchar * device = NULL;
找得到 dpu@ → 回 "DPU"
找得到 dcss@ → 回 "DCSS"
找不到 → 回 NULL
讓程式變成一個可被程式判斷和處理狀態
if (strstr (entry->d_name, "dpu@")) {
device = "DPU";
break;
}
if (strstr (entry->d_name, "dcss@")) {
device = "DCSS";
break;
}
if (strstr (entry->d_name, "lcdif@")) {
device = "LCDIF";
break;
}
g_strcmp0(get_imx_drm_device_name(), "DPU") == 0 g_strcmp0(a, b) 和 strcmp(a, b) 類似,但差別在: 它允許 a 或 b 是NULL 不會因為NULL直接crash只會回傳「不相等」
留言
張貼留言