[{"data":1,"prerenderedAt":676},["ShallowReactive",2],{"category-posts-devlog":3},[4,571],{"id":5,"title":6,"body":7,"category":559,"cover":560,"coverAlt":561,"date":562,"description":563,"extension":564,"meta":565,"navigation":351,"path":566,"pinned":567,"seo":568,"stem":569,"__hash__":570},"posts/posts/raspberrypi.md","树莓派之慢速电影",{"type":8,"value":9,"toc":557},"minimark",[10,14,17,28,31,35,38,54,57,66,68,71,74,77,80,82,85,88,101,108,114,117,126,129,131,134,137,140,149,181,184,197,200,202,205,212,215,218,253,256,263,268,284,287,490,493,498,536,539,541,553],[11,12,13],"p",{},"树莓派这个东西，初见是初中看我的世界维基，作为一个并行的版本被单列出来。没想到真正上手实践是用在这里，也是记录一下我第一次上手嵌入式的过程。",[11,15,16],{},"这是一个有多次完整实践、文档详细而全面的项目：以极慢速，即以分钟级的时间播放一帧，在墨水屏上播放整个电影。既是赠予异地心上人，泰坦尼克号是个好主题，希望这段感情不为占有，而是可以让彼此依靠成长。",[11,18,19,20,27],{},"本文主要参考",[21,22,26],"a",{"href":23,"rel":24},"https://shumeipai.nxez.com/2020/10/13/how-to-build-a-very-slow-movie-player-in-2020.html",[25],"nofollow","这篇文章","，文章内容有些过时，本文尝试给出一些更优的实践并指出常见的坑。",[29,30],"hr",{},[32,33,34],"h1",{"id":34},"硬件需求",[11,36,37],{},"原文用了120英镑，本文在尽量使用高配的情况下也只用了600多人民币，这就是工业克苏鲁带给我的自信。",[39,40,41,45,48,51],"ol",{},[42,43,44],"li",{},"树莓派4B(4GB) + 5V3A适配器 （2GB内存及以上即可，实际使用较低端的单片机都可以）",[42,46,47],{},"Waveshare树莓派4 7.5寸墨水屏模块 + HAT驱动板",[42,49,50],{},"Micro SD 64GB（实际用不了那么大，墨水屏分辨率也没那么大）",[42,52,53],{},"7寸相框（照片12.7*17.8cm）+ 卡纸（用于遮盖墨水屏边缘）+ 棉线胶布",[11,55,56],{},"以下为非消耗品，或需要准备的环境：",[39,58,60,63],{"start":59},5,[42,61,62],{},"无线热点或键鼠显示器（用于连接树莓派）",[42,64,65],{},"Micro SD读卡器",[29,67],{},[32,69,70],{"id":70},"外设准备",[11,72,73],{},"其实就是把墨水屏通过驱动板连接到树莓派上，直接参考链接中文章的图片即可。当然自己连也不会连出第二个样子，这种嵌入式的防呆设计都不错。",[11,75,76],{},"有一点可能需要注意的是驱动板链接柔性PCB导线的时候需要拨动一下黑色塑料，本人在这里浪费了几分钟。",[11,78,79],{},"SD卡的位置在树莓派的背面，充电器就连接在仅有的USB-C上即可。",[29,81],{},[32,83,84],{"id":84},"系统准备",[11,86,87],{},"这个东西就相当于树莓派的外存/硬盘，至少得往里面写一个系统（黑话叫做“烧入”）才能开机。",[11,89,90,91,95,100],{},"注意，如果想要使用最新系统，此处",[92,93,94],"strong",{},"强烈推荐",[21,96,99],{"href":97,"rel":98},"https://www.raspberrypi.com/software/",[25],"Imager","，而非文章中的Etcher，因为在某个较新的版本的安全策略升级，导致烧入后配置Wi-Fi非常繁琐。使用Etcher可以使用2021年及以前的系统，就可以按文中的方式配置网络。",[11,102,103,104,107],{},"Imager十分好用，在电脑上插入SD卡，启动Imager即可烧入。本文选择了最新的64位桌面版（实际可以不用桌面）。如果使用无线方式配置树莓派（没有键鼠显示器），烧入前请",[92,105,106],{},"务必","修改无线名和密码以连接到与PC同一网络。",[11,109,110,111,113],{},"另外请",[92,112,106],{},"记住烧入的用户名和密码（新系统不再是默认的pi和raspberrypi）。",[11,115,116],{},"烧入完成后，如果想用无线方式链接树莓派，需要在SD卡根目录下新建一个名为ssh的空文件。否则尝试使用ssh连接时会显示阻止连接。",[11,118,119,120,125],{},"如果不小心烧错了，需要用",[21,121,124],{"href":122,"rel":123},"https://www.sdcard.org/downloads/formatter/",[25],"这个","格式化一下（快速格式化即可）再重新烧入新的系统。",[11,127,128],{},"一切就绪后，将SD卡插入树莓派，连接电源，树莓派会自动开机。",[29,130],{},[32,132,133],{"id":133},"软件准备",[11,135,136],{},"开机大约半分钟左右，树莓派会连接到配置好的Wi-Fi上，这时就可以用SSH连接树莓派了。可以使用文中推荐的PuTTY连接，实际上用命令提示符也能连。",[11,138,139],{},"连接时需要进入路由器后台找到树莓派的IP地址，名字很好辨认，一般就是raspberrypi，会给分配一个192.168.x.x这样的地址。然后使用同一网络下的设备就可以通过SSH，输入用户名和密码连接了。",[11,141,142,143,148],{},"时隔多年早已有好事者把这个项目整理为傻瓜级别，本文直接用之。具体为这个",[21,144,147],{"href":145,"rel":146},"https://github.com/TomWhitwell/SlowMovie",[25],"Github项目","，有一条傻瓜一样的安装指令：",[150,151,156],"pre",{"className":152,"code":153,"language":154,"meta":155,"style":155},"language-bash shiki shiki-themes one-dark-pro one-dark-pro min-light","bash \u003C(curl https://raw.githubusercontent.com/TomWhitwell/SlowMovie/main/Install/install.sh)\n","bash","",[157,158,159],"code",{"__ignoreMap":155},[160,161,164,167,171,174,178],"span",{"class":162,"line":163},"line",1,[160,165,154],{"class":166},"slNdt",[160,168,170],{"class":169},"sZaK-"," \u003C(",[160,172,173],{"class":166},"curl",[160,175,177],{"class":176},"sVtDz"," https://raw.githubusercontent.com/TomWhitwell/SlowMovie/main/Install/install.sh",[160,179,180],{"class":169},")\n",[11,182,183],{},"直接在用户目录下运行这个指令，会自动安装该项目及其所有依赖。注意如果是墙内可能会超时几次，但一般重试几次都可以成功安装。运行结束后，用户目录下会多一个SlowMovie目录，进去后运行：",[150,185,187],{"className":152,"code":186,"language":154,"meta":155,"style":155},"python slowmovie.py\n",[157,188,189],{"__ignoreMap":155},[160,190,191,194],{"class":162,"line":163},[160,192,193],{"class":166},"python",[160,195,196],{"class":176}," slowmovie.py\n",[11,198,199],{},"就可以看见墨水屏闪烁几下，出现一个人开车的画面，过一段时间会切换。实际上这是播放了SlowMovie/Videos中的test.mp4的内容，使用默认参数。至此所有需要的软件已经安装并跑通。",[29,201],{},[32,203,204],{"id":204},"自定义播放",[11,206,207,208,211],{},"既然是送礼，不能指望对方打开SSH连进来再一通操作，本文最终实现的是",[92,209,210],{},"插上电自动继续播放，断电保留在断电时的画面","，不需要联网。",[11,213,214],{},"首先准备一个有意义的视频片段，放到SlowMovie/Videos中，我的泰坦尼克号是.mkv格式的也可以直接播放。传输文件可以用FileZilla通过SFTP，当然用XFTP软件等等都可以。",[11,216,217],{},"然后确定一下自己想要的参数，指令运行时该项目会自动计算播放完所需时间。同时该项目本身就支持直接续播，不需要额外配置。例如以下指令：",[150,219,221],{"className":152,"code":220,"language":154,"meta":155,"style":155},"python slowmovie.py -f Videos/Titanic.mkv -d 150 -i 1 -l\n",[157,222,223],{"__ignoreMap":155},[160,224,225,227,230,234,237,240,244,247,250],{"class":162,"line":163},[160,226,193],{"class":166},[160,228,229],{"class":176}," slowmovie.py",[160,231,233],{"class":232},"stC8A"," -f",[160,235,236],{"class":176}," Videos/Titanic.mkv",[160,238,239],{"class":232}," -d",[160,241,243],{"class":242},"sWEYk"," 150",[160,245,246],{"class":232}," -i",[160,248,249],{"class":242}," 1",[160,251,252],{"class":232}," -l\n",[11,254,255],{},"代表播放泰坦尼克号，每150秒播放1帧，播完后从头播放。更具体的选项可以在Github原仓库页面查看。",[11,257,258,259,262],{},"需要注意的是，如果想实现连电播放，需要配置systemd",[92,260,261],{},"而非/etc/profile中的内容","，后者起的作用是用SSH登录后执行指令。具体操作如下：",[39,264,265],{},[42,266,267],{},"建立服务文件",[150,269,271],{"className":152,"code":270,"language":154,"meta":155,"style":155},"sudo nano /etc/systemd/system/slowmovie.service\n",[157,272,273],{"__ignoreMap":155},[160,274,275,278,281],{"class":162,"line":163},[160,276,277],{"class":166},"sudo",[160,279,280],{"class":176}," nano",[160,282,283],{"class":176}," /etc/systemd/system/slowmovie.service\n",[11,285,286],{},"在里面写入以下内容（注意视频路径和参数修改为自己的）：",[150,288,292],{"className":289,"code":290,"language":291,"meta":155,"style":155},"language-ini shiki shiki-themes one-dark-pro one-dark-pro min-light","[Unit]\nDescription=SlowMovie Startup Script\nAfter=network-online.target\nWants=network-online.target\nStartLimitIntervalSec=0\n\n[Service]\nType=simple\nUser=pi\nWorkingDirectory=/home/pi/SlowMovie\nEnvironment=PYTHONUNBUFFERED=1\nExecStart=/home/pi/SlowMovie/.SlowMovie/bin/python /home/pi/SlowMovie/slowmovie.py \\\n          -f /home/pi/SlowMovie/Videos/Titanic.mkv -d 60 -i 1 -l\nRestart=on-failure\nRestartSec=5\nStandardOutput=journal\nStandardError=journal\n\n[Install]\nWantedBy=multi-user.target\n","ini",[157,293,294,300,315,326,336,346,353,359,370,381,392,408,419,425,436,447,458,468,473,479],{"__ignoreMap":155},[160,295,296],{"class":162,"line":163},[160,297,299],{"class":298},"skjSQ","[Unit]\n",[160,301,303,307,311],{"class":162,"line":302},2,[160,304,306],{"class":305},"sSCA1","Description",[160,308,310],{"class":309},"s3Kl_","=",[160,312,314],{"class":313},"sbbSH","SlowMovie Startup Script\n",[160,316,318,321,323],{"class":162,"line":317},3,[160,319,320],{"class":305},"After",[160,322,310],{"class":309},[160,324,325],{"class":313},"network-online.target\n",[160,327,329,332,334],{"class":162,"line":328},4,[160,330,331],{"class":305},"Wants",[160,333,310],{"class":309},[160,335,325],{"class":313},[160,337,338,341,343],{"class":162,"line":59},[160,339,340],{"class":305},"StartLimitIntervalSec",[160,342,310],{"class":309},[160,344,345],{"class":313},"0\n",[160,347,349],{"class":162,"line":348},6,[160,350,352],{"emptyLinePlaceholder":351},true,"\n",[160,354,356],{"class":162,"line":355},7,[160,357,358],{"class":298},"[Service]\n",[160,360,362,365,367],{"class":162,"line":361},8,[160,363,364],{"class":305},"Type",[160,366,310],{"class":309},[160,368,369],{"class":313},"simple\n",[160,371,373,376,378],{"class":162,"line":372},9,[160,374,375],{"class":305},"User",[160,377,310],{"class":309},[160,379,380],{"class":313},"pi\n",[160,382,384,387,389],{"class":162,"line":383},10,[160,385,386],{"class":305},"WorkingDirectory",[160,388,310],{"class":309},[160,390,391],{"class":313},"/home/pi/SlowMovie\n",[160,393,395,398,400,403,405],{"class":162,"line":394},11,[160,396,397],{"class":305},"Environment",[160,399,310],{"class":309},[160,401,402],{"class":305},"PYTHONUNBUFFERED",[160,404,310],{"class":309},[160,406,407],{"class":313},"1\n",[160,409,411,414,416],{"class":162,"line":410},12,[160,412,413],{"class":305},"ExecStart",[160,415,310],{"class":309},[160,417,418],{"class":313},"/home/pi/SlowMovie/.SlowMovie/bin/python /home/pi/SlowMovie/slowmovie.py \\\n",[160,420,422],{"class":162,"line":421},13,[160,423,424],{"class":313},"          -f /home/pi/SlowMovie/Videos/Titanic.mkv -d 60 -i 1 -l\n",[160,426,428,431,433],{"class":162,"line":427},14,[160,429,430],{"class":305},"Restart",[160,432,310],{"class":309},[160,434,435],{"class":313},"on-failure\n",[160,437,439,442,444],{"class":162,"line":438},15,[160,440,441],{"class":305},"RestartSec",[160,443,310],{"class":309},[160,445,446],{"class":313},"5\n",[160,448,450,453,455],{"class":162,"line":449},16,[160,451,452],{"class":305},"StandardOutput",[160,454,310],{"class":309},[160,456,457],{"class":313},"journal\n",[160,459,461,464,466],{"class":162,"line":460},17,[160,462,463],{"class":305},"StandardError",[160,465,310],{"class":309},[160,467,457],{"class":313},[160,469,471],{"class":162,"line":470},18,[160,472,352],{"emptyLinePlaceholder":351},[160,474,476],{"class":162,"line":475},19,[160,477,478],{"class":298},"[Install]\n",[160,480,482,485,487],{"class":162,"line":481},20,[160,483,484],{"class":305},"WantedBy",[160,486,310],{"class":309},[160,488,489],{"class":313},"multi-user.target\n",[11,491,492],{},"然后按Ctrl+O后回车保存，Ctrl+X退出。虽然不是Vim这种乌干达恶意软件，但还是值得说一下。",[39,494,495],{"start":302},[42,496,497],{},"开启服务",[150,499,501],{"className":152,"code":500,"language":154,"meta":155,"style":155},"sudo systemctl daemon-reload\nsudo systemctl enable slowmovie.service\nsudo systemctl start slowmovie.service\n",[157,502,503,513,525],{"__ignoreMap":155},[160,504,505,507,510],{"class":162,"line":163},[160,506,277],{"class":166},[160,508,509],{"class":176}," systemctl",[160,511,512],{"class":176}," daemon-reload\n",[160,514,515,517,519,522],{"class":162,"line":302},[160,516,277],{"class":166},[160,518,509],{"class":176},[160,520,521],{"class":176}," enable",[160,523,524],{"class":176}," slowmovie.service\n",[160,526,527,529,531,534],{"class":162,"line":317},[160,528,277],{"class":166},[160,530,509],{"class":176},[160,532,533],{"class":176}," start",[160,535,524],{"class":176},[11,537,538],{},"这样应该就可以了，断电重插一次，看看是否符合预期。",[29,540],{},[542,543,544,547,550],"blockquote",{},[11,545,546],{},"Once more, you open the door",[11,548,549],{},"And you're here in my heart",[11,551,552],{},"And my heart will go on and on",[554,555,556],"style",{},"html pre.shiki code .slNdt, html code.shiki .slNdt{--shiki-default:#61AFEF;--shiki-dark:#61AFEF;--shiki-light:#6F42C1}html pre.shiki code .sZaK-, html code.shiki .sZaK-{--shiki-default:#98C379;--shiki-dark:#98C379;--shiki-light:#22863A}html pre.shiki code .sVtDz, html code.shiki .sVtDz{--shiki-default:#98C379;--shiki-dark:#98C379;--shiki-light:#2B5581}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html pre.shiki code .stC8A, html code.shiki .stC8A{--shiki-default:#D19A66;--shiki-dark:#D19A66;--shiki-light:#2B5581}html pre.shiki code .sWEYk, html code.shiki .sWEYk{--shiki-default:#D19A66;--shiki-dark:#D19A66;--shiki-light:#1976D2}html pre.shiki code .skjSQ, html code.shiki .skjSQ{--shiki-default:#61AFEF;--shiki-dark:#61AFEF;--shiki-light:#24292EFF}html pre.shiki code .sSCA1, html code.shiki .sSCA1{--shiki-default:#C678DD;--shiki-dark:#C678DD;--shiki-light:#D32F2F}html pre.shiki code .s3Kl_, html code.shiki .s3Kl_{--shiki-default:#ABB2BF;--shiki-dark:#ABB2BF;--shiki-light:#D32F2F}html pre.shiki code .sbbSH, html code.shiki .sbbSH{--shiki-default:#98C379;--shiki-dark:#98C379;--shiki-light:#24292EFF}",{"title":155,"searchDepth":302,"depth":302,"links":558},[],"devlog","Titanic.jpg",null,"2025-11-13","我心永恒","md",{},"/posts/raspberrypi",false,{"title":6,"description":563},"posts/raspberrypi","4XZMHRzy0FeZPdUg6FUoXudcT5URK3VhZji2969izzo",{"id":572,"title":573,"body":574,"category":559,"cover":668,"coverAlt":561,"date":669,"description":670,"extension":564,"meta":671,"navigation":351,"path":672,"pinned":567,"seo":673,"stem":674,"__hash__":675},"posts/posts/devlog-fix.md","QML笑传之ComboComboBox",{"type":8,"value":575,"toc":666},[576,579,584,587,590,660,663],[11,577,578],{},"调整前端布局的方式有很多，但是这个有点意外。",[542,580,581],{},[11,582,583],{},"现在我明白问题所在了！",[11,585,586],{},"最近用上了cursor，别的不说，虽然离自然语言编程有点距离，但情绪价值是拉满的，我也在这一声声你是对的里面不断给大模型机会，希望他能真正找到问题。",[11,588,589],{},"但是这一次，我是真的错怪大模型了。QML的底层代码简直是一坨狗屎，很多问题在stackoverflow甚至搜不到，这次的项目中，我们遇到了一个GUI会莫名其妙变形挤压的问题，本以为是自己学艺不精在哪里配错了css，但忙了一下午，由下面一段代码修复了问题：",[150,591,595],{"className":592,"code":593,"language":594,"meta":155,"style":155},"language-qml shiki shiki-themes one-dark-pro one-dark-pro min-light"," ComboBox {\n    width: 0\n    height: 40\n    model: [\"Don't remove this ComboBox\"]\n    indicator: Canvas {}\n}\n","qml",[157,596,597,607,618,628,642,655],{"__ignoreMap":155},[160,598,599,603],{"class":162,"line":163},[160,600,602],{"class":601},"s1pBA"," ComboBox",[160,604,606],{"class":605},"s0bQm"," {\n",[160,608,609,613,616],{"class":162,"line":302},[160,610,612],{"class":611},"sQkFB","    width",[160,614,615],{"class":605},": ",[160,617,345],{"class":242},[160,619,620,623,625],{"class":162,"line":317},[160,621,622],{"class":611},"    height",[160,624,615],{"class":605},[160,626,627],{"class":242},"40\n",[160,629,630,633,636,639],{"class":162,"line":328},[160,631,632],{"class":611},"    model",[160,634,635],{"class":605},": [",[160,637,638],{"class":169},"\"Don't remove this ComboBox\"",[160,640,641],{"class":605},"]\n",[160,643,644,647,649,652],{"class":162,"line":59},[160,645,646],{"class":611},"    indicator",[160,648,615],{"class":605},[160,650,651],{"class":601},"Canvas",[160,653,654],{"class":605}," {}\n",[160,656,657],{"class":162,"line":348},[160,658,659],{"class":605},"}\n",[11,661,662],{},"这个不会显示任何东西，但可以为QML的莫名其妙distortion挡下一刀，维持其他组件的正常运转。很神奇吧。",[554,664,665],{},"html pre.shiki code .s1pBA, html code.shiki .s1pBA{--shiki-default:#E5C07B;--shiki-dark:#E5C07B;--shiki-light:#6F42C1}html pre.shiki code .s0bQm, html code.shiki .s0bQm{--shiki-default:#ABB2BF;--shiki-dark:#ABB2BF;--shiki-light:#24292EFF}html pre.shiki code .sQkFB, html code.shiki .sQkFB{--shiki-default:#E06C75;--shiki-default-font-style:italic;--shiki-dark:#E06C75;--shiki-dark-font-style:italic;--shiki-light:#24292EFF;--shiki-light-font-style:inherit}html pre.shiki code .sWEYk, html code.shiki .sWEYk{--shiki-default:#D19A66;--shiki-dark:#D19A66;--shiki-light:#1976D2}html pre.shiki code .sZaK-, html code.shiki .sZaK-{--shiki-default:#98C379;--shiki-dark:#98C379;--shiki-light:#22863A}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}",{"title":155,"searchDepth":302,"depth":302,"links":667},[],"ccb.png","2025-08-14","靠近QML，人生就会变得不幸",{},"/posts/devlog-fix",{"title":573,"description":670},"posts/devlog-fix","_GngkvQZSsNTVxim3oWAU6JcBCkW_zWdGPbEDHSXtOU",1766568023004]