# pip3 install -i https://mirrors.aliyun.com/pypi/simple/ m3u8 # pip3 install -i https://mirrors.aliyun.com/pypi/simple/ oss2 # pip3 install --upgrade pip # 在Centos中安装ffmpeg和aria2c import m3u8, sys import os, subprocess import oss2, requests, datetime # ======================================================================== # 前面需要截取的时间长度,单位:秒 prefixCutSeconds = 10 # 后面需要截取的时间长度,单位:秒 suffixCutSeconds = 5 # 上传的路径前缀 prefix = 'down/M3u8_ZhengZhou103/' # ======================================================================== # 访问oss的用户名与密码,无需修改 access_key_id = 'xxxxxxxxxxxx' access_key_secret = 'xxxxxxxxxxxx' bucket_name = 'dsideal-yy' # 检查是内网还是外网 def CheckInOut(): # 探测内网外网 print('正在探测使用环境是阿里云内网还是外网,请稍等...') url = 'http://' + bucket_name + '.oss-cn-qingdao-internal.aliyuncs.com/down/Material/42/42385DBE-E03F-FF6A-A37C-CC8A04612BE4.doc' try: requests.get(url, timeout=1) endpoint = 'http://oss-cn-qingdao-internal.aliyuncs.com/' print('内部网络访问,将使用endpoint:' + endpoint) except Exception as err: endpoint = 'http://oss-cn-qingdao.aliyuncs.com/' print('外网访问,将使用endpoint:' + endpoint) return endpoint # 从哪个结点下进行操作 endpoint = CheckInOut() # 从哪里下载回来,如果是内网,应该写成 http://dsideal_yy.oss-cn-qingdao-internal.aliyuncs.com if 'internal' in endpoint: downloadPrefixUrl = 'http://' + bucket_name + '.oss-cn-qingdao-internal.aliyuncs.com/down/M3u8/' else: downloadPrefixUrl = 'http://' + bucket_name + '.oss-cn-qingdao.aliyuncs.com/down/M3u8/' # 获取视频的时间长度 def GetVideoLength(fileName): cmd = "ffmpeg -i " + fileName + " 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//" p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) out, err = p.communicate() for line in out.splitlines(): return (line.decode()[0:8]) # 将时间换算成秒数 def t2s(t): h, m, s = t.strip().split(":") return int(h) * 3600 + int(m) * 60 + int(s) # 下载m3u8的所有ts文件 def DoActionM3u8(m3u8_url): # m3u8文件的真实名称 m3u8FileName = WorkingPath + "/" + m3u8_url.split('/')[-1] print('M3u8真实文件名称:' + m3u8FileName) # 构造两个文本文件 m3u8List = [] m3u8FileList = [] m3u8_obj = m3u8.load(m3u8_url) for l in m3u8_obj.segments: m3u8List.append(downloadPrefixUrl + l.uri[0:2] + '/' + l.uri) m3u8FileList.append("file '" + l.uri + "'") # 形成文本文件,这个用于调用aria2c进行批量下载使用 tempFile = WorkingPath + '/url.txt' result = map(lambda x: x.strip() + '\n', m3u8List) with open(tempFile, 'w') as f: f.writelines(result) # 下载回来转码后的视频ts cmd = 'aria2c -c -s 4 -d ' + WorkingPath + ' -j 8 -i ' + tempFile os.system(cmd) # 形成文本文件,用于将ts文件拼接成大的ts文件时使用 tempFile = WorkingPath + '/mylist.txt' result = map(lambda x: x.strip() + '\n', m3u8FileList) with open(tempFile, 'w') as f: f.writelines(result) # 使用ffmpeg 拼成大的ts tempAllTs = WorkingPath + '/output.ts' if os.path.exists(tempAllTs): os.remove(tempAllTs) tempAllTs_new = WorkingPath + '/output_new.ts' if os.path.exists(tempAllTs_new): os.remove(tempAllTs_new) tempAllMp4 = WorkingPath + '/output.mp4' if os.path.exists(tempAllMp4): os.remove(tempAllMp4) tempAllMp4_new = WorkingPath + '/output_new.mp4' if os.path.exists(tempAllMp4_new): os.remove(tempAllMp4_new) # 拼接为原始的ts cmd = 'ffmpeg -f concat -i ' + tempFile + ' -c copy ' + tempAllTs + ' -y' os.system(cmd) # # 将大的ts转为mp4 cmd = 'ffmpeg -i ' + tempAllTs + ' -c:v copy -c:a copy -bsf:a aac_adtstoasc ' + tempAllMp4 os.system(cmd) os.remove(tempAllTs) # 以下为new的步骤========================================================================= # # 截取一部分 # (1) 测出文件有多长 videoLength = GetVideoLength(tempAllMp4) # 去掉后suffixCutSeconds秒 seconds = t2s(videoLength) - suffixCutSeconds m, s = divmod(seconds, 60) h, m = divmod(m, 60) endTime = "%02d:%02d:%02d" % (h, m, s) # 开始的秒数 m, s = divmod(prefixCutSeconds, 60) h, m = divmod(m, 60) startTime = "%02d:%02d:%02d" % (h, m, s) # # # # (2)去头部prefixCutSeconds秒,尾部suffixCutSeconds秒 print('截取并生成mp4!') cmd = 'ffmpeg -i ' + tempAllMp4 + ' -vcodec copy -acodec copy -ss ' + startTime + ' -to ' + endTime + ' ' + tempAllMp4_new + ' -y' os.system(cmd) os.remove(tempAllMp4) print('生成新mp4成功!到这里都是非常正常的!!!!!') # (3) mp4 转 ts cmd = 'ffmpeg -y -i ' + tempAllMp4_new + ' -vcodec copy -acodec copy -vbsf h264_mp4toannexb ' + tempAllTs_new os.system(cmd) os.remove(tempAllMp4_new) # (4) 切割ts prefixName = m3u8_url.split('/')[-1][0:36] cmd = 'ffmpeg -i ' + tempAllTs_new + ' -c copy -map 0 -f segment -segment_list ' + WorkingPath + '/' + prefixName + '.m3u8 -segment_time 10 ' + WorkingPath + '/' + prefixName + '%03d.ts' os.system(cmd) os.remove(tempAllTs_new) # (5)上传到oss,放到另一个目录下 path = os.listdir(os.getcwd()+'/M3u8') for filename in path: if os.path.isfile(WorkingPath+'/'+filename): if '.m3u8' in filename or '.ts' in filename: logInfo('开始进行文件上传:' + filename) key = prefix + filename[0:2] + '/' + filename bucket.put_object_from_file(key, WorkingPath + '/' + filename, progress_callback=percentage) print('文件上传云存储成功完成!' + filename) # 黄海定义的输出信息的办法,带当前时间 def logInfo(msg): i = datetime.datetime.now() print(" %s %s" % (i, msg)) # 进度条功能 def percentage(consumed_bytes, total_bytes): if total_bytes: per = int(100 * (float(consumed_bytes)) / (float(total_bytes))) s1 = "\r[%s%s]%d%%" % ("=" * int(per), " " * (100 - int(per)), per) sys.stdout.write(s1) sys.stdout.flush() if __name__ == '__main__': # 删除临时目录并重新创建 WorkingPath = '/usr/local/software/TestM3u8/M3u8' os.system('rm -rf ' + WorkingPath) os.mkdir(WorkingPath) # 构建OSS存储对象 auth = oss2.Auth(access_key_id, access_key_secret) # 阿里云上应该用这个内部网络选项 bucket = oss2.Bucket(auth, endpoint, bucket_name) # 以一个名师云课为例 m3u8_url = downloadPrefixUrl+'C4/C4CD770E-C98A-AF8C-8B53-8541210B355B.m3u8' print(m3u8_url) DoActionM3u8(m3u8_url) # http://video.edusoa.com/down/M3u8_ZhengZhou103/C4/C4CD770E-C98A-AF8C-8B53-8541210B355B.m3u8 # http://dsideal-yy.oss-cn-qingdao.aliyuncs.com/down/M3u8_ZhengZhou103/C4/C4CD770E-C98A-AF8C-8B53-8541210B355B.m3u8 #