用ffmpeg合并.m3u8对应的TS文件

目录

一、前言

二、需求来源

三、解决方案

1、batch/powershell命令

2、徒手撸个应用

#主要的代码

#运行效果

四、结束语

附录:安装ffmpeg

1、下载

2、安装

3、测试命令


一、前言

目前大多数在线视频网站,很多都是使用.m3u8格式,这样,及时我们把视频下载到本地后,得到的依然是零散的ts格式的文件,如何把这些文件合并生成一个MP4文件呢,在这里分享一个最近撸码解决的办法。

二、需求来源

最近在参加一个在线网课,和目前大多数在线视频网站一样,使用的是.m3u8格式,.m3u8格式的具体实现原理和详细的介绍这里就不进行说明了,大致的原理就是把原来一整个大的视频文件,拆分成多个ts格式的小的视频文件,然后再按顺序加载到用户浏览器中播放,这一点可以再浏览器的控制台的网络请求中检测到详细:

为了方便学习,我把在线课程的视频下载到了本地,打开下载的内容是这样的,得到一个.m3u8文件,和一大堆ts文件,现在为了方便文件的管理和播放,我需要把这些ts文件合并成一个MP4文件,又不想去下写乱七八糟的工具,怎么办呢?

这时候很多人第一想到的是大名鼎鼎的ffmpeg,没错,我也想到了ffmpeg,着多简单呀,不就是合并ts文件嘛,一行命令就可以了。

注意:本文中的ffmpeg命令,需要先安装ffmpeg,安装的具体步骤可以参考文末的附录说明。

ffmpeg -i "concat:1.ts|2.ts|3.ts" -c copy output.mp4

# 或者把ts文件写到一个txt文件(input_list.txt)中,做一个文件清单,然后用这个命令
# file '1.ts'
# file '2.ts'
# file '3.ts'

ffmpeg -f concat -i input_list.txt -c copy output.mp4

但是,现在有4、5百个ts文件,我总不能一个一个写吧……于是,你就想到了这个命令,然后开开心心的打开mp4文件,然后你很可能会发现,MP4的视频很可能并没有按照ts的实际顺序来合并,造成视频内容乱了。

# 把folder文件夹下的所有ts文件做合并

ffmpeg -safe 0 -i "concat:folder/*.ts" -c copy output.mp4

三、解决方案

我们如何保证TS文件的顺序不出错呢?打开.m3u8文件,看看里面的内容,里面每一行的注释这里就不详细介绍了,如果想做进一步的了解,请自行问度娘吧。.m3u8文件中的ts文件的顺序,就是视频播放时的加载顺序,我们按照里面的顺序进行合并,肯定就不会错了。

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:18
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:17.4508,
index/0.ts
#EXTINF:8.34167,
index/1.ts
#EXTINF:8.34168,
index/2.ts
#EXTINF:13.7471,
index/3.ts
#EXTINF:8.34168,
index/4.ts
#EXTINF:8.34168,
index/5.ts
#EXTINF:12.012,
index/6.ts
……

现在解决方案已经很明朗了,我们需要使用下面的命令来合并生成MP4文件:

ffmpeg -f concat -i input_list.txt -c copy output.mp4

现在关键的问题是要生成 input_list.txt 文件,实现逻辑是读取.m3u8文件,按照原来的顺序把每一行的index/*.ts,加上“file”前缀,变成file 'index/*.ts',然后写入到新的txt文件。

要实现这个可以用两种方法:

1、batch/powershell命令

编写命令脚本,实现对.m3u8文件每一行的遍历,然后创建新的ts文件清单文件,这个做法要求对命令的语法什么的要求比较高,而且其中的逻辑控制,可能无法满足最终的需求,所以我放弃了这个方法(主要是对命令确实不熟(>_<) )

# 使用for /f循环读取xxx.m3u8文件,对每一行进行处理
for /f ["options"] %%i in ('xxx.m3u8') do (

# 每一行进行处理的逻辑


) 

2、徒手撸个应用

考虑到是windows操作系统中,所以就用C#写个简单的程序来跑吧,既然是用到代码,那可操作性就很高了,实现的逻辑步骤主要有:

(1)扫描当前目录,查找.m3u8文件,如果找到,则解析当前目录的.m3u8文件。

(2)如果当前目录没有.m3u8文件,则遍历当前的子目录,查找子目录的.m3u8文件进行解析。

(3)解析.m3u8文件,每个.m3u8文件生成一个对应的临时ts文件清单,然后根据文件清单合并生成一个MP4文件。

#主要的代码

(1)从.m3u8文件中提取ts文件List,这里直接去除以#符号大头的行,具体逻辑可以根据实际情况继续完善。

        /// <summary>
        /// 根据m3u8文件路径,获取ts文件路径序列
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        private static List<string> GetTsFileByM3u8(string filePath)
        {
            List<string> list = new List<string>();
            using (StreamReader reader = new StreamReader(filePath))
            {
                string line;
                // 逐行读取文件内容  
                while ((line = reader.ReadLine()) != null)
                {
                    if (!line.StartsWith("#"))
                    {
                        list.Add(line);
                    }
                }
            }
            return list;
        }

(2)启动ffmpeg,根据临时生成的ts文件描述文件,合并输出MP4文件。

/// <summary>
        /// 运行ffmpeg命令,合并生成MP4文案
        /// </summary>
        /// <param name="fileListPath">ts文件清单说明txt文件</param>
        /// <param name="outputFile">合并输出文件</param>
        private static void ExecuFFMpeg(string fileListPath, string outputFile)
        {
            if (!File.Exists(fileListPath))
            {
                //throw new Exception(String.Format("{0}文件不存在!", fileListPath));
                Console.WriteLine(String.Format("缓存文件不存在:{0}", fileListPath));
            }
            else
            {
                outputFile = GetFileName(outputFile);

                List<string> ffmpegArguments = new List<string>  
                {  
                    "-f", "concat",  
                    "-safe", "0",  
                    "-i", fileListPath,  
                    "-c", "copy",  
                    outputFile  
                };


                try
                {
                    // 合并FFmpeg命令和参数  
                    string ffmpegCommand = "ffmpeg";
                    string ffmpegCmdLine = string.Join(" ", ffmpegArguments);

                    Console.WriteLine("启动ffmpeg进程,开始合并,请稍后……");

                    //// 创建并配置Process对象  
                    Process ffmpegProcess = new Process
                    {
                        StartInfo = new ProcessStartInfo
                        {
                            FileName = ffmpegCommand,
                            Arguments = ffmpegCmdLine,
                            RedirectStandardOutput = true,
                            RedirectStandardError = true,
                            UseShellExecute = false,
                            CreateNoWindow = true
                        }
                    };

                    DateTime now = DateTime.Now;

                    // 启动FFmpeg进程并等待其退出  
                    ffmpegProcess.Start();
                    string ffmpegOutput = ffmpegProcess.StandardOutput.ReadToEnd();
                    string ffmpegError = ffmpegProcess.StandardError.ReadToEnd();
                    ffmpegProcess.WaitForExit();

                    DateTime end = DateTime.Now;

                    // 输出FFmpeg的结果  
                    Console.WriteLine("【FFmpeg Output】:");
                    Console.WriteLine(ffmpegOutput);

                    if (!string.IsNullOrEmpty(ffmpegError))
                    {
                        Console.WriteLine("【FFmpeg Error】:");
                        Console.WriteLine(ffmpegError);
                    }
                    //outputFile
                    Console.WriteLine(String.Format("合并完成,已生成{0}文件", outputFile));
                    Console.WriteLine(String.Format("耗时 {0} 秒", (end - now).TotalSeconds));

                }
                catch (Exception err)
                {
                    throw err;
                }
                finally
                {
                    // 清理临时文件  
                    // 可以在程序结束时删除临时文件,或者根据需要保留  
                    // File.Delete(tempFileListPath);  
                }
            }
        }

代码有点长,所以不在文章里贴出来了,完整代码已经上传,具体可以下载下来参考参考,主要的地方都做了注释,如果要使用,可以根据自己的需要进行修改后运行。

#运行效果

编译输出后,生成FFMpegTsMerged.exe运行程序,然后拷贝到.m3u8文件同级目录,运行看看效果,运行后生成第一章的1.mp4文件和temp_filelist_1_index.txt临时文件。(index中是.m3u8中所包含的所有ts文件)

把FFMpegTsMerged.exe拷贝到上一级目录,运行看看效果,sec1-sec4分别对应第一到第四节课的视频。

运行程序:

四、结束语

基本达到要求了,代码里还有好多异常判断拉之类的逻辑要处理,不过也不想完善了,目前已经帮我把视频生成了就可以了。

附录:安装ffmpeg

1、下载

官方下载地址:Download FFmpeg

下载:Builds - CODEX FFMPEG @ gyan.dev

选ffmpeg-release-full-shared.7z下载,可能有点慢,耐心等待,下载完成后解压出来。

注意:不要下错了去下个源码回来。

2、安装

解释也没有什么所谓的安装了,就是把ffmpeg加到环境变量Path中,确保ffmpeg可以直接运行就可以了。

3、测试命令

运行 ffmpeg -version 命令,如果没有提示命令不存在或者报错,着说明配置正常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值