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 相关文章推荐
c++生成dll使用python调用dll的方法
Jan 20 Python
Python实现多行注释的另类方法
Aug 22 Python
使用paramiko远程执行命令、下发文件的实例
Oct 01 Python
python使用pyqt写带界面工具的示例代码
Oct 23 Python
python中的内置函数max()和min()及mas()函数的高级用法
Mar 29 Python
Python使用matplotlib模块绘制图像并设置标题与坐标轴等信息示例
May 04 Python
pytorch cnn 识别手写的字实现自建图片数据
May 20 Python
python验证码识别教程之滑动验证码
Jun 04 Python
对python pandas读取剪贴板内容的方法详解
Jan 24 Python
django模型动态修改参数,增加 filter 字段的方式
Mar 16 Python
基于Python爬取搜狐证券股票过程解析
Nov 18 Python
Python实现网络聊天室的示例代码(支持多人聊天与私聊)
Jan 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如何得到当前页和上一页的地址?
2006/11/27 PHP
php 字符过滤类,用于过滤各类用户输入的数据
2009/05/27 PHP
Yii2.0中的COOKIE和SESSION用法
2016/08/12 PHP
PHP实现的回溯算法示例
2017/08/15 PHP
JS网络游戏-(模拟城市webgame)提供的一些例子下载
2007/10/14 Javascript
客户端 使用XML DOM加载json数据的方法
2010/09/28 Javascript
JavaScript Array对象扩展indexOf()方法
2014/05/09 Javascript
jquery实现初次打开有动画效果的网页TAB切换代码
2015/09/06 Javascript
快速掌握Node.js事件驱动模型
2016/03/21 Javascript
bootstrap fileinput 插件使用项目总结(经验)
2017/02/22 Javascript
JS正则表达式验证密码格式的集中情况总结
2017/02/23 Javascript
js手机号4位显示空格,银行卡每4位显示空格效果
2017/03/23 Javascript
浅谈mvvm-simple双向绑定简单实现
2018/04/18 Javascript
使用JavaScript保存文本文件到本地的两种方法
2019/01/22 Javascript
聊聊Vue 中 title 的动态修改问题
2019/06/11 Javascript
移动端底部导航固定配合vue-router实现组件切换功能
2019/06/13 Javascript
jQuery Ajax async=>false异步改为同步时,解决导致浏览器假死的问题
2019/07/22 jQuery
[41:17]完美世界DOTA2联赛PWL S3 access vs CPG 第二场 12.13
2020/12/17 DOTA
python 解析XML python模块xml.dom解析xml实例代码
2014/02/07 Python
[原创]使用豆瓣提供的国内pypi源
2017/07/02 Python
Python星号*与**用法分析
2018/02/02 Python
Python3实现的爬虫爬取数据并存入mysql数据库操作示例
2018/06/06 Python
python3 flask实现文件上传功能
2020/03/20 Python
python 读取Linux服务器上的文件方法
2018/12/27 Python
python使用隐式循环快速求和的实现示例
2020/09/11 Python
新年抽奖获奖感言
2014/03/02 职场文书
家长对老师的评语
2014/04/18 职场文书
敬老院活动总结
2014/04/28 职场文书
2014中考励志标语
2014/06/05 职场文书
毕业班工作总结
2015/08/10 职场文书
提档介绍信范文
2015/10/22 职场文书
小学生组织委员竞选稿
2015/11/21 职场文书
利用Nginx代理如何解决前端跨域问题详析
2021/04/02 Servers
python迷宫问题深度优先遍历实例
2021/06/20 Python
基于MySql验证的vsftpd虚拟用户
2021/11/07 MySQL
「我的青春恋爱物语果然有问题。-妄言录-」第20卷封面公开
2022/03/21 日漫