<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
  <title>九月半的笔记</title>
  <description>九月半的个人博客，记录前端开发、折腾过程、生活碎片和随手想法。</description>
  <link>https://552412.xyz/</link>
  <atom:link href="https://552412.xyz/rss.xml" rel="self" type="application/rss+xml" />
<item>
  <title>hello word !</title>
  <link>https://552412.xyz/blog/2026-04-11/</link>
  <guid isPermaLink="true">https://552412.xyz/blog/2026-04-11/</guid>
  <description>九月半的第一篇博客</description>
  <pubDate>Fri, 12 Jun 2026 20:22:33 +0800</pubDate>
  <content:encoded><![CDATA[<p>我的博客上线了</p>]]></content:encoded>
</item>
<item>
  <title>实况图翻车记录</title>
  <link>https://552412.xyz/blog/2026-04-30/</link>
  <guid isPermaLink="true">https://552412.xyz/blog/2026-04-30/</guid>
  <description>博客里折腾实况图时，配套视频在部分浏览器里横过来的排查和处理。</description>
  <pubDate>Fri, 12 Jun 2026 20:22:33 +0800</pubDate>
  <content:encoded><![CDATA[<p>最近给博客加实况图，本来以为最麻烦的地方会是上传、压缩、封面和视频怎么绑在一起，结果真正卡住我的反而是一个很莫名其妙的问题：同一段竖屏视频，在 Chrome 和 Edge 里都好好的，到了 ColorOS 自带的欢太浏览器里，画面直接横过来了。</p>
<p>封面图是正的，横屏 Live 也正常，只有竖屏视频一播放就不对。那种感觉就很微妙，代码看起来没错，文件看起来也没错，只有浏览器在很认真地告诉你：我有自己的想法。（左图是封面，视频文件还在加载中，右图是视频播放中）</p>
<div class="content-media-row content-media-row--2">
  <img src="https://blogfiles.552412.xyz/72507e11b4c9cb4ba62bf4eb5f6d4244-1777104848899.webp" alt="72507e11b4c9cb4ba62bf4eb5f6d4244-1777104848899" />
  <img src="https://blogfiles.552412.xyz/60e0027e62dd9e1451afbf1faca5243c-1777104856741.webp" alt="60e0027e62dd9e1451afbf1faca5243c-1777104856741" />
</div>
<p>一开始我以为是 <code>rotation: 90</code> 这个信息没被读到。后来又对比了几段视频，感觉这个判断不一定完全准。横屏视频不管手机充电口朝右拍，还是朝左拍，在欢太浏览器里都没问题；真正翻车的是竖屏视频。也就是说，它未必是完全没读 rotation，更像是某个环节先按视频宽高比例判断了方向，后面再和旋转信息没对齐。</p>
<p>要理解这个问题为什么容易出现，还得从竖屏视频本身说起。以前视频更多是电视、电影、相机这类场景，默认就是横屏，编码和播放链路也基本围绕横屏来设计。到了手机时代，大家开始天天竖着拿手机拍视频，但底层的传感器、编码器，还有很多播放器逻辑，仍然带着过去那套横屏习惯。</p>
<p>所以手机厂商为了录制性能和处理速度，很多时候不会在拍摄时把每一帧都真的转成竖着的像素，而是继续按更方便处理的横向画面去编码，再在 MP4 里面写一个方向提示，也就是类似 <code>rotation: 90</code> 的标识。大概意思是：文件里的画面先这样存，播放的时候记得帮我转一下。</p>
<p>所以一个看起来是竖屏的视频，在文件内部可能长这样：</p>
<pre><code class="language-text">真实编码帧：1920 x 1080
播放时方向：旋转 90 度
最终看起来：1080 x 1920
</code></pre>
<p>这套设计其实挺合理的。手机录制视频的时候少做一层旋转处理，性能和链路都会省心一点。播放器如果足够听话，读到方向矩阵之后按它来展示，用户也完全感觉不到中间发生了什么。</p>
<p>问题就在这里：它要求播放器不只是读到方向信息，还要在宽高判断、页面布局、视频解码和最终渲染这几步里都保持一致。</p>
<p>Chrome、Edge 这些浏览器处理得没问题，封面、布局、视频方向都能对上。但一些系统浏览器或者 WebView 里，视频这条链路可能不是同一套逻辑走到底。也许前面按 <code>videoWidth</code> / <code>videoHeight</code> 或原始编码帧宽高判断它是横屏，也许后面又读到了 rotation，也许硬解那里还有自己的处理方式。只要其中一步没对齐，最后落到页面上，就可能变成封面是竖的，框也是竖的，但视频画面一开始动就横了。</p>
<p>这个问题最烦的地方是，它不是那种一眼能修的 bug。你不能简单写一句 CSS 旋转一下，因为在正常浏览器里它又会被你转歪。你也不能只改 metadata，重新写个 <code>rotate=90</code>，因为出问题的浏览器本来就可能是不稳定地处理这个信息。它愿意听的时候都正常，不愿意听的时候你再写一遍也没什么用。</p>
<p>后来我干脆换了思路：不让浏览器猜了，直接把方向烙进视频像素里。</p>
<p>也就是用 FFmpeg 重新转一遍。输入文件如果是“横向编码帧 + 旋转提示”，转码时让 FFmpeg 先按这个提示把画面摆正，再输出一个真正竖屏尺寸的 MP4。处理完之后文件就变成：</p>
<pre><code class="language-text">真实编码帧：720 x 1280
播放时方向：不用额外旋转
</code></pre>
<p>这样浏览器就不用理解什么 display matrix，也不用在播放时猜方向。它只需要做一件最普通的事：播放一个正常的 H.264 MP4。</p>
<p>我后来把这套逻辑放进了 CMS。实际上传的时候不是无脑把所有视频都重压一遍，而是先让浏览器读一下视频的展示宽高。如果读出来是横屏，并且没有勾选“横屏也转码压缩”，就直接上传原文件；如果是竖屏，或者我手动要求横屏也压缩，才会拉起 FFmpeg 处理。</p>
<p>CMS 里现在有几个预设：均衡是 720 / CRF 24 / 30fps / 96k 音频，清晰是 1080 / CRF 21，小体积是 540 / CRF 28。平时我基本用均衡档，够清楚，文件也不会太夸张。</p>
<p>它最后拼出来的 FFmpeg 参数大概是这样：</p>
<pre><code class="language-text">ffmpeg -i input.mov \
  -map 0:v:0 -map 0:a? \
  -vf &quot;scale=w=min(720\,iw):h=-2,setsar=1,format=yuv420p&quot; \
  -r 30 \
  -c:v libx264 -preset veryfast -crf 24 \
  -profile:v main -level 4.0 \
  -c:a aac -b:a 96k -ac 2 -ar 44100 \
  -map_metadata -1 -map_chapters -1 \
  -metadata:s:v:0 rotate=0 \
  -movflags +faststart \
  output.mp4
</code></pre>
<p>这里不是为了追求参数有多漂亮，主要是把几个容易出问题的地方提前收掉。<code>scale</code> 控制尺寸，避免一张实况图视频动不动就很大；<code>setsar=1</code> 把像素比例归一，少一点奇怪的宽高比问题；<code>format=yuv420p</code> 和 <code>libx264</code> 是为了让输出尽量普通，普通到大部分浏览器都能直接播；<code>rotate=0</code> 是把方向问题在转码阶段解决掉，别再留一个旋转提示给播放器猜；<code>+faststart</code> 则是让 MP4 在网页里更快开始加载。</p>
<p>上传链路里还做了几层小保险。比如会扫视频头里的 <code>hvc1</code>、<code>hev1</code>、<code>avc1</code> 这些标识，检测到 HEVC / H.265 就直接拦下来，因为这个格式在网页预览里太容易翻车。iPhone 单视频上传时，CMS 会从视频里截一帧当封面；安卓 Motion Photo 则会先从 JPG 里把封面和内嵌 MP4 拆开，封面再用 canvas 过一遍方向，视频再走同一套 FFmpeg 归一化。最后上传到 R2 的时候，已经是封面图和视频分开的两份资源，再生成一段 <code>&lt;p&gt;&lt;a href=&quot;...&quot;&gt;&lt;img src=&quot;...&quot; alt=&quot;Live Photo&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</code> 给文章用。</p>
<p>这个方案肯定不算最省事，也不一定最省体积，但对博客来说挺合适。文章里的实况图不是拿来做无损存档的，重点是别人打开页面时能正常看，不要在某个浏览器里突然横着躺下。</p>
<p>顺便还遇到另一个问题。QQ 浏览器这类带 TBS/X5 内核的安卓浏览器，会对页面里的 video 做自己的处理。我给视频加了 <code>playsinline</code>、<code>webkit-playsinline</code>、<code>x5-playsinline</code>、<code>x5-video-player-type=&quot;h5&quot;</code>，也禁了画中画和远程播放，但实际表现还是不够稳定：有时视频层会被接管，盖到封面上面；有时点击之后又会走浏览器自己的播放提示，甚至跳到单独页面播放。</p>
<p>折腾到这里我就不想硬刚了。展示端现在直接检测 Android 上的 QQBrowser / MQQBrowser / TBS，命中后进入封面模式：关掉自动播放和循环，移除 video 的 <code>src</code>，只保留封面。这样至少页面不会坏，也不会给读者一个半能播半不能播的奇怪体验。</p>
<div class="content-media-row content-media-row--3">
  <img src="https://blogfiles.552412.xyz/1bfd05d0e87ec65c5fda5c387f1b2754-1777107325520.webp" />
  <img src="https://blogfiles.552412.xyz/fae1448cd6d44ec07adc4bd761442135-1777105982630.webp" />
  <img src="https://blogfiles.552412.xyz/09e8d2d4803031b203328ac13679770c-1777106004961.webp" />
  <img src="https://blogfiles.552412.xyz/31da735aa9c6d569b8c1fede1d6f61b8-1777107574737.webp" />
</div>
<p>本文专业性问题，靠 AI 搜索专业文献后总结整理，理解上如果有偏差，请大佬指正</p>
<p>最后给自己记个结论：</p>
<pre><code class="language-text">如果视频只是自己看，保留 rotation metadata 一般没问题。
如果视频要放到网页里给各种浏览器播放，尤其还要照顾系统浏览器和 WebView，最好把方向直接转进像素里。
</code></pre>
<p>这次折腾下来最大的感受是，网页里的视频兼容性比图片麻烦多了。图片基本就是给一个地址，浏览器展示出来；视频中间还隔着编码、封装、方向矩阵、硬解、内联播放、浏览器策略。每一层都可能很合理，但叠在一起就会出现一些很不好解释的现象。</p>
<p>所以跟视频相关的东西，把麻烦尽量留在上传阶段，别把播放效果交给浏览器临场发挥。浏览器能不能正确处理这些细节不太确定，能提前处理掉就提前处理掉。</p>
<p>最后放两张live图</p>
<div class="content-media-row content-media-row--2">
  <p><a href="https://blogfiles.552412.xyz/live/android/5424/5424-1777087470324.mp4"><img src="https://blogfiles.552412.xyz/live/android/5424/5424-1777087470324.jpg" alt="Live Photo" /></a></p>
  <p><a href="https://blogfiles.552412.xyz/live/iphone/e35424d6_3e00_4de1_8da7_44d4aa86233f/E35424D6-3E00-4DE1-8DA7-44D4AA86233F-1777110291876.mp4"><img src="https://blogfiles.552412.xyz/live/iphone/e35424d6_3e00_4de1_8da7_44d4aa86233f/E35424D6-3E00-4DE1-8DA7-44D4AA86233F-1777110291876.jpg" alt="Live Photo" /></a></p>
</div>]]></content:encoded>
</item>
<item>
  <title>跟一位工作七八年的前端同事沟通让我血压飙升</title>
  <link>https://552412.xyz/blog/2026-06-12/</link>
  <guid isPermaLink="true">https://552412.xyz/blog/2026-06-12/</guid>
  <description>事情是这样，我有个分支要上测试服给测试看；我先用我自己分支拉取了下master，然后本地切到测试分支拉我自己分支，出现好几个文件的冲突，我不想自己解决，随即找到该冲突的提交人。我不想自己解决冲突的还一个原因，之前跟这位同事做同一个需求，非说我把他东西合没了，做那个需求的时候，我拉...</description>
  <pubDate>Fri, 12 Jun 2026 20:08:00 +0800</pubDate>
  <content:encoded><![CDATA[<p>事情是这样，我有个分支要上测试服给测试看；我先用我自己分支拉取了下master，然后本地切到测试分支拉我自己分支，出现好几个文件的冲突，我不想自己解决，随即找到该冲突的提交人。我不想自己解决冲突的还一个原因，之前跟这位同事做同一个需求，非说我把他东西合没了，做那个需求的时候，我拉代码都没起过冲突，来一口莫名其妙的锅。然后就发生了图上的对话，我实在难以想象一个干了这么多年的人能这么蠢，到现在不知道写代码要以主分支为主，跟他聊几句给我气的冒汗了，纯tm傻逼，最后还是我自己解决的，这位同事的雷点多的数不清，这里就懒得写太多了</p>
<div class="content-media-row content-media-row--2">
  <img src="https://blogfiles.552412.xyz/%E5%85%B6%E4%BB%96/sbts1.webp" alt="sbts1" />
  <img src="https://blogfiles.552412.xyz/%E5%85%B6%E4%BB%96/sbts2.webp" alt="sbts2" />
</div>]]></content:encoded>
</item>
<item>
  <title>blogsclub 5.20号兑换的鼠标垫到了</title>
  <link>https://552412.xyz/blog/2026-05-24/</link>
  <guid isPermaLink="true">https://552412.xyz/blog/2026-05-24/</guid>
  <description>上次的两周年纪念币没抢到，这次520活动又有兑换鼠标垫的活动，我的积分还不到1，有个0.01兑换的只有六份 并且我刚好满足条件（需要有一篇博客入选时光精选 我博客才搭建不久，还只发过3篇 能入选一篇十分荣幸），本来准备晚上十二点钟抢的，结果又搞忘记了（下次我一定要定个闹钟），上午...</description>
  <pubDate>Sun, 24 May 2026 21:41:00 +0800</pubDate>
  <content:encoded><![CDATA[<p>上次的两周年纪念币没抢到，这次520活动又有兑换鼠标垫的活动，我的积分还不到1，有个0.01兑换的只有六份 并且我刚好满足条件（需要有一篇博客入选时光精选 我博客才搭建不久，还只发过3篇 能入选一篇十分荣幸），本来准备晚上十二点钟抢的，结果又搞忘记了（下次我一定要定个闹钟），上午上班打开qq看到blogsclub群里在说这个事才想起来，点进去一看，运气爆棚刚好还一个库存。</p>
<div class="content-media-row">
  <img src="https://blogfiles.552412.xyz/image-1779238329360.webp" alt="image-1779238329360" />
</div> 
<p>快递其实昨天就拿到了，只是拖延症又犯了今天才写博客记录。拆开里面居然有三张，可以拿一张放公司用了。</p>
<p>白熊大佬真是大善人，为爱发电搭建blogsclub 还经常不定期做这种实物活动，当初申请其他几个博客收录网站，因创建时间短、文章数量少都被拒绝收录了，只有blogsclub跟笔墨迹收留了我。真心祝愿blogsclub越来越好</p>
<div class="content-media-row content-media-row--2">
  <img src="https://blogfiles.552412.xyz/life/IMG20260523130328-1779627642472.webp" alt="IMG20260523130328-1779627642472" />
  <img src="https://blogfiles.552412.xyz/life/IMG_20260524_204700-1779627671384.webp" alt="IMG_20260524_204700-1779627671384" />
</div>]]></content:encoded>
</item>
<item>
  <title>还没候补到五一返程票</title>
  <link>https://552412.xyz/blog/2026-05-05/</link>
  <guid isPermaLink="true">https://552412.xyz/blog/2026-05-05/</guid>
  <description>失眠了，5号下午回去的高铁票 35%的成功率，没候补到还要重新订酒店，还得请一天假，玩也没心思玩了。</description>
  <pubDate>Tue, 05 May 2026 03:02:00 +0800</pubDate>
  <content:encoded><![CDATA[<p>失眠了，5号下午回去的高铁票 35%的成功率，没候补到还要重新订酒店，还得请一天假，玩也没心思玩了。</p>]]></content:encoded>
</item>
<item>
  <title>充实的周末</title>
  <link>https://552412.xyz/blog/2026-04-26/</link>
  <guid isPermaLink="true">https://552412.xyz/blog/2026-04-26/</guid>
  <description>周末随笔</description>
  <pubDate>Mon, 27 Apr 2026 00:32:00 +0800</pubDate>
  <content:encoded><![CDATA[<p>今天一觉睡到十点多，天气很不错，跟朋友约好了一起去露营。想到今天要给手机贴膜来着然后忘记预约了，这个预约不能预约当天，就试着去oppo售后看看能不能贴，结果是可以的。而且售后服务很好，进来还给端了茶水，贴完还给手机里外都用酒精仔细擦拭了一遍，跟我说下次贴膜可以直接过来，他们可以直接用IMEI码扣除次数。ps:oppo账号每年都有免费贴膜次数，次数多少按等级来的，而且这个等级 可以把账号登录到没登过的设备就可以加成长值。</p>
<p>中午去小吃街买了点吃的，然后就一直在找能绑下个两张吊床的三棵树 找了好久，在吊床睡上到五点多，出去觅食后回家路上经过移动营业厅，七点四十几刚好还没下班，之前想来弄个移动爱家一直没空来，五张卡消费满80，送200分钟共享通话跟18g流量。还有40年网龄也拉满了，可以选2000分钟通话跟80g流量。我选的80g，80元档还可以免费办理300m宽带一条，营业厅工作人员说我怎么比他们还清楚 哈哈哈。我父母移动卡都被我改成了保号套餐 然后另外给他们一人弄了一张流量卡，但是偶尔还是会切成移动的流量，弄完这个再也不用担心他们流量或者通话用超了。
最后放几张周末的照片</p>
<div class="content-media-masonry content-media-masonry--3">
  <img src="https://blogfiles.552412.xyz/IMG20260425193052-1777219249804.webp" alt="IMG20260425193052-1777219249804" />
  <img src="https://blogfiles.552412.xyz/IMG20260426140357-1777219983398.webp" alt="IMG20260426140357-1777219983398" />
  <img src="https://blogfiles.552412.xyz/IMG20260426152333-1777220428834.webp" alt="IMG20260426152333-1777220428834" />
  <p><a href="https://blogfiles.552412.xyz/live/android/5543/5543-1777220345342.mp4"><img src="https://blogfiles.552412.xyz/live/android/5543/5543-1777220345342.jpg" alt="Live Photo" /></a></p>
  <p><a href="https://blogfiles.552412.xyz/live/android/5545/5545-1777219821807.mp4"><img src="https://blogfiles.552412.xyz/live/android/5545/5545-1777219821807.jpg" alt="Live Photo" /></a></p>
  <p><a href="https://blogfiles.552412.xyz/live/android/5528/5528-1777220068294.mp4"><img src="https://blogfiles.552412.xyz/live/android/5528/5528-1777220068294.jpg" alt="Live Photo" /></a></p>
</div>
<p>实况图上传设置的60帧 文件有点大可能加载会有点慢</p>
<div class="content-media-row content-media-row--3">
  <img src="https://blogfiles.552412.xyz/Screenshot_2026-04-27-00-19-25-69_40deb401b9ffe8e1df2f1cc5ba480b12-1777220449797.webp" alt="Screenshot_2026-04-27-00-19-25-69_40deb401b9ffe8e1df2f1cc5ba480b12-1777220449797" />
</div>
<img src="https://blogfiles.552412.xyz/40c4f3ca24ae566d0511ae72c7336263-1777250362214.webp" alt="40c4f3ca24ae566d0511ae72c7336263-1777250362214.webp" />
<div class="content-media-row content-media-row--2">
  <img src="https://blogfiles.552412.xyz/IMG_20260427_001143-1777219926414.webp" />
  <img src="https://blogfiles.552412.xyz/Screenshot_2026-04-26-22-04-58-86_4a6fd1fd883187ffdfd8f285cf1ef901-1777219404816.webp" />
</div>
<p>写完已经十二点半了 手机端cms系统还是有点难用 尤其是插图这块 有空了再优化吧</p>]]></content:encoded>
</item>
</channel>
</rss>