
结果发现要接收 n 个帧,必须发送 n + 2 个帧,难顶。下面的例子之所以能收到两个是因为第二个超时了,我也不懂为什么超时就能收到第二个包。
看来得参考 RTP 自己造轮子了。
10-20 16:27:34.582 I sdp: v=0 o=- 0 0 IN IP4 127.0.0.1 s=No Name c=IN IP4 239.0.0.1 t=0 0 a=tool:libavformat 61.1.100 m=video 16384 RTP/AVP 96 a=rtpmap:96 H264/90000 a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z2QAHqzZQKAv+XARAAADAAEAAAMAMg8WLZY=,aOvjyyLA; profile-level-id=64001E 10-20 16:27:34.583 I send packet, pts: 0 10-20 16:27:34.600 I send packet, pts: 16666 10-20 16:27:34.617 I send packet, pts: 33332 10-20 16:27:34.617 I pkt pts: -9223372036854775808 10-20 16:27:44.629 I pkt pts: 1500 ]]>
我对 ffmpeg 的印象就是一个开源音视频编解码程序,对其影响力认识较少。能给我这个门外汉讲讲到底有多牛吗 ]]>需求:搜集到的无损音乐太占空间,决定传到 B 站网盘。但 pr 导出太太太耗时,于是使用 FFmepeg 的 GPU 加速
前置条件清单
1.支持 NVENC 的 NVIDIA 显卡 确认是否支持 NVENC: 在 CMD 中执行:
nvidia-smi 或通过 NVIDIA 官方列表 查询您的显卡型号。
2.更新到最新 NVIDIA 显卡驱动
3.支持 h264_nvenc 的 FFmpeg 版本
h264_nvenc:ffmpeg -encoders | findstr "h264_nvenc" 如果输出中有 h264_nvenc,则支持。
开始:
1.将 FFmpeg 的 bin 目录加入环境变量
2.输入
ffmpeg -hwaccel cuda -threads 24 -loop 1 -i "picture.png" -i "music.flac" -vf "hwupload" -c:v h264_nvenc -preset 0 -cq 23 -rc constqp -c:a flac -shortest "output.mkv" 解析:
ffmpeg:开源命令行工具-hwaccel cuda:启用 CUDA 硬件加速,利用 NVIDIA 显卡的 CUDA 核心来加速视频处理,从而提高处理效率。-threads 24:设置处理时使用的线程数为 24 个,多线程加快处理速度,根据电脑配置增减。-loop 1:使输入的图像循环播放,这里设置循环次数为 1 次,让图像持续显示。-i "picture.png":指定输入文件为名为picture.png的图像文件。-i "music.flac":指定输入文件为名为music.flac的音频文件。-vf "hwupload":视频滤镜,将输入视频数据上传到硬件设备(这里与前面的硬件加速相关),以便后续在硬件上进行处理。-c:v h264_nvenc:指定视频编码格式为 H.264 ,并使用 NVIDIA NVENC 编码器进行编码,利用 NVIDIA 显卡的编码能力来生成视频流。-preset 0:设置编码预设,0 是最快但视频质量最差,可以按需提高。-cq 23:设置恒定质量因子为 23 。恒定质量因子模式下,编码器会尝试保持输出视频质量恒定,通过调整码率来适应不同的场景复杂度。较低的 CQ 值通常意味着更高的质量,但可能产生更大的文件。-rc constqp:指定使用恒定 QP (量化参数)模式进行编码,与-cq类似,用于控制视频质量。-c:a flac:指定音频编码格式为 FLAC ,保持音频的原始编码格式不变-shortest:使输出视频的时长与输入中最短的流的时长相同,即当音频和视频时长不同时,以最短的时长为准来生成输出视频,确保音频和视频同步结束。"output.mkv":指定输出文件名为output.mkv,然后发到 B 站网盘就行了。批量处理:
视频按顺序数字重命名(如 video1.mp4, video2.mp4 等),且需要与对应的图片(如 pic1.png, pic2.png)
1.每个视频关联一张图片
@echo off set "input_dir=.\videos" # 视频存放目录(如已重命名的 video1.mp4 ) set "image_dir=.\images" # 图片存放目录(需要同名的 pic1.png 等) set "output_dir=.\outputs" # 输出目录 for %%a in ("%input_dir%\*.mp4") do ( set "video_file=%%~nxa" set "prefix=%%~na" ffmpeg -hwaccel cuda -threads 24 -i "%%a" -i "%image_dir%\pic%%~na.png" ^ # 注意:这里的图片名格式可自定义(如 pic1.png 需替换为 pic##匹配你的命名) -filter_complex "[0:v]scale=trunc(iw/2)*2:trunc(ih/2)*2[vid]; [vid][1:v] overlay=10:10" ^ # 图片叠加在左上角( 10 像素偏移) -c:v h264_nvenc -preset 0 -cq 23 -rc constqp ^ -c:a copy ^ # 音频直接复制(加速处理) "%output_dir%\output_%%~na.mkv" ) 2.所有视频使用同一张背景图片
@echo off set "input_dir=.\videos" # 视频目录 set "image_file=.\background.png" # 固定背景图片路径 set "output_dir=.\outputs" for %%a in ("%input_dir%\*.mp4") do ( ffmpeg -hwaccel cuda -threads 24 -i "%%a" -loop 1 -i "%image_file%" ^ # 循环播放图片 -filter_complex "[0:v]scale=trunc(iw/2)*2:trunc(ih/2)*2[vid]; [1:v]scale=trunc(iw/2)*2:trunc(ih/2)*2[img]; [vid][img] overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2" ^ # 图片居中叠加 -c:v h264_nvenc -preset 0 -cq 23 -rc constqp ^ -c:a copy "%output_dir%\output_%%~na.mkv" ) 3.注意事项
# 输入视频目录: videos/ ├── video1.mp4 ├── video2.mp4 └── video3.mp4 # 输入图片目录(场景 1 ): images/ ├── pic1.png ├── pic2.png └── pic3.png # 输出目录: outputs/ ├── output_video1.mkv ├── output_video2.mkv └── output_video3.mkv 5.自动化
# 保存为 batch_process.bat ,双击运行即可。 echo Processing videos: FOR /L %i IN (1,1,50) DO ( echo %i%% ping localhost -n 1 >nul ) 然后可以快速完成批量视频与图片的合成处理,传到 B 站网盘。如需进一步定制(如动态图片透明度、图片/视频尺寸调整、不同叠加效果、音轨混音等)自行添加命令
使用开源的 B 站音频播放器电梓播放器
然后完美音乐软件 get☆ daze
https://github.com/arthenica/ffmpeg-kit
FFmpegKit has been officially retired. There will be no further ffmpeg-kit releases.
All previously released ffmpeg-kit binaries will be removed according to the following schedule.
| FFmpegKit Version | Available Until |
|---|---|
| Less than 6.0 | February 1st, 2025 |
| 6.0 | April 1st, 2025 |
为了实现浏览器 seek 的效果, 选择由服务端通过 PTS 时间点和 timeBase 来根据关键帧提前生成切片范围, 在请求对应切片后实时转码到 mpegts (并通过浏览器预缓冲避免播放卡顿).
但无论如何调节, 似乎偶尔都会出现音频不连续的问题, 转储后发现目标切片似乎时间和请求长度不完全一致, 调节多次参数仍未解决此问题 (为使切片有足够起始长度只测试到 muxdelay 方法可用, -ss/-t 放于输入之后似乎也无果, 包括 -start_at_zero 等的替代也都尝试过, 使用 hls 或 segment 的话较难控制自由点播进度).
由于 nodejs 服务端较难调用 FFmpeg API, 是用的 命令+管道 的方式. 在这种情况下, 有方法可以解决或规避此问题吗?
服务端的完整代码, 其中相关的代码如下:
let args = [ '-ss', startTimeStr, '-t', durationTimeStr, '-accurate_seek', '-i', videoPath, '-map', '0:v:0', '-c:v', encoder, '-b:v', String(bitrate), '-bsf:v', 'h264_mp4toannexb', '-avoid_negative_ts', 'make_zero', '-start_at_zero', '-muxdelay', delayTimeStr, '-muxpreload', delayTimeStr, '-f', 'mpegts', 'pipe:1' ]; 请求方法:
m3u: http://127.0.0.1:8082/video/rttPlaylist?videoPath=1.mkv
segment: http://127.0.0.1:8002/video/rttSegment?videoPath=1.mkv&start=0.0000&duration=4.0000
(BTW: 其实大部分是 Gemini 写的.)
]]>ffmpeg -re -rtsp_transport tcp -stimeout 5000000 -i rtsp://xxxx -c:v libx264 -f flv rtmp://xxx 上面这个指令,在一切正常的时候没有问题,但是当输入的 RTSP 中断了一会,这个推流就会处于一个跑飞了的状态,不再推送有效数据,并且进程也没有终止; 然后我网上搜说用rw_timeout参数可破,可是我将指令修改为
ffmpeg -re -rtsp_transport tcp -rw_timeout 5000000 -stimeout 5000000 -i rtsp://xxxx -c:v libx264 -f flv rtmp://xxx 可是整个指令根本跑不起来。提示-rw_timeout不存在,除非输入换成 RTMP ,但是加了这个参数其实也不好使。 由于输出的地址不是我们自己管控的,所以不像保存文件一样能定期检测文件大小是否变化来判断是不是应该 kill 掉进程,所以要怎么才能在他没数据传输的时候干掉他,或者能通过配置参数让他自己退?
先谢谢大佬们
]]>转换的目的是为了减小文件的大小
]]>可硬件加速,CPU 占用率很低。 但是我在我的 c++代码里使用来创建:int ret = av_hwdevice_ctx_create = (&hw_device_ctx,AV_HWDEVICE_TYPE_VAAPI,"/dev/dri/renderD128");
我打印了 ret:-12 ,我查阅了资料是因为无法创建内存空间导致的。
忘了说,我用的是 qtcreator ,我在 qt 的 pro 文件了引入了-lavcodec -lavformat -lavutil -lswscale ,在不用硬件加速的时候可以看到视频,也可以播放,但是用了 vaapi 那个加速就会打印-12
我查阅资料可能是没有引入 libva 和 libva-drm 。
有没有大佬了解过这些! 跪谢!困扰我一周了!(我没法尝试是因为公司电脑关了,这周末难受的我啊,解决不了问题我都睡不好)
]]>我测试一个视频的时候还行,视频数量上到了 16 个就开始花屏+卡顿了。
]]>ffmpeg -f alsa -i hw:1,0 -f x11grab -s 1920x1080 -i :0.0 -async 1 ubuntu.avi ]]>现在的方案是通过 ffmpeg.wasm 压缩, 官方测试结果比原生 ffmpeg 慢 10-20 倍
项目中测试只要涉及画面转码都是严重超过 1 分钟 退而求其次尝试维持视频流只减帧, 但是维持原视频流需要 copy 参数, 此时无法通过-r 设置参数, filter 只是过滤器无法压缩视频体积
昨天找了一下午没找到可用的参数, 只能请教大佬了
参数如下
const args = [ "-i", "input.mov", "-preset", "ultrafast", "-c:a", "copy", "-c:v", "copy", "-r", "24", "output.mp4" ] ]]>问题详细描述:
1. 用完全重编码的方法将一个 10s 的视频转换为 3.971s 并去掉音频:
ffmpeg -t 3.971 -i "加载.mp4" -c:v libx264 -tune animation -crf 1 -an loading.mp4
ffprobe 结果文件 loading.mp4 如下:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'loading.mp4': Metadata: major_brand : isom minor_version : 512 compatible_brands: isomiso2avc1mp41 encoder : Lavf61.7.100 Duration: 00:00:03.98, start: 0.000000, bitrate: 49072 kb/s Stream #0:0[0x1](eng): Video: h264 (High 4:4:4 Predictive) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1920x1080, 49068 kb/s, 60 fps, 60 tbr, 15360 tbn (default) Metadata: handler_name : ?Mainconcept Video Media Handler vendor_id : [0][0][0][0] encoder : Lavc61.19.100 libx264 疑点:时长为 3.98 ,已经不精确?
原始视频的 ffprobe ,是不是原始视频有什么不正常:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '加载.mp4': Metadata: major_brand : mp42 minor_version : 0 compatible_brands: mp42mp41 creation_time : 2022-03-26T12:31:39.000000Z Duration: 00:00:10.00, start: 0.000000, bitrate: 9763 kb/s Stream #0:0[0x1](eng): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1920x1080, 9395 kb/s, 60 fps, 60 tbr, 60k tbn (default) Metadata: creation_time : 2022-03-26T12:31:39.000000Z handler_name : ?Mainconcept Video Media Handler vendor_id : [0][0][0][0] encoder : AVC Coding Stream #0:1[0x2](eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 317 kb/s (default) Metadata: creation_time : 2022-03-26T12:31:40.000000Z handler_name : #Mainconcept MP4 Sound Media Handler vendor_id : [0][0][0][0] 2. 将一个 webm 视频 overlay 到上述视频上,并加入音频,且音视频都重编码:
疑点:webm 视频的时长显示为 N/A ,但实际为 3.5s 左右
用了 -filter_complex chromakey,scale;overlay
结果的 ffprobe 如下:
Input #0, matroska,webm, from 'opening.mkv': Metadata: COMPATIBLE_BRANDS: isomiso2avc1mp41 MAJOR_BRAND : isom MINOR_VERSION : 512 ENCODER : Lavf61.7.100 Duration: 00:00:03.98, start: 0.000000, bitrate: 70572 kb/s Stream #0:0: Video: h264 (High 4:4:4 Predictive), yuv420p(tv, bt709, progressive), 1920x1080, 60 fps, 60 tbr, 1k tbn Metadata: ENCODER : Lavc61.19.100 libx264 DURATION : 00:00:03.984000000 Stream #0:1: Audio: flac, 44100 Hz, stereo, s16 Metadata: ENCODER : Lavc61.19.100 flac DURATION : 00:00:03.970000000 这一步结果视频长度 3.984s
3. 将上一步的结果用 concat 加到另外两个视频流的中间:
-filter_complex "[10:v]trim=0:3.97[t10v]", "[10:a]atrim=0:3.97[t10a]", "[fv1t][fa1t][t10v][t10a][fv2t][fa2t]cOncat=3:1:1", 其中 "[10]" 代表上一步结果的视频流和音频流,已经用 trim 处理
结果:在生成的文件中,这一段的实际占用时间为 10s ,而不是我需要的 3.971s ,后面 7s 是最后一帧静止画面和静音。
]]>(1) 解码结果:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'E:\tmp\1080p_60_10M.mp4': Metadata: major_brand : isom minor_version : 512 compatible_brands: isomiso2avc1mp41 encoder : Lavf60.3.100 Duration: 00:01:36.67, start: 0.000000, bitrate: 10533 kb/s Stream #0:00x1: Video: h264 (High) (avc1 / 0x31637661), yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], 10528 kb/s, 60 fps, 60 tbr, 15360 tbn (default) Metadata: handler_name : VideoHandler vendor_id : [0][0][0][0] encoder : Lavc60.3.100 libx264 Stream mapping: Stream #0:0 -> #0:0 (h264 (native) -> wrapped_avframe (native)) Press [q] to stop, [?] for help Output #0, null, to 'pipe:': Metadata: major_brand : isom minor_version : 512 compatible_brands: isomiso2avc1mp41 encoder : Lavf60.22.101 Stream #0:0(und): Video: wrapped_avframe, nv12(progressive), 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 200 kb/s, 60 fps, 60 tbn (default) Metadata: handler_name : VideoHandler vendor_id : [0][0][0][0] encoder : Lavc60.40.100 wrapped_avframe [out#0/null @ 0000017e54639b80] video:2719KiB audio:0KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: unknown frame= 5800 fps=780 q=-0.0 Lsize=N/A time=00:01:36.66 bitrate=N/A speed= 13x
(2) 解码结果: Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'E:\tmp\1080p_60_10M.mp4': Metadata: major_brand : isom minor_version : 512 compatible_brands: isomiso2avc1mp41 encoder : Lavf60.3.100 Duration: 00:01:36.67, start: 0.000000, bitrate: 10533 kb/s Stream #0:00x1: Video: h264 (High) (avc1 / 0x31637661), yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], 10528 kb/s, 60 fps, 60 tbr, 15360 tbn (default) Metadata: handler_name : VideoHandler vendor_id : [0][0][0][0] encoder : Lavc60.3.100 libx264 Stream mapping: Stream #0:0 -> #0:0 (h264 (native) -> wrapped_avframe (native)) Press [q] to stop, [?] for help Output #0, null, to 'pipe:': Metadata: major_brand : isom minor_version : 512 compatible_brands: isomiso2avc1mp41 encoder : Lavf60.22.101 Stream #0:0(und): Video: wrapped_avframe, yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 200 kb/s, 60 fps, 60 tbn (default) Metadata: handler_name : VideoHandler vendor_id : [0][0][0][0] encoder : Lavc60.40.100 wrapped_avframe [out#0/null @ 000001f2b2f29c00] video:2719KiB audio:0KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: unknown frame= 5800 fps=1617 q=-0.0 Lsize=N/A time=00:01:36.66 bitrate=N/A speed=26.9x
问题:指定了 -hwaccel cuda 参数进行解码的 fps 要比不指定这个参数进行解码的帧率少了一倍,自己的主机是 nvidia 显卡,这个可能是什么原因?
]]>然后根据自己的 os 和 arch 找到相应的入口图标;
点击图标,然后提示跳转到第三方网站进行下载?
这是什么魔幻操作?
]]>剪映制作 10 秒的模板视频,轮换 4 张图,具有蒙版和转场特效。需要通过 ffmpeg 在保留蒙版和转场的前提下替换图片
vx YW55ZWZlbmdqaW5nbGluZw==
]]>hello ,兄弟们,我又来分享我的 ffmpeg 脚本啦。
上次分享了一个使用 ffmpeg ,将多张图片转换成类似幻灯片的视频,支持多种转场效果,说过在研究自定义效果,目前有点小成果,于是有了本文。
本次没有新增脚本,而是增强了ffmpeg.img2video.js,预置了一些自定义效果,并支持自己添加效果。
以下的都是本次的技术分享。如果你不感兴趣,可以直接到 GitHub 更新脚本。
GitHub 地址:https://github.com/jifengg/ffmpeg-script
使用xfade过滤器做视频转场切换效果,本身 ffmpeg 已经提供了 56 种效果,能满足大部分需求。不过,更复杂的过渡效果(例如翻页)还没有。
根据文档,使用 transition=custom+expr ,可以实现自定义的效果。但是,官方文档并没有对expr如何编写做详细说明,也没有 google 到。
因此,对其进行了一番研究,尝试实现了几种效果。简单做一个使用教程,希望能够帮助到有需要的人。
https://github.com/jifengg/ffmpeg-script/assets/17020523/b3cec5b1-d747-46bd-aae1-924289aaddce
https://github.com/jifengg/ffmpeg-script/assets/17020523/1bef9ae3-41c3-4747-ae41-9056ae4e6892
https://github.com/jifengg/ffmpeg-script/assets/17020523/30c810a1-7522-4829-8450-4602c8203853
https://trac.ffmpeg.org/wiki/Xfade
以下翻译自FFmpeg xfade 官方文档
xfade 将淡入淡出从一个输入视频流应用到另一个输入视频流。淡入淡出将持续指定的时间。 两个输入必须是恒定帧速率,并且具有相同的分辨率、像素格式、帧速率和时间基准。 该过滤器接受以下选项: transition 'custom' [忽略] duration 设置交叉淡入淡出持续时间(以秒为单位)。范围为 0 至 60 秒。默认持续时间为 1 秒。 offset 设置相对于第一个输入流的交叉淡入淡出开始时间(以秒为单位)。默认偏移量为 0 。 expr 设置自定义过渡效果的表达式。 表达式可以使用以下变量和函数: X Y 当前样本的坐标。 W H 图像的宽度和高度。 P 过渡效果的进展。 [译注] 过渡开始时,P=1.0 ,过渡结束时,P=0.0 。 PLANE 目前正在处理的平面。 [译注] 这里的平面,其实就是指像素格式的分量。 [译注] 取值范围由输入流的像素格式 pix_fmt 决定,如 yuv420p ,则取值范围是 0 ,1 ,2 ;如 rgba ,则取值范围是 0 ,1 ,2 ,3 。 A 返回第一个输入流在当前位置和平面的值。 B 返回第二个输入流在当前位置和平面的值。 a0(x,y) a1(x,y) a2(x,y) a3(x,y) 返回第一个输入的第一/第二/第三/第四个分量的 位置 (x,y) 处的像素的值。 [译注] 例如,像素格式是 yuv420p ,a0 返回的是 Y 分量。a1 返回的是 U 分量。a2 返回的是 V 分量。没有 a3 b0(x,y) b1(x,y) b2(x,y) b3(x,y) 返回第二个输入的第一/第二/第三/第四个分量的 位置 (x,y) 处的像素的值。 一般来说,ffmpeg 中支持时间轴编辑的过滤器,都有t和n参数可以用在表达式中,其中t表示时间秒,n表示帧数。
但是 xfade 里却是用的 P ,它不是t或n。如果你理解错了,会发现自定义效果完全没效。
因为,它表示的是过渡效果的进度,而且,重要的是,它是个递减的数。
X,Y 表示坐标,是指“当前正在计算表达式的像素的坐标”,按照我们要实现的效果,决定该像素对应的颜色码。
W,H 是图像的宽高,这个在整个渐变过程是保持不变的。
a0(x,y)表示第一个视频坐标 x,y 处的像素的第一个分量值。 PLANE 表示当前是计算的第几个分量值。 A 是一个简写,当 PLANE=0 时,A=a0(X,Y); PLANE=1 时,A=a1(X,Y); PLANE=2 时,A=a2(X,Y);以此类推。 b 和 B 同 a 和 A 。
注意,无法通过类似
a(plane,x,y)的方法来获得指定坐标指定分量的值,因此在像素有位移的时候,表达式会比较长。如if(eq(PLANE,0),a0(X,Y),if(eq(PLANE,1),a1(X,Y),if(eq(PLANE,2),a2(X,Y),0)))
xfade的expr,返回一个值,但是这个值是什么含义呢,一般人看文档很难理解。
以 300x200 的输入源为例,假设其像素格式是 yuv420p ,则其分量个数是 3 。( ffmpeg 支持的像素格式及格式信息,可以通过ffmpeg -pix_fmts查看)。 像素点是60000个,每一帧的像素分量总数就是60000*3=18 万个。
那么,过渡开始的第一帧,ffmpeg 会遍历每个像素点的每个分量,分别调用expr,并设置 X,Y,PLANE 等值。总共调用18 万次获得对应的值,来完成第一帧的渲染。 如果我们希望每一帧就是显示第一个视频的画面,那么可以写expr=A即可。A表示的就是第一个视频当前像素当前分量的值。
如果我们希望实现第一个视频渐渐变透明,第二个视频由透明渐渐显现,类似xfade默认的效果fade,那么可以写expr='A*P+B*(1-P)'。
因为 P 是从 1.0 线性变成 0.0 的。所以一开始 P=1 ,表达式计算结果=A,看到的就是只有第一个视频画面,到一半时,P=0.5 ,结果=0.5A+0.5B,画面就是两个视频分别半透明叠加在一起。最后 P=0.0 时,结果=B,就只剩下第二个视频的画面了。
同样的,如果我们希望实现一个从右往左擦除的效果(图片引用自https://trac.ffmpeg.org/wiki/Xfade):

分析一下,分割线在画面水平线上的位置 X ,除以宽度 W ,其实就是等于 P ,于是,我们可以让分割线左边的显示画面 A ,右边的显示画面 B 。 expr='if(lt(X/W,P),A,B)':当X/W<P的时候,说明 X 在分割线左边,于是显示 A ,否则显示 B 。
分割线上显示 A 还是 B ,影响不大。这里是显示了 B ,如果要显示 A ,可以用
lte代替lt。
从上面两个例子你大概能理解 expr 要返回什么内容了。我们接着第三个例子。 如果我们希望实现的是一个从右往左推走的效果:

你会发现,变得更复杂了。你可以先暂停试试自己能否写出来。
为什么更复杂了?以坐标(0,0)为例,他显示的像素时刻都在变化(因为画面在往左移动)。
例如,在 P=0.8 的时候,它(0,0)应该是视频 A X=W*0.2,Y=0 坐标处的像素值。(这里需要好好理解,参考下图帮忙理解)
在X/W>P的地方,应该显示视频 B 的画面,其坐标转换关系是(X-P*W,Y)。
注意,此时你没法再用值A和B了,因为它们是坐标(X,Y)的分量,而我们要在(X,Y)处显示别的坐标的像素,这个我们在上面理解 PLANE,A,B,a0(x,y),...,b0(x,y),...的地方说过了。
那么这个表达式要怎么写呢?
expr='if(lt(X/W,P),^ if(eq(PLANE,0),a0(X+(1-P)*W,Y),^ if(eq(PLANE,1),a1(X+(1-P)*W,Y),^ if(eq(PLANE,2),a2(X+(1-P)*W,Y),0)))^ ,^ if(eq(PLANE,0),b0(X-P*W,Y),^ if(eq(PLANE,1),b1(X-P*W,Y),^ if(eq(PLANE,2),b2(X-P*W,Y),0)))^ )' 我测试的时候用的是 windows 的 bat 脚本,为了方便理解和修改,用^进行了换行。注意不要有空格,否则会报错。
测试的时候用的是 yuv420p 像素格式,因此表达式没有用到 a3 ,如果是用了 4 个分量的像素格式需要把 a3 按照上面的格式加进去。
其中,分割线左边显示视频 A 的画面,且 x 坐标左移了(1-P)*W 个像素,因此其 x 坐标表达式是X+(1-P)*W;
右边显示视频 B 的画面,且 x 坐标右移到了分割线右边,因此其 x 坐标表达式是X-P*W。
因为是水平移动,所以 y 坐标保持Y即可。
于是,随着 P 从 1.0 渐变到 0.0 ,视频 A 就像被视频 B 从右边推到了左边,完成了一个过渡效果。
现在,你已经了解了 expr 要怎么编写来实现过渡效果了。我还实现了一些其它效果,包括示例里的,你可以在 GitHub 上查看。
在 windows 下创建 2 个 bat 文件,分别输入测试命令:
@echo off @REM 使用 custom 实现 slideleft 效果 ffmpeg -y -hide_banner ^ -f lavfi -i "pal100bars=r=1/1000" ^ -f lavfi -i "colorchart=r=1/1000" ^ -filter_complex ^ [0:v]format=yuv420p,scale=960:480,fps=25,trim=duration=40[v1];^ [1:v]format=yuv420p,scale=960:480,fps=25,trim=duration=40.04[v2];^ [v1][v2]xfade=duration=40:offset=0:transition=custom:^ expr='if(lt(X/W,P),^ if(eq(PLANE,0),a0(X+(1-P)*W,Y),^ if(eq(PLANE,1),a1(X+(1-P)*W,Y),^ if(eq(PLANE,2),a2(X+(1-P)*W,Y),0)))^ ,^ if(eq(PLANE,0),b0(X-P*W,Y),^ if(eq(PLANE,1),b1(X-P*W,Y),^ if(eq(PLANE,2),b2(X-P*W,Y),0)))^ )' ^ -crf 23 -c:v h264 -pix_fmt yuv420p -movflags +faststart -r 25 -aspect 960:480 ^ out1.mp4 @echo off @REM 使用内置的 slideleft 效果 ffmpeg -y -hide_banner ^ -f lavfi -i "pal100bars=r=1/1000" ^ -f lavfi -i "colorchart=r=1/1000" ^ -filter_complex ^ [0:v]format=yuv420p,scale=960:480,fps=25,trim=duration=40[v1];^ [1:v]format=yuv420p,scale=960:480,fps=25,trim=duration=40.04[v2];^ [v1][v2]xfade=duration=40:offset=0:transition=slideleft ^ -crf 23 -c:v h264 -pix_fmt yuv420p -movflags +faststart -r 25 -aspect 960:480 ^ out2.mp4 这里使用的动画时长是 40 秒,可以自行修改成 0~60 秒。
在我电脑上运行,耗时分别是:自定义17.514 秒,内置1.605 秒。
可以看出,使用自定义的效果,远比内置效果更耗时。原因我们在“理解 expr”有提过,因为每一帧需要调用 expr 次数=960×480×3=1,382,400 。一百多万次。而且是纯 CPU 运算,因此效率自然底下。
好在一般的过场时长是 3 、4 秒左右,影响还在可接受范围内。
如果你在寻找更高效的自定义效果,可以考虑使用xfade_opencl过滤器,或者自行编译 ffmpeg ,加入gl-transition过滤器。
要使用xfade_opencl,需要编译的时候加入--enable-opencl,且运行的机器有支持 opencl 的设备(一般指显卡)。
要查看当前机器有哪些 opencl 的设备,可以运行以下命令:
ffmpeg -v debug -init_hw_device opencl 打印出类似信息:
[AVHWDeviceContext @ 0000027894f28400] 1 OpenCL platforms found. [AVHWDeviceContext @ 0000027894f28400] 1 OpenCL devices found on platform "NVIDIA CUDA". [AVHWDeviceContext @ 0000027894f28400] 0.0: NVIDIA CUDA / NVIDIA GeForce RTX ***** 其中0.0就是可用的 opencl 设备编号,在 ffmpeg 命令中指定使用该设备:
ffmpeg -y -hide_banner -init_hw_device opencl=ocldev:0.0 -filter_hw_device ocldev ^ -f lavfi -r 25 -t 40 -i "pal100bars" ^ -f lavfi -r 25 -t 40.04 -i "colorchart" ^ -filter_complex ^ [0:v]format=yuv420p,scale=960:480,hwupload[v0];^ [1:v]format=yuv420p,scale=960:480,hwupload[v1];^ [v0][v1]xfade_opencl=duration=40:offset=0:transition=slideleft,hwdownload,format=yuv420p ^ -c:v h264_nvenc -pix_fmt yuv420p -movflags +faststart -r 25 -aspect 960:480 ^ out3.mp4 性能比自定义 xfade 效果好很多,唯一要求就是需要支持 opencl 的设备(一般指显卡)。
且,xfade_opencl也是支持自定义效果的,官方文档。
内置的几个效果的源码可以查看 GitHub 上 ffmpeg 的源码:https://github.com/FFmpeg/FFmpeg/blob/master/libavfilter/opencl/xfade.cl
gl-transitions是由开发者 Gilles Lamothe 创建的,它封装了大量的 GPU 加速过渡效果,包括但不限于溶解、推拉、旋转等多种类型。这些过渡效果可以轻松地整合到你的图形应用程序中,无论你是开发游戏、视频编辑软件还是实验性的艺术项目。
它使用 OpenGL 进行加速,因此,也需要支持 OpenGL 的设备(一般指显卡)。
它不是 ffmpeg 专属的,但是可以做为一个过滤器添加到 ffmpeg 中。参考这个 GitHub 项目transitive-bullshit/ffmpeg-gl-transition。 编译后,你将可以使用其官网上的所有效果,当然也可以自己编写自定义的效果。
性能方面,因为我没有自行编译测试,所以无法给出具体数据。
它使用 GLSL 语言编写,如果你看了上面 OpenCL 的部分,你会发现它们有很多共同点。
甚至,我在编写xfade自定义表达式的时候,也参考了它的 GLSL 代码。比如效果预览中的水滴,就是参考了WaterDrop。
不知道是 ffmpeg 官方觉得 xfade 的 expr 编写太过容易,还是觉得性能不行不建议使用,反正官方文档及 wiki 都没有示例,也没有提及如何编写。
我自己基本上是自己看着文档猜测、尝试,慢慢的摸索出来一些门道。想着网上没有一个类似的教程,于是变写了这个文章。
如果你发现文章哪里有问题,欢迎指出,大家共同进步。
本文存档:https://github.com/jifengg/ffmpeg-script/blob/main/docs/ffmpeg.xfade.md
]]>本人在用系统 macos sonama 14.5 fcp 版本为 10.6.5 已知 fcp 支持导入 hevc 视频,图证 https://imgse.com/i/pkY4h9S 使用了两个相同内容的素材,分别为两位压制者进行的压制,其中上图可以正常导入 fcp ,下图并不可以 https://imgse.com/i/pkY47Bn https://imgse.com/i/pkY45cQ 本人琢磨了半天也不明白,感觉应该和 hevc 问题不大,可能是其他项的问题 我又拿了一个完全不一样的视频进行了证明,该视频可正常导入 fcp ,mediainfo 如图 https://imgse.com/i/pkY5pu9
如果您有头绪,麻烦请告诉我,我感激不谢!
]]>func main() { url := "http://a.mp4" args := strings.Split("ffmpeg -y -i pipe:0 -f mpegts pipe:1", " ") ctx, cancel := context.WithCancel(context.Background()) cmd := exec.CommandContext(ctx, args[0], args[1:]...) pipe0, _ := cmd.StdinPipe() pipe1, _ := cmd.StdoutPipe() cmd.Start() go func () { cmd.Wait() } go func () { file := os.Openfile.... io.Copy(file, pipe1) } io.Copy(pipe0, http.resp.body) } 问题是,write 完成了,但是我不确定转码完成了没。去监听 stderr 吗?看 stderr 的已完成转码时长是不是等于预期?
]]>1.准备加密密钥
openssl rand 16 > enc.key
2.生成 IV
3 创建 enc.info 文件
然后利用 ffmpeg 进行加密 ffmpeg -y
-i test.mp4
-hls_time 9
-hls_key_info_file enc.info
-hls_playlist_type vod
-hls_segment_filename "index%d.ts"
playlist.m3u8
结果是播放器不能直接打 ts 文件开播放。达到了对 ts 文件加密的效果?
但是假设前端去实现播放视频的功能时,不还是要向后端获取 m3u8 文件吗,因为 m3u8 文件里有着秘钥 。只要获取到 m3u8 文件就能播放了。也就是说只要能够获取到 m3u8 文件就能播放加密的 ts 文件,那如果通过抓包工具获取到 m3u8 地址,那 ts 加密不是没用了吗
]]>在网上搜索一番后,整了个 ffmpeg 工具命令,探索下来,压缩的功能没有问题挺 ok 的,但是在保留元数据的地方总是卡壳,输出的视频带不上原来的经纬度等信息。
环境是 mac ,命令如下,已经添加了网上说的 map_metadata 和 movflags 两个参数,但是输出的文件中还是没有元数据
ffmpeg -i input.mov -c:v copy -c:a copy -map_metadata 0 -movflags use_metadata_tags output.mp4 尝试使用了 hevc 和 h264 好像也都不行,有老哥可以帮忙指导一下的,感激不尽
]]>使用 macOS 自带终端运行:ffmpeg -i ./index.m3u8 -c copy test.mp4 和在 nodejs 里使用“fluent-ffmpeg”这个库(依然是使用‘/opt/homebrew/Cellar/ffmpeg/6.0/bin/ffmpeg’)处理
终端处理仅仅需要 30 秒不到
而 nodejs 运行则需要 21 分钟
我是 nodejs 小白,执行命令的方式是在 vscode 这个编辑器里的终端执行 node ./foo.js
有人了解这个巨大差异产生的原因吗?
我推测是不是 vscode 或者 nodejs 只使用了单线程的关系??
]]>ChatGPT 说从 4.1 版本( 2018 年 11 月发布的)开始有这选项,但是我在官网下载的编译好的没有这个选项啊
然后我就想自己编译,Git clone 源码后,按照 ChatGPT 说的配置添加 segment 支持后编译安装,结果还是没有这个选项
./configure --enable-gpl --enable-libx264 --enable-libmp3lame --enable-libopus --enable-libvorbis --enable-libvpx --enable-libx265 --enable-libaom --enable-version3 --enable-libfdk-aac --enable-nonfree --enable-muxer=segment 到底 FFmpeg 有没有这个选项???
]]>




使用命令如下: ffmpeg -i url -c copy output.mp4
]]>ffmpeg -y -c:v h264_qsv -i input.mp4 -c:v hevc_qsv -low_power 1 output.mp4 输出的错误信息如下
[hevc_qsv @ 0x562ef30a0480] Selected ratecontrol mode is unsupported [hevc_qsv @ 0x562ef30a0480] some encoding parameters are not supported by the QSV runtime. Please double check the input parameters. Error initializing output stream 0:0 -- Error while opening encoder for output stream #0:0 - maybe incorrect parameters such as bit_rate, rate, width or height [aac @ 0x562ef34099c0] Qavg: 65536.000 [aac @ 0x562ef34099c0] 2 frames left in the queue on closing Conversion failed! vainfo 输出如下
Trying display: wayland Trying display: x11 error: can't connect to X server! Trying display: drm vainfo: VA-API version: 1.16 (libva 2.16.0) vainfo: Driver version: Intel iHD driver for Intel(R) Gen Graphics - 22.4.4 () vainfo: Supported profile and entrypoints VAProfileNone : VAEntrypointVideoProc VAProfileNone : VAEntrypointStats VAProfileMPEG2Simple : VAEntrypointVLD VAProfileMPEG2Main : VAEntrypointVLD VAProfileH264Main : VAEntrypointVLD VAProfileH264Main : VAEntrypointEncSliceLP VAProfileH264High : VAEntrypointVLD VAProfileH264High : VAEntrypointEncSliceLP VAProfileVC1Simple : VAEntrypointVLD VAProfileVC1Main : VAEntrypointVLD VAProfileVC1Advanced : VAEntrypointVLD VAProfileJPEGBaseline : VAEntrypointVLD VAProfileJPEGBaseline : VAEntrypointEncPicture VAProfileH264ConstrainedBaseline: VAEntrypointVLD VAProfileH264ConstrainedBaseline: VAEntrypointEncSliceLP VAProfileVP8Version0_3 : VAEntrypointVLD VAProfileHEVCMain : VAEntrypointVLD VAProfileHEVCMain : VAEntrypointEncSliceLP VAProfileHEVCMain10 : VAEntrypointVLD VAProfileHEVCMain10 : VAEntrypointEncSliceLP VAProfileVP9Profile0 : VAEntrypointVLD VAProfileVP9Profile1 : VAEntrypointVLD VAProfileVP9Profile2 : VAEntrypointVLD VAProfileVP9Profile3 : VAEntrypointVLD VAProfileHEVCMain422_10 : VAEntrypointVLD VAProfileHEVCMain444 : VAEntrypointVLD VAProfileHEVCMain444 : VAEntrypointEncSliceLP VAProfileHEVCMain444_10 : VAEntrypointVLD VAProfileHEVCMain444_10 : VAEntrypointEncSliceLP CPU 和 GPU 分别如下
CPU: Intel Celeron N5105 (4) @ 2.900GHz GPU: Intel JasperLake [UHD Graphics] 谢谢各位了
]]>命令如下: ffmpeg.exe -r 10 -loop 1 -i 5197.jpg -i audio5197.wav -c:v libx264 -x264-params keyint=1:scenecut=0 -c:a aac -b:a 32k -pix_fmt yuvj420p -shortest out.mp4
]]>有这么个场景,服务端那边跟播放器一个 ts 链接里,有可能碰到 264 数据后面直接紧跟着 265 的数据。
而播放器不知道码流切换了,264 的 AVCodec 碰到 265 的数据,当然就报错,导致播放器卡住。
现在在想,如何不修改服务端的情况,264 解码器识别出切 265 了,还有 265 解码器识别出切 264 了。
尝试在 libavcodec 里的 h2645_parse.c 里把错误识别,抛出去,但是可能小弟对 ffmepg 还不够熟悉,有些正常解码 264 的情况也会有解码失败的报错。
所以,有大神能指导下吗?想要直接去拦截比特数据,找起始码 0001 ,识别 264 、265 ,但是这好像要 ffmpeg 很底层,稍上层拿到的都是 pkt ,frame 。这也太难了
]]>达不到 32 倍速,于是查找瓶颈在哪。
试了非 10 秒分片的 ts ,这个 ts 包含 30 分钟的视频,这种情况能够达到 60 倍速。
所以瓶颈应该是 m3u8 里面每隔 10 秒,重新连 ts ,这个过程很耗时。
ffmpeg 好像有个 multiple_requests 的参数,可以复用一个链接,在 avformat_open_input 之前调用 av_dict_set_int(&opts, "multiple_requests", 1, 0) 可没看到效果。
哪位大佬指点下,有什么办法可破,谢谢!
]]>我尝试着下载了一个视频文件,大概 400MB 左右,然后用 ffmpeg 压缩了一下(压缩后的分辨率,我看了一下,能够接受)
ffmpeg -i c:\temp\1.mp4 -vf "scale=iw/4:ih/4" c:\temp\1-1.mp4 体积能够缩小到 50MB 左右。但是,我发现压缩后的视频,拨放的时候,有的地方会“丢帧”,如图所示。命令行里面运行时,也会有一些错误提示,不清楚是什么原因造成的。
特来请教一下,有没有办法正常压缩不出错? ffmpeg 命令哪里用错了?
谢谢!

大明王朝 1566 2007.WEB-DL.Ep01.1080P.H264.AAC.mkv
]]>现在 ffmpeg 会先将录制的视频缓冲在内存中,等到停止录制,ffmpeg 在硬盘最开始写个 mp4 头部,然后把一整个内存里的视频数据写入硬盘,这样导致内存占用很大,而且还有 OOM 的风险。
所以想要找个能实时将录制的视频数据写入磁盘的办法。有没有大神指点一二?
]]>int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, void *logctx, int is_nalff, int nal_length_size, enum AVCodecID codec_id) { ...... if (codec_id == AV_CODEC_ID_HEVC) ret = hevc_parse_nal_header(nal, logctx); else ret = h264_parse_nal_header(nal, logctx); if (ret <= 0 || nal->size <= 0) { if (ret < 0) { av_log(logctx, AV_LOG_ERROR, "Invalid NAL unit %d, skipping.\n", nal->type); } pkt->nb_nals--; } ...... } ]]>因为毕设要求,需要 ffmpeg sdk 将 mp4 转封装切分为 m3u8 。从官方示例里拿 remuxing.c 编译尝试了一下,转封装切分倒是成功了,但是 m3u8 的 #EXT-X-MEDIA-SEQUENCE 标签不是从 0 开始,而是从 36 开始,到 40 结束(但是从 0.ts 到 40.ts 都切分出来了);#EXT-X-TARGETDURATION 标签为 5
我想请教一下,如何让它可以从 0 开始呢?切片的时间如何设置呢?
以下是代码 https://gist.github.com/xQmQ/3ce63bf6a234a5b4e28977c2debb35cd
编译 gcc -o remuxing remuxing.c -lavformat -lavcodec -lavutil
执行 ./remuxing input.mp4 output.m3u8
打印的输入文件和输出文件信息 https://gist.github.com/xQmQ/89c83d9da5611de03a4922d95f9f7668
]]> ffmpeg \ -i A.mp4 \ -i B.mp4 \ -filter_complex "[0:v]pad=iw*2:ih[v_wide];[v_wide][1:v]overlay=W/2:0[out_video]" \ -map "[out_video]" \ -c:v libx265 \ -crf 28 \ -map 0:a:0 \ -c:a copy -y \ ./C.mp4 但是直接这么做,音量太小了,所以我又进行了一道步骤:把生成的视频 C ,进行音量提升的操作
ffmpeg -i C.mp4 -af volume=20dB -c:v libx265 C_high_volume.mp4 问题是,有没有办法把这两步合成为一步呢?(我觉得这样可以降低处理时间)
]]>