python 实现多线程下载m3u8格式视频并使用fmmpeg合并


Posted in Python onNovember 15, 2019

电影之类的长视频好像都用m3u8格式了,这就导致了多线程下载视频的意义不是很大,都是短视频,线不线程就没什么意义了嘛。

我们知道,m3u8的链接会下载一个文档,相当长,半小时的视频,应该有接近千行ts链接。

这些ts链接下载成ts文件,就是碎片化的视频,加以合并,就成了需要的视频。

那,即便网速很快,下几千行视频,效率也就低了,更何况还要合并。我就琢磨了一下午,怎么样才能多线程下载m3u8格式的视频呢?

先上代码,再说重难点:

import datetime
import os
import re
import threading
import requests
from queue import Queue
# 预下载,获取m3u8文件,读出ts链接,并写入文档
def down():
  # m3u8链接
  url = 'https://ali-video.acfun.cn/mediacloud/acfun/acfun_video/segment/3zf_GAW6nFMuDXrTLL89OZYOZ4mwxGoASH6UcZbsj1_6eAxUxtp3xm8wFmGMNOnZ.m3u8?auth_key=1573739375-474267152-0-a5aa2b6df4cb4168381bf8b04d88ddb1'
  # 当ts文件链接不完整时,需拼凑
  # 大部分网站可使用该方法拼接,部分特殊网站需单独拼接
  base_url = re.split(r"[a-zA-Z0-9-_\.]+\.m3u8", url)[0]
  # print(base_url)
  resp = requests.get(url)
  m3u8_text = resp.text
  # print(m3u8_text)
  # 按行拆分m3u8文档
  ts_queue = Queue(10000)
  lines = m3u8_text.split('\n')
  # 找到文档中含有ts字段的行
  concatfile = 'cache/' + "s" + '.txt'
  for line in lines:
    if '.ts' in line:
      if 'http' in line:
        # print("ts>>", line)
        ts_queue.put(line)
      else:
        line = base_url + line
        ts_queue.put(line)
        # print('ts>>',line)
      filename = re.search('([a-zA-Z0-9-]+.ts)', line).group(1).strip()
      # 一定要先写文件,因为线程的下载是无序的,文件无法按照
      # 123456。。。去顺序排序,而文件中的命名也无法保证是按顺序的
      # 这会导致下载的ts文件无序,合并时,就会顺序错误,导致视频有问题。
      open(concatfile, 'a+').write("file %s\n" % filename)
  return ts_queue,concatfile
# 线程模式,执行线程下载
def run(ts_queue):
  tt_name = threading.current_thread().getName()
  while not ts_queue.empty():
    url = ts_queue.get()
    r = requests.get(url, stream=True)
    filename = re.search('([a-zA-Z0-9-]+.ts)', url).group(1).strip()
    with open('cache/' + filename, 'wb') as fp:
      for chunk in r.iter_content(5242):
        if chunk:
          fp.write(chunk)
    print(tt_name + " " + filename + ' 下载成功')
# 视频合并方法,使用ffmpeg
def merge(concatfile, name):
  try:
    path = 'cache/' + name + '.mp4'
    command = 'ffmpeg -y -f concat -i %s -crf 18 -ar 48000 -vcodec libx264 -c:a aac -r 25 -g 25 -keyint_min 25 -strict -2 %s' % (concatfile, path)
    os.system(command)
    print('视频合并完成')
  except:
    print('合并失败')
if __name__ == '__main__':
  name = input('请输入视频名称:')
  start = datetime.datetime.now().replace(microsecond=0)
  s,concatfile = down()
  # print(s,concatfile)
  threads = []
  for i in range(15):
    t = threading.Thread(target=run, name='th-'+str(i), kwargs={'ts_queue': s})
    threads.append(t)
  for t in threads:
    t.start()
  for t in threads:
    t.join()
  end = datetime.datetime.now().replace(microsecond=0)
  print('下载耗时:' + str(end - start))
  merge(concatfile,name)
  over = datetime.datetime.now().replace(microsecond=0)
  print('合并耗时:' + str(over - end))

效果图:

python 实现多线程下载m3u8格式视频并使用fmmpeg合并

代码开始:自己输入视频名称(也可以去原网站爬名称)

查看下载耗时,fmmpeg开始合并:

python 实现多线程下载m3u8格式视频并使用fmmpeg合并

合并耗时:

python 实现多线程下载m3u8格式视频并使用fmmpeg合并

7分多钟,90个ts文件,接近40MB。两秒下载完成。

更大的文件,开更多的线程。

然后我们画画重难点:

第一:ts文件命名问题。

我们知道,每一个线程启动,除了队列不会重复,那么代码里都会重新跑(线程里的代码),那么,1.ts,2.ts....这种命名是不可能的了,文件会被覆盖。命名我使用了ts链接中的部分链接。

第二:合并问题。

文件的合并是根据文档内的顺序,也就是,如果边下载边合并,那么,线程的无序性导致下载无序,文件写入也就无序化了,合并时,时间线会错误,合出来的视频就无法看。因此,文件要提前写好才行,这和命名有很大的关联,看代码即知。

第三:有的m3u8是特殊处理的,代码具有一定的局限性。

写的时候挺难的,脑子都乱了,就这些吧,记录一下。

对了,贴一下下载的图:90个ts文件,一个mp4文件,一个文档。

python 实现多线程下载m3u8格式视频并使用fmmpeg合并

总结

以上所述是小编给大家介绍的python 实现多线程下载m3u8格式视频并使用fmmpeg合并,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Python 相关文章推荐
Python基于回溯法子集树模板解决找零问题示例
Sep 11 Python
python里使用正则表达式的组嵌套实例详解
Oct 24 Python
删除python pandas.DataFrame 的多重index实例
Jun 08 Python
使用sklearn之LabelEncoder将Label标准化的方法
Jul 11 Python
Python实现的KMeans聚类算法实例分析
Dec 29 Python
Python3 单行多行万能正则匹配方法
Jan 07 Python
在Python中调用Ping命令,批量IP的方法
Jan 26 Python
Python3.4学习笔记之常用操作符,条件分支和循环用法示例
Mar 01 Python
pyqt5 comboBox获得下标、文本和事件选中函数的方法
Jun 14 Python
Python日志syslog使用原理详解
Feb 18 Python
python中如何进行连乘计算
May 28 Python
Pycharm操作Git及GitHub的步骤详解
Oct 27 Python
浅析python内置模块collections
Nov 15 #Python
Python树莓派学习笔记之UDP传输视频帧操作详解
Nov 15 #Python
Python numpy数组转置与轴变换
Nov 15 #Python
python修改文件内容的3种方法详解
Nov 15 #Python
Python实现基于socket的udp传输与接收功能详解
Nov 15 #Python
python根据文本生成词云图代码实例
Nov 15 #Python
解决django后台管理界面添加中文内容乱码问题
Nov 15 #Python
You might like
PHP用户指南-cookies部分
2006/10/09 PHP
php 获取全局变量的代码
2011/04/21 PHP
PHP函数addslashes和mysql_real_escape_string的区别
2014/04/22 PHP
php使用CURL不依赖COOKIEJAR获取COOKIE的方法
2015/06/17 PHP
深入剖析浏览器退出之后php还会继续执行么
2016/05/17 PHP
PHP+原生态ajax实现的省市联动功能详解
2017/08/15 PHP
Laravel如何使用数据库事务及捕获事务失败后的异常详解
2017/10/23 PHP
PHP使用PDO抽象层获取查询结果的方法示例
2018/05/10 PHP
thinkphp5框架结合mysql实现微信登录和自定义分享链接与图文功能示例
2019/08/13 PHP
PHP 实现链式操作
2021/03/09 PHP
Javascript面象对象成员、共享成员变量实验
2010/11/19 Javascript
window.open不被拦截的实现代码
2012/08/22 Javascript
js中使用replace方法完成某个字符的转换
2014/08/20 Javascript
轻松创建nodejs服务器(6):作出响应
2014/12/18 NodeJs
javascript判断移动端访问设备并解析对应CSS的方法
2015/02/05 Javascript
JS实现点击按钮获取页面高度的方法
2015/11/02 Javascript
jQuery实现侧浮窗与中浮窗切换效果的方法
2016/09/05 Javascript
解决jquery appaend元素中id绑定事件失效的问题
2017/09/12 jQuery
详解webpack-dev-server使用http-proxy解决跨域问题
2018/01/13 Javascript
在 Vue 应用中使用 Netlify 表单功能的方法详解
2019/06/03 Javascript
JavaScript array常用方法代码实例详解
2020/09/02 Javascript
[02:32]【DOTA2亚洲邀请赛】iceice,梦开始的地方
2017/03/13 DOTA
Python中基础的socket编程实战攻略
2016/06/01 Python
Pandas之drop_duplicates:去除重复项方法
2018/04/18 Python
在python中利用GDAL对tif文件进行读写的方法
2018/11/29 Python
Python对HTML转义字符进行反转义的实现方法
2019/04/28 Python
解决python tkinter界面卡死的问题
2019/07/17 Python
python实现PID算法及测试的例子
2019/08/08 Python
python使用beautifulsoup4爬取酷狗音乐代码实例
2019/12/04 Python
python 对象真假值的实例(哪些视为False)
2020/12/11 Python
HTML5 语音搜索(淘宝店语音搜素)
2013/01/03 HTML / CSS
兰芝美国网上商城:购买LANEIGE睡眠面膜等
2017/06/30 全球购物
国际领先的在线时尚服装和配饰店:DressLily
2019/03/03 全球购物
利达恒信公司.NET笔试题面试题
2016/03/05 面试题
动态密码技术
2012/10/18 面试题
有子女的离婚协议书怎么写(范本)
2014/09/29 职场文书