使用ffmpeg把mp4与m3u8相互转换的操作
FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。它提供了录制、转换以及流化音视频的完整解决方案。
一、MP4 转 M3U8
M3U8 是 Unicode 版本的 M3U,用 UTF-8 编码。”M3U” 和 “M3U8” 文件都是苹果公司使用的 HTTP Live Streaming(HLS) 协议格式的基础,这种协议格式可以在 iPhone 和 Macbook 等设备播放。
简单来说,m3u8是一个视频格式,就是将一个视频分成很多的小部分,这样方便视频的加载。
1、操作简单,但效率低
ffmpeg -i input.mp4 -c:v libx264 -c:a aac -strict -2 -f hls -hls_list_size 2 -hls_time 15 output.m3u8
生成的效果是:
将 input.mp4 视频文件每 15 秒生成一个 ts 文件,最后生成一个 m3u8 文件,m3u8 文件是 ts 的索引文件。
我们直接用 VLC media player 等播放软件是可以直接打开 m3u8 文件,像播放 mp4 一样。
默认的每片长度为 2 秒,m3u8 文件中默认只保存最新的 5 条片的信息,导致最后播放的时候只能播最后的一小部分(直播的时候特别注意)。
-hls_time n 设置每片的长度,默认值为 2,单位为秒。
-hls_list_size n 设置播放列表保存的最多条目,设置为 0 会保存有所片信息,默认值为5。
-hls_wrap n 设置多少片之后开始覆盖,如果设置为0则不会覆盖,默认值为0。这个选项能够避免在磁盘上存储过多的 片,而且能够限制写入磁盘的最多的片的数量。
-hls_start_number n 设置播放列表中 sequence number 的值为 number,默认值为 0。
注意:播放列表的 sequence number 对每个 segment 来说都必须是唯一的,而且它不能和片的文件名(当使用 wrap 选项时,文件名有可能会重复使用)混淆。
2、效率优化版,提升效率
TS 文件是一种媒体的扩展名,它是日本高清摄像机拍摄下进行的封装格式。MPEG2-TS(Transport Stream“传输流”;又称TS、TP、MPEG-TS 或 M2T)是用于音效、图像与数据的通信协定,最早应用于DVD的实时传送节目。MPEG2-TS格式的特点就是要求从视频流的任一片段开始都是可以独立解码的。
# 1.视频整体转码ts
ffmpeg -y -i music.mp4 -vcodec copy -acodec copy -vbsf h264_mp4toannexb out\music.ts
# 2. ts 文件切片
ffmpeg -i music.ts -c copy -map 0 -f segment -segment_list out\music.m3u8 -segment_time 10 out\15s_%3d.ts
3、hls_time 切片时间不准确的问题
播放 m3u8 的 ts 切片,必须要完整的下载一个 ts 切片,才能够播放,设置hls_time 的时间间隔越短越好( 根据实际情况来 ),实际过程中设置切片时间间隔为 2 秒,调用如下指令:
ffmpeg -i test.mp4 -c:v libx264 -c:a aac -strict -2 -f hls -hls_time 2 index.m3u8
但没有按照参数输入,进行切片。
原因:
ts 文件的切割,还跟原文件视频的 GOP 大小有关系(也就是两个 I 帧之间的时间间隔),因为任何一个 ts 分片第一帧必须是I帧,否则无法最快播放,并且第一帧不是 I 帧,对于播放器也是没有任何的意义,直接被播放器扔掉。任何一个视频流必须在获取到第一个I帧才能成功解码出图片。虽然指定了 1 秒切割一个 ts 文件,实际上,由于原视频流可能好几秒才有一个 I 帧,所以必须等到下一个 I 帧,才会重新开始切片。
解决:
既然知道要1秒产生一个ts分片,那就必须产生切片的过程中,强制一秒中产生一个关键帧。
设置关键帧间隔,设置间隔为 2 秒的参数如下:-force_key_frames "expr:gte(t,n_forced*2)
“
完整指令如:
ffmpeg -i test.mp4 -force_key_frames "expr:gte(t,n_forced*2)" -strict -2 -c:a aac -c:v libx264 -hls_time 2 -f hls index.m3u8
本文福利, 免费领取C++音视频学习资料包、技术视频/代码,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,编解码,推拉流,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓
4、m3u8 格式解析
完整的 m3u8 文件有三部分:
- index.m3u8,保存视频的基本信息和分段文件顺序;
- key,如果视频加密,保存密钥;
- data文件,其他都是视频的数据文件。
具体内容解析:
#EXTM3U
,是文件开始#EXT-X-VERSION
,标识HLS的协议版本号;#EXT-X-TARGETDURATION
,表示每个视频分段最大的时长(单位秒);#EXT-X-MEDIA-SEQUENCE
,表示播放列表第一个 URL 片段文件的序列号;#EXT-X-PLAYLIST-TYPE
,表明流媒体类型;#EXT-X-KEY
,加密方式,这里加密方式为AES-128
,同时指定IV
,在解密时需要;#EXTINF
,表示其后 URL 指定的媒体片段时长(单位为秒)。
二、播放演示
HLS 的工作原理是把整个流分成一个个小的基于 HTTP 的文件来下载,每次只下载一些。
当媒体流正在播放时,客户端可以选择从许多不同的备用源中以不同的速率下载同样的资源,允许流媒体会话适应不同的数据速率。
在开始一个流媒体会话时,客户端会下载一个包含元数据的 extended M3U (m3u8) playlist文件,用于寻找可用的媒体流。
HLS 只请求基本的 HTTP 报文,与实时传输协议(RTP)不同,HLS 可以穿过任何允许 HTTP 数据通过的防火墙或者代理服务器。
它也很容易使用内容分发网络来传输媒体流。
三、m3u8(ts) 合并为 MP4
远程文件
ffmpeg -i “https://xushanxiang.com/demo/ffmpeg/hls265/output.m3u8” -vcodec copy -acodec copy -absf aac_adtstoasc output.mp4
本地文件
1、打开 cmd
2、输入指令,按照文件的实际路径合并
合并成 ts
文件 copy /b F:\f\*.ts E:\f\new.ts
合并成 MP4
文件 copy /b F:\f\*.ts E:\f\new.MP4
而通过 ffmpeg 命令如下:
直接转:
ffmpeg -i new.ts -c copy -map 0:v -map 0:a output.mp4
指定音频流(一般用这个):
ffmpeg -i new.ts -c copy -map 0:v -map 0:a -bsf:a aac_adtstoasc output.mp4
重编码视频:
ffmpeg -y -i new.ts -c:v libx264 -c:a copy -bsf:a aac_adtstoasc output.mp4
php实现代码
$url = 'https://******.m3u8?Expires=1585381145&OSSAccessKeyId=******&Signature=******';$ts_content = file_get_contents($url);
$ts_content = explode(',', $ts_content);
$ts_file = array();foreach ($ts_content as $key => $value) {if($key == 0) continue;$value = trim($value);$ts_file[] = substr($value, 0, strpos($value, '.ts') + 3);
}$url_prefix = substr($url, 0, strpos($url, '.m3u8'));
$url_prefix = substr($url, 0, strrpos($url, '/') + 1);
$file_content = '';foreach ($ts_file as $key => $value) {$file_content .= file_get_contents($url_prefix . $value);
}file_put_contents('tmp_out.ts', $file_content);// FFMPEG_PATH 是你自己解压ffmpeg的bin路径,例如我的是F:/ffmpeg/bin/
exec(FFMPEG_PATH . "ffmpeg -i tmp_out.ts tmp_out.mp4");
Python实现代码
目录结构 ./|-- m3u8.py|-- result|-- 文件1|-- key|-- index.m3u8|-- data...|-- 文件2|-- ...
import os
import sys
import time
from Crypto.Cipher import AESdef fileList(findex):rpath = os.path.dirname(os.path.realpath(findex))name = rpath.split("\\")[-1]fi = open(findex, 'r')flag = FalseIV = Nonetl = []for line in fi.readlines():if line.startswith("#EXT-X-KEY"):# 如果存在 IV 则提取;if line.split(",")[-1].startswith("IV="):IV = line.split(",")[-1][5:]IV = bytes.fromhex(IV)if line.startswith("#EXTINF"):flag = not flagcontinueif flag:tmp = line.strip().split("/")[-1]tmp = os.path.join(rpath, tmp)tl.append(tmp)flag = not flagfi.close()fk = open(os.path.join(rpath, "key"), 'rb')key = fk.read()fk.close()return name, tl, key, IVdef aes_decode(data, key, IV):# 如果没有指定 IV 值,则直接使用 key 值if not IV:IV = keycryptor = AES.new(key, AES.MODE_CBC, IV)plain_text = cryptor.decrypt(data)return plain_textdef main():fp = os.listdir()used = [s[:-4] for s in os.listdir("./result/")]for ind in fp:if not ind.isdigit():continueif ind in used:continuetry: name, fl, key, IV = fileList(os.path.join(ind, "index.m3u8"))except:print("-"*30)print("[-] Errot! file: ", ind)print("-"*30)continueprint("[*] Begin process file: ", name)start = time.time()f = open(os.path.join("./result/", name+".mp4"), 'ab')for i in fl:with open(i, 'rb') as inf:data = inf.read()f.write(aes_decode(data, key, IV))f.close()print("[+] Sucessfully! Cost time: ", time.time()-start)main()
原文链接
本文福利, 免费领取C++音视频学习资料包、技术视频/代码,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,编解码,推拉流,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓
使用ffmpeg把mp4与m3u8相互转换的操作相关推荐
- Java使用FFmpeg实现mp4转m3u8
Java使用FFmpeg实现mp4转m3u8 前言 FFmpeg M3U8 一.需求及思路分析 二.安装FFmpeg 1.windows下安装FFmpeg 2.linux下安装FFmpeg Ubunt ...
- 使用FFMpeg将MP4转为m3u8
使用ffmpeg将mp4切成ts片段的时候会碰到一个问题,就是生成的m3u8文件里只有最后的五个片段的信息. 这是因为ffmpeg 默认的list size 为5,所以只获得最后的5个片段.为了解决这 ...
- 使用FFmpeg进行mp4与m3u8之间转换
首先是给服务器安装ffmpeg,我自建的服务器上是用的ubuntu,非常幸运,ubuntu上安装非常简单,执行如下代码就行: sudo apt install ffmpeg ffmpeg -versi ...
- Java 利用ffmpeg工具实现视频MP4转m3u8
Java 利用ffmpeg工具实现视频MP4转m3u8(一) 前言 (一)ffmpeg工具转码 1.如何安装ffmpeg工具 2.如何使用ffmpeg工具进行视频转码 (二)播放m3u8文件 1.vi ...
- 利用ffmpeg 把.mp4转换为.flv
1. 下载安装 ffmpeg Download FFmpeg windows下载编译之后的exe文件,放到path环境变量中. Linux 下 tar xvf xxx.tar.bz2 ./config ...
- FFmpeg总结(九)用ffmpeg进行切片生成m3u8索引文件
在直播和点播中,通常后台并不会直接给一个http://xxx.xxx.xxx.xxx/xxx.mp4这样的url给客户端,而是通过m3u8索引列表,给客户端.今天来通过ffmpeg进行切片生成m3u8 ...
- FFmpeg入门详解之103:FFmpeg Nginx VLC打造M3U8直播点播
FFmpeg+Nginx+VLC打造M3U8点播 Nginx: web服务器(win10,本地nginx) FFmpeg: m3u8切片(4.3.1) VLC: 点播客户端 切片命令行: ffmpe ...
- ffmpeg 从mp4上提取H264的nalu
1.获取数据 ffmpeg读取mp4中的H264数据,并不能直接得到NALU,文件中也没有储存0x00000001的分隔符.下面这张图为packet.data中的数据 从图中可以发现,packet中的 ...
- 使用FFmpeg合并MP4视频
使用FFmpeg合并MP4视频 1. 使用mpeg拼接 2. ==使用ts拼接== 使用FFmpeg合并MP4视频 windows/linux下均可用 1. 使用mpeg拼接 速度慢,文件大 将 mp ...
最新文章
- linux挂载分区失败,Ubuntu分区挂载错误与Grub引导错误的修复
- [转]40种网页常用小技巧----Ajax中国
- 详解如何进行第三方App接入微信登录
- 浅谈js本地图片预览
- Django return
- sql几种删除语句的联系与区别
- apache hive_Hive:使用Apache Hive查询客户最喜欢的搜索查询和产品视图计数
- sql mysql assoc和row_mysql_fetch_row,mysql_fetch_array,mysql_fetch_assoc的区别
- 软件测试学习指南(更新中)
- 远场语音识别套件评测
- 通过函数指针实现四则运算
- 韦根w34是多少位_韦根(Wiegand)数据传输格式
- oracle中那个日期怎么相减_oracle 日期相减
- 英文论文查重规则是什么?
- Java中的私有权限(private)
- 《蜗居》的经典台词(转载)二
- 即时聊天软件与开放平台
- Postman INTERCEPTOR DISCONNECTED
- phpstudy mysql密码默认或重置,phpstudy伪静态开启,网站发布外网
- 深圳见!本周五,GIAC全球互联网架构大会强势来袭!
热门文章
- 在VS中怎么用vb画矩形_怎样画颜色绚丽的插画?
- Android 尺寸转换器(适配各种屏幕)
- 高效搬砖之EXCEL查找公式LOOKUP系列
- java response.write_response.write()区别response.getWrite().write()
- 利用C++实现简单的文件加密
- 代码:法向质心法提取线激光条纹中心线(CPP+OpenCV)
- res资源文件学习之res/values/attr.xml
- mysql原理(1) mysql底层数据结构
- 如何获取京东微信小程序页面路径
- 云端敏捷部署单节点MySQl与Redis服务(以Ubuntu为例)