# 归档 | 记录一次视频切片并上传大厂图床的尝试


经常在各种影视站看到图床切片的视频，研究了下。

首先看效果（新人练手项目，代码很烂，重在思路）

<div style="position: relative; padding: 28% 45%;">
<iframe style="position: absolute; width: 100%; height: 100%; left: 0; top: 0;" allowfullscreen="true" src="https://player.icodeq.com/v3/?url=https://s-bj-2220-zkeq.oss.dogecdn.com/video-meituan-demo.m3u8" frameborder="no" scrolling="no"></iframe>
</div>

视频仅提供示例，随便下的一个[视频](https://www.bilibili.com/video/BV1P3411J7uj)

**本文不提供相关接口，仅做技术复现！**

### 前期准备

> 需要首先安装 `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`

```python
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` 文件

单个 `ts` 转 `m3u8`

```python
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` 后缀

```python
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](https://cdn.hashnode.com/res/hashnode/image/upload/v1653446859266/cmio0NXfK.png)

```python
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` ）

```
89504E470D0A1A0A0000000D4948445200000320000003200803000000ECAEF65A0000001974455874536F6674776172650041646F626520496D616765526561647971C9653C00000006504C5445000000000000A567B9CF0000000174524E530040E6D866000002864944415478DAECC1010D000000C2A0F74F6D0E37A0
```

### 四、文件上传以及重写 `M3U8` 文件

文件上传

```python
# 上传图片
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`

```python
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 文件

```python
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")
```

### 五、串联以上代码的入口函数

```python
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

完整代码
(无上传接口版本)
```python
# 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")

```
