分类: 工具

  • 应用创意:视频粗剪工具

    应用创意:视频粗剪工具

    今年业余时间主攻视频和直播,有大量视频剪辑的需求。一个一个细细剪对我来说实在不现实,一直想找人帮忙——但是没钱,所以退而求其次,想找工具自动化处理。所以才有了上篇博客:使用 jumpcutter 粗剪视频,移除静音片段

    可惜的是,这个工具不够强大,也不太合适我用。我不是 Vloger,我的视频大部分都是对着屏幕讲解代码和效果,所以我不太可能用👍👎拆分视频,也无法让👍👎帮我处理视频。我需要的是:

    1. 自动剪掉“嗯”、“啊”、“哦”、“这个”、“那个”
    2. 自动剪掉没有声音的空白帧
    3. 根据语音命令,自动生成补帧:
      1. 强调“XXXX”:自动在屏幕上打上“XXXX”几个大字
      2. 前面这段不要:提醒我要删掉一段内容
      3. 插图“XXXX”:插入一张图片,内容是“XXXX”搜索的结果
    4. 修改文字,等同修改视频
    5. 利用剩下的文字自动生成字幕
    6. 导出 Pr/FCP 等的项目工程文件,方便继续编辑
    7. 在线剪辑

    大约是即整合这三个视频之所长:

    Automatic on-the-fly video editing tool!
    我開發了自動剪輯神器!讓Youtuber更快產片!剪輯師接更多案!【六指淵 Huber】
    Introducing Descript

    目前看来,除了在线剪辑、输出配置文件,其它功能都不太难:

    1. 从视频中提取音频(ffmpeg)
    2. 使用阿里云 STT 服务将音频转换成包含分词、包含时间节点的字幕文件
    3. 展示文案,允许编辑,跳到指定位置播放
    4. 输出 ffmpeg 命令,直至输出视频

    似乎这些我都能做,好像可以试着动手了。但是这样一来,就没时间剪上周录的视频了……不知道究竟是工欲善其事必先利其器,还是给自己挖下一个新坑呢……

  • 使用 jumpcutter 粗剪视频,移除静音片段

    使用 jumpcutter 粗剪视频,移除静音片段

    今年打算在直播和视频上做点努力,所以通过直播录了不少视频,周末想剪一剪,但是一方面我不擅长剪视频,另一方面也没有合适的工具,所以颇费了一些周折。

    后来发现 jumpcutter,按照其作者的设计,它可以识别视频中的 👍 和 👎,只保留 👍 的片段,剪掉 👎 的片段;并且可以自动剪掉没有声音的部分,这样视频可以很快完成初剪。

    前面的功能很炫酷,不过对于我来说不太实用,后面的功能比较有价值,于是我试用了一下,记录过程如下:

    # clone 代码到本地
    git clone git@github.com:carykh/jumpcutter.git
    
    # 安装依赖,位于 requirements.txt
    pip3 install Pillow audiotsm scipy numpy pytube
    
    # 然后就可以使用了
    python3.9 jumpcutter.py --input_file left.mp4 --output_file ./1.mp4 --silent_threshold 0.06 --silent_speed 99

    其它参数如下:

    --input_file目标视频
    --urlYouTube 视频,国内用户用途不大
    --output_file输出视频
    --silent_threshold静音阈值,即多小的声音可以认为是有声音的(浮点数,0~1,默认 0.03)
    --sounded_speed有声音的片段,以怎样的速率播放(浮点数,默认 1)
    --silent_speed静音的片段,以怎样的速度播放(浮点数,默认5,即 5 倍速度)
    --frame_margin在有声音的片段两边保留多少间隔(默认1)
    --sample_rate声音取样率
    --frame_rate帧数
    --frame_quality质量
    参数列表

    比如前面我用的命令,就是认为小于 0.06 的声音为静音,静音播放速率 99(基本上直接跳过了)。

    我处理了两段视频,感兴趣的同学可以试一试:

    接下来我还想做两个功能,有了这两个功能视频处理后基本就能满足我的需求了:

    1. 找到“嗯”、“哦”、“那个”等无意义的语气助词,把它们干掉
    2. 识别“上一段不要”这样的语音命令,并且找到最合适的片段干掉
  • Windows 10 配置 WSL2 以及图形界面

    Windows 10 配置 WSL2 以及图形界面

    前阵子把台式机的 WSL 升级到了 WSL2,顺便配置好图形界面,写篇博客记录一下。

    0. 卸载 WSL,开启 CPU 虚拟化功能

    如果之前安装过 WSL,需要先备份重要数据,然后卸载,再安装 WSL2。

    重启,在 BIOS 设置里开启 CPU 虚拟化支持。

    1. 简单安装:利用 Windows Insider

    加入 Windows Insider 计划,升级到预览版本(>=20262),直接安装。好处是方便,而且可以安装最新版本,可以访问 Linux 分区。

    坏处是不太稳定,预览版嘛。我觉得不太放心,决定还是在稳定版上安装。

    2. 手动在 Windows 10 标准版上安装

    2.1 检查 Windows 10 版本

    需 >= 1903(18362)。我每周更新,没有问题。

    2.2 启动虚拟化支持

    dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

    2.3 下载 WSL2 升级包并安装

    WSL2 Linux kernel update package for x64 machines

    2.4 配置 WSL 默认版本为 2

    # 设置 WSL 默认版本
    wsl --set-default-version 2
    
    # 列出所有 WSL 版本
    wsl --list --verbose
    
    # 将特定发行版设置为指定版本
    wsl --set-version <distribution name> <versionNumber>  

    2.5 在 Microsoft 商店里安装 Linux 发行版

    我安装的是 Ubuntu 20.04。安装后需要进行一些配置工作,此处不再赘述。

    至此,WSL2 配置完成,接下来配置图形界面。

    3. 配置 WSL2 的图形界面

    3.0 更新系统

    按照惯例先把能更新的系统组件更新到最新:

    sudo apt update
    sudo apt upgrade

    3.1 安装 GUI 组件

    sudo apt install -y tasksel
    sudo tasksel install xubuntu-desktop
    sudo apt install gtk2-engines

    WSL2 目前并不支持图形界面,所以这里计划让 Ubuntu 使用 Windows X-server 来绕过。安装的过程会比较久,因为要下载很多东西,请耐心等待。

    3.2 配置显示器信息

    接下来要配置显示器信息,方便 Linux 使用:

    export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2; exit;}'):0.0
    export LIBGL_ALWAYS_INDIRECT=1
    sudo /etc/init.d/dbus start &> /dev/null

    把上面这段配置加入 ~/.bashrc,当我们登入 WSL 时,就会自动完成配置。不过这样一来,每次登入都要敲密码,也有点麻烦,所以可以自己取舍一下。或者把上面的配置单独存放一个脚本文件,需要使用 GUI 的时候再运行启动。

    3.3 在 Windows 10 安装 X-server

    参考文档中推荐了两个软件:VcXsrv(免费)和 x410(收费)。我本来想花钱点,可是后者不支持国区购买,所以只好选用 VcXsrv。

    下载,安装,启动 VcXsrv。接下来 VcXsrv 会要求我们配置使用方式,依次选择“Multiple Windows”、“Start no client”,并且勾选“Disable access control”,然后保存配置文件到本地,完成启动。以后可以通过双击配置文件启动 VcXsrv。

    此时,在系统托盘里可以看到 VcXsrv 服务。

    3.4 启动 GUI 程序

    接下来正常启动 GUI 程序即可,比如 Firefox:

    sudo apt install firefox
    
    # 安装完成后,启动 firefox
    # 注意,这里必须用 sudo
    sudo firefox 

    总结&参考文档

    至此,安装配置完成。安装配置中我参考了以下文章:

    遗留问题

    涉及到硬盘操作的功能会非常慢,比如打开目录,到目录内容完全呈现出来,需要数分钟之久。我记得当年初用 WSL 的时候也遇到过这个问题,后来通过关闭安全扫描解决了,不知道这次是不是同样的问题。(这次没找到关闭安全扫描的位置……)

  • 使用 site-validator 验证网站链接

    使用 site-validator 验证网站链接

    网站死链的问题比较常见,坏处就不多说了,大家应该都明白。想解决这个问题并不容易,主要难点在发现死链。如果是纯静态网站就比较简单,直接查服务器的 404 日志即可;如果是动态的,比如 SPA,就比较难搞。

    所以我做了这个项目:site-validator。其实非常简单,用 puppeteer 访问网站,找出所有链接,一级一级点下去,直到把一个网站的链接都点一遍为止。记录下所有的死链,输出,然后排查。

    代码简单,但是确实很实用,帮我厂找到不少死链,很好的提升了搜索表现。将来考虑再加一些新功能进去,比如集成 lighthouse 审计之类的。有兴趣的同学可以下载使用,也欢迎提意见和 issue 哦。

  • 推荐网页 IM:Drift

    推荐网页 IM:Drift

    可能有些同学注意到了,最近两个月,只要打开这个博客并且稍微浏览一会儿,右下角就会弹出一个聊天框。此时读者就可以跟我聊天,如果我当时在线(打开了管理端),就能看到消息并且实时回复;如果我不在线,可以上线后再回复,读者下次回到博客时,也可以看到消息。

    这个工具就是 Drift,它本质上是一个面向商家的网页 IM,支持匿名聊天,方便客户与商家交流。有点类似淘宝旺旺,只不过它可以嵌入任意网站。

    实际上我是帮我厂试水,装上之后还真的有人用它咨询问题,然后聊了几句,各方面体验都不错。就很快实装到我厂官网了。

    上线之后表现很好,工作日期间每隔一两天就会有人来咨询,而且接下来的进展也都比较理想,大部分可以发展到试用阶段。对比过去几年“联系我们”的邮箱,两者在接待客户方面真是天壤之别。

    不过 Drift 也有不少小毛病,比如:因为网站在国外,所以国内的启动速度比较慢;静态资源的缓存设置也有问题,导致每次加载都要很久(我都想去给他们调 CDN 配置了……)。国内的同学可以考虑用去哪儿的 StarTalk,不过从架设难度上比 drift 难用很多、功能弱很多、界面丑很多……

    总之,在网页上添加客服 IM 对增加客户有很大帮助,建议大家有机会都搞一下。

  • 给 Hexo 增加替换大图并生成缩略图的功能

    给 Hexo 增加替换大图并生成缩略图的功能

    我厂的官方博客使用 Hexo 搭建,静态页比较符合我厂的技术风格。

    我厂博客可能会用到一些很大的火焰图 SVG,厂长担心打开速度会受拖累,所以让我想办法把大图替换成缩略图,单击再打开原图。

    经过一些研究,我大概得到以下线索:

    1. Hexo 会加载 `/scripts` 下面的脚本
    2. Hexo 是用钩子机制,跟 WordPress 非常像
    3. Hexo 的钩子函数可以使用 Promise

    那么,大概方案就出来了:

    1. 添加脚本,等待 `after_post_render` 钩子。这个钩子触发的时候,博文已经从 markdown 渲染成 html。
    2. 使用 cheerio,找到所有图片,检查图片大小,略过不太大的图片(我的标准是 500K)
    3. 对大图生成缩略图,替换 `src`。

    因为目标是 SVG => PNG/JPG,在 npm 里搜了一圈,发现大家不是 phantom.js 就是 puppeteer,那我就不需要用库了,自己直接写好了。

    经过反复的尝试,最终完成的代码如下:

    hexo.extend.filter.register('after_post_render', async function (data) {
      /** 摘录、详情、内容 */
      const dispose = ['excerpt', 'more', 'content'];
      for (const key of dispose) {
        const $ = cheerio.load(data[key], {
          ignoreWhitespace: false,
          xmlMode: false,
          lowerCaseTags: false,
          decodeEntities: false
        });
    
        // 获取所有需要调整大小的图片路径
        let images = $('img').map(async function () {
          let src = $(this).attr('src');
          if (!src) {
            if (config.log) {
              console.info("no src attr, skipped...");
              console.info($(this));
            }
            return;
          }
    
          // 顺便加上 `loading="lazy"`
          $(this).attr('loading', 'lazy');
    
          // take snapshot fo big SVGs
          const originalSrc = src;
          if (/\.svg$/.test(src)) {
            const img = resolve(__dirname, '../source', originalSrc);
            const {size} = await stat(img);
            if (size <= config.limit) {
              return;
            }
            $(this)
              .attr('data-src', src)
              .attr('src', `${src}.png`);
            return img;
          }
        }).get();
        images = await Promise.all(images);
        images = images.filter(image => !!image);
        // 只启动一次 pupppeteer,希望减少系统消耗
        if (images.length > 0) {
          const browser = await puppeteer.launch({
            defaultViewport: config,
          });
          const page = await browser.newPage();
          for (const image of images) {
            await page.goto(`file://${image}`);
            const buffer = await page.screenshot();
            const name = basename(image);
            console.log('screenshot for svg: ' + name);
            // 这一步很重要,因为 `after_post_render` 的时候图片还没有复制,所以要利用 hexo 自身的复制功能复制图片
            route.set(`images/${name}.png`, buffer);
          }
          await browser.close();
        }
        data[key] = $.html();
      }
      return data;
    });

    这段代码里,搞清楚应该用 route.set() 稍微花了些时间,Hexo 的文档写的真是差强人意。这个方法可以向指定位置写入内容,写入的可以是文本,也可以是二进制 buffer。如果写入的是绝对路径,那么就是简单的写入;如果是相对路径,就是向博文环境内写入,接下来的复制过程也会复制到最终代码里。

  • startalk 客服版安装笔记

    startalk 客服版安装笔记

    startalk 是去哪儿团队推出的企业级 IM 软件,我厂使用它作为私有 IM。本文主要记录客服版安装笔记,这方面文档好像不太多。

    组成部分

    startalk 客服版主要由三部分组成:

    1. 服务器端:一个 ejabberd 后端,可以同时提供服务给 qtalk
    2. startalk_node node.js 代理:用来适配前端请求和服务器接口
    3. startalk_web web 前端:提供 web 服务

    其中,服务器端的安装配置我暂时不太清楚,是去哪儿的同学帮忙搞的。

    部署步骤

    1. 准备好服务器(过程不知,略)
    2. clone 上面说的两个项目
    3. 修改 startalk_web 中的配置文件,指向自己的服务器
    4. 编译,生成 dist 目录
    5. 将 startalk_node 项目部署到服务器上
    6. 将刚才 startalk_web 生成的文件部署到 startalk_node 的 public 目录下
    7. 使用 pm2 等进程管理工具启动服务
    8. 完成

    配置客服

    startalk 使用 pgSQL,所以直接连上数据库,修改 supplier 表即可,内容见字段名,应该比较容易理解。

    其它要修改的表内容见 Google Drive 里的范例文档。


    先总结到这里,回头给他们提 PR。

  • FFMPEG 笔记

    FFMPEG 笔记

    截取视频

    ffmpeg -i abc.mp4 -ss 3:13 -to 2:41:13 -c copy output.mp4
    • -i 输入文件
    • -ss 开始时间
    • -to 结束时间
    • -c copy 直接截取

    这样的截取方式,如果源视频的关键帧间隙很大,可能出现因缺失第一个关键帧导致的黑屏。此时,可以考虑用 -c:v libx264 之类的参数重新编码。

    合并

    ffmpeg -f concat -safe 0 -i files.txt -c copy -y output.wav

    其中,files.txt 是所有待合并的文件,以以下的形式记录:

    file /path/to/wav/1.wav
    file /path/to/wav/2.wav
    ....

    转换格式

    转换格式很简单,有输入有输出,ffmpeg 会根据它们的扩展名自动选择合适的编码器,生成通用性最好的目标文件。比如 wav 2 mp3:

    ffmpeg -i a.wav a.mp3

    如果需要截取或者使用特定的编码器,那么就按照一般的用法添加参数即可,比如 flv 2 mp4:

    ffmpeg -i 1.flv -c:v libx264 -crf 19 -strict experimental 1.mp4

    其中,-c:v 是“视频编码器”的意思,音频编码器就是 -c:acrf 是质量,最小越好,取值范围是 18 -28。类似的,rm 2 MP4:

    ffmpeg -i ss.rm -c:v libx264 -c:a aac -b:a 32k -strict experimental ss.avi

    在 Ubuntu 下不能使用 libfaac,只能使用 aac。还要调整级别,-strict -2 不行,必须是 -strict experimental

    转换 iPad 支持的视频

    ffmpeg -i input.mkv -c:v libx264 -profile:v main -level 3.1 -preset medium -crf 23 -x264-params ref=4 -c:a copy -movflags +faststart output.mp4

    不知道为啥,直接 .mp4 或者 -c:v libx264 都不行,必须用上面这个。

    缩放

    ffmpeg -i input.mp4 -vf scale=320:-1 -strict -2 output.mp4

    好吧,这次 -strict -2 好使了。如果报错,可以试着把 -1 改成 -2

    裁剪画面

    ffmpeg -i input.mp4 -filter:v "crop=500:1080:1420:0" output.mp4

    crop 的参数为:宽、高、x、y。

    调整声音

    有些视频声音太小,需要调整一下:

    ffmpeg -i input.mp4 -filter:a "volume=N" output.mp4

    其中,N 可以是百分比,比如 1.0(一倍,不变),2.0(两倍);或者是加减的分贝,比如 10dB(增加10分贝),-20dB(减少20分贝)。不过根据我实地测试,调整后的视频的平均音量并不完全是调整的分贝。

    获取平均音量:

    ffmpeg -i input.mp4 -filter:a volumedetect -f null /dev/null 

    提取声音

    # 不转码,只提取声音,很快
    ffmpeg -i input-video.avi -vn -acodec copy output-audio.aac
    # 转码,便于四处播放
    ffmpeg -i sample.avi -q:a 0 -map a sample.mp3