页次: 1
基本思路:
DLNA客户端可以接收并播放以DLNA协议推送的流媒体
而B站可以将视频通过DLNA协议推送
所以我们给哪吒D1配置DLNA客户端 就可以实现在同一网络下B站投屏了
gmrender-resurrect是一个接收DLNA内容并用gstreamer播放的组件
我们用gmrender-resurrect就可以配置出一个DLNA客户端
我们已经实现了使用gstreamer1.0调用openmax硬解H264
B站通过DLNA投屏时会发送flv封装的H264流 类似于直播
也就是说 我们可以用gstreamer硬解B站投屏视频
但是在实践中发现gstreamer硬解B站投屏会出现闪屏现象 并且不能自动硬件缩放
为了避免这些问题 我查找了gmrender-resurrect和tplayer相关资料 将gmrender-resurrect进行了魔改 将原来gstreamer播放视频改成了tina自带的王牌播放器tplayer来播放视频 于是gmrender-resurrect便成了tprender
因为package里没有相关库 所以要手动交叉编译出tprender和DLNA的底层upnp库 附件里提供了编译完成的
演示环境搭建
用PhoenixSuit.exe烧录flash镜像
附件提供了配置好的flash镜像
进入d1系统 先配个wifi 我的是wifi是qwer 密码是1231232008 把wifi名和密码换成你的
wifi_connect_ap_test qwer 1231232008
注意要看一下ifconfig wlan0有没ip4地址 如果没有用下面命令获取一下
udhcpc -i wlan0
第一次运行wifi_connect_ap_test 会自动获取ip4地址 但是下次开机会自动连接wifi 但不会自动获取ip4地址 所以要检查一下
附件中提供了tprender_app 里面是编译好的tprender和upnp库
用adb把tprender_app发送到D1
adb push d:tprender_app /root/
进入目录
cd /root/tprender_app
把里面的库复制到系统路径
cp libs/* /usr/lib/
添加tprender执行权限
chmod +x tprender
开启DLNA客户端
./tprender -f "D1"
接下来可以用B站投屏了
操作提示
B站放视频时右上角有个TV图标 点它 再点投屏设备 就行了
B站更新到新版本才有投屏分辨率选择
演示视频
动画
1080P
验证平台
硬件 哪吒D1开发板
系统 tina1.01 带0730补丁
配置过程
因为tplayer是tina自带的 而tprender 和upnp在package要交叉编译
所以不需要配置sdk
tprender编译
附件中提供了魔改好的tprender源码 使用cmake构建工程 只需在源码目录的CMakeLists.txt里修改编译器、链接库、头文件的路径 然后再执行构建(注意 有个点)
cmake .
再执行编译
make
即可以编译出tprender
upnp编译
附件中提供了upnp源码 按照里面README.md编译出libupnp.so和libixml.so库即可
逸俊晨晖 说:memory 说:你开幻灯片演示自动滑动试试
请教这个怎么开呢?
lv_ex_conf.h
#define LV_DEMO_WIDGETS_SLIDESHOW 1
你开幻灯片演示自动滑动试试
请问打0730补丁具体如何操作呢?
0730补丁下载
https://bbs.aw-ol.com/assets/uploads/files/1629346267638-d1_open_tina_multimedia_update_0730.tar.gz
0730打补丁具体操作
这里采用直接替换的方法 .patch文件不用管它
1.
把D1_open_tina_multimedia_update_0730/dl里面的文件复制到dl
2.
把D1_open_tina_multimedia_update_0730/libs里面的文件复制到package/libs
3.
删除package/allwinner/tina_multimedia里面所有文件
把D1_open_tina_multimedia_update_0730/tina_multimedia里面的文件复制到package/allwinner/tina_multimedia
4.
删除package/multimedia里面所有文件
把D1_open_tina_multimedia_update_0730/multimedia里面的文件复制到package/multimedia
gst-launch-1.0 filesrc location=bad_apple.mp4 ! qtdemux ! h264parse ! omxh264dec ! sunxifbsink
这个参数里面,叹号是管道的意思吗?
感叹号是连接元件的意思
管道是将所有元件连接起来 形成的传输通道
gstreamer设计是借鉴了电工电路组成的思想
一个好的gstreamer学习的博客:
https://www.cnblogs.com/xleng/p/10948838.html
D1的tina系统支持了libcedar的openmax接口 使得gstreamer可以用gst-omx插件调用libcedar进行视频硬解码
再加上tina支持了gst-aw插件 提供了gst的一个元件sunxifbsink 就是一个可以进行硬件转换YV12->RGB的硬件图层插件 即DE的应用
这样一来 D1使用gst进行播放视频 效果会非常流畅
演示环境搭建
用PhoenixSuit.exe烧录flash镜像
附件提供了flash镜像
把视频文件用adb发送到D1 附件中提供了测试视频文件
adb push D:\bad_apple.mp4 /root/
使用playbin元件自动寻找元件播放音视频
gst-launch-1.0 playbin uri=file:///root/bad_apple.mp4
因为加了一些同类的元件 为了调试方便 再写几条用来测试的命令
使用decodebin元件自动寻找解码器 指定fb元件播放视频
gst-launch-1.0 filesrc location=bad_apple.mp4 ! qtdemux ! decodebin ! sunxifbsink
指定硬解码器 指定fb元件播放视频
gst-launch-1.0 filesrc location=bad_apple.mp4 ! qtdemux ! h264parse ! omxh264dec ! sunxifbsink
指定元件播放音视频
gst-launch-1.0 filesrc location=bad_apple.mp4 ! qtdemux name=demux demux.audio_0 ! queue ! decodebin ! audioconvert ! audioresample ! alsasink demux.video_0 ! queue ! h264parse ! omxh264dec ! sunxifbsink
演示效果
配置流程
首先 SDK版本为tina1.01要打上0730补丁 要配置HDMI作为fb输出
SDK配置
make menuconfig
-*- libcedarx
Select cedarx configuration options --->
(拉到最后)
{*} Add for openmax support
Multimedia --->
<*> gst-omx
-*- gstreamer1-libs
Select GStreamer libraries --->
{ }Include all GStreamer1 core libraries
*** Libraries ***
-*- GStreamer core library libgstreamer1
-*- GStreamer core library libgst1check
-*- GStreamer core library libgst1controller
-*- GStreamer core library libgst1net
<*> gst1-libav(这个不是用来软解视频的 而是用来软解音频)
<*> gstreamer1-plugins-aw
Select GStreamer aw modules --->
{ } Include all GStreamer aw plugins
*** Modules ***
<*> GStreamer fbdev2sink module
<*> GStreamer sunxifbsink module
{*} sunxi g2d rotation support
*** Libraries ***
-*- GStreamer framebuffersink library
<*> gstreamer1-plugins-bad
Select GStreamer bad modules and libraries --->
<*> GStreamer fbdevsink module
<*> GStreamer id3tag module(MP3的id3信息封装)
<*> GStreamer videoparsersbad module
-*- GStreamer codecparsers library
-*- gstreamer1-plugins-base
Select GStreamer base modules and libraries --->
-*- GStreamer alsa module
<*> GStreamer audioconvert module
<*> GStreamer audiorate module
<*> GStreamer audioresample module
<*> GStreamer audiotestsrc module
<*> GStreamer playback module (playbin元件 自动寻找连接元件)
<*> GStreamer typefindfunctions module (这个是给playbin自动寻找解封装元件 之前不知道 导致playbin播不了)
<*> GStreamer videoconvert module
<*> GStreamer videorate module
<*> GStreamer videoscale module
<*> GStreamer videotestsrc module
-*- GStreamer allocators library
-*- GStreamer app library
-*- GStreamer audio library
-*- GStreamer pbutils library
-*- GStreamer riff library
-*- GStreamer rtp library
-*- GStreamer tag library
-*- GStreamer video library
<*> gstreamer1-plugins-good
Select GStreamer good modules --->
<*> GStreamer audioparsers module
<*> GStreamer flv module
<*> GStreamer id3demux module(MP3的id3信息解封装)
<*> GStreamer matroska module(mkv文件解封装)
<*> GStreamer isomp4 module(mp4文件解封装)
<*> GStreamer soup module
<*> gstreamer1-utils
附件提供SDK配置的config文件 方便出问题排查
配置完成后编译打包就可以了 如果编译报错 主要检查补丁有没生效
今天我们来试试移植lvgl8到哪吒D1 并在24寸1080P显示器上渲染
上lvgl的github下载源码
修改几处
lv_conf.h
增加lvgl最大使用内存
#define LV_MEM_SIZE (1024U * 1024U)
打开CPU占用和FPS指示
#define LV_USE_PERF_MONITOR 1
开启音乐播放器演示
lv_demo_conf.h
#define LV_USE_DEMO_MUSIC 1
#define LV_DEMO_MUSIC_LANDSCAPE 1
#define LV_DEMO_MUSIC_LARGE 1
#define LV_DEMO_MUSIC_AUTO_PLAY 1
增大缓冲 双缓冲
main.c
#define DISP_BUF_SIZE (1920 * 1080 * 4)
static lv_color_t buf[DISP_BUF_SIZE];
static lv_color_t buf2[DISP_BUF_SIZE];
lv_disp_draw_buf_init(&disp_buf, buf, buf2, DISP_BUF_SIZE);
把原来的lv_demo_widget改成
lv_demo_music();
我把整个源码重新用cmake构建了一遍 这样就不用去看原来的makefile了
附件中提供了源码工程 只要改一下CMakeLists.txt里的编译器 执行(注意有个点)
cmake .
再执行
make
就可以直接编译了
附件中还提供了应用程序 放进去直接运行看效果
演示视频:
lvgl8播放器
lvgl8窗口
lvgl7窗口
效果还不错
在移植LVGL的时候发现如果不把默认显示输出改成HDMI的话 那么LVGL通过fbdev读出来的fb分辨率就是原来800*1280的 所以用HDMI的来显示的话必须得修改
参考来源:
https://bbs.aw-ol.com/topic/253
https://bbs.aw-ol.com/topic/297
原文比较长 看起来比较费劲 其实改动不大 重新总结归纳了如下
在tina目录下修改下面两个文件 要改的东西是一样的
vim device/config/chips/d1/configs/nezha/uboot-board.dts
vim device/config/chips/d1/configs/nezha/linux-5.4/board.dts
修改以下项的值为
screen0_output_type = <3>;
screen0_output_mode = <10>;
screen1_output_type = <1>;
screen1_output_mode = <4>;
dev0_output_type = <4>;
dev0_output_mode = <10>;
dev0_do_hpd = <1>;
因为单独make编译的时候默认是不编译uboot的 所以要先编译一遍uboot
使用此命令进入进入uboot路径
cboot
单独编译uboot 编完uboot文件会自动复制到方案下
muboot
回到tina目录
cd ../../../
重新编译
make -j64
把logo文件复制到以下路径 logo在原文下载
cp bootlogo.bmp device/config/chips/d1/boot-resource/boot-resource/bat/bootlogo.bmp
cp bootlogo.bmp device/config/chips/d1/boot-resource/boot-resource/bootlogo.bmp
cp bootlogo.bmp device/config/chips/d1/configs/nezha/configs/bootlogo.bmp
如果没做这步那么开机的时候会绿屏
最后打包
pack
烧录完后启动系统 就能发现HDMI上显示出了logo
板子断电状态下按住fel按键 -> 从OTG的那个type-c接口接PC的USB接口上电 -> 成功进入fal模式 PC识别出USB设备
打开PhoenixSuit 选择打包出来的固件 但是PhoenixSuit认不出来 重新装全志USB驱动 认出来了直接烧录
全志USB驱动下载
https://d1.docs.aw-ol.com/study/study_4compile/
用了全志官方配置好编译环境的虚拟机 从原来的vmware ubuntu20换到了virtualbox ubuntu14 再次编译打包 出来固件了
https://d1.docs.aw-ol.com/study/study_3ubuntu/
从晕哥的百度盘下载D1的tina源码
https://whycan.com/t_6440.html
执行命令
source build/envsetup.sh
lunch d1_nezha-tina
make -j32
出现问题
Build dependency: Please install GNU 'awk'
/home/ljh/d1/D1/build/prereq.mk:12: recipe for target 'prereq' failed
Prerequisite check failed. Use FORCE=1 to override.
/home/ljh/d1/D1/build/toplevel.mk:263: recipe for target 'out/host/.prereq-build' failed
make[2]: *** [out/host/.prereq-build] Error 1
/home/ljh/d1/D1/build/toplevel.mk:83: recipe for target 'prepare-tmpinfo' failed
make[1]: *** [prepare-tmpinfo] Error 2
/home/ljh/d1/D1/build/toplevel.mk:304: recipe for target 'world' failed
make: *** [world] Error 2
#### make failed to build some targets (01:05 (mm:ss)) ####
安装gawk
apt-get install gawk
继续编译
出现问题
checking whether mknod can create fifo without root privileges... configure: error: in `/home/ljh/d1/D1/out/d1-nezha/compile_dir/host/tar-1.28':
configure: error: you should not run configure as root (set FORCE_UNSAFE_CONFIGURE=1 in environment to bypass this check)
See `config.log' for more details
Makefile:30: recipe for target '/home/ljh/d1/D1/out/d1-nezha/compile_dir/host/tar-1.28/.configured' failed
make[3]: *** [/home/ljh/d1/D1/out/d1-nezha/compile_dir/host/tar-1.28/.configured] Error 1
make[3]: Leaving directory '/home/ljh/d1/D1/tools/tar'
tools/Makefile:134: recipe for target 'tools/tar/compile' failed
make[2]: *** [tools/tar/compile] Error 2
make[2]: Leaving directory '/home/ljh/d1/D1'
tools/Makefile:133: recipe for target '/home/ljh/d1/D1/out/d1-nezha/staging_dir/target/stamp/.tools_install_yyyynyyynyyyyyyynnnyyyyyyyyyyynnyyyyyyyynyyynyyyyy' failed
make[1]: *** [/home/ljh/d1/D1/out/d1-nezha/staging_dir/target/stamp/.tools_install_yyyynyyynyyyyyyynnnyyyyyyyyyyynnyyyyyyyynyyynyyyyy] Error 2
make[1]: Leaving directory '/home/ljh/d1/D1'
Build failed - please re-run with -j1 to see the real error message
/home/ljh/d1/D1/build/toplevel.mk:304: recipe for target 'world' failed
make: *** [world] Error 1
[2]+ Done $T/tools/build/buildserver --path $T
#### make failed to build some targets (46 seconds) ####
不能以root权限运行 除非设置FORCE_UNSAFE_CONFIGURE=1
设置
export FORCE_UNSAFE_CONFIGURE=1
继续编译
出现问题
tools/Makefile:133: recipe for target '/home/ljh/d1/D1/out/d1-nezha/staging_dir/target/stamp/.tools_install_yyyynyyynyyyyyyynnnyyyyyyyyyyynnyyyyyyyynyyynyyyyy' failed
make[1]: *** [/home/ljh/d1/D1/out/d1-nezha/staging_dir/target/stamp/.tools_install_yyyynyyynyyyyyyynnnyyyyyyyyyyynnyyyyyyyynyyynyyyyy] Error 2
make[1]: Leaving directory '/home/ljh/d1/D1'
Build failed - please re-run with -j1 to see the real error message
/home/ljh/d1/D1/build/toplevel.mk:304: recipe for target 'world' failed
make: *** [world] Error 1
[1]+ Done $T/tools/build/buildserver --path $T
#### make failed to build some targets (02:18 (mm:ss)) ####
用单线程编译看错误?
make –j1
好像又没出现问题
终于 编译完成了 居然用了1个半钟 破机子 踢踢
#### make completed successfully (01:22:17 (hh:mm:ss)) ####
打包
pack
出现问题
/home/ljh/d1/D1/scripts/pack_img.sh: line 1324: /home/ljh/d1/D1/out/host/bin/fsbuild: No such file or directory
pack boot package
GetPrivateProfileSection read to end
content_count=3
LICHEE_REDUNDANT_ENV_SIZE config in BoardConfig.mk
--mkenvimage create redundant env data!--
---redundant env data size 0x20000---
packing for tina linux
normal
ERROR: unable to open file boot-resource.fex
ERROR: update mbr file fail
ERROR: update_mbr failed
目前卡在打包这里 查了下 是在执行这条命令时报的错 错误是找不到文件
fsbuild boot-resource.ini split_xxxx.fex > /dev/null
boot-resource.ini split_xxxx.fex 这个两个文件是存在的
给这两个文件和fsbuild加了chmod 777还是不行
感谢挖坑晕哥和珠海全志送来的哪吒D1开发板 RISC-V 64位处理器 带AI加速指令集 Linux平台 我将持续发掘D1带来的精彩应用 不负所爱 自创奇迹
先来几张开箱照
开箱后我们可以看到套装内含:
D1开发板 * 1
电源适配器 * 1
串口线 * 1
数据线type-c * 2
铜柱 * 4
装好铜柱 接串口接口 注意顺序是黑绿白
看见有个typeC接口标识了PWR 这个是专门用来上电的接口
上电后 左边的PWR电源指示LED会亮红色 系统运行时PWR上面的LED会闪绿色
LED闪绿色后敲一下回车 成功进入Tina系统
找舍友借了个24寸HDMI显示屏
输入以下命令切换为HDMI信号
cd /sys/kernel/debug/dispdbg
echo disp0 > name; echo switch1 > command; echo 4 4 0 0 0x4 0x101 0 0 0 8 > param; echo 1 > start;
此时可以看见 屏幕上显示出了Tina小企鹅logo
显示colorbar
echo 1 > /sys/class/disp/disp/attr/colorbar
播放本地视频:(从文件名可以看出这是1080P H265编码 60帧的视频)
tplayerdemo /usr/lib/tt-data/01-1080P-HEVC-AAC-60F.mkv
播放效果非常丝滑 不愧是官方适配的系统
D1还有很多值得发掘的潜能 当然开发中还有很多困难等我们去克服 没事 我们有晕哥带头填坑
让我们一起 不负所爱 自创奇迹
在buildroot进入目录output/build/libcedarc-master
cd output/build/libcedarc-master
修改源文件omx_vdec_aw_decoder_linux.c
vim openmax/vdec/src/omx_vdec_aw_decoder_linux.c
在结构体类型typedef struct OmxAwDecoderContext增加以下成员
int tWidth;
int tHeight;
在
#if (ENABLE_SCALEDOWN_WHEN_RESOLUTION_MOER_THAN_1080P)
if (pCtx->mStreamInfo.nWidth > 1920
&& pCtx->mStreamInfo.nHeight > 1088)
{
pCtx->mVideoConfig.bScaleDownEn = 1;
pCtx->mVideoConfig.nHorizonScaleDownRatio = 1;
pCtx->mVideoConfig.nVerticalScaleDownRatio = 1;
}
#endif
下面添加
pCtx->tWidth = pCtx->mStreamInfo.nWidth;
pCtx->tHeight = pCtx->mStreamInfo.nHeight;
pCtx->mStreamInfo.nWidth = (pCtx->mStreamInfo.nWidth + 31) & ~31;
pCtx->mStreamInfo.nHeight = (pCtx->mStreamInfo.nHeight + 31) & ~31;
在函数
static int __liCallback(OmxDecoder* pDec, DecoderCallback callback,
void* pUserData)
上面添加一个函数
static int yv12_align_fill(char* p_dst, int w, int h, int aw, int ah)
{
int i, j;
int map = aw * ah;
int v_size = (map) >> 2;
char *pv = p_dst + map;
char *pu = pv + v_size;// / 4
int dw = aw - w;
int dh = ah -h;
int dw_h = dw / 2;
int dh_h = dh / 2;
int w_h = w / 2;
int h_h = h / 2;
int aw_h = aw / 2;
int ah_h = ah / 2;
int map_oft = aw_h * h_h;
if((w == aw) && (h == ah))
return 0;
for(i=0;i<h_h;i++)
{
for(j=0;j<dw_h;j++)
{
pv[w_h + j + aw_h * i] = 128;
pu[w_h + j + aw_h * i] = 128;
}
}
for(i=0;i<dh_h;i++)
{
for(j=0;j<aw_h;j++)
{
pv[map_oft + j + aw_h * i] = 128;
pu[map_oft + j + aw_h * i] = 128;
}
}
return 0;
}
在函数__liDrain中
RotatePicture(pCtx->decMemOps, pCtx->pPicture, &pCtx->CvtPicture, 0, 32, 32);
的下面添加
yv12_align_fill(pCtx->CvtPicture.pData0, pCtx-> tWidth, pCtx-> tWidth, pCtx->mStreamInfo.nWidth, pCtx->mStreamInfo.nHeight);
保存退出
修改源文件pixel_format.c
vim vdecoder/pixel_format.c
把函数
MB32_CVT_YV12
替换成
static void MB32_CVT_YV12(char* pSrc, char* pSrc_v, char* pDst, int nWidth, int nHeight)
{
int i = 0;
int j = 0;
int m = 0;
int n = 0;
int k = 0;
int nMbWidth = 0;
int nMbHeight = 0;
int nMbWidth_uv = 0;
int nMbHeight_uv = 0;
int nLineStride = 0;
int nLineStride_uv = 0;
int lineNum = 0;
int lineNum_uv = 0;
int offset = 0;
int offset_uv = 0;
int maxNum = 0;
char* ptr = NULL;
char* ptr_uv = NULL;
char* pDstU = NULL;
char* pDstV = NULL;
int nWidth_uv = 0;
int nHeight_uv = 0;
char bufferY[32];
char bufferV[16], bufferU[16];
int nWidthMatchFlag = 0;
int nWidthMatchFlag_uv = 0;
int nCopyMbWidth = 0;
int nCopyMbWidth_uv = 0;
char *dstAsm = NULL;
char *dst0Asm = NULL;
char *dst1Asm = NULL;
char *srcAsm = NULL;
char *srcAsm_uv = NULL;
int bCnt2 = 1;
nLineStride = (nWidth + 15) &~15;
nMbWidth = (nWidth + 31)&~31;
nMbWidth >>= 5;//n 32 width / 32
nMbHeight = (nHeight + 31)&~31;
nMbHeight >>= 5;// / 32
ptr = pSrc;
nWidthMatchFlag = 0;
nCopyMbWidth = nMbWidth - 1;
nWidth_uv = (nWidth + 1) / 2;
nHeight_uv = (nHeight + 1) / 2;
nLineStride_uv = (nWidth_uv + 7)&~7;
nMbWidth_uv = (nWidth_uv * 2 + 31)&~31;
nMbWidth_uv >>= 5;// / 32
nMbHeight_uv = (nHeight_uv + 31)&~31;
nMbHeight_uv >>= 5;// / 32
ptr_uv = pSrc_v;
pDstU = pDst + (nWidth * nHeight) + (nWidth / 2 * nHeight / 2);
pDstV = pDst + (nWidth * nHeight);
nWidthMatchFlag_uv = 0;
nCopyMbWidth_uv = nMbWidth_uv - 1;
if ((nMbWidth << 5) == nLineStride)// * 32
{
nWidthMatchFlag = 1;
nCopyMbWidth = nMbWidth;
}
if ((nMbWidth_uv << 4) == nLineStride_uv)//*16
{
nWidthMatchFlag_uv = 1;
nCopyMbWidth_uv = nMbWidth_uv;
}
for (i = 0; i < nMbHeight; i++)
{
for (j = 0; j < nCopyMbWidth; j++)
{
for (m = 0; m < 32; m++)
{
if (((i << 5) + m) >= nHeight)// * 32
{
ptr += 32;
continue;
}
srcAsm = ptr;
lineNum = (i << 5) + m; //line num * 32
offset = lineNum * nLineStride + (j << 5);// * 32
dstAsm = pDst + offset;
memcpy(dstAsm, srcAsm, 32);
if (bCnt2)
{
srcAsm_uv = ptr_uv;
lineNum_uv = (i << 4) + m; //line num i / 2 * 32
offset_uv = lineNum_uv * nLineStride_uv + (j << 4);// * 16
dst0Asm = pDstU + offset_uv;
dst1Asm = pDstV + offset_uv;
//memcpy(dst0Asm, srcAsm_uv, 16);
//memcpy(dst1Asm, (void *)(srcAsm_uv + 16), 16);
dst0Asm[0] = srcAsm_uv[0];
dst0Asm[1] = srcAsm_uv[2];
dst0Asm[2] = srcAsm_uv[4];
dst0Asm[3] = srcAsm_uv[6];
dst0Asm[4] = srcAsm_uv[8];
dst0Asm[5] = srcAsm_uv[10];
dst0Asm[6] = srcAsm_uv[12];
dst0Asm[7] = srcAsm_uv[14];
dst0Asm[8] = srcAsm_uv[16];
dst0Asm[9] = srcAsm_uv[18];
dst0Asm[10] = srcAsm_uv[20];
dst0Asm[11] = srcAsm_uv[22];
dst0Asm[12] = srcAsm_uv[24];
dst0Asm[13] = srcAsm_uv[26];
dst0Asm[14] = srcAsm_uv[28];
dst0Asm[15] = srcAsm_uv[30];
dst1Asm[0] = srcAsm_uv[1];
dst1Asm[1] = srcAsm_uv[3];
dst1Asm[2] = srcAsm_uv[5];
dst1Asm[3] = srcAsm_uv[7];
dst1Asm[4] = srcAsm_uv[9];
dst1Asm[5] = srcAsm_uv[11];
dst1Asm[6] = srcAsm_uv[13];
dst1Asm[7] = srcAsm_uv[15];
dst1Asm[8] = srcAsm_uv[17];
dst1Asm[9] = srcAsm_uv[19];
dst1Asm[10] = srcAsm_uv[21];
dst1Asm[11] = srcAsm_uv[23];
dst1Asm[12] = srcAsm_uv[25];
dst1Asm[13] = srcAsm_uv[27];
dst1Asm[14] = srcAsm_uv[29];
dst1Asm[15] = srcAsm_uv[31];
ptr_uv += 32;
}
ptr += 32;
}
}
if (nWidthMatchFlag != 1)
{
for (m = 0; m < 32; m++)
{
if (((i << 5) + m) >= nHeight)// * 32
{
ptr += 32;
continue;
}
dstAsm = bufferY;
srcAsm = ptr;
lineNum = (i << 5) + m; //line num * 32
offset = lineNum * nLineStride + (j << 5);// * 32
memcpy(dstAsm, srcAsm, 32);
ptr += 32;
for (k = 0; k < 32; k++)
{
if ((j * 32 + k) >= nLineStride)
{
break;
}
pDst[offset + k] = bufferY[k];
}
}
}
if (bCnt2) {
if (nWidthMatchFlag_uv != 1)
{
for (m = 0; m < 32; m++)
{
if (((i << 4) + m) >= nHeight_uv)//i / 2 * 32
{
ptr_uv += 32;
continue;
}
srcAsm_uv = ptr_uv;
lineNum_uv = (i << 4) + m; //line num i / 2 * 32
offset = lineNum_uv * nLineStride_uv + (j << 4);// * 16
dst0Asm = bufferU;
dst1Asm = bufferV;
//memcpy(dst0Asm, srcAsm, 16);
//memcpy(dst1Asm, (char *)(srcAsm + 16), 16);
dst0Asm[0] = srcAsm_uv[0];
dst0Asm[1] = srcAsm_uv[2];
dst0Asm[2] = srcAsm_uv[4];
dst0Asm[3] = srcAsm_uv[6];
dst0Asm[4] = srcAsm_uv[8];
dst0Asm[5] = srcAsm_uv[10];
dst0Asm[6] = srcAsm_uv[12];
dst0Asm[7] = srcAsm_uv[14];
dst0Asm[8] = srcAsm_uv[16];
dst0Asm[9] = srcAsm_uv[18];
dst0Asm[10] = srcAsm_uv[20];
dst0Asm[11] = srcAsm_uv[22];
dst0Asm[12] = srcAsm_uv[24];
dst0Asm[13] = srcAsm_uv[26];
dst0Asm[14] = srcAsm_uv[28];
dst0Asm[15] = srcAsm_uv[30];
dst1Asm[0] = srcAsm_uv[1];
dst1Asm[1] = srcAsm_uv[3];
dst1Asm[2] = srcAsm_uv[5];
dst1Asm[3] = srcAsm_uv[7];
dst1Asm[4] = srcAsm_uv[9];
dst1Asm[5] = srcAsm_uv[11];
dst1Asm[6] = srcAsm_uv[13];
dst1Asm[7] = srcAsm_uv[15];
dst1Asm[8] = srcAsm_uv[17];
dst1Asm[9] = srcAsm_uv[19];
dst1Asm[10] = srcAsm_uv[21];
dst1Asm[11] = srcAsm_uv[23];
dst1Asm[12] = srcAsm_uv[25];
dst1Asm[13] = srcAsm_uv[27];
dst1Asm[14] = srcAsm_uv[29];
dst1Asm[15] = srcAsm_uv[31];
ptr_uv += 32;
for (k = 0; k < 16; k++)
{
if (((j << 4) + k) >= nLineStride_uv)// j * 16
{
break;
}
pDstV[offset + k] = bufferV[k];
pDstU[offset + k] = bufferU[k];
}
}
}
}
bCnt2 = !bCnt2;
}
}
保存退出
清除libcedarc之前的编译文件
make clean
清除buildroot对于libcedarc的编译标记
rm .stamp_built
回到buildroot目录
cd ../../../
编译
make
这样源文件的修改就完成了
18楼的问题已修复 修复了两个问题
1.字节对齐问题
就是https://whycan.com/t_6139.html里说的 “并且分辨率: 32的整数倍* 32的整数倍 偏离一个像素都可能导致错误。”
现在分辨率不是32整数倍的视频也可以正常播放了
2.颜色错误问题
测试其他视频发现颜色不对 现已修复
测试镜像:
F1C200s主线gstreamer使用openmax调用cedar硬解码附件20210813.zip
下楼改源文件修复问题
基本思路:
网络摄像机(IPC)由摄像头 编码器 网络 推流 这几个部分组成
摄像头获取图像帧 交给编码器编码 通过网络推流到流媒体服务器 最后从流媒体服务器拉流到就能看到摄像头的画面了
摄像头用的是ov2640 接荔枝派zero的DVP接口 需要配置设备树的DVP引脚和i2c引脚 使用Linux的V4L2框架进行操作摄像头 需要配置内核V4L和多媒体支持 在获取图像时要配置成NV21格式给编码器 配置参考: https://whycan.com/t_2039.html
完成以上操作后 要保证有/dev/video0
编码器是用的主线cedar硬编码 将NV21的图像编码成H264 配置参考: https://whycan.com/t_4219.html
完成以上操作后 要保证能在/dev目录下找到cedar_dev和ion
网络是用的WIFI模块rtl8723bs 配置参考: https://whycan.com/t_652.html
推流是使用ffmpeg库进行RTMP推流到PC的nginx的RTMP流媒体服务器
演示环境搭建
荔枝派zero配置
附件中提供了完成以上配置的用于演示的荔枝派镜像 wifi固件 编译好的应用程序
lichee_zero-linux.dd是镜像文件 在linux下使用dd命令烧录进tf卡 以tf卡是/dev/sdb为例
sudo dd if=lichee_zero-linux.dd of=/dev/sdb bs=1M
烧录好镜像到tf卡后 把tf卡拔了再插进入 然后把下面文件复制进tf卡第二分区200多M的 目录/root里
ipc_cedarc_venc
rtl8723bs_nic.bin
烧录完成后启动系统 需要插入ov2640驱动模块 和配置wifi模块
insmod /lib/modules/5.2.0-licheepi-zero/kernel/drivers/media/i2c/ov2640.ko
复制rtl8723bs固件
mkdir -p /lib/firmware/rtlwifi/
cp /root/rtl8723bs_nic.bin /lib/firmware/rtlwifi/
加载驱动 打开网卡
modprobe r8723bs.ko
ifconfig wlan0 up
替换wifi配置内容
编辑要连接的wifi名和密码 替换wifiname 和password
vi /etc/wpa_supplicant.conf
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=0
ap_scan=1
network={
ssid="wifiname"
scan_ssid=1
key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
pairwise=TKIP CCMP
group=CCMP TKIP WEP104 WEP40
psk="password"
priority=5
}
根据配置开始扫描并连接指定wifi
wpa_supplicant -B -d -i wlan0 -c /etc/wpa_supplicant.conf
等wifi连接后 获取ip等信息
udhcpc -i wlan0
至此荔枝派zero演示环境已经配置好了
PC操作系统为win10
在PC上安装Nginx 并加入RTMP插件 配置好nginx-win.conf文件
附件上有配置好的Nginx 可以直接用
在PC上安装ffmpeg 并配置好环境变量
附件上有ffmpeg 要配置一下环境变量
“计算机”->“属性”->“高级系统设置“->”环境变量“->“系统变量”->“Path“->“编辑” 将.exe文件所在的路径添加进去即可。
例如:
D:\CS\ffmpeg\ffmpeg-4.3.1-win64-shared\bin
配置好环境变量后在cmd输入命令检验
ffmpeg -version
在安装好Nginx和ffmpeg后 进行流媒体服务器推流拉流测试
启动Nginx
打开cmd 进入Nginx目录执行命令启动
比如路径在d:\cs\nginx 1.7.11.3 Gryphon
依次执行以下命令
d:
cd cs\nginx 1.7.11.3 Gryphon
nginx.exe -c conf\nginx-win.conf
执行完后cmd不会输出什么信息 流媒体服务器已经启动了 此时可以关掉这个cmd
再打开两个cmd 进行ffmpeg推流拉流
先进行ffmpeg 拉流:
ffplay rtmp://localhost:1935/live/home
再进行ffmpeg推流:
ffmpeg -re -i d:\bad_apple.mp4 -vcodec libx264 -acodec aac -f flv rtmp://127.0.0.1:1935/live/home
附件上有测试文件bad_apple.mp4
执行完后 出现正在播放视频窗口 说明流媒体服务器和推流拉流测试正常 PC演示环境已经配置好了
推流拉流可能会出现失败提示
[rtmp @ 0x42b50] Cannot read RTMP handshake response
重新再执行一次命令就行 荔枝派推流失败出现同样的提示时同理
在推流的cmd按ctrl+c关掉推流 用同样的方式关掉拉流或者直接关掉视频窗口
接下来用荔枝派zero推流给PC
再在PC打开拉流
ffplay rtmp://localhost:1935/live/home
在荔枝派推流
./ipc_cedarc_venc 800x600 /dev/video0 rtmp://192.168.43.64/live/home
参数分别是 分辨率 输入摄像头设备 输出RTMP流媒体服务器地址
其中192.168.43.64要换成你的PC的IP地址 确保PC和荔枝派在同一个局域网
过一会 就可以在PC看到摄像头画面的视频窗口
有时候过了10-20秒还没出现视频窗口则需要重新执行拉流推流 如果还不行则需要重启荔枝派
至此演示环境搭建好了
演示效果:
验证平台:
硬件 荔枝派zero 主控V3s
Linux 主线内核5.2荔枝派官方的
根目录 Buildroot 2019.08
编译器 Buildroot 里的gcc 8.3
流媒体服务器Nginx 1.7.11.3 Gryphon 带RTMP插件
PC拉流 ffmpeg 4.3.1
荔枝派推流 ffmpeg 4.2
应用程序编译
项目功能由编程实现 项目附件中有工程源码 交叉编译产生应用程序 工程是用CMake构建Makefile
在PC上安装Cmake
apt-get install cmake
然后在CMakeLists.txt修改链接库路径和编译器路径 修改好后 在源码目录下 输入(注意有个点)
cmake .
再输入
make
就编译出了应用程序 复制进荔枝派就可以运行了
系统构建配置
自己构建系统会比较容易遇到问题 所以我在附件里提供了设备树 内核配置文件 Buildrood配置文件
逸俊晨晖 说:镜像和使用方法
zero配置DLNA镜像和使用方法.zip用的这个镜像,本地播放很好,投屏卡的厉害,投屏没走硬解?
怀疑有没走硬件 你可以把omx注册的硬解码器优先级改0试试
厉害厉害,学习了,这回可玩性就大多了,有声音吗?
我说我杀人不眨眼 你问我眼睛酸不酸?
上面搞了这么多 都是硬解视频流 声音要先把声卡配出来 然后用以下命令解码才有
gst-launch-1.0 filesrc location=bad_apple.mp4 ! qtdemux name=demux demux.audio_0 \
! queue ! decodebin ! audioconvert ! audioresample ! alsasink \
demux.video_0 ! queue ! h264parse ! omxh264dec ! videoconvert ! videoscale ! fbdevsink
yuanhao0230 说:逸俊晨晖 说:镜像和使用方法
gst-omx硬解码镜像.zip大神,可否帮忙生成一个f1v100s+800*480的镜像,感激不尽啊……
https://whycan.com/files/members/3078/2020-12-19_105626.png
我的荔枝派视频解码时候, cpu占用率100%, 这样正常吗?
硬解出来的YV12要经过软件转换成RGB再显示在屏幕上 估计是这里占了CPU 把DE用起来就会占这么多了
用歪朵拉的老法师们 看这个帖子
https://whycan.com/t_5824.html
F1C200s硬解码播放现场:
镜像和使用方法
https://whycan.com/files/members/1105/F1C200s_gst-omx硬解码镜像.zip
验证平台:
硬件 Widora R3 晕哥特供
linux 主线内核5.2荔枝派官方的
启动方式 TF卡 屏幕800 * 480
h264文件 bad_apple.mp4
最后感谢晕哥在歪朵拉R3断货时 雪中送炭 支援了我一块 真够豪爽的
之前发了个v3s使用gstreamer的插件openmax调用cedar硬解码的主题
https://whycan.com/t_5398.html
不少小伙伴用F1C200s尝试使用遇到了问题
报了个初始化解码库失败的错误
经排查发现是配置libcedarc时要选择一个编译硬解码库的gcc
之前用v3s时这个配置项默认是arm-linux-gnueabihf 恰好是适合v3s使用的gcc
但是在F1C200s就不能用了 要进行修改
在修改完以后 继续尝试播放 发现屏幕显示一片墨绿 过一会内核崩溃了 绿的我发慌
重启还起不来 发现是有和启动相关的库被破坏掉了 要重新烧录才行能正常启动
后来排查发现是硬解码输出帧格式的问题 (但不至于内核奔溃甚至破坏启动库吧)
我们在用v3s进行硬解码时 openmax是被默认配置为输出YV12 所以v3s用起来没问题 但是到F1C200s就不行了 F1C200s只能输出MB32 (详细资料看隔壁硬解码主题8楼 https://whycan.com/t_5429.html)
所以我们只要将openmax配置修改一下 再对输出格式做个转换 就可以了
下面开始修改内容
1.配置编译硬解码库的gcc
在buildroot配置libcedarc
Target packages ->
Hardware handling ->
libcedarc ->
Arch library select
改成arm-none-linux-gnueabi
2.修改openmax
在buildroot进入目录output/build/libcedarc-master
cd output/build/libcedarc-master
修改源文件omx_vdec_aw_decoder_linux.c
vim openmax/vdec/src/omx_vdec_aw_decoder_linux.c
在结构体类型typedef struct OmxAwDecoderContext增加以下成员
char* pYV12;
VideoPicture CvtPicture;
在函数__liPrepare中
把
pCtx->mVideoConfig.eOutputPixelFormat = PIXEL_FORMAT_YV12;
改为
pCtx->mVideoConfig.eOutputPixelFormat = PIXEL_FORMAT_YUV_MB32_420;
在语句ret = InitializeVideoDecoder(pCtx->m_decoder, 上面一行添加以下内容
pCtx->pYV12 = (char*)malloc(sizeof(char) * pCtx->mStreamInfo.nWidth * pCtx->mStreamInfo.nHeight * 3 / 2);
if(pCtx->pYV12 == NULL)
{
loge("pCtx->pYV12 malloc fail\n");
return -1;
}
pCtx->CvtPicture.pData0 = pCtx->pYV12;
pCtx->CvtPicture.ePixelFormat = PIXEL_FORMAT_YV12;
在函数__liDrain中
在logv("*** picture info: w(%d),h(%d),offset,t(%d),b(%d),l(%d),r(%d)",上面一行添加以下内容
RotatePicture(pCtx->decMemOps, pCtx->pPicture, &pCtx->CvtPicture, 0, 32, 32);
将
AlignCopyYV12((unsigned char*)pOutBufHdr->pBuffer,
(unsigned char*)pCtx->pPicture->pData0,
outDef->format.video.nFrameWidth,
outDef->format.video.nFrameHeight);
改成
AlignCopyYV12((unsigned char*)pOutBufHdr->pBuffer,
(unsigned char*)pCtx->CvtPicture.pData0,
outDef->format.video.nFrameWidth,
outDef->format.video.nFrameHeight);
在函数__liGetFormat
把
pCtx->mVideoConfig.eOutputPixelFormat = PIXEL_FORMAT_YV12;
改为
pCtx->mVideoConfig.eOutputPixelFormat = PIXEL_FORMAT_YUV_MB32_420;
在函数__liClose
在if(pCtx->m_decoder != NULL)上面一行添加以下内容
if(pCtx->pYV12 != NULL)
{
free(pCtx->pYV12);
pCtx->pYV12 = NULL;
}
3.修改libcedarc 添加格式转换
修改源文件pixel_format.c
vim vdecoder/pixel_format.c
在函数ConvertPixelFormat上面添加一个函数
void MB32_CVT_YV12_(char* pSrc, char* pSrc_v, char* pDst, int nWidth, int nHeight)
{
int i = 0;
int j = 0;
int m = 0;
int n = 0;
int k = 0;
int nMbWidth = 0;
int nMbHeight = 0;
int nMbWidth_uv = 0;
int nMbHeight_uv = 0;
int nLineStride = 0;
int nLineStride_uv = 0;
int lineNum = 0;
int lineNum_uv = 0;
int offset = 0;
int offset_uv = 0;
int maxNum = 0;
char* ptr = NULL;
char* ptr_uv = NULL;
char* pDstU = NULL;
char* pDstV = NULL;
int nWidth_uv = 0;
int nHeight_uv = 0;
char bufferY[32];
char bufferV[16], bufferU[16];
int nWidthMatchFlag = 0;
int nWidthMatchFlag_uv = 0;
int nCopyMbWidth = 0;
int nCopyMbWidth_uv = 0;
char *dstAsm = NULL;
char *dst0Asm = NULL;
char *dst1Asm = NULL;
char *srcAsm = NULL;
char *srcAsm_uv = NULL;
int bCnt2 = 1;
nLineStride = (nWidth + 15) &~15;
nMbWidth = (nWidth + 31)&~31;
nMbWidth >>= 5;//n 32 width / 32
nMbHeight = (nHeight + 31)&~31;
nMbHeight >>= 5;// / 32
ptr = pSrc;
nWidthMatchFlag = 0;
nCopyMbWidth = nMbWidth - 1;
nWidth_uv = (nWidth + 1) / 2;
nHeight_uv = (nHeight + 1) / 2;
nLineStride_uv = (nWidth_uv + 7)&~7;
nMbWidth_uv = (nWidth_uv * 2 + 31)&~31;
nMbWidth_uv >>= 5;// / 32
nMbHeight_uv = (nHeight_uv + 31)&~31;
nMbHeight_uv >>= 5;// / 32
ptr_uv = pSrc_v;
pDstU = pDst + (nWidth * nHeight) + (nWidth / 2 * nHeight / 2);
pDstV = pDst + (nWidth * nHeight);
nWidthMatchFlag_uv = 0;
nCopyMbWidth_uv = nMbWidth_uv - 1;
if ((nMbWidth << 5) == nLineStride)// * 32
{
nWidthMatchFlag = 1;
nCopyMbWidth = nMbWidth;
}
if ((nMbWidth_uv << 4) == nLineStride_uv)//*16
{
nWidthMatchFlag_uv = 1;
nCopyMbWidth_uv = nMbWidth_uv;
}
for (i = 0; i < nMbHeight; i++)
{
for (j = 0; j < nCopyMbWidth; j++)
{
for (m = 0; m < 32; m++)
{
if (((i << 5) + m) >= nHeight)// * 32
{
ptr += 32;
continue;
}
srcAsm = ptr;
lineNum = (i << 5) + m; //line num * 32
offset = lineNum * nLineStride + (j << 5);// * 32
dstAsm = pDst + offset;
memcpy(dstAsm, srcAsm, 32);
if (bCnt2)
{
srcAsm_uv = ptr_uv;
lineNum_uv = (i << 4) + m; //line num i / 2 * 32
offset_uv = lineNum_uv * nLineStride_uv + (j << 4);// * 16
dst0Asm = pDstU + offset_uv;
dst1Asm = pDstV + offset_uv;
memcpy(dst0Asm, srcAsm_uv, 16);
memcpy(dst1Asm, (void *)(srcAsm_uv + 16), 16);
ptr_uv += 32;
}
ptr += 32;
}
}
if (nWidthMatchFlag != 1)
{
for (m = 0; m < 32; m++)
{
if (((i << 5) + m) >= nHeight)// * 32
{
ptr += 32;
continue;
}
dstAsm = bufferY;
srcAsm = ptr;
lineNum = (i << 5) + m; //line num * 32
offset = lineNum * nLineStride + (j << 5);// * 32
memcpy(dstAsm, srcAsm, 32);
ptr += 32;
for (k = 0; k < 32; k++)
{
if ((j * 32 + k) >= nLineStride)
{
break;
}
pDst[offset + k] = bufferY[k];
}
}
}
if (bCnt2) {
if (nWidthMatchFlag_uv != 1)
{
for (m = 0; m < 32; m++)
{
if (((i << 4) + m) >= nHeight_uv)//i / 2 * 32
{
ptr_uv += 32;
continue;
}
srcAsm = ptr_uv;
lineNum_uv = (i << 4) + m; //line num i / 2 * 32
offset = lineNum_uv * nLineStride_uv + (j << 4);// * 16
dst0Asm = bufferU;
dst1Asm = bufferV;
memcpy(dst0Asm, srcAsm, 16);
memcpy(dst1Asm, (char *)(srcAsm + 16), 16);
ptr_uv += 32;
for (k = 0; k < 16; k++)
{
if (((j << 4) + k) >= nLineStride_uv)// j * 16
{
break;
}
pDstV[offset + k] = bufferV[k];
pDstU[offset + k] = bufferU[k];
}
}
}
}
bCnt2 = !bCnt2;
}
}
在函数ConvertPixelFormat的
if(pPictureOut->ePixelFormat==PIXEL_FORMAT_YV12){
和#ifdef CEDARX_DECODER_ARM32之间添加以下内容
if(pPictureIn->ePixelFormat == PIXEL_FORMAT_YUV_MB32_420)
{
MB32_CVT_YV12(pPictureIn->pData0, pPictureIn->pData1, pPictureOut->pData0, \
pPictureIn->nWidth, pPictureIn->nHeight);
}
清除libcedarc之前的编译文件
make clean
清除buildroot对于libcedarc的编译标记
rm .stamp_built
3.和v3s一样 给gstreamer的openmax插件添加全志的颜色空间定义
cd ../gst-omx-1.16.0/
vim omx/gstomxvideo.c
在函数gst_omx_video_get_format_from_omx的switch下添加case
case OMX_COLOR_FormatYVU420Planar:
format = GST_VIDEO_FORMAT_YV12;
break;
保存退出
清除gst-omx之前的编译文件
(之前那篇帖子有人说OMX_COLOR_FormatYVU420Planar找不到定义 我估计就是这个没有清)
make clean
清除buildroot对于gst-omx的编译标记
rm .stamp_built
回到buildroot目录
cd ../../../
编译
make
这样源文件的修改就完成了 gstreamer的配置就看回上面v3s的主题
打包烧录后进入系统 进行gst-omx注册后就可以进行硬解码播放了
首先spi可以通过配置spidev 出现/dev/spidev 给用户层操作 ( https://whycan.com/t_3754.html )
然后spi可以通过配置cs脚实现spi复用 挂载多个spi设备( https://whycan.com/t_2418.html )
那么如何将这两个结合在一起?
比如我f1c100s的spi0已经挂载了flash 怎么通过cs复用脚 再配置出一个spidev设备来
我试了下这样配置 发现是无效的 flash使用正常 但是没有出现/dev/spidev
&pio {
spi0_cs_pins: spi0_cs_pins {
pins = "PC1", "PE3";
function = "gpio_out";
};
};
&spi0 {
pinctrl-names = "default";
pinctrl-0 = <&spi0_pins_a &spi0_cs_pins>;
cs-gpios = <&pio 2 1 GPIO_ACTIVE_HIGH>, <&pio 5 3 GPIO_ACTIVE_HIGH>;//PC1 PE3
status = "okay";
flash: w25q128@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "winbond,w25q128", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <50000000>;
partitions{
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
lable = "u-boot";
reg = <0x000000 0x100000>;
read-only;
};
partition@100000 {
lable = "dtb";
reg = <0x100000 0x10000>;
read-only;
};
partition@110000 {
label = "kernel";
reg = <0x110000 0x400000>;
read-only;
};
partition@510000 {
label = "rootfs";
reg = <0x510000 0xAF0000>;
};
};
};
spidev@0x00 {
compatible = "spidev";
spi-max-frequency = <100000000>;
reg = <0>;
};
};
# gst-launch-1.0 filesrc location=bad_apple.mp4 ! qtdemux ! h264parse ! omxh264d
ec ! autovideoconvert ! fbdevsink
WARNING: erroneous pipeline: no element "omxh264dec"报错 no element "omxh264dec" 无法播放视频 软解是可以播放的
查看/usr/lib目录并没有/usr/lib/libOmxCore.so这个文件 请问这个文件是如何生成的 是buildroot编译生成的吗
libcedarc\openmax\omxcore\Makefile.am说明此路径产生libOmxCore.so 没有就说明前置贴没配好 就是帖子顶部那个链接
逸俊晨晖 说:你标题上写个DE我还要以为你要用硬件转呢 一点进来发现是软件转
软件转很慢的 f1c的话还是操作libdrm使的fb直接显示yuv吧你可能没注意看,我就是要用硬件的display engine转,左上角就是硬件yuv转的rgb但是明显变色了,转换系数不对,右下角是软件转的,只是看下有没有大佬会算,给出来参考下。
然后linux上f1c的有实现硬件yuv转rgb吗?能否给个链接,非常感谢。之前看别人说用过libdrm没效果可能sdk不对。
确实没认真看
注意fb颜色空间格式是rgb还是其它顺序
我也没见过人家用 之前我用两层rgb叠层 发现透明度是有问题的 可能驱动有问题
镜像和使用方法
zero配置DLNA镜像和使用方法.zip
基本思路:
B站投屏和网易云推送音乐是通过DLNA协议实现的 它可以把B站视频和网易云音乐推送到同一网络下支持DLNA的设备
为荔枝派zero配置DLNA客户端需要用到组件gmrender-resurrect 可在buildroot里添加组件 而gmrender-resurrect基于gstreamer1.0实现
我们已经实现了使用gstreamer1.0调用openmax硬解H264
B站通过DLNA投屏时会发送flv封装的H264流 类似于直播
也就是说 我们可以用gstreamer硬解B站投屏视频
联网使用荔枝派zero配套的wifi模块rtl8723bs
视频显示使用配套的800*480屏幕
音频播放使用USB声卡
前置参考:
1. gstreamer硬解码 https://whycan.com/t_5398.html
2. rtl8723bs联网 https://whycan.com/t_652.html
3. USB声卡 https://whycan.com/t_2400.html
buildroot配置:
进入buildroot
make menuconfig
-> Target packages
-> Libraries
-> Networking
liburiparser libhttpparser libsoup libupnpp
-> Target packages
-> Libraries
-> Networking
-> libcurl (BR2_PACKAGE_LIBCURL [=y])
-> SSL/TLS library to use (<choice> [=y])
GnuTLS
-> Target packages
-> Networking applications
lftp
HTTP protocol
-> Target packages
-> Libraries
-> Crypto
gnutls
OpenSSL compatibility library
install tools
-> Target packages
-> Audio and video applications
-> gstreamer 1.x
gst1-plugins-good
id3demux
flv
mpg123
souphttpsrc
gst1-plugins-bad
id3tag
mpegdemux
faad
fbdev
gst1-libav取消选择
gst-omx
-> Target packages
-> Audio and video applications
gmrender-resurrect
注意:
gmediarender在启动时会注册所有gstreamer检测到的插件 其中gst1-libav是ffmpeg的所有编解码器 会占用非常大的资源 所以要取消选择 否则无法正常播放 之前试了下 开了它要额外占用6-70M的swap区RAM 这里也可以不取消 直接在荔枝派系统上删除
rm /usr/lib/gstreamer-1.0/libgstlibav.so
进入buildroot的gstreamer修改过的插件目录进行删除标记 否则新添加或者删除的组件不会生效
cd output/build/gst1-plugins-good-1.16.0 rm .stamp_built .stamp_configured .stamp_target_installed
cd ../gst1-plugins-bad-1.16.0/
rm .stamp_built .stamp_configured .stamp_target_installed .stamp_staging_installed
cd ../gst1-libav-1.16.0/
rm .stamp_built .stamp_configured .stamp_target_installed
cd ../../../
rm output/target/usr/lib/gstreamer-1.0/libgstlibav.so
make
编译构建烧录
进入荔枝派zero系统
配置好wifi联网
配置gst-omx硬解码注册
vi /etc/xdg/gstomx.conf
可以发现有两个omxh264dec
第一个把它优先级改为0
rank=0
第二个把它所有键值对替换成
type-name=GstOMXH264Dec
core-name=/usr/lib/libOmxCore.so
component-name=OMX.allwinner.video.decoder.avc
rank=256
in-port-index=0
out-port-index=1
hacks=no-component-role;no-disable-outport
保存退出
:wq
先用此命令确定gstreamer可以正常播放音视频
gst-launch-1.0 filesrc location=bad_apple.mp4 ! qtdemux name=demux demux.audio_0 \
! queue ! decodebin ! audioconvert ! audioresample ! alsasink \
demux.video_0 ! queue ! h264parse ! omxh264dec ! videoconvert ! videoscale ! fbdevsink
接下来可以通过gmediarender运行DLNA客户端了
gmediarender -f "licheePi Zero" --gstout-videosink=fbdevsink --gstout-audiosink=alsasink
B站投屏操作:
手机打开B站搜索bad apple视频打开
点一下视频使其右上角出现TV图标
点击TV图标
点击出现的licheePi Zero设备
网易云推送操作:
点击左上角三条杠
点击设置 直接拉倒最下面
点击连接DLNA设备
点击选择DLNA设备
点击出现的licheePi Zero设备
win10自带播放器推送操作:
在PC上右键一个mp3文件
选择播放到设备
选择licheePi Zero
(如果没找到设备 则再次右键 选择播放到设备 荔枝派zero刚开DLNA客户端可能要重复这个操作几次)
找不到licheePi Zero?
注意:
手机和荔枝派zero要连接到同一个局域网
并且这个局域网不能是这个手机开的热点
比如手机A开热点 荔枝派zero连接上 那么手机A将看不到荔枝派
此时手机B再连接上手机A热点 那么手机B就能看到荔枝派
所以最好将手机和荔枝派都连接到一个路由器wifi上 不要手机开热点
手机开热点 PC和荔枝派zero连接上后 PC可以推送音视频给荔枝派zero
我用f1c100s试了下出现这个错误:
Setting pipeline to PAUSED ...
ERROR: Pipeline doesn't want to pause.
ERROR: from element /GstPipeline:pipeline0/GstOMXH264Dec-omxh264dec:omxh264dec-omxh264dec0: Could not initialize supporting library.
Additional debug info:
gstvideodecoder.c(2530): gst_video_decoder_change_state (): /GstPipeline:pipeline0/GstOMXH264Dec-omxh264dec:omxh264dec-omxh264dec0:
Failed to open decoder
Setting pipeline to NULL ...
Freeing pipeline我在builroot没有看到gst1-plugins-bayer2rgb-neon这个选项,跟这个有关系吗
你这个是gst-omx注册失败的问题 把我发文件里的那个注册文件替换你原来的文件
镜像和使用方法
gst-omx硬解码镜像.zip
硬解码输出帧格式
omxh264dec解出来的帧为yvu420(YV12)然后经过元件 autovideoconvert 转换为BGR格式给fbdev显示
那能不能直接让解码器直接输出BGR格式呢?全志硬解码api上是支持的
但是openmax修改输出格式还没试验成功 目前发现
1.在文件libcedarc\openmax\vdec\src\omx_vdec_aw_decoder_linux.c中
结构体成员eOutputPixelFormat被直接赋值帧格式常量 可能直接修改这个常量就可以输出其他格式
2.然后在文件libcedarc\openmax\vdec\inc\omx_vdec_config.h
的宏定义#define COLOR_FORMAT_DEFAULT OMX_COLOR_FormatYVU420Planar 修改后可以改变默认的omx认为的帧格式
这两处应该是很大关系的
对比一下硬解和软解的命令
gst-launch-1.0 filesrc location=bad_apple.mp4 ! qtdemux ! h264parse ! omxh264dec ! autovideoconvert ! fbdevsink
gst-launch-1.0 filesrc location=bad_apple.mp4 ! qtdemux ! avdec_h264 ! autovideoconvert ! fbdevsink
硬解比软件多用了个gstreamer元件 h264parse
这是因为avdec_h264的sink(输入)视频流格式可以是avc和byte-stream 而omxh264dec的sink只能是byte-stream
而qtdemux的src(输出)的视频流格式是avc 所以 要用元件 h264parse 将avc转化为byte-stream 给omxh264dec 不然是无法解码的
前置要求:
基于aodzip的cedar:
https://whycan.com/t_4219.html
完成以上操作后 要保证能在/dev目录下找到cedar_dev和ion
基本思路:
aodzip已经搞出了libcedar和openmax
全志的硬编解码库(即libcedarc\library\arm-linux-gnueabihf里面的库)可以操作设备/dev/cedar_dev
libcedar可以操作全志硬编解码库和设备/dev/ion
openmax是对libcedar的操作封装 用于作为ffmpeg和gstreamer的编解码器插件
全志已经对openmax操作libcedar做好了适配 我们可以用支持openmax插件的音视频编解码器进行硬件编解码
aodzip原贴里有人提到过可以使用gstreamer1.0进行验证 本贴就是通过gstreamer1.0的插件openmax调用cedar进行H264解码
注意:openmax可以作为ffmpeg的编码器插件 不能直接作为ffmpeg的解码器插件 有个例外 树莓派可用使用openmax作为ffmpeg的解码器插件 这个是特殊接口
gstremer适配:
buildroot:
因为全志的硬编解码库默认是用glibc编译的 所以要确定buildroot使用的c库是glibc
打开buildroot菜单
make menuconfig
检查
Toolchain->C library (glibc)
添加openmax组件
Target packages->Audio and video applications->bellagio
添加gstreamer组件
Target packages->Audio and video applications->gstreamer 1.x
同目录下
enable command-line parser
enable tracing subsystem
enable gst-debug trace support
enable plugin registry
install gst-launch & gst-inspect
添加gstreamer插件
同目录下
gst1-plugins-base
videotestsrc
videoconvert
videorate
gst1-plugins-bayer2rgb-neon
gst1-plugins-good
avi (*.avi video)
videofilter
gst1-plugins-bad
autoconvert
videoparsers
videosignal
fbdev 对fb设备操作的支持 选择后才能输出在fb上
fdk-aac
gst1-libav 这个是ffmpeg的解码库 可以做个软解对比
gst-omx 这个是openmax的插件接口
选择好后保存编译
make
openmax接口修改:
此时编译好后gstreamer的openmax插件接口是不可以正常使用的
使用全志的openmax插件解码器进行解码时会出现gstreamer协商错误
这是因为全志在openmax插件上新定义了颜色空间 而gstreamer的openmax接口不知道 所以我们要让gstreamer的openmax接口知道
(在文件libcedarc\openmax\include\OMX_IVCommon.h中的OMX_COLOR_FORMATTYPE枚举型下可以看到全志扩展了两个类型)
(在文件libcedarc\openmax\vdec\inc\omx_vdec_config.h的宏定义#define COLOR_FORMAT_DEFAULT OMX_COLOR_FormatYVU420Planar 可以知道解码默认输出YVU420即YV12)
在gstreamer的openmax接口添加全志的颜色空间定义:
进入目录
cd output/build/gst-omx-1.16.0/
修改文件
vim omx/gstomxvideo.c
在函数gst_omx_video_get_format_from_omx的switch下添加case
case OMX_COLOR_FormatYVU420Planar:
format = GST_VIDEO_FORMAT_YV12;
break;
保存退出
:wq
在当前目录下删掉buildroot对于gst-omx的编译构建标记
rm .stamp_built .stamp_configured .stamp_target_installed .stamp_staging_installed
回到buildroot目录下
cd ../../../
再次编译
make
此时 带gstream和openmax的文件系统构建完成
开机进行硬解码验证
gst-omx注册:
gstreamer使用openmax前要先进行注册
先备份一下注册文件
cp /etc/xdg/gstomx.conf /etc/xdg/gstomx.conf.bck
修改gst-omx插件注册文件
vi /etc/xdg/gstomx.conf
(注意使用vi时不要用方向键 不然可能会乱码 用hjkl键移动光标)
可以发现有两个omxh264dec 对这两个项 添加或者替换以下键值对
core-name=/usr/lib/libOmxCore.so
component-name=OMX.allwinner.video.decoder.avc
hacks=no-component-role;no-disable-outport
(最后这个no-disable-outport一定要加 不然无法解码)
此时注册gst-omx成功
最后一步!!!!!!
以下命令验证
使用gstreamer的插件openmax调用cedar硬解码
gst-launch-1.0 filesrc location=bad_apple.mp4 ! qtdemux ! h264parse ! omxh264dec ! autovideoconvert ! fbdevsink
命令简析
filesrc location= 要解码的文件
qtdemux 解容器 输出视频流
h264parse 流格式转换
omxh264dec 输入视频流 输出帧
autovideoconvert 帧格式转换
fbdevsink 显示在fb
使用ffmpeg的h264解码器进行软解 对比效果
gst-launch-1.0 filesrc location=bad_apple.mp4 ! qtdemux ! avdec_h264 ! autovideoconvert ! fbdevsink
验证平台:
硬件 荔枝派zero
linux 主线内核5.2荔枝派官方的
启动方式 TF卡
h264文件 bad_apple.mp4
其余的硬件编解码器可以用同样的方式使用
f1c100s也可以这样使用
至此 硬解码连接通用音视频解码器的最后一公里已经完成了 主要的多媒体功能已经步入正轨 标志着v3s和f1c100s可以摆脱方案商的奇怪sdk 使用主流的开发框架进行开发
最后感谢前人的努力 感谢aodzip 感谢挖坑网 感谢晕哥
buildroot-tiny200 (F1C100/200s) 开发包近期更新内容 * 已支持DVP摄像头 *
http://whycan.com/t_5221.html
(出处:哇酷开发者社区【全志 V3S/F1C100s/X3】)最新的tiny200 sdk已经包含了上面的cedarc
我在搞v3s
https://github.com/aodzip/libcedarc
我按照步骤弄到这 在配置打开ffmpeg的openmax 编译提示找不到omx_core. h 然后我就在buildroot里打开了相关依赖包 但我想想好像不对劲 上面链接里也有个openmax 它里面也调用了全志硬解api 按道理openmax应该是芯片厂家实现的 就是要用上面链接的openmax 如果是 那怎么把它配置成给ffmpeg调用
我在用f1c100s的测按键轮询 在对应的设备树文件添加内容
key_pins: key_pins@0 {
pins = "PE4";
function = "gpio_in";
bias-pull-up;
};
gpio_keys {
compatible = "gpio-keys-polled";
pinctrl-names = "default";
pinctrl-0 = <&key_pins>;
#address-cells = <1>;
#size-cells = <0>;
poll-interval = <20>;
button@0 {
label = "Left Joystick Right";
linux,code = <ABS_Z>;
linux,input-type = <EV_ABS>;
linux,input-value = <1>;
gpios = <&pio 4 4 GPIO_ACTIVE_LOW>; /* PE4 */
};
};
然后编译打包烧录 开机提示io被占用 没有相应的/dev/evenX
[ 0.944905] suniv-f1c100s-pinctrl 1c20800.pinctrl: pin PE4 already requested by gpio_keys; cannot claim for 1c20800.pinctrl:132
[ 0.956462] suniv-f1c100s-pinctrl 1c20800.pinctrl: pin-132 (1c20800.pinctrl:132) status -22
[ 0.964843] gpio-keys-polled gpio_keys: failed to get gpio: -22
[ 0.970843] gpio-keys-polled: probe of gpio_keys failed with error -22
[ 0.978318] input: 1c23400.lradc as /devices/platform/soc/1c23400.lradc/input/input1
我查了设备树 发现根本没占用 换了几个IO都是这样
然后我把这句屏蔽掉了 pinctrl-0 = <&key_pins>;
发现就可以了 有相应的/dev/evenX 测试也有效 只是没有pinctrl-0 = <&key_pins>;里的上拉作用
不知道为什么会这样
根据楼上说的 我找了下文档发现确实是可以这样做 有空再测试一下
Documentation\usb\gadget_printer.txt
HOWTO USE THIS DRIVER
=====================
To load the USB device controller driver and the printer gadget driver. The
following example uses the Netchip 2280 USB device controller driver:
modprobe net2280
modprobe g_printer
The follow command line parameter can be used when loading the printer gadget
(ex: modprobe g_printer idVendor=0x0525 idProduct=0xa4a8 ):
idVendor - This is the Vendor ID used in the device descriptor. The default is
the Netchip vendor id 0x0525. YOU MUST CHANGE TO YOUR OWN VENDOR ID
BEFORE RELEASING A PRODUCT. If you plan to release a product and don't
already have a Vendor ID please see www.usb.org for details on how to
get one.
idProduct - This is the Product ID used in the device descriptor. The default
is 0xa4a8, you should change this to an ID that's not used by any of
your other USB products if you have any. It would be a good idea to
start numbering your products starting with say 0x0001.
bcdDevice - This is the version number of your product. It would be a good idea
to put your firmware version here.
iManufacturer - A string containing the name of the Vendor.
iProduct - A string containing the Product Name.
iSerialNum - A string containing the Serial Number. This should be changed for
each unit of your product.
iPNPstring - The PNP ID string used for this printer. You will want to set
either on the command line or hard code the PNP ID string used for
your printer product.
qlen - The number of 8k buffers to use per endpoint. The default is 10, you
should tune this for your product. You may also want to tune the
size of each buffer for your product.
移植littlevGL版本为7.0 基于linux fb运行
从littlevGL下载基于linux fb运行的littlevGL源码
https://github.com/lvgl/lv_port_linux_frame_buffer
使用cmake构建makefile 安装cmake
apt-get install cmake
在littlevGL目录下编写cmake配置文件CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(Ui C)
#set(CMAKE_C_STANDARD 11)
SET(CROSS_COMPILE 1)
set(CMAKE_SYSTEM_NAME Linux)
#设置编译器 用buildroot里面的
set(CMAKE_C_COMPILER "/home/ljh/f1c100s/buildroot-2017.08/output/host/bin/arm-linux-gcc")
SET(TOOLCHAIN_DIR "/usr/bin/")
#SET(CMAKE_FIND_ROOT_PATH "/usr/arm-linux-gnueabi" "/usr/arm-linux-gnueabi/lib" "/usr/arm-linux-gnueabi/include")
#include_directories(/home/biglion/project/buildroot/rootfs/include)
#link_directories(/home/biglion/project/buildroot/rootfs/lib)
link_directories(/home/ljh/f1c100s/buildroot-2017.08/rootfs/lib)
#引入所有编译用到的源码目录
include_directories(
/home/ljh/f1c100s/buildroot-2017.08/rootfs/include
lv_drivers
lv_examples
lvgl
lv_drivers/display
lv_drivers/indev
lv_examples/assets
lv_examples/src/lv_demo_benchmark
lv_examples/src/lv_demo_keypad_encoder
lv_examples/src/lv_demo_printer
lv_examples/src/lv_demo_stress
lv_examples/src/lv_demo_widgets
lv_examples/src/lv_ex_get_started
lv_examples/src/lv_ex_style
lvgl/porting
lvgl/src/lv_core
lvgl/src/lv_draw
lvgl/src/lv_font
lvgl/src/lv_gpu
lvgl/src/lv_hal
lvgl/src/lv_misc
lvgl/src/lv_themes
lvgl/src/lv_widgets
lvgl/tests/lv_test_core
lvgl/tests/lv_test_objx
./
)
#通过源码目录 引入所有源文件 形成文件变量
aux_source_directory(lv_drivers LV_drivers)
aux_source_directory(lv_examples LV_examples)
aux_source_directory(lvgl LVgl)
aux_source_directory(lv_drivers/display DISPLAY)
aux_source_directory(lv_drivers/indev INDEV)
aux_source_directory(lv_examples/assets ASSETS)
aux_source_directory(lv_examples/src/lv_demo_benchmark BENCHMARK)
aux_source_directory(lv_examples/src/lv_demo_keypad_encoder ENCODER)
aux_source_directory(lv_examples/src/lv_demo_printer PRINTER)
aux_source_directory(lv_examples/src/lv_demo_stress STRESS)
aux_source_directory(lv_examples/src/lv_demo_widgets WIDGET)
aux_source_directory(lv_examples/src/lv_ex_get_started STARTED)
aux_source_directory(lv_examples/src/lv_ex_style STYLE)
aux_source_directory(lvgl/porting PORTING)
aux_source_directory(lvgl/src/lv_core CORE)
aux_source_directory(lvgl/src/lv_draw DRAW)
aux_source_directory(lvgl/src/lv_font FONT)
aux_source_directory(lvgl/src/lv_gpu GPU)
aux_source_directory(lvgl/src/lv_hal HAL)
aux_source_directory(lvgl/src/lv_misc MISC)
aux_source_directory(lvgl/src/lv_themes THEMES)
aux_source_directory(lvgl/src/lv_widgets WIDGETS)
aux_source_directory(lvgl/tests/lv_test_core TEST_CORE)
aux_source_directory(lvgl/tests/lv_test_objx TEST_OBJX)
aux_source_directory(lvgl LVgl)
aux_source_directory(./ CUR)
#引入所有要编译的源文件
add_executable(Ui
${LV_drivers}
${LV_examples}
${LVgl}
${DISPLAY}
${ASSETS}
${BENCHMARK}
${ENCODER}
${PRINTER}
${STRESS}
${WIDGET}
${STARTED}
${STYLE}
${PORTING}
${CORE}
${DRAW}
${FONT}
${GPU}
${HAL}
${MISC}
${THEMES}
${WIDGETS}
${TEST_CORE}
${TEST_OBJX}
${CUR}
)
注意:每次修改CmakeLists.txt时 最好删除目录下的CMakeCache.txt和CmakeFiles文件
形成Makefile文件
cmake .
编译
make
得到应用程序Ui
发送文件到f1c100s上执行即可看演示效果
发现左上角有闪动的光标 移除方法:
echo 0 > /sys/class/graphics/fbcon/cursor_blink
echo 0 > /sys/class/vtconsole/vtcon1/bind
楼上说到发送数据要带\n结尾 那如何设置为像单片机串口一样接收 不用带\n结尾呢?
1.linux应用程序下的串口编程 参考
https://www.cnblogs.com/silencehuan/p/11103074.html
2.shell环境下通过stty配置
stty -F /dev/ttyUSB0 raw min 1 time 10
其中raw是设置本设备不作为串口的‘控制终端’”。如果不使用该选项,会有一些输入字符影响进程运行(如一些产生中断信号的键盘输入字符 以及上面说的串口回显等)
其中min是从串口缓冲里读出的最小的接收数据
其中time是每次cat 串口的读取超时时间 单位100ms
shell操作串口参考
https://blog.csdn.net/chenliang0224/article/details/100593900
stty命令参考
http://linux.51yip.com/search/stty
没有解决,后来测试几次,都是这样的现象。
没再玩了。
我已经找到问题了 11楼
https://whycan.cn/t_4732.html#p47554
找到问题了 原来是linux下串口的会带部分收发规则 参考
https://blog.csdn.net/lvliang2008/article/details/6192863
这个 pc发给板子 然后pc收到了发的内容 的现象是因为默认开启了串口回显功能
shell环境下可以使用stty命令可以对串口进行配置
Linux 查看串口配置
stty -F /dev/ttyG0
去掉串口回显
stty -F /dev/ttyG0 -echo
还有串口默认规则是 板子使用echo "send data" > /dev/ttyG0 发送给PC时 会自动对发送数据添加换行符\n
并且接收数据时 也是通过换行符\n作为接收结束 所以PC发送给板子时必须在发送数据末尾加换行符\n
晕哥,
我昨晚测试荔枝zero,内核也是的用4.13y,USB Gadget Support在官方默认配置下,是CDC Composite Device (Ethernet and ACM) 。
这个配置,在我的电脑上未出现任何USB设备。
看到这个帖子(https://whycan.cn/t_1788.html-Zero通过otg与PC共享网络)里可以改成串口配置,我就改成了Serial Gadget (with CDC ACM and CDC OBEX support) 。电脑上就出现了USB虚拟串口。
经过测试发现虚拟串口不太正常:
1. 开发板可以正常发送到PC端的串口助手:
开发板发送:echo "125awsdQWEDFffe" > /dev/ttyGS0
2. PC端发送到开发板不正常,开发板可以接收到内容,但是PC串口助手同时也接收到了自己发送的内容:
开发板接收:cat /dev/ttyGS0
串口助手sscom5.13显示的接收:
[20:21:54.484]收←◆125awsdffe [20:22:04.544]收←◆125awsdQWEDFffe [20:22:26.619]发→◇LLLK □ [20:22:26.620]收←◆LLLK LLLK [20:22:31.627]发→◇LLLK □ [20:22:31.628]收←◆LLLK
遇到的问题就是,PC串口助手发送的同时,也接收到了自己发送的内容
你这个问题解决没有 我也遇到这个问题
你发的这个链接里10楼和我情况一样 然后我1楼发的链接的题主写了个博客
https://blog.csdn.net/lan120576664/article/details/101037170
里面测试结果的截图也是一样 都是pc发给板子 然后pc收到了发的内容
按照以下套路
https://whycan.cn/t_2889.html
发现可以产生/dev/ttyG0了 但是连接PC 没有usb设备
我发现 别人加载驱动后是这样的
# modprobe g_serial
[ 39.439805] g_serial gadget: Gadget Serial v2.4
[ 39.444487] g_serial gadget: g_serial ready
[ 39.847760] g_serial gadget: high-speed config #2: CDC ACM config
[ 39.853932] gs_console_connect: port num [0] is not support console
我加载后 是这样的 少了后面两句
# modprobe g_serial
[ 28.790748] g_serial gadget: Gadget Serial v2.4
[ 28.795303] g_serial gadget: g_serial ready
我用spi1接8266-12f 数据线时钟线都有数据了 可是出现了以下错误 不知道什么原因 插个眼
...
esp8089_spi: /home/dika/DVPM_linux-5.2/spiwifi1/ESP8089-SPI-master/spi_sif_esp.c, 1681
rx:[0xff],[0x00],[0x02],[0xff],[0xff],[0xff],[0xff],[0xff],[0xff],[0xff]
esp8089_spi: /home/dika/DVPM_linux-5.2/spiwifi1/ESP8089-SPI-master/spi_sif_esp.c, 1694
rx:[0xff],[0x00],[0x01],[0xff],[0xff],[0xff],[0xff],[0xff],[0xff],[0xff]
esp8089_spi: spierr byte read cmd resp 0x00 no recv
esp8089_spi: spierr byte read cmd resp 0x00 no recv
...
esp8089_spi: spierr byte read cmd resp 0x00 no recv
看到很多人问为什么rootfs构建出来是100m的
我说说我的发现 如果你们是用
http://nano.lichee.pro/build_sys/rootfs.html
下载的.config 那么就是100m的 因为这个是给tf卡准备的
给flash的应该是先用没有配置的 然后按照网站给的手动配置几个项
一些配置的简单说明
Target options --->
Target Architecture Variant (arm926t) ---> // arm926ejs架构
[ ] Enable VFP extension support // Nano 没有 VFP单元,勾选会导致某些应用无法运行
Target ABI (EABI) --->
Floating point strategy (Soft float) ---> // 软浮点
System configuration --->
(Lichee Pi) System hostname // hostname
(licheepi) Root password // 默认账户为root 密码为licheepi
[*] remount root filesystem read-write during boot // 启动时重新挂在文件系统使其可读写
这样构建出来的rootfs就几个m 再需要什么功能自己加
setenv bootm_boot_mode sec
setenv machid 1029
load mmc 0:1 0x41000000 zImage
load mmc 0:1 0x41800000 suniv-f1c100s-licheepi-nano.dtb
bootz 0x41000000 - 0x41800000粘贴到u-boot 命令行, 手动执行这几行命令看效果。
楼主 你这个是v3s的地址
f1c100s的地址和具体含义参考官网 http://nano.lichee.pro/build_sys/bootargs.html
以下仅参考地址
setenv bootargs console=tty0 console=ttyS0,115200 panic=5 rootwait root=/dev/mmcblk0p2 rw
load mmc 0:1 0x80C00000 suniv-f1c100s-licheepi-nano.dtb
load mmc 0:1 0x80008000 zImage
bootz 0x80008000 - 0x80C00000
http://nano.lichee.pro/build_sys/rootfs.html
里面有一句 buildroot不能进行多线程编译
如图 我觉得tab 1 2 3 三个按钮太大了 想改它们的高度 如何改
lv_obj_t * obj = lv_tabview_create(scr, NULL);
lv_obj_set_size(obj, 197, 231);
lv_obj_t * t1 = lv_tabview_add_tab(obj, "Tab 1");
lv_obj_t * t2 = lv_tabview_add_tab(obj, "Tab 2");
//lv_obj_set_size(t1, 20,20);
//lv_obj_set_event_cb(obj, general_event_handler);
lv_obj_t * label = lv_label_create(t1, NULL);
lv_label_set_text(label, "This the first tab");
label = lv_label_create(t2, NULL);
lv_label_set_text(label, "Second tab");
按道理应该是lv_obj_set_size(t1, 20,20); 但是没有用
原来是设备树没配好 重要的设备节点漏了
参考了链接 http://linux-sunxi.org/SPIdev
把/dev/spidev1.0配出来了
想通过应用层操作spi
首先我保证这几个内核配置是开了的:
CONFIG_SPI_SUN6I=y
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_SPIDEV=y
然后因为我用spi flash启动 已经占用了spi0 所以要加新的接口spi1
改设备树文件suniv.dtsi 通过参考spi0来增加
spi0_pins_a: spi0-pins-pc {
pins = "PC0", "PC1", "PC2", "PC3";
function = "spi0";
};
spi1_pins_a: spi1-pins-pa {
pins = "PA2", "PA0", "PA3", "PA1";
function = "spi1";
};
改设备树文件suniv-f1c100s-licheepi-nano.dts 通过参考spi0来增加
&spi0 {
pinctrl-names = "default";
pinctrl-0 = <&spi0_pins_a>;
status = "okay";
flash: w25q128@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "winbond,w25q128", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <50000000>;
partitions{
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
lable = "u-boot";
reg = <0x000000 0x100000>;
read-only;
};
partition@100000 {
lable = "dtb";
reg = <0x100000 0x10000>;
read-only;
};
partition@110000 {
label = "kernel";
reg = <0x110000 0x400000>;
read-only;
};
partition@510000 {
label = "rootfs";
reg = <0x510000 0xAF0000>;
};
};
};
};
&spi1 {
pinctrl-names = "default";
pinctrl-0 = <&spi1_pins_a>;
status = "okay";
};
然后编译内核和设备树重新打包下载进板子
如果添加spi1成功了 会多出来个/dev/spi1 但实际上没有 只有原来的spi0.0 说明可能哪里错了 大神来指点一下?
1. RGB666 这是硬件位深度18bit, f1c100s实际上也可以输出RGB888, 但这样多占了几个IO, 当然你不介意显示精度也可以RGB111, 只是这样画面太美不敢想象.
2. 不管实际硬件是RGB888/RGB666/RG565/RGB111, 主线Linux驱动为了方便处理都是当RGB888, 每像素占用32bit宽度.
3. lv_conf.h 的 32bit 估计是他显存的处理方式, 也是和2一样, 为了方便软件处理, 最终如果你的物理/虚拟显示屏是16bit(2字节宽度), 在驱动部分再做一次 RGB888 <=> RGB656 的双向转换.
以上说法可能不全对, 仅供参考.
原来做了转换 明白他们的关系了 感谢晕哥讲解
1.首先可以从licheePi nano原理图中看出LCD接线是RGB666的 也就是位深度是18
2.从官网设备树找到屏幕设备是qd43003c0_40 然后在panel-simple.c找到该设备属性
static const struct drm_display_mode qd43003c0_40_mode = {
.clock = 9000,
.hdisplay = 480,
.hsync_start = 480 + 8,
.hsync_end = 480 + 8 + 4,
.htotal = 480 + 8 + 4 + 39,
.vdisplay = 272,
.vsync_start = 272 + 4,
.vsync_end = 272 + 4 + 10,
.vtotal = 272 + 4 + 10 + 2,
.vrefresh = 60,
};
static const struct panel_desc qd43003c0_40 = {
.modes = &qd43003c0_40_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 95,
.height = 53,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
};
可以看到位深度是RGB888 也就是24
3.然后在littlevGL的lv_conf.h要把位深度设置为32显示才正常
这几个位深度度如何理解?什么情况该怎么填?
工程地址是哪个?
http://nano.lichee.pro/application/littlevgl.html
官网littlevGL的使用
gcc的是rootbuild里面那个
编译后提示在main.c里
错误找不到fbdev_flush
警告找不到fbdev_init
在荔枝派linux里找的到/dev/fb0
我是用cmake构建makefile的
官网里面有一句 我没有写:
SET(CMAKE_FIND_ROOT_PATH "/usr/arm-linux-gnueabi" "/usr/arm-linux-gnueabi/lib" "/usr/arm-linux-gnueabi/include")
# lib 与 include 的目录,使用 ``arm-linux-gnueabi-gcc -v`` 也可输出目录相关信息
因为我用的GCC是rootbuild里面的 找不到它的lib和include目录在哪
看下这个驱动:
https://github.com/torvalds/linux/blob/master/drivers/char/hangcheck-timer.cstatic DEFINE_TIMER(hangcheck_ticktock, hangcheck_fire);
触发时间间隔在回调函数里面设定.
按照你给的驱动参考 可以正常使用了 谢谢
f1c100s linux交叉编译驱动模块里使用软件定时器
我找了网上linux内核定时器的方法 发现定时器结构体是这样的
struct timer_list {
/*
* All fields that change during normal runtime grouped to
* the same cacheline
*/
struct hlist_node entry;
unsigned long expires;
void (*function)(unsigned long);
unsigned long data;
u32 flags;
int slack;
#ifdef CONFIG_TIMER_STATS
int start_pid;
void *start_site;
char start_comm[16];
#endif
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
而我看f1c100s的linux内核文件include/linux/timer.h里的定时器结构是这样的:
struct timer_list {
/*
* All fields that change during normal runtime grouped to the
* same cacheline
*/
struct hlist_node entry;
unsigned long expires;
void (*function)(struct timer_list *);
u32 flags;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
里面有东西没有 特别是成员data 这个是循环时间 没有它怎么指定定时器时间?
启动定时器用的是 DEFINE_TIMER(_name, _function) 运行时不能正常调用回调函数
我看了下你的sys_config
把
[uart_para]
uart_debug_port = 0
uart_debug_tx = port:PE1<5>
uart_debug_rx = port:PE0<5>
改成
[uart_para]
uart_debug_port = 0
uart_debug_tx = port:PE1<5>
;uart_debug_rx = port:PE0<5>
把
[uart_para0]
uart_used = 1
uart_port = 0
uart_type = 2
uart_debug_tx = port:PE1<5>
uart_debug_rx = port:PE0<5>
改成
[uart_para0]
;uart_used = 1
;uart_port = 0
;uart_type = 2
;uart_debug_tx = port:PE1<5>
;uart_debug_rx = port:PE0<5>
/**
* Initialize a display buffer
* @param disp_buf pointer `lv_disp_buf_t` variable to initialize
* @param buf1 A buffer to be used by LittlevGL to draw the image.
* Always has to specified and can't be NULL.
* Can be an array allocated by the user. E.g. `static lv_color_t disp_buf1[1024 * 10]`
* Or a memory address e.g. in external SRAM
* @param buf2 Optionally specify a second buffer to make image rendering and image flushing
* (sending to the display) parallel.
* In the `disp_drv->flush` you should use DMA or similar hardware to send
* the image to the display in the background.
* It lets LittlevGL to render next frame into the other buffer while previous is being
* sent. Set to `NULL` if unused.
* @param size_in_px_cnt size of the `buf1` and `buf2` in pixel count.
*/
void lv_disp_buf_init(lv_disp_buf_t * disp_buf, void * buf1, void * buf2, uint32_t size_in_px_cnt)
{
memset(disp_buf, 0, sizeof(lv_disp_buf_t));
disp_buf->buf1 = buf1;
disp_buf->buf2 = buf2;
disp_buf->buf_act = disp_buf->buf1;
disp_buf->size = size_in_px_cnt;
}
硬件是STM32F429 RGB565 470272 显示区地址是在外扩SDRAM
一开始buf2是不使用的 buf1是使用的 buf1地址是在显示区之外
那这里有两个buffer 一个是显示buffer 一个是缓冲buf1 这个是叫双缓冲还是单缓冲?
那如果使用buf2 就有三个buffer 一个是显示buffer 两个是缓冲buf1 buf2 这个是叫三缓冲还是双缓冲?
我都搞混了
https://whycan.cn/files/members/1105/7.png
初始化完成后读寄存器
左边是ram运行 右边是flash运行
这个红色的位就很皮了 感觉和它有关 查了600的手册 发现这个位并没有定义 在程序上手动置低又不行 置不低
看错了 是spi0的 不影响
晕哥 说:樊星 说:我是加载到flash跑的。没试过加到人RAM里。另我看到在咱们论坛令一个帖子里,chong大神基于Linux4.19出过一个补丁。好像是也是解决的类似问题。就是在RAM里能运行在flash里不能运行。我能力弱,还没看懂那个补丁,说是有clk设置不对。晕哥应该知道。
那个帖子后面那个补丁可以在 FLASH里面跑了, 可以关注一下.
对比了一下提供的补丁,里面是修改了USB PHY的时钟位,以前错误的是bit8(应该不是F1c100s的),后面变成bit1(根据手册上看bit1是对的)。然后这个工程我当时写了一个usb_phy_open_clock();函数,里面USBPHY_CLK_GAT_BIT定义的是1没错。所以可能还有其它地方是sunxi帮忙初始化了的,这个后面再仔细翻一翻Linux的代码。
对比了一下RAM运行和flash运行时 读了USB PHY的时钟位 RAM运行的是0x3 flash运行的是0x2 也就是说brom除了D1要置高外 D0也要置高 但改了后还是在flash不能运行
我还发现 flash运行在初始化时USBC系列的寄存器 除了ISCR外都写不进去 比如VEND0 PCTL 写操作完一读 都是0 估计是哪个时钟没配好
工程打包发上来看看神马情况.
基于晕哥给的F1C100S的KeilMDK裸机程序
我初始化好DRAM后 想在KeilMDK里把裸机程序加载进DRAM
我修改了指定rom和ram的文件
然后编译出了问题: Image does not have an entry point. (Not specified or not set due to multiple choices.)
上网一查 说是没指定入口 于是在Misc Controls添加了--entry Reset_Go
结果编译提示:Ignoring --entry command. Cannot find argument 'Reset_Go'.
黑人问号????求大神出马
Answer: From IAR, I was told (and have confirmed) that the following is the correct syntax:
"bne.n 1f\n"
Or in context:void irqrestore(int flags)
{
asm volatile(
"tst %0, #1\n"
"bne.n 1f\n"
"cpsie i\n"
"1:\n"
:
: "r" (flags)
: "memory");
}IAR的语法看起来和gcc 内联 汇编语法一样。
按上面的语法改下试一试.
对于MRS MSR报错:
Error[Og006]: Error in inline assembly: "This instruction is not available in the selected cpu/core"
https://whycan.cn/files/members/3/20140903173055295.jpg
你说的是这个DEMO对吧?
https://whycan.cn/t_1527.html#p8241比如图上的 CPSR 寄存器打开/关闭 IRQ/FIQ 中断的指令所有ARM9都是一样的,
但是和具体外设相关就不同了,
比如新唐NUC90x用的是 AIC 中断管理(IP???), f1c100s 用的是 (INTC),
还有各自的外设配置(比如上面demo中定时器中断)也要看对应的手册设置。反正,套路相同, 只是外设不同,指令集、内核都是一样的。
对的 比较在意汇编写的启动文件内容
还有 我把那一段
__asm
{
MRS temp, CPSR
AND temp, temp, 0x7F
MSR CPSR_c, temp
}
放入IAR工程 居然认不出里面的汇编指令MRS MSR
lilo 说:逸俊晨晖 说:如题 Xboot可以支持usb吗 在带有LCD屏的应用中 BSP Linux系统开销会不会比Xboot大很多
xboot 目前不支持 usb 协议栈,
你这种需求最好还是用官方 melis对,melis 更轻量级了.
唱戏机就是用 melis 2.0的:
https://whycan.cn/t_1720.html网上能下载到免费都是 melis 1.0 版本的,而且还不知道有没有坑。
melis下载下来还不会用=(
感谢晕哥和原贴LZ
页次: 1