经常在各种影视站看到图床切片的视频,研究了下。

首先看效果(新人练手项目,代码很烂,重在思路)

视频仅提供示例,随便下的一个视频

本文不提供相关接口,仅做技术复现!

前期准备

需要首先安装 ffmpeg 并配置到环境变量(使用命令行输入 ffmpeg 可以正常打开的那种)
https://www.gyan.dev/ffmpeg/builds/

https://github.com/BtbN/FFmpeg-Builds/releases

目录结构

项目分为以下几部分

  1. 对 mp4 文件进行格式转换,转成单个 ts 文件
  2. 对 单个 ts 文件进行转换,转成 m3u8 文件和 ts 切片文件
  3. 对 ts 切片文件进行重构,使其具有 PNG 文件格式的文件头
  4. 上传图床并根据返回的结果重写之前 m3u8 文件。

一、文件转换部分

mp4 转 单个 ts

1
2
3
4
5
def video_to_ts(video_path):
ts_all = ".//ts_single//ts_single.ts"
cmd_str = f'ffmpeg -y -i {video_path} -vcodec copy -acodec copy -vbsf h264_mp4toannexb {ts_all}'
subprocess.run(cmd_str, encoding="utf-8", shell=True)
print(f'从 {video_path} 转换到 {cmd_str} 成功!')

二、生成 m3u8 文件

单个 tsm3u8

1
2
3
4
def ts_to_m3u8(ts_single, singlg_time):
cmd_str = f'ffmpeg -i {ts_single} -c copy -map 0 -f segment -segment_list temp_playlist.m3u8 -segment_time {singlg_time} ./ts_all/%03d.ts'
subprocess.run(cmd_str, encoding="utf-8", shell=True)
print(f'从 {ts_single} 转换到 temp_playlist.m3u8 成功!')

三、ts 文件格式处理部分

首先重命名为 PNG 后缀

1
2
3
4
5
6
7
def rename_ts_to_png():
file_list = os.listdir("./ts_all")
for i in file_list:
if i.endswith(".ts"):
new_name = i.replace(".ts", ".png")
os.rename("./ts_all/" + i, "./ts_all/" + new_name)
print("rename_ts_to_png")

重写覆写 ts文件头,使其拥有 PNG 文件头

11

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def rewrite_ts_to_png():
file_list = os.listdir("./ts_all")
for i in file_list:
copyfile("PNG", "./ts_rewrite/" + i)
print("rewrite_ts_to_png")
file_list = os.listdir("./ts_rewrite")
for i in file_list:
if i.endswith(".png"):
bin_file = open("./ts_all/" + i, 'rb') # 打开二进制文件
# 合并文件
with open("./ts_rewrite/" + i, 'ab') as f:
f.write(bin_file.read())
bin_file.close()
return None

PNG 文件头 16 进制数据如下(放在项目目录命名为 PNG

1
89504E470D0A1A0A0000000D4948445200000320000003200803000000ECAEF65A0000001974455874536F6674776172650041646F626520496D616765526561647971C9653C00000006504C5445000000000000A567B9CF0000000174524E530040E6D866000002864944415478DAECC1010D000000C2A0F74F6D0E37A0

四、文件上传以及重写 M3U8 文件

文件上传

1
2
3
4
5
6
7
# 上传图片
def updateImage(filepath):
_upload_url = "******************************/api/content/file/upload"
files = {'media': open(filepath, 'rb')}
upload_res = requests.post(_upload_url, files=files)
print('正在上传:', filepath)
return upload_res.json()

提取返回的 url

1
2
3
4
5
6
7
def upload_list(_upload_url):
_file_dict = {}
file_list = os.listdir(_upload_url)
for i in file_list:
data_json = updateImage(_upload_url + i)
_file_dict[i] = data_json["***"]["*pic*"] + "\n"
return _file_dict

重写 m3u8 文件

1
2
3
4
5
6
7
8
9
10
11
12
def rewrite_m3u8(m3u8_file, file_dict):
print(file_dict)
with open(m3u8_file, 'r') as f:
lines = f.readlines()
for i in lines:
rename = i.replace("ts", "png").replace("\n", "")
if rename in file_dict.keys():
lines[lines.index(i)] = file_dict[rename]
print("正在替换:", i)
with open(m3u8_file, 'w') as f:
f.writelines(lines)
print("rewrite_m3u8")

五、串联以上代码的入口函数

1
2
3
4
5
6
7
8
9
if __name__ == '__main__':
video_to_ts("video.mp4")
ts_to_m3u8("./ts_single/ts_single.ts", "5")
rename_ts_to_png()
rewrite_ts_to_png()
upload_url = "./ts_rewrite/"
file_dict = upload_list(upload_url)
rewrite_m3u8("./temp_playlist.m3u8", file_dict)
print("main")

需要自行创建文件夹及准备文件

  • ./ts_single/
  • ./ts_all/
  • ./ts_rewrite/
  • ./video.mp4
  • ./PNG

完整代码
(无上传接口版本)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# coding:utf-8

import subprocess
import requests
from shutil import copyfile
import os


def video_to_ts(video_path):
ts_all = ".//ts_single//ts_single.ts"
cmd_str = f'ffmpeg -y -i {video_path} -vcodec copy -acodec copy -vbsf h264_mp4toannexb {ts_all}'
subprocess.run(cmd_str, encoding="utf-8", shell=True)
print(f'从 {video_path} 转换到 {cmd_str} 成功!')


def ts_to_m3u8(ts_single, singlg_time):
cmd_str = f'ffmpeg -i {ts_single} -c copy -map 0 -f segment -segment_list temp_playlist.m3u8 -segment_time {singlg_time} ./ts_all/%03d.ts'
subprocess.run(cmd_str, encoding="utf-8", shell=True)
print(f'从 {ts_single} 转换到 temp_playlist.m3u8 成功!')


def rename_ts_to_png():
file_list = os.listdir("./ts_all")
for i in file_list:
if i.endswith(".ts"):
new_name = i.replace(".ts", ".png")
os.rename("./ts_all/" + i, "./ts_all/" + new_name)
print("rename_ts_to_png")


def rewrite_ts_to_png():
file_list = os.listdir("./ts_all")
for i in file_list:
copyfile("PNG", "./ts_rewrite/" + i)
print("rewrite_ts_to_png")
file_list = os.listdir("./ts_rewrite")
for i in file_list:
if i.endswith(".png"):
bin_file = open("./ts_all/" + i, 'rb') # 打开二进制文件
# 合并文件
with open("./ts_rewrite/" + i, 'ab') as f:
f.write(bin_file.read())
bin_file.close()
return None


# 上传图片
def updateImage(filepath):
_upload_url = "*************************************************"
files = {'media': open(filepath, 'rb')}
upload_res = requests.post(_upload_url, files=files)
print('正在上传:', filepath)
return upload_res.json()


def upload_list(_upload_url):
_file_dict = {}
file_list = os.listdir(_upload_url)
for i in file_list:
data_json = updateImage(_upload_url + i)
_file_dict[i] = data_json["****"]["******"] + "\n"
return _file_dict


def rewrite_m3u8(m3u8_file, file_dict):
print(file_dict)
with open(m3u8_file, 'r') as f:
lines = f.readlines()
for i in lines:
rename = i.replace("ts", "png").replace("\n", "")
if rename in file_dict.keys():
lines[lines.index(i)] = file_dict[rename]
print("正在替换:", i)
with open(m3u8_file, 'w') as f:
f.writelines(lines)
print("rewrite_m3u8")


if __name__ == '__main__':
video_to_ts("video.mp4")
ts_to_m3u8("./ts_single/ts_single.ts", "5")
rename_ts_to_png()
rewrite_ts_to_png()
upload_url = "./ts_rewrite/"
file_dict = upload_list(upload_url)
rewrite_m3u8("./temp_playlist.m3u8", file_dict)
print("main")