@lwhmen 666
bigfly 发布的最佳帖子
-
Melis4.0测试cedar多媒体解码库,视频和lvgl混合显示发布在 MR Series
1.测试audio_test命令播放mp3
首先要把cedar模块编译进内核:在 melis 的根目录执行 make menuconfig 命令,选中 cedar 模块。
Modules Setup -->cedar module support
测试命令也包含进来:
Kernel Setup --> Drivers Test Sample --> cedar Test
编译,烧录,运行,输入help命令可以看到下面的命令:
msh />help ...... cedar_close - cedar_close cedar_test - cedar_test audio_close_test - audio_close_test audio_test - audio_play_test ......1.1 finish命令中文件路径的写法(测试)
audio_test命令的格式为:
audio_test [文件名]我的sd卡目录下有个 mp3 文件夹,在finish中进入文件夹后的路径为:
cd /mnt/F/mp3 msh /mnt/F/mp3>ls 1906.真的爱你-Beyond.mp3 1912.千千阙歌-陈慧娴.mp3 1916.红日-李克勤.mp3 1917.都是你的错-陈慧琳.mp3 1917.都是你的错65k.mp3 distance.mp3这时,我要播放distance.mp3,我使用了下面4种路径:
audio_test /mnt/F/mp3/distance.mp3 ------- 播放失败 audio_test \\mnt\\F\\mp3\\distance.mp3 ------- 播放失败 audio_test F:\\mp3\\distance.mp3 ======= 播放成功 audio_test F:/mp3/distance.mp3 ------- 播放失败只有一种路径是正确的:
audio_test F:\\mp3\\distance.mp3测试播放纯音频文件不用考虑图层,比较简单。
2.测试cedar_test命令播放mp4
先禁止melis桌面加载,在《startup.sh》注释掉相关内容:
packecho "Execute startup script begin.............." #insmod d:\mod\orange.mod #insmod d:\apps\desktop.mod echo "...............Execute startup script end"此时开机只显示全志logo。查询一下此时的图层信息:
msh />disp screen 0: # allwinner logo使用 ch[0] lyr[0]图层,alpha_mode = 0 (pixel alpha),alpha = 255,zorder 为 0 BUF enable ch[0] lyr[0] z[0] prem[N] a[pixel 255] fmt[ 0] fb[ 640, 480; 640, 480; 640, 480] crop[ 0, 0, 640, 480] frame[ 80, 0, 640, 480] addr[0x4132b000,0x00000000,0x00000000] flags[0x 0] trd[0,0]alpha = 255属于全覆盖,不和其他图层混合显示。zorder=0表示最底层,其他图层只要大于0就会覆盖它。当然,覆盖是在图层都是alpha=255的情况下。
2.1 不清除logo图层,无法显示视频
在这种情况下,使用cedar_test播放视频,只有声音,没有图像。
msh />cedar_test F:\\hanfu02.mp4这种情况下,查看一下图层信息(可以看到2个图层都属于ch[0],图层格式一个是RGB,一个是YUV):
msh />disp screen 0: BUF enable ch[0] lyr[0] z[0] prem[N] a[pixel 255] fmt[ 0] fb[ 640, 480; 640, 480; 640, 480] crop[ 0, 0, 640, 480] frame[ 80, 0, 640, 480] addr[0x4132b000,0x00000000,0x00000000] flags[0x 0] trd[0,0] BUF enable ch[0] lyr[1] z[1] prem[N] a[pixel 0] fmt[ 72] fb[1280, 720; 640, 360; 640, 360] crop[ 0, 0,1280, 720] frame[ 0, 15, 800, 450] addr[0x42b2d000,0x00000000,0x4273a000] flags[0x 0] trd[0,0]
这里是不是说同一通道的4图层,只能使用相同的格式?2.2 使用disp_layer_alpha_test命令清除logo图层,正常播放视频的disp_layer_alpha_test命令再修改一下:
int disp_layer_alpha_test(int argc, char **argv) { ...... if (argc == 2) { // 如果带有一个参数,不用理会参数是什么,清除所有图层 disp_layer_clear_all(0); return 0; }else if(argc == 4){ // 带3个参数,分别是: [1]=mode [2]=alpha [3]=zorder mode = atoi(argv[1]); alpha = atoi(argv[2]); i = atoi(argv[3]); show_ui_layer(&test_cfg, 1, mode, alpha,(unsigned char)i); return 0; } else g_screen_index = 0; ...... }输入下面的命令,注意:只带一个参数。
msh />disp_layer_alpha_test 0查询图层信息(可以看到没有图层信息):
msh />disp screen 0: de_rate 300000000 hz, ref_fps: 59 mgr0: 800x480 fmt[rgb] cs[0x204] range[full] eotf[0x4] bits[8bits] err[0] force_sync[0] unblank direct_show[false] dmabuf: cache[0] cache max[0] umap skip[0] overflow[0] lcd output backlight(192) fps:58.4 800x 480 err:77961 skip:16 irq:124292 vsync:0 vsync_skip:0现在才可以正常播放视频。播放完毕后,查询图层信息:
msh />disp screen 0: # vi图层ch[0] lyr[1]是,alpha_mode = 0 (pixel alpha),alpha = 0,format = 72,zorder 为 1 BUF enable ch[0] lyr[1] z[1] prem[N] a[pixel 0] fmt[ 72] fb[1280, 720; 640, 360; 640, 360] crop[ 0, 0,1280, 720] frame[ 0, 15, 800, 450] addr[0x42b2d000,0x00000000,0x4273a000] flags[0x 0] trd[0,0]3. lvgl设置
3.1 ui图层配置
lvgl属于ui图层,所以使用ch[1] lyr[0] ,alpha_mode = 2 (global pixel alpha),alpha = 255,format = 0(ARGB),zorder 为 2(zorder可以改变,其他参数固定)。仿照 show_ui_layer() 写一个show_lvgl_layer() 的函数:
int request_lvgl_layer(unsigned char zorder) { static int isMemInited=0; // struct test_layer_cfg test_cfg; struct test_layer_cfg *cfg = &test_cfg; memset(&test_cfg, 0, sizeof(struct test_layer_cfg)); printf("request mem_id 0,800, 480,\n"); // 第一次初始化,清除所有图层,申请内存;后面就不用了,只是改变zorder if(isMemInited == 0){ disp_layer_clear_all(g_screen_index); disp_mem(0, 800, 480, 0, "r"); memset(g_p_mem_base,0,800*480*4); } isMemInited = 1; cfg->mem_id = 0; cfg->screen_id = 0; cfg->layer_cfg.channel = 1; cfg->layer_id = 0; cfg->layer_cfg.layer_id = 0; cfg->layer_cfg.info.fb.format = 0; cfg->layer_cfg.info.fb.size[0].width = 800; cfg->layer_cfg.info.fb.size[0].height = 480; cfg->layer_cfg.info.fb.crop.x = 0; cfg->layer_cfg.info.fb.crop.y = 0; cfg->layer_cfg.info.fb.crop.width = 800; cfg->layer_cfg.info.fb.crop.height = 480; cfg->layer_cfg.info.fb.align[0] = 4; cfg->layer_cfg.info.mode = 0; cfg->layer_cfg.info.alpha_mode = 2; cfg->layer_cfg.info.alpha_value = 255; cfg->layer_cfg.info.zorder = zorder; cfg->layer_cfg.info.screen_win.x = 0; cfg->layer_cfg.info.screen_win.y = 0; return disp_layer_cfg(cfg); }3.2 lvgl本身配置
参考文章《LVGL视频播放界面实现方法》。
需要在lv_conf.h中设置参数:
#define LV_COLOR_SCREEN_TRANSP 1然后设置界面背景色的透明度,LV_OPA_0 为透明,LV_OPA_COVER为覆盖,根据需要配置:
/* init screen style */ static lv_style_t style_scr_act; lv_style_init(&style_scr_act); /* set style to LV_OPA_0 为透明,LV_OPA_COVER为覆盖*/ lv_style_set_bg_opa(&style_scr_act, LV_OPA_0); lv_obj_add_style(lv_scr_act(), &style_scr_act, 0);测试界面源码:
void lv_example_btn_1(void) { // 创建一个组,稍后将需要使用键盘或编码器或按钮控制的部件(对象)添加进去,并且将输入设备和组关联 // 如果将这个组设置为默认组,那么对于那些在创建时会添加到默认组的部件(对象)就可以省略 lv_group_add_obj() lv_group_t * g = lv_group_create(); // 将上面创建的组设置为默认组 // 如果稍后创建的部件(对象),使用默认组那必须要在其创建之前设置好默认组,否则不生效 lv_group_set_default(g); // 将输入设备和组关联(使用前先打开上面注释掉的头文件) lv_indev_set_group(g_keypad_device_object, g); // 键盘 //lv_indev_set_group(lv_win32_encoder_device_object, g); // 鼠标上的滚轮(编码器) /* init screen style */ static lv_style_t style_scr_act; lv_style_init(&style_scr_act); /* set style to LV_OPA_0,no cover*/ lv_style_set_bg_opa(&style_scr_act, LV_OPA_0); lv_obj_add_style(lv_scr_act(), &style_scr_act, 0); #define RIGHT_OFFSET 40 /* 创建一个btn部件(对象) */ lv_obj_t * btn1 = lv_btn_create(lv_scr_act()); // 创建一个btn部件(对象),他的父对象是活动屏幕对象 lv_obj_set_size(btn1, 100, 50); lv_obj_align(btn1, LV_ALIGN_LEFT_MID, 140, 165); lv_obj_t * btn2 = lv_btn_create(lv_scr_act()); // 创建一个btn部件(对象),他的父对象是活动屏幕对象 lv_obj_set_size(btn2, 100, 50); lv_obj_align_to(btn2, btn1, LV_ALIGN_OUT_RIGHT_MID, RIGHT_OFFSET, 0); lv_obj_t * btn3 = lv_btn_create(lv_scr_act()); // 创建一个btn部件(对象),他的父对象是活动屏幕对象 lv_obj_set_size(btn3, 100, 50); lv_obj_align_to(btn3, btn2, LV_ALIGN_OUT_RIGHT_MID, RIGHT_OFFSET, 0); lv_obj_t * btn4 = lv_btn_create(lv_scr_act()); // 创建一个btn部件(对象),他的父对象是活动屏幕对象 lv_obj_set_size(btn4, 100, 50); lv_obj_align_to(btn4, btn3, LV_ALIGN_OUT_RIGHT_MID, RIGHT_OFFSET, 0); lv_obj_t * slider = lv_slider_create(lv_scr_act()); lv_obj_align(slider, LV_ALIGN_BOTTOM_MID, 0, -20); }3.3 播放视频效果
播放视频效果(按键切换):

原文链接:https://blog.csdn.net/hwd00001/article/details/130145030
-
【米尔MYD-YT507开发板试用】基于Fluter+Django+OpenCV的米尔行车记录仪发布在 其它全志芯片讨论区
经过充分的学习T507开发板,最终选择应用Fluter+Django+OpenCV架构,来实现了一款米尔行车记录仪,现将实现的具体内容,与大家分享。
目录:
- 行车记录仪业务逻辑规划
- 硬件设备准备
- 摄像头信息记录和实时画面播放服务开发
- 摄像头视频信息记录
- 摄像头服务的完整代码
- 历史数据RestFul服务开发
- Flutter Web界面开发
- 整体运行效果
- 车试
- 实际代码使用
- 感谢
- 总结
一、行车记录仪业务逻辑规划
经过详细的分析,规划了如下的基本业务逻辑结构:

整体分为三个部分:
-
记录服务:用于记录摄像头拍摄的视频信息,以及提供摄像头当前画面的实时播放服务。
-
Django服务:包括RestFul提供API接口获取历史数据信息,以及为Flutter的Web界面提供访问服务。
-
Flutter Web界面,用于实时画面播放、历史记录播放的界面。
为了又快又好的开发行车记录仪的实际界面,以及后续进行各移动平台的App开发,选择了Flutter。事实证明,坑太多了。不过,跨平台特性,确实好。
二、硬件设备准备:
开发这款行车记录仪,实际使用到的硬件设备如下:
1.主控板:米尔MYD-YT507开发板
2.摄像头:海康威视DS-E11 720P USB摄像头
3.存储卡:闪迪32GB高速MicroSD存储卡
4.路由器:云来宝盒无线路由器
路由器没有拍照,用普通无线路由器即可,当然带宽越高越好。
开发板上有两个USB3.0接口,选一个接上路由器即可。
然后,将开发板使用网线连接到路由器,再上电,就可以进行实际的操作了。
我这边实际使用中,电源接口有点松,容易突然断电,所以使用胶带进行了加固。
三、摄像头实时画面播放服务开发
在之前尝试MJPEG视频流直播的时候,使用了mjpeg_streamer,但不清楚如何进行视频的分割。
因为行车记录仪,一般都是按照一定的时间进行视频的分割存放,避免单个视频过大。
经过仔细的学习了解,OpenCV也可以获取摄像头的信息,并按照需要写入文件。
最后,采用了Python+OpenCV的方案,有Python负责具体的逻辑,Python-OpenCV负责摄像头视频数据的采集。
视频采集部分,包含的具体功能为:
- 能够采集摄像头的数据
- 能够提供实时视频查看
- 能够按时间写入视频数据到文件,自动进行分割
采集摄像头的数据,Python-opencv搞定。
写入视频数据到文件,Python简单搞定。
提供实时视频预览,这个花了不少功夫。
因为同时要写入到文件,还要提供预览,数据需要复用。
经过学习了解,可以将Python-opencv采集的画面,按帧在HTTP以JPEG数据发送,那么播放端,就能收到MJPEG数据流,进行播放了。
因此,第一版,参考资料,实现了一个Python版的MJPEG播放服务,读取帧,写入临时文件,然后从临时文件读取数据返回。
为了提高效率,还进行了优化,不写入临时文件,直接在内存中进行转换。
最终形成的代码如下:
# http服务器请求处理:网页、MJPEG数据流 class CamHandler(BaseHTTPRequestHandler): def do_GET(self): # mjpeg推流 if self.path.endswith('.mjpg'): self.send_response(200) self.send_header('Content-type','multipart/x-mixed-replace; boundary=--jpgboundary') self.end_headers() while True: if is_stop: break try: # rc,img = cameraCapture.read() rc,img = success,frame if not rc: continue if True: imgRGB=cv2.cvtColor(img,cv2.COLOR_BGR2RGB) jpg = Image.fromarray(imgRGB) tmpFile = BytesIO() jpg.save(tmpFile,'JPEG') self.wfile.write(b"--jpgboundary") self.send_header(b'Content-type','image/jpeg') self.send_header(b'Content-length',str(tmpFile.getbuffer().nbytes)) self.end_headers() jpg.save(self.wfile,'JPEG') else: img_fps = JPEG_QUALITY_VALUE img_param = [int(cv2.IMWRITE_JPEG_QUALITY), img_fps] img_str = cv2.imencode('.jpg', img, img_param)[1].tobytes() # change image to jpeg format self.send_header('Content-type','image/jpeg') self.end_headers() self.wfile.write(img_str) self.wfile.write(b" --jpgboundary ") # end of this part time.sleep(0.033) except KeyboardInterrupt: self.wfile.write(b" --jpgboundary-- ") break except BrokenPipeError: continue return # 网页 if self.path == '/' or self.path.endswith('.html'): self.send_response(200) self.send_header('Content-type','text/html') self.end_headers() self.wfile.write(b'<html><head><title>Live video</title></head><body>') self.wfile.write(('<img src="http://%s/live.mjpg"/>' % self.headers.get('Host')).encode()) self.wfile.write(b'</body></html>') return这段代码,提供了两个功能:
-
如果通过浏览器访问http://ip:端口/index.html,就会返回包含MJPEG调用地址的网页
-
如果通过浏览器访问http://ip:端口/live.mjpg,就会返回MJPEG流媒体数据,以便播放
在开发过程中,运行该服务后,随时可以通过浏览器查看效果。
其中涉及到opencv相关的知识,以及webserver相关的知识,大家可以了解相关的资料做基础,这里就不详细说了。
本来以为提供了MJPEG服务,就能够在Flutter开发的Web界面中调用了。然而,实际使用时,发现坑来了。
Flutter的公共库里面,有MJPEG的库,但是在目前的版本中,已经不能使用了。且官方认为用的人不多,在可预见的将来,不会修复。悲催啊!!!
条条大道通罗马,此处不通开新路。
经过再次的学习了解,Flutter的Video功能,支持Stream模式,其可以采用WebSocket的方式来获取数据,然后进行播放。
那么,只要能够在服务端,将获取的帧数据,使用WebSocket提供,就能够正常播放了。
最终,使用Python开发了能够提供实时视频数据的WebSocket服务,具体代码如下:
# websocket服务请求处理 async def CamTransmitHandler(websocket, path): print("Client Connected !") try : while True: # rc,img = cameraCapture.read() rc,img = success,frame if not rc: continue img_fps = JPEG_QUALITY_VALUE img_param = [int(cv2.IMWRITE_JPEG_QUALITY), img_fps] encoded = cv2.imencode('.jpg', img, img_param)[1] data = str(base64.b64encode(encoded)) data = data[2:len(data)-1] await websocket.send(data) # cv2.imshow("Transimission", frame) # if cv2.waitKey(1) & 0xFF == ord('q'): # break # cap.release() except EXCEPTION_CONNECTION_CLOSE as e: print("Client Disconnected !") # cap.release() except: print("Someting went Wrong !")这个部分比之前的更简单,就是简单的转换数据,喂数据给WebSocket即可。
上述的两部分代码中,都没有包含完整的逻辑处理过程,只有关键代码部分。
各部分分别讲完以后,将提供完整的代码以供学习。
到这里,实时流媒体功能就实现了。
四、摄像头视频信息记录
实际上,上一步的实时视频功能,也依赖于这一步,因为其需要共享实际获取的摄像头信息。
其基本逻辑也比较简单,步骤如下:- 初始化opencv,开始摄像头数据帧的获取
- 检测是否达到预定时间
- 未达到时间,则继续写入当前视频
- 达到时间了,则关闭当前视频,写入缩略图,并开启新的文件写入
具体代码如下:
# 捕获摄像头 cameraCapture = cv2.VideoCapture(CAMERA_NO) # 摄像头参数设置 cameraCapture.set(cv2.CAP_PROP_FRAME_WIDTH, 320) cameraCapture.set(cv2.CAP_PROP_FRAME_WIDTH, 240) cameraCapture.set(cv2.CAP_PROP_SATURATION, 135) fps = 30 size=(int(cameraCapture.get(cv2.CAP_PROP_FRAME_WIDTH)),int(cameraCapture.get(cv2.CAP_PROP_FRAME_HEIGHT))) # 读取捕获的数据 success,frame = cameraCapture.read()...
while True: if is_stop: success = False break; success,frame = cameraCapture.read() if not success: continue time_now = get_current_time() if time_now["time"] - time_record["time"] >= ROTATE_TIME: if time_record_prev: thubm_file = get_file_name(time_record_prev, 'thumbs', 'jpg') print("[Info] write to thumb: %s" % thubm_file) if not os.path.isfile(thubm_file): cv2.imwrite(thubm_file, frame) time_record = time_now time_record_prev = get_current_time() video_file = get_file_name(time_record_prev, 'videos', MEDIA_EXT) print("[Info] write to video: %s" % video_file) # encode = cv2.VideoWriter_fourcc(*"mp4v") encode = cv2.VideoWriter_fourcc(*'X264') # encode = cv2.VideoWriter_fourcc(*'AVC1') # encode = cv2.VideoWriter_fourcc(*'XVID') # encode = cv2.VideoWriter_fourcc(*'H264') videoWriter=cv2.VideoWriter(video_file, encode,fps,size) # mp4 numFrameRemaining = ROTATE_TIME * fps #摄像头捕获持续时间 while success and numFrameRemaining > 0: videoWriter.write(frame) success,frame = cameraCapture.read() numFrameRemaining -= 1 cameraCapture.release()上述代码的逻辑其实很清晰,有opencv的基础,一看就懂。
有一个关键点需要注意的就是
encode = cv2.VideoWriter_fourcc(*'X264'),在不同的环境下面,提供的编码方式不完全相同。在米尔MYD-YT507开发板的Ubuntu环境中,可以使用X264编码。
上述代码,会持续不断的读取摄像头的数据帧,存放到frame变量中,然后写入到视频文件中。并进行时间判断,以确定是否需要写入到新的视频文件中。
frame变量,在之前实时视频服务中,也会使用,相当于是共享了。
五、摄像头服务的完整代码
经过上面的两个部分,就完成了摄像头部分的服务代码。
整体的代码如下:
# -*- coding: utf-8 -*- import signal import cv2 import time from PIL import Image from threading import Thread from http.server import BaseHTTPRequestHandler,HTTPServer from socketserver import ThreadingMixIn from io import BytesIO import os import sys import websockets import asyncio import base64 import ctypes import inspect CAMERA_NO = 2 ROTATE_TIME = 120 MJPEG_ENABLE = 1 WEBSOCKET_ENABLE = 1 MJPEG_SERVER_PORT = 28888 WEBSOCKET_PORT = 28889 JPEG_QUALITY_VALUE = 65 STORE_DIR = "./data/" if os.uname()[0] == 'Darwin' else "/sdcard/data/" MEDIA_EXT = "mkv" EXCEPTION_CONNECTION_CLOSE = websockets.exceptions.ConnectionClosed if sys.version[:3] == '3.6' else websockets.ConnectionClosed def _async_raise(tid, exctype): """raises the exception, performs cleanup if needed""" try: tid = ctypes.c_long(tid) if not inspect.isclass(exctype): exctype = type(exctype) res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype)) if res == 0: # pass raise ValueError("invalid thread id") elif res != 1: # """if it returns a number greater than one, you're in trouble, # and you should call it again with exc=NULL to revert the effect""" ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None) raise SystemError("PyThreadState_SetAsyncExc failed") except Exception as err: print(err) def stop_thread(thread): """终止线程""" _async_raise(thread.ident, SystemExit) # 信号处理回调 def signal_handler(signum, frame): # global cameraCapture # global thread # global server # global is_stop # global success print('signal_handler: caught signal ' + str(signum)) if signum == signal.SIGINT.value: print('stop server:') is_stop = True success = False print("mjpeg server.socket.close...") server.socket.close() print("mjpeg server.shutdown...") server.shutdown() print("ws server.socket.close...") server_ws.ws_server.close() time.sleep(1) # print("ws server.shutdown...") # await server_ws.ws_server.wait_closed() print("mjpeg thread.shutdown...") thread_mjpeg.join() print("ws loop.shutdown...") # event_loop_ws.stop() event_loop_ws.call_soon_threadsafe(event_loop_ws.stop) time.sleep(1) # print("ws thread.shutdown...") # stop_thread(thread_ws) # time.sleep(1) # print(server) # print(server_ws) print(thread_mjpeg.is_alive()) print(thread_ws.is_alive()) print(event_loop_ws.is_running()) # thread_ws.join() print("cameraCapture.release...") cameraCapture.release() print("quit...") # print(server_ws) sys.exit(0) # http服务器请求处理:网页、MJPEG数据流 class CamHandler(BaseHTTPRequestHandler): def do_GET(self): # mjpeg推流 if self.path.endswith('.mjpg'): self.send_response(200) self.send_header('Content-type','multipart/x-mixed-replace; boundary=--jpgboundary') self.end_headers() while True: if is_stop: break try: # rc,img = cameraCapture.read() rc,img = success,frame if not rc: continue if True: imgRGB=cv2.cvtColor(img,cv2.COLOR_BGR2RGB) jpg = Image.fromarray(imgRGB) tmpFile = BytesIO() jpg.save(tmpFile,'JPEG') self.wfile.write(b"--jpgboundary") self.send_header(b'Content-type','image/jpeg') self.send_header(b'Content-length',str(tmpFile.getbuffer().nbytes)) self.end_headers() jpg.save(self.wfile,'JPEG') else: img_fps = JPEG_QUALITY_VALUE img_param = [int(cv2.IMWRITE_JPEG_QUALITY), img_fps] img_str = cv2.imencode('.jpg', img, img_param)[1].tobytes() # change image to jpeg format self.send_header('Content-type','image/jpeg') self.end_headers() self.wfile.write(img_str) self.wfile.write(b" --jpgboundary ") # end of this part time.sleep(0.033) except KeyboardInterrupt: self.wfile.write(b" --jpgboundary-- ") break except BrokenPipeError: continue return # 网页 if self.path == '/' or self.path.endswith('.html'): self.send_response(200) self.send_header('Content-type','text/html') self.end_headers() self.wfile.write(b'<html><head><title>Live video</title></head><body>') self.wfile.write(('<img src="http://%s/live.mjpg"/>' % self.headers.get('Host')).encode()) self.wfile.write(b'</body></html>') return class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): """Handle requests in a separate thread.""" # 启动MJPEG服务 def mjpeg_server_star(): global success global server global thread_mjpeg try: server = ThreadedHTTPServer(('0.0.0.0', MJPEG_SERVER_PORT), CamHandler) print("mjpeg server started: http://0.0.0.0:%d" % MJPEG_SERVER_PORT) # server.serve_forever() thread_mjpeg = Thread(target=server.serve_forever); thread_mjpeg.start() except KeyboardInterrupt: print("mjpeg server stoping...") server.socket.close() server.shutdown() print("mjpeg server stoped") # websocket服务请求处理 async def CamTransmitHandler(websocket, path): print("Client Connected !") try : while True: # rc,img = cameraCapture.read() rc,img = success,frame if not rc: continue img_fps = JPEG_QUALITY_VALUE img_param = [int(cv2.IMWRITE_JPEG_QUALITY), img_fps] encoded = cv2.imencode('.jpg', img, img_param)[1] data = str(base64.b64encode(encoded)) data = data[2:len(data)-1] await websocket.send(data) # cv2.imshow("Transimission", frame) # if cv2.waitKey(1) & 0xFF == ord('q'): # break # cap.release() except EXCEPTION_CONNECTION_CLOSE as e: print("Client Disconnected !") # cap.release() except: print("Someting went Wrong !") # websocket服务器启动 def websocket_server_start(): global thread_ws global server_ws global event_loop_ws event_loop_ws = asyncio.new_event_loop() def run_server(): global server_ws print("websocket server started: ws://0.0.0.0:%d" % WEBSOCKET_PORT) server_ws = websockets.serve(CamTransmitHandler, port=WEBSOCKET_PORT, loop=event_loop_ws) event_loop_ws.run_until_complete(server_ws) event_loop_ws.run_forever() thread_ws = Thread(target=run_server) thread_ws.start() # try: # yield # except e: # print("An exception occurred") # finally: # event_loop.call_soon_threadsafe(event_loop.stop) # 获取存储的文件名 def get_file_name(time_obj, path, ext): file_name_time = "%04d-%02d-%02d_%02d-%02d-%02d" % (time_obj["year"], time_obj["month"], time_obj["day"], time_obj["hour"], time_obj["min"], 0) return '%s/%s/%s.%s' % (STORE_DIR, path, file_name_time, ext) # 获取当前整分时间 def get_current_time(): time_now = time.localtime() time_int = int(time.time()) return { "year": time_now.tm_year, "month": time_now.tm_mon, "day": time_now.tm_mday, "hour": time_now.tm_hour, "min": time_now.tm_min, "sec": time_now.tm_sec, "time": time_int - time_now.tm_sec } # 设置信号回调 signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) # 捕获摄像头 cameraCapture = cv2.VideoCapture(CAMERA_NO) # 摄像头参数设置 cameraCapture.set(cv2.CAP_PROP_FRAME_WIDTH, 320) cameraCapture.set(cv2.CAP_PROP_FRAME_WIDTH, 240) cameraCapture.set(cv2.CAP_PROP_SATURATION, 135) fps = 30 size=(int(cameraCapture.get(cv2.CAP_PROP_FRAME_WIDTH)),int(cameraCapture.get(cv2.CAP_PROP_FRAME_HEIGHT))) # 读取捕获的数据 success,frame = cameraCapture.read() if not success: print("camera start failed.") quit() is_stop = False server = None server_ws = None event_loop_ws = None thread_mjpeg = None thread_ws = None mjpeg_server_star() websocket_server_start() print("record server star:") thubm_file = None video_file = None time_start = int(time.time()) time_record = {"time":0} time_record_prev = None while True: if is_stop: success = False break; success,frame = cameraCapture.read() if not success: continue time_now = get_current_time() if time_now["time"] - time_record["time"] >= ROTATE_TIME: if time_record_prev: thubm_file = get_file_name(time_record_prev, 'thumbs', 'jpg') print("[Info] write to thumb: %s" % thubm_file) if not os.path.isfile(thubm_file): cv2.imwrite(thubm_file, frame) time_record = time_now time_record_prev = get_current_time() video_file = get_file_name(time_record_prev, 'videos', MEDIA_EXT) print("[Info] write to video: %s" % video_file) # encode = cv2.VideoWriter_fourcc(*"mp4v") encode = cv2.VideoWriter_fourcc(*'X264') # encode = cv2.VideoWriter_fourcc(*'AVC1') # encode = cv2.VideoWriter_fourcc(*'XVID') # encode = cv2.VideoWriter_fourcc(*'H264') videoWriter=cv2.VideoWriter(video_file, encode,fps,size) # mp4 numFrameRemaining = ROTATE_TIME * fps #摄像头捕获持续时间 while success and numFrameRemaining > 0: videoWriter.write(frame) success,frame = cameraCapture.read() numFrameRemaining -= 1 cameraCapture.release()在上述代码中,除了前面说过的三个部分,还包括启动web和websocket线程的部分。因为核心逻辑为读取视频数据并写入文件,所以其他部分,以线程的模式启动,以便同时进行处理。
将上述代码保存为DrivingRecorderAndMjpegServer.py,然后运行即可。(依赖包,见代码库中requirements.txt)

实际访问效果如下:

六、历史数据RestFul服务开发
历史数据服务,本来也可以使用Python直接手写,但考虑到可扩展性,使用Django来进行了编写。
Djano服务,需要提供如下的功能:
- 提供api接口,以便获取历史数据记录列表,便于前端界面呈现展示
- 提供Flutter Web界面代码文件的托管,以便通过浏览器访问
- 提供静态文件的访问,例如查看历史视频文件
2和3本质都是一个问题,通过Django的static功能,就能实现。
也就是在settings.py配置中,提供下面的配置即可:
STATIC_URL = 'static/' STATICFILES_DIRS = [ BASE_DIR / "static" ]1对外提供api服务,则需要设置对应的url接口,以及读取历史文件信息,生成前端需要的json数据结构,这部分的具体代码如下:
# 媒体文件存放目录,以及缩略图和视频文件的后缀 THUMB_HOME_DIR = "%s/%s/data/thumbs/" % (BASE_DIR, STATIC_URL) VIDEO_HOME_DIR = "%s/%s/data/videos/" % (BASE_DIR, STATIC_URL) IMG_FILTER = [".jpg"] MEDIA_FILTER = [ ".mkv"]import json from django.shortcuts import render, HttpResponse from rest_framework.response import Response from rest_framework.permissions import AllowAny from rest_framework.decorators import api_view, permission_classes import os from django.conf import settings THUMB_HOME_DIR = settings.THUMB_HOME_DIR VIDEO_HOME_DIR = settings.VIDEO_HOME_DIR IMG_FILTER = settings.IMG_FILTER MEDIA_FILTER = settings.MEDIA_FILTER # Create your views here. @api_view(['GET'],) @permission_classes([AllowAny],) def hello_django(request): str = '''[ { "id": 1, "time": "2022-07-28 21:00", "title": "2022-07-28 21:00", "body": "videos/2022-07-28_2100.mp4" }, { "id": 2, "time": "2022-07-28 23:00", "title": "2022-07-28 23:00", "body": "videos/2022-07-28_2300.mp4" }, { "id": 3, "time": "2022-07-28 25:00", "title": "2022-07-28 25:00", "body": "videos/2022-07-28_2500.mp4" } ]''' _json = json.loads(str) return HttpResponse(json.dumps(_json), content_type='application/json') @api_view(['GET'],) @permission_classes([AllowAny],) def history_list(request): next = request.GET.get("next", '') print(f"thumb next = {next}") path = "/".join(request.path.split("/")[3:]) print(f"thumb request.path= {request.path}") print(f"thumb path = {path}") #print os.listdir(FILE_HOME_DIR+".none/") data = {"files":[], "dirs":[]} print(data) child_path = THUMB_HOME_DIR+next print(f"child_path = {child_path}") data['cur_dir'] = path+next print(data) for dir in os.listdir(child_path): if os.path.isfile(child_path+"/"+dir): if os.path.splitext(dir)[1] in IMG_FILTER: data['files'].append(dir) else: data['dirs'].append(dir) print(data) data['files']=sorted(data['files']) data['files'].reverse() data['infos'] = [] for i in range(0,len(data['files'])): thumb_name = data['files'][i] video_name = thumb_name.replace('.jpg', MEDIA_FILTER[0]) file_time = thumb_name.replace('.jpg', '').replace('_', ' ') data['infos'].append( { "id": i, "time": file_time, "title": file_time, "body": thumb_name, 'thumb': thumb_name, 'video': video_name } ) return Response(data['infos'], status = 200)其中有两个接口:
hello_django是最开始学习使用的,返回写死的json数据。history_list,则是自动遍历缩略图文件夹,获取缩略图文件信息,并生成所需要的json数据格式。在对应的代码库文件中,也包含了requirements.txt,其中标明了实际需要的依赖库。
下载代码,进入manage.py所在的目录后,执行下面的命令即可启动:

访问 192.168.1.15:8000/app/hellodjango :

访问:History List – Django REST framework

可以看到 history_list接口,已经可以提供实际需要的数据了。
七、Flutter Web界面开发
这个部分设计的代码比较多,所以只对关键部分的代码进行说明。
开发的实际代码,位于lib目录,具体为:

- globals.dart:全局变量定义
- main.dart:程序入口
- home_page.dart:首页
- live_page.dart:实时播放
- live_page_mp4.dart:测试播放mp4视频
- history_page.dart:历史记录列表页面
- video_detail.dart:单条历史记录详情
- video_play.dart:播放具体的历史视频
- video_model.dart:单条记录的数据模型
- http_service.dart:请求RestFul接口
- websocket.dart:实时视频的WebSocket请求
整个界面,使用了
Scaffold来模拟手机/Pad的操作界面,具体界面如下:
在实时画面界面中,使用了WebSocket监听,获取到信息,就使用Stream模式,推送给视频播放。
在历史记录界面中,则通过RestFul请求列表数据,然后呈现。
八、整体运行效果
实际的运行效果,不用多说,看界面就成:
实时画面:

历史记录列表:

历史记录播放:

九、车试:
经过反复的测试验证,确保各项功能完整后,进行了上车实测。

因为最近的疫情原因,所以只在村里转了一圈,进行了实际测试,可以查看最后的视频。后续有机会,再找个晴朗的天气,去环境优美的地方实际拍摄录制。
十、实际代码说明:
完整的代码,请通过 米尔行车记录仪: 米尔行车记录仪 (https://gitee.com/honestqiao/MYiR-Driving-Recorder) 获取。
代码目录说明如下:
- DrivingRecorder:摄像头服务
- backend:RestFul服务
- frontend:Flutter Web界面
在以上仓库中,包含了详细的代码使用说明。
在实际应用中,将记录视频的data目录与后端static/data目录关联,以便两者统一。
十一、感谢
在研究学习的过程中,参考了数十篇各类资料,先将部分列出如下。对所有学习过的资料的作者,表示深深的感谢。
janakj/py-mjpeg: Python MJPEG streaming utilities (github.com)
Simple Python Motion Jpeg (mjpeg server) from webcam. Using: OpenCV,BaseHTTPServer (github.com)
Python 使用USB Camera录制MP4视频_Frank_Abagnale的博客-CSDN博客
用 Python、nginx 搭建在线家庭影院 - 知乎 (zhihu.com)
Django报错解决:RuntimeError: Model class ...apps... doesn't declare an explicit app_label and isn't in a_lyp039078的博客-CSDN博客
Python OpenCV 调用摄像头并截图保存_Clannad_niu的博客-CSDN博客
用 Python、nginx 搭建在线家庭影院mob604756e97f09的技术博客51CTO博客
Python-OpenCV录制H264编码的MP4视频 - 掘金 (juejin.cn)
[VideoWriter]保存H264/MPEG4格式MP4视频 - image processing (zj-image-processing.readthedocs.io)
Manual USB camera settings in Linux | KUROKESU
UVC Web Cameras (indilib.org)
编写你的第一个 Flutter 网页应用 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
macOS install | Flutter
[Django 設定 LANGUAGE_CODE 時所遇到的麻煩] OSError: No translation files found for default language zh-TW. (github.com)**
Django And Flutter — 样板应用程序|的分步教程作者:Clever Tech Memes |中等 (medium.com)
joke2k/django-environ: Django-environ allows you to utilize 12factor inspired environment variables to configure your Django application. (github.com)
django 之跨域访问问题解决 access-control-allow-origin - 腾讯云开发者社区-腾讯云 (tencent.com)
django-cors-headers · PyPI
Django项目解决跨域问题 - SegmentFault 思否
video_player | Flutter Package (pub.dev)
视频的播放和暂停 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
5.7 页面骨架(Scaffold) | 《Flutter实战·第二版》 (flutterchina.club)
itfitness/BottomNavigationBarDemo - 码云 - 开源中国 (gitee.com)
Flutter底部导航 - 简书 (jianshu.com)
Flutter之自定义底部导航条以及页面切换实例——Flutter基础系列houruoyu3的博客-CSDN博客flutter 自定义底部导航
How To Use HTTP Requests in Flutter | DigitalOcean
在Flutter中发起HTTP网络请求 - Flutter中文网 (flutterchina.club)
Fetch data from the internet | Flutter
获取网络数据 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
深入理解 Function & Closure - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
Django And Flutter — A Step by Step Tutorial for a Boilerplate Application | by Clever Tech Memes | Medium
multithreading - Multithreaded web server in python - Stack Overflow
Simple Python HTTP Server with multi-threading and partial-content support (github.com)
meska/mjpeg_stream_webcam: Webcam Streamer for Octoprint MacOs (github.com)
blueimp/mjpeg-server: MJPEG Server implements MJPEG over HTTP using FFmpeg or any other input source capable of piping a multipart JPEG stream to stdout. Its primary use case is providing Webdriver screen recordings. (github.com)
n3wtron/simple_mjpeg_streamer_http_server: simple python mjpeg streamer http server (github.com)
Python3远程监控程序实现肥宅Sean的博客-CSDN博客
opencv imencode跟imdecode函数jpg(python) - PythonTechWorld
flutter_mjpeg | Flutter Package (pub.dev)
Can't work on web platform. · Issue #13 · mylisabox/flutter_mjpeg (github.com)
Consider if fetch is widely supported enough to use · Issue #595 · dart-lang/http (github.com)
在 Flutter | 中创建实时视频流应用程序作者:Mitrajeet Golsangi |开发人员学生社区 Vishwakarma 技术学院,浦那 |中等 (medium.com)
Python websockets.serve方法代碼示例 - 純淨天空 (vimsky.com)
Flutter 常用組件講解 | ImageWidget - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天 (ithome.com.tw)
Bad State: Stream has already been listened to. · Issue #29105 · flutter/flutter (github.com)
flutter - Streambuilder with WebSockets stream in TabBarView: Bad state: Stream has already been listened to - Stack Overflow
使用WebSockets - Flutter中文网 (flutterchina.club)
VideoStreaming.dart (github.com)
在 Flutter | 中创建实时视频流应用程序作者:Mitrajeet Golsangi |开发人员学生社区 Vishwakarma 技术学院,浦那 |中等 (medium.com)
Flutter:WebSocket封装-实现心跳、重连机制 - 让我留在你身边 (ricardolsw.github.io)
2.3 状态管理 | 《Flutter实战·第二版》 (flutterchina.club)
路由和导航 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
7.6 异步UI更新(FutureBuilder、StreamBuilder) | 《Flutter实战·第二版》 (flutterchina.club)
Flutter 常用組件講解 | ImageWidget - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天 (ithome.com.tw)
Step By Step Tutorial in Learning Flutter: Lesson 12 — Adding Image (Ice Pokemon) | by Misterflutter | Quick Code | Medium
Django CORS on static asset - Stack Overflow
配置 | Django 文档 | Django (djangoproject.com)
Global Variables in Dart - Stack Overflow
UVC - Community Help Wiki (ubuntu.com)
利用OpenCV进行H264视频编码的简易方式 - 知乎 (zhihu.com)
Documentation for OPENCV_FFMPEG_WRITER_OPTIONS and OPENCV_FFMPEG_CAPTURE_OPTIONS · Issue #21155 · opencv/opencv (github.com)
利用OpenCV进行H264视频编码的简易方式 - 知乎 (zhihu.com)
FFmpeg概述及编码支持 - 知乎 (zhihu.com)
Web 渲染器 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter十二、总结
在研究学习的过程中,对Linux系统下的UVC框架有了进一步的了解,对Flutter进行应用开发有了实际的了解,对OpenCV的实际应用也有了具体的了解。
在实际开发的过程中,遇到的最大的坑来自Flutter,因为变化太快,有一些功能可能兼容性没有跟上。不过更多是自己学艺不精导致的。
另外,目前还只是V1.0版本,后续还存在较大的优化空间。例如对于OpenCV的应用,可以调整参数,优化获取的视频数据的指令和大小等。这些有待于进一步学习后进行。
最主要的,对米尔MYD-YT507开发板有了深入的了解,进行了实际的应用。作为一款车规级处理器T507的开发板,名不虚传!
-
回复: RT-Thread on D1H. LCD work, USB in progress.发布在 MR Series
@ylyamin 在 RT-Thread on D1H. LCD work, USB in progress. 中说:
I’m writing a series of articles covering the knowledge and experience I’ve gained:
D1-1. Introduction - Motivation and intention.
D1-2. Boot process - Existing Allwinner D1H bootloaders best practice in example with booting Linux and RT-Thread, also JTAG and GDB.
D1-3. RT-Thread overview and Build - Overview of RT-Thread structure and libraries. Compile RT-Thread for Allwinner D1H platform.
D1-4. Makefile and Hardware changes - My repository structure, Makefile and Hardware changes was needed to be done.
D1-5. LCD Display driver - Display driver for DevTerm R-01, uConsole R-01 and Sipeed Lichee RV.
D1-6. USB Keyboard - USB Keyboard driver for ClockworkPi DevTerm, still not working.Detailed article,nice
bigfly 发布的最新帖子
-
回复: RT-Thread on D1H. LCD work, USB in progress.发布在 MR Series
@ylyamin 在 RT-Thread on D1H. LCD work, USB in progress. 中说:
I’m writing a series of articles covering the knowledge and experience I’ve gained:
D1-1. Introduction - Motivation and intention.
D1-2. Boot process - Existing Allwinner D1H bootloaders best practice in example with booting Linux and RT-Thread, also JTAG and GDB.
D1-3. RT-Thread overview and Build - Overview of RT-Thread structure and libraries. Compile RT-Thread for Allwinner D1H platform.
D1-4. Makefile and Hardware changes - My repository structure, Makefile and Hardware changes was needed to be done.
D1-5. LCD Display driver - Display driver for DevTerm R-01, uConsole R-01 and Sipeed Lichee RV.
D1-6. USB Keyboard - USB Keyboard driver for ClockworkPi DevTerm, still not working.Detailed article,nice
-
回复: 更改分区发布在 其它全志芯片讨论区
@yyyyppppp Tina Linux 存储介质切换:eMMC,SPI NAND,SPI NOR,SD Card,SD NAND
https://bbs.aw-ol.com/topic/1701/share/1 -
更换lcd屏幕发布在 飞凌嵌入式专区
我手上有一块480854的屏幕,现在想测试一下 在.fex文件中我发现,只要我把下面的这两个参数改成480854,在后面打包、烧录运行时就会出现问题
fb0_width = 480 fb0_height = 854问题如下:
/etc/init.d/rcS: line 60: 1231 Segmentation fault insmod /system/vendor/modules/mali.ko
挂载mali.ko文件显示段错误,具体打印消息如下:
我这种情况是gpu不能用吗?我应该怎么解决这个问题[ 4.223285] Mali: Enable gpu power successfully. [ 4.223364] Mali: Set gpu frequency to 384 MHz [ 4.223434] Mali: Mali GPU initialization finished. [ 4.223881] Mali: ERR: /home/forlinx/work/lichee/linux-3.10/modules/gpu/mali400/kernel_mode/driver/src/devicedrv/mali/common/mali_mem_validation.c [ 4.223892] mali_mem_validation_add_range() 35 Failed to add frame buffer memory; incorrect alignment [ 4.223906] Mali: ERR: /home/forlinx/work/lichee/linux-3.10/modules/gpu/mali400/kernel_mode/driver/src/devicedrv/mali/common/mali_kernel_core.c [ 4.223912] mali_parse_config_memory() 700 Failed to register frame buffer memory region [ 4.224137] Unable to handle kernel paging request at virtual address 00100104 [ 4.224146] pgd = e1938000 [ 4.224152] [00100104] *pgd=6232e831, *pte=00000000, *ppte=00000000 [ 4.224169] Internal error: Oops: 817 [#1] PREEMPT SMP ARM [ 4.224177] Modules linked in: mali(O+) gt9xxnew_ts [ 4.224196] CPU: 0 PID: 1231 Comm: insmod Tainted: G W O 3.10.65 #446 [ 4.224205] task: e2f47a80 ti: e183a000 task.ti: e183a000 [ 4.224221] PC is at unregister_shrinker+0x30/0x5c [ 4.224232] LR is at _raw_spin_unlock_irqrestore+0x38/0x58 [ 4.224241] pc : [<c00d4614>] lr : [<c06ff900>] psr: 40070013 sp : e183bc80 ip : e183bc20 fp : e183bc94 [ 4.224249] r10: e22a9664 r9 : 00000001 r8 : bf03f564 [ 4.224257] r7 : 00000000 r6 : e2e9d600 r5 : c0ad4eb0 r4 : bf03f364 [ 4.224264] r3 : 00200200 r2 : 00100100 r1 : 60070013 r0 : c0ad4eb0 [ 4.224273] Flags: nZcv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user [ 4.224280] Control: 10c53c7d Table: 6193806a DAC: 00000015 [ 4.224286] PC: 0xc00d4594: [ 4.224292] 4594 e24cb004 e52de004 e8bd4000 e3a03000 e1a05000 e59f4030 e5803014 e1a00004 [ 4.224316] 45b4 eb18a540 e5943014 e285200c e2841010 e5842014 e585100c e1a00004 e5853010 [ 4.224339] 45d4 e5832000 ebfdd6c9 e89da830 c0ad4eb0 e1a0c00d e92dd830 e24cb004 e52de004 [ 4.224362] 45f4 e8bd4000 e1a04000 e59f5030 e1a00005 eb18a52c e5943010 e1a00005 e594200c [ 4.224385] 4614 e5823004 e5832000 e59f3014 e584300c e59f3010 e5843010 ebfdd6b4 e89da830 [ 4.224408] 4634 c0ad4eb0 00100100 00200200 e1a0c00d e92dd800 e24cb004 e52de004 e8bd4000 [ 4.224431] 4654 e1a03001 e590214c e1a00003 e59f1004 eb014a32 e89da800 c00d4670 e1a0c00d [ 4.224454] 4674 e92dd8f0 e24cb004 e24dd008 e52de004 e8bd4000 e59f5074 e3e03000 e50b3024 [ 4.224479] LR: 0xc06ff880: [ 4.224485] f880 e52de004 e8bd4000 f57ff05b e1d030b0 e2833001 e1c030b0 f57ff04f e320f004 [ 4.224508] f8a0 e3a00001 eb000a32 e1a0300d e3c33d7f e3c3303f e5933000 e3130002 089da800 [ 4.224531] f8c0 ebfffc6d e89da800 e1a0c00d e92dd800 e24cb004 e52de004 e8bd4000 f57ff05b [ 4.224554] f8e0 e1d030b0 e2833001 e1c030b0 f57ff04f e320f004 e121f001 e3a00001 eb000a1c [ 4.224577] f900 e1a0300d e3c33d7f e3c3303f e5933000 e3130002 089da800 ebfffc57 e89da800 [ 4.224600] f920 e1a0c00d e92dd800 e24cb004 e52de004 e8bd4000 f57ff05b e1d030b0 e2833001 [ 4.224623] f940 e1c030b0 f57ff04f e320f004 f1080080 e3a00001 eb000a06 e1a0300d e3c33d7f [ 4.224646] f960 e3c3303f e5933000 e3130002 089da800 ebfffc41 e89da800 e1a0c00d e92dd800 [ 4.224670] SP: 0xe183bc00: [ 4.224676] bc00 c003d4d0 c06ff4e0 e183bc2c c06ff900 e183bc2c e183bc20 c00d4614 40070013 [ 4.224699] bc20 ffffffff e183bc6c e183bc94 e183bc38 c0700098 c000a16c c0ad4eb0 60070013 [ 4.224722] bc40 00100100 00200200 bf03f364 c0ad4eb0 e2e9d600 00000000 bf03f564 00000001 [ 4.224744] bc60 e22a9664 e183bc94 e183bc20 e183bc80 c06ff900 c00d4614 40070013 ffffffff [ 4.224767] bc80 bf03f34c 00000000 e183bcb4 e183bc98 bf0138b4 c00d45f0 bf040434 00000000 [ 4.224790] bca0 e2e9d600 00000000 e183bcc4 e183bcb8 bf0124d8 bf0138a0 e183bcdc e183bcc8 [ 4.224813] bcc0 bf01aba4 bf0124c4 ffffffff bf040434 e183bd2c e183bce0 bf01acc4 bf01aafc [ 4.224836] bce0 00000001 bf03ff88 00000000 e2e9d600 00000000 bf03f564 00000001 e22a9664 [ 4.224859] IP: 0xe183bba0: [ 4.224865] bba0 00000000 c06ff958 e183bbc4 e1876b80 00000004 c0bec00c e183bc04 e183bbc8 [ 4.224888] bbc0 c003d04c c004dec8 e183bbfc 00000000 c00fcbb0 e1876b80 e23e75c0 e1876b80 [ 4.224910] bbe0 e183bc24 e183bc30 e1876bc0 e1876b90 00000005 c003d4d0 e183bc6c e183bc08 [ 4.224933] bc00 c003d4d0 c06ff4e0 e183bc2c c06ff900 e183bc2c e183bc20 c00d4614 40070013 [ 4.224956] bc20 ffffffff e183bc6c e183bc94 e183bc38 c0700098 c000a16c c0ad4eb0 60070013 [ 4.224979] bc40 00100100 00200200 bf03f364 c0ad4eb0 e2e9d600 00000000 bf03f564 00000001 [ 4.225001] bc60 e22a9664 e183bc94 e183bc20 e183bc80 c06ff900 c00d4614 40070013 ffffffff [ 4.225024] bc80 bf03f34c 00000000 e183bcb4 e183bc98 bf0138b4 c00d45f0 bf040434 00000000 [ 4.225048] FP: 0xe183bc14: [ 4.225054] bc14 e183bc20 c00d4614 40070013 ffffffff e183bc6c e183bc94 e183bc38 c0700098 [ 4.225077] bc34 c000a16c c0ad4eb0 60070013 00100100 00200200 bf03f364 c0ad4eb0 e2e9d600 [ 4.225100] bc54 00000000 bf03f564 00000001 e22a9664 e183bc94 e183bc20 e183bc80 c06ff900 [ 4.225122] bc74 c00d4614 40070013 ffffffff bf03f34c 00000000 e183bcb4 e183bc98 bf0138b4 [ 4.225145] bc94 c00d45f0 bf040434 00000000 e2e9d600 00000000 e183bcc4 e183bcb8 bf0124d8 [ 4.225168] bcb4 bf0138a0 e183bcdc e183bcc8 bf01aba4 bf0124c4 ffffffff bf040434 e183bd2c [ 4.225191] bcd4 e183bce0 bf01acc4 bf01aafc 00000001 bf03ff88 00000000 e2e9d600 00000000 [ 4.225213] bcf4 bf03f564 00000001 e22a9664 e183bd2c e183bd10 bf01035c c0040e8c bf040468 [ 4.225237] R0: 0xc0ad4e30: [ 4.225243] 4e30 00000020 00000000 000001f4 0000000a 00000000 00000000 00000000 61666544 [ 4.225264] 4e50 00746c75 65646f4e 00000000 656e6f5a 00000000 00000001 00000000 c0ad4e6c [ 4.225286] 4e70 c0ad4e6c 00000000 00000000 0000086f c0c1562c c0c1562c ffff8ca3 c0c15101 [ 4.225309] 4e90 c00ce330 00000000 ffffffff 00000014 0000000a 00000070 00000bb8 000001f4 [ 4.225331] 4eb0 ffffffff 003d003d c0ad4eb8 c0ad4eb8 e2c3ee64 e2030a64 0000003c c00d44f4 [ 4.225353] 4ed0 c00a708c c00a708c c00a708c c00d4444 c00a708c c00a708c c00a708c c00d4280 [ 4.225376] 4ef0 c00a708c c00a708c c00a708c c00d4208 c00a708c c00a708c c00a708c c00d4388 [ 4.225399] 4f10 c00a708c c00a708c c00a708c c00d41bc c00a708c c00a708c c00a708c c00d42f8 [ 4.225424] R5: 0xc0ad4e30: [ 4.225430] 4e30 00000020 00000000 000001f4 0000000a 00000000 00000000 00000000 61666544 [ 4.225452] 4e50 00746c75 65646f4e 00000000 656e6f5a 00000000 00000001 00000000 c0ad4e6c [ 4.225473] 4e70 c0ad4e6c 00000000 00000000 0000086f c0c1562c c0c1562c ffff8ca3 c0c15101 [ 4.225496] 4e90 c00ce330 00000000 ffffffff 00000014 0000000a 00000070 00000bb8 000001f4 [ 4.225518] 4eb0 ffffffff 003d003d c0ad4eb8 c0ad4eb8 e2c3ee64 e2030a64 0000003c c00d44f4 [ 4.225541] 4ed0 c00a708c c00a708c c00a708c c00d4444 c00a708c c00a708c c00a708c c00d4280 [ 4.225564] 4ef0 c00a708c c00a708c c00a708c c00d4208 c00a708c c00a708c c00a708c c00d4388 [ 4.225587] 4f10 c00a708c c00a708c c00a708c c00d41bc c00a708c c00a708c c00a708c c00d42f8 [ 4.225611] R6: 0xe2e9d580: [ 4.225617] d580 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 4.225638] d5a0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 4.225658] d5c0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 4.225679] d5e0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 4.225700] d600 e2e9ec40 ffffffff 00000000 00000000 00000000 e2e97740 e2e9ec40 e2e9d41c [ 4.225722] d620 e2e9d81c e2d0434c e2d04340 c0b9cfd8 e2da48c8 00000002 00000007 00000000 [ 4.225744] d640 00000000 00000000 00000000 e2e9d64c e2e9d64c e2f47a80 00000000 c0b9d290 [ 4.225766] d660 bf03f564 e20532c0 00000000 00000020 00050005 e2e9d474 e2e9d874 7fffffff [ 4.225790] R10: 0xe22a95e4: [ 4.225796] 95e4 00000000 00000000 00000000 00000000 00000000 00000000 00000000 e22a95c0 [ 4.225817] 9604 e22a9604 e22a9604 bf03fe58 00000000 c0adf9c8 e219d3c8 00000001 00000003 [ 4.225839] 9624 00000000 00000000 00000000 00000000 00000000 00000000 00000000 e22a9600 [ 4.225861] 9644 00000001 e22a9d00 00000124 00000024 bf031518 c0078a5c 00000000 00000000 [ 4.225883] 9664 00000000 00000000 00000000 00000000 00000000 00000000 00000000 74636573 [ 4.225904] 9684 736e6f69 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 4.225925] 96a4 00000000 00000000 00000000 00000000 00000000 00000000 00000000 7274732e [ 4.225946] 96c4 00626174 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 4.225970] Process insmod (pid: 1231, stack limit = 0xe183a238) [ 4.225978] Stack: (0xe183bc80 to 0xe183c000) [ 4.225990] bc80: bf03f34c 00000000 e183bcb4 e183bc98 bf0138b4 c00d45f0 bf040434 00000000 [ 4.226002] bca0: e2e9d600 00000000 e183bcc4 e183bcb8 bf0124d8 bf0138a0 e183bcdc e183bcc8 [ 4.226014] bcc0: bf01aba4 bf0124c4 ffffffff bf040434 e183bd2c e183bce0 bf01acc4 bf01aafc [ 4.226025] bce0: 00000001 bf03ff88 00000000 e2e9d600 00000000 bf03f564 00000001 e22a9664 [ 4.226037] bd00: e183bd2c e183bd10 bf01035c c0040e8c bf040468 bf040468 e2e9d600 00000000 [ 4.226048] bd20: e183bd4c e183bd30 bf01c390 bf01abcc e2e9d610 c0c5e31c 00000000 00000001 [ 4.226060] bd40: e183bd5c e183bd50 c0311a48 bf01c2e8 e183bd84 e183bd60 c031061c c0311a30 [ 4.226072] bd60: e2e9d610 e2e9d644 bf03f564 c0b9d290 00000000 00000001 e183bda4 e183bd88 [ 4.226084] bd80: c031082c c0310564 00000000 bf03f564 c03107b4 c0b9d290 e183bdcc e183bda8 [ 4.226095] bda0: c030eb1c c03107c0 e2d1e3dc e2e97774 c06ff8a8 bf03f564 00000000 e2782ac0 [ 4.226107] bdc0: e183bddc e183bdd0 c03100e4 c030eaac e183be04 e183bde0 c030fc80 c03100c8 [ 4.226119] bde0: bf034a1b e183bdf0 bf03f564 bf01c540 c0bf3700 bf03fe58 e183be24 e183be08 [ 4.226132] be00: c0310e3c c030fb98 e183a000 bf01c540 c0bf3700 bf03fe58 e183be34 e183be28 [ 4.226144] be20: c031203c c0310d9c e183be4c e183be38 bf01c55c c0311ff4 e183a000 bf01c540 [ 4.226156] be40: e183be8c e183be50 c000a4d8 bf01c54c c00f4e2c e183bf48 00000001 bf03fe10 [ 4.226167] be60: bf03fe58 e22a9640 e183be8c e183bf48 00000001 bf03fe10 bf03fe58 e22a9640 [ 4.226179] be80: e183bf44 e183be90 c007b3ec c000a43c bf03fe1c 00007fff c00772ec c0be8c40 [ 4.226191] bea0: 000ad8e5 bf03ff74 eb765f84 e183beb8 c0709f2c c0078b88 e22a9648 00000000 [ 4.226203] bec0: bf03fe1c e183a000 c00f5218 c00f49bc ffffffff c007b9f8 c007b9f8 bf03153c [ 4.226213] bee0: 0000000b bf031594 00000003 00000000 00000000 00000000 00000000 00000000 [ 4.226224] bf00: 00000000 00000000 00000000 00000000 00000000 00000000 ffffffff b6952008 [ 4.226236] bf20: 000ad8e5 00442fd4 00000080 c000fac8 e183a000 00000000 e183bfa4 e183bf48 [ 4.226248] bf40: c007ba74 c0079e44 eb323000 00442fd4 eb7655ac eb65dc38 eb66a4dc 00030958 [ 4.226258] bf60: 0003b498 00000000 00000000 00000000 0000003f 00000040 00000028 00000000 [ 4.226270] bf80: 00000016 00000000 c0013994 00000000 00000069 bee8ede4 00000000 e183bfa8 [ 4.226281] bfa0: c000f880 c007b9ac 00000000 00000069 b6952008 00442fd4 000ad8e5 00000000 [ 4.226292] bfc0: 00000000 00000069 bee8ede4 00000080 00000001 bee8edec b6f20000 0009b9aa [ 4.226304] bfe0: b6e29901 bee8ea98 0002810f b6e29908 80080030 b6952008 000027ff 00002800 [ 4.226421] [<c00d4614>] (unregister_shrinker+0x30/0x5c) from [<bf0138b4>] (mali_mem_os_term+0x20/0xd0 [mali]) [ 4.226574] [<bf0138b4>] (mali_mem_os_term+0x20/0xd0 [mali]) from [<bf0124d8>] (mali_memory_terminate+0x20/0x34 [mali]) [ 4.226733] [<bf0124d8>] (mali_memory_terminate+0x20/0x34 [mali]) from [<bf01aba4>] (mali_terminate_subsystems+0xb4/0xd0 [mali]) [ 4.226904] [<bf01aba4>] (mali_terminate_subsystems+0xb4/0xd0 [mali]) from [<bf01acc4>] (mali_initialize_subsystems+0x104/0x518 [mali]) [ 4.227076] [<bf01acc4>] (mali_initialize_subsystems+0x104/0x518 [mali]) from [<bf01c390>] (mali_probe+0xb4/0x220 [mali]) [ 4.227174] [<bf01c390>] (mali_probe+0xb4/0x220 [mali]) from [<c0311a48>] (platform_drv_probe+0x24/0x28) [ 4.227191] [<c0311a48>] (platform_drv_probe+0x24/0x28) from [<c031061c>] (driver_probe_device+0xc4/0x208) [ 4.227205] [<c031061c>] (driver_probe_device+0xc4/0x208) from [<c031082c>] (__driver_attach+0x78/0x9c) [ 4.227219] [<c031082c>] (__driver_attach+0x78/0x9c) from [<c030eb1c>] (bus_for_each_dev+0x7c/0xa0) [ 4.227233] [<c030eb1c>] (bus_for_each_dev+0x7c/0xa0) from [<c03100e4>] (driver_attach+0x28/0x30) [ 4.227247] [<c03100e4>] (driver_attach+0x28/0x30) from [<c030fc80>] (bus_add_driver+0xf4/0x228) [ 4.227261] [<c030fc80>] (bus_add_driver+0xf4/0x228) from [<c0310e3c>] (driver_register+0xac/0x130) [ 4.227276] [<c0310e3c>] (driver_register+0xac/0x130) from [<c031203c>] (platform_driver_register+0x54/0x68) [ 4.227370] [<c031203c>] (platform_driver_register+0x54/0x68) from [<bf01c55c>] (init_module+0x1c/0x64 [mali]) [ 4.227466] [<bf01c55c>] (init_module+0x1c/0x64 [mali]) from [<c000a4d8>] (do_one_initcall+0xa8/0x144) [ 4.227483] [<c000a4d8>] (do_one_initcall+0xa8/0x144) from [<c007b3ec>] (load_module+0x15b4/0x1b68) [ 4.227498] [<c007b3ec>] (load_module+0x15b4/0x1b68) from [<c007ba74>] (SyS_init_module+0xd4/0xdc) [ 4.227512] [<c007ba74>] (SyS_init_module+0xd4/0xdc) from [<c000f880>] (ret_fast_syscall+0x0/0x30) [ 4.227524] Code: eb18a52c e5943010 e1a00005 e594200c (e5823004) [ 4.227534] ---[ end trace c57267c46477aee1 ]--- [ 4.420068] insmod_device_driver [ 4.577148] fbid=0 uiid=0 [ 4.577166] [DISP] sunxi_fb_to_display,line:590:sunxi_fb_to_display fb0 UIid 0 [ 4.577179] [DISP] sunxi_fb_to_display,line:653:sunxi_fb_to_display set fb0 UIid 0 chan[1]lid[0]z[3]


