庆祝期末考试结束的最好办法就是不歇气写10个小时的代码。
从pass的办法衍生出来,其实也不完全一样,只是思路有点像。
证明:
aaa:乐视云 aab:本地 都用ffmpeg直接解流不再封装,直接比对hash # md5sum aaa.aac aab.aac ac9fb614c863349835f51d41b390d400 aaa.aac ac9fb614c863349835f51d41b390d400 aab.aac # md5sum aaa.h264 aab.h264 1670d9a42f32d8746994bd54129ba3d7 aaa.h264 1670d9a42f32d8746994bd54129ba3d7 aab.h264
代码:
https://github.com/cnbeining/audioblacker
再来一份扔下面。
#!/usr/bin/env python #coding:utf-8 # Author: Beining --<ACICFG> # Contact: http://www.cnbeining.com/ |https://github.com/cnbeining/audioblacker # Purpose: Patch video's audio part to bypass Letvcloud's transcode. # Created: 08/21/2014 # LICENSE: GNU v2 import sys import os import os, sys, subprocess, shlex, re from subprocess import call import uuid import math import shutil import getopt #---------------------------------------------------------------------- def probe_file(filename): cmnd = ['ffprobe', '-show_format', '-pretty', '-loglevel', 'quiet', filename] p = subprocess.Popen(cmnd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) #print filename out, err = p.communicate() #print out if err: print err return None return out #---------------------------------------------------------------------- def time_to_sec(time_raw): """ str->int ignore .*.""" hr = int(time_raw.split(':')[0]) * 3600 minute = int(time_raw.split(':')[1]) * 60 sec = int(float(time_raw.split(':')[2])) return int(hr + minute + sec) #---------------------------------------------------------------------- def get_abspath(filename): """""" return str(os.path.abspath(filename)) #---------------------------------------------------------------------- def process(filename, target_bitrate, audiobitrate, safe, outputfile): """str,int,int,str->? filename,outputfile comes with the path. safe=0: directly convert the file to m4a""" tmpdir = '/tmp/Audioblacker-' + str(uuid.uuid4()) if not os.path.exists(tmpdir): os.makedirs(tmpdir) audio_format = '' audio_duration = '' audio_bitrate = '' video_format = '' video_duration = '' video_bitrate = '' #demux audio file # Add this to save time, for experienced users print('INFO: Checking audio and remux...') if safe == 0: #directly to m4a to save space os.system('ffmpeg -i \'' + filename + '\' -vn -c:a copy ' + tmpdir+'/audio.m4a' +'> /dev/null 2>&1') try: for line in probe_file(tmpdir+'/audio.m4a').split('\n'): #print(line) if 'duration' in line: audio_duration = str(line.split('=')[1]) except: print('ERROR: Cannot read audio file!') exit() else: os.system('ffmpeg -i \'' + filename + '\' -vn -c:a copy ' + tmpdir+'/audio.aac' +'> /dev/null 2>&1') try: for line in probe_file(tmpdir+'/audio.aac').split('\n'): if 'format_name' in line: audio_format = str(line.split('=')[1]) if 'duration' in line: audio_duration = str(line.split('=')[1]) print('INFO: Audio safe, converting to m4a and clean cache...') os.system('ffmpeg -i '+ tmpdir+'/audio.aac -vn -c:a copy ' + tmpdir+'/audio.m4a' +'> /dev/null 2>&1') try: os.remove(tmpdir+'/audio.aac') except: print('WARNING: Cannot remove the aac file now...') except: print('ERROR: Cannot read audio file!') exit() #In case someone screw the audio up if not 'aac' in audio_format: print('ERROR: You have to use AAC as audio format!') exit() #Check original file try: for line in probe_file(filename).split('\n'): if 'duration' in line: video_duration = str(line.split('=')[1]) except: print('ERROR: Cannot read video file!') exit() #Calc... #time_by_video print('INFO: Doing calculation...') video_duration_sec = time_to_sec(video_duration) video_size_byte = int(os.path.getsize(filename)) audio_duration_sec = time_to_sec(audio_duration) audio_size_byte = int(os.path.getsize(tmpdir+'/audio.m4a')) #!!!!!FLOAT DUE TO ACCURACY!!!!! target_byterate = target_bitrate / 8 target_audiobyterate = audiobitrate / 8 time_video = int(math.ceil((video_size_byte - target_byterate * video_duration_sec) / (target_byterate - 300))) time_audio = int(math.ceil((audio_size_byte - target_audiobyterate * audio_duration_sec) / (target_audiobyterate - 300))) if time_audio < 0 and time_video < 0: print('ERROR: Cannot calculate target, your target bitrate is higher than the original file!') shutil.rmtree(tmpdir) exit() if time_audio == 0 and time_video == 0: time_patch = 60 elif time_audio > time_video: time_patch = time_audio + 10 else: time_patch = time_video + 10 #Make audio patch f = open(tmpdir + '/audiocode.txt', 'w') ff = 'file \'' + tmpdir + '/audio.m4a\'' + '\n' os.getcwd() py_path = sys.path[0] os.chdir(py_path) for i in range(time_patch): ff = ff + 'file \'' + str(os.getcwd()) + '/'+ '1sblack.m4a\'' + '\n' ff = ff.encode("utf8") f.write(ff) f.close() print('INFO: Concating audios...') os.system('ffmpeg -f concat -i '+ tmpdir + '/audiocode.txt -c copy '+ tmpdir +'/audiopatched.m4a'+'> /dev/null 2>&1') print('INFO: Making final output file...') os.system('ffmpeg -i ' + filename + ' -i ' + tmpdir +'/audiopatched.m4a -c copy -map 0:0 -map 1:0 '+outputfile +'> /dev/null 2>&1') print('Done!') #clean up try: shutil.rmtree(tmpdir) except: print('ERROR: Cannot remove temp dir, do it by yourself!') #---------------------------------------------------------------------- def usage(): """""" print('''Usage: python audioblacker.py (-h) (-i input.mp4) (-o output.mp4) (-b 1990000) (-a 120000) (-s 1) -h: Default: None Help. -i: Default: Blank Input file. If the file and audioblacker are not under the same path, it is suggested to use absolute path to avoid possible failure. -o Default: input-filename.black.mp4 Output file. Would be in the same folder with the original file if not specified. -b: Default: 1990000 Target bitrate. -a: Default: 110000 Target audio bitrate. audioblacker would calculate both of the required black time, and choose the larger one to make sure your convert is successful. -s: Default: 1 Use safe mode. audioblacker would check whether the file's audio is AAC. Disabling would save you some space and time, if you know what you are doing. ''') #---------------------------------------------------------------------- if __name__=='__main__': argv_list = [] argv_list = sys.argv[1:] filename = '' target_bitrate = 1990000 outputfile = '' safe = 1 audiobitrate = 110000 try: opts, args = getopt.getopt(argv_list, "hi:b:a:o:s:", ['help', 'input','bitrate', 'audiobitrate' 'outputfile', 'safe']) except getopt.GetoptError: usage() exit() for o, a in opts: if o in ('-h', '--help'): usage() exit() elif o in ('-i', '--input'): filename = a try: argv_list.remove('-i') except: break elif o in ('-b', '--bitrate'): target_bitrate = int(a) try: argv_list.remove('-b') except: break elif o in ('-a', '--audiobitrate'): audiobitrate = int(a) try: argv_list.remove('-a') except: break elif o in ('-o', '--outputfile'): outputfile = a try: argv_list.remove('-o') except: break elif o in ('-s', '--safe'): safe = int(a) try: argv_list.remove('-s') except: break if filename == '': print('ERROR: No input file!') exit() if outputfile == '': outputfile = filename.split('.')[0] + '.black.mp4' process(filename, target_bitrate, audiobitrate, safe, outputfile)
#!!!!!FLOAT DUE TO ACCURACY!!!!!
看样子你在用 Python 2,所有 /8 请改成 /8.0。
Python 2 里 1/2 等于 0。
本身就已经不精确了。
因为
1)音频是拿Audition弄的,但是其实是1s69
2)音频不是300字节,封装后变成1.02k
所以肯定会有差别。
但是不碍事。
当时想用一个FLV解析的包,但是发现不行,还不如ffprobe自己算。
这个包是2.7的,就这样了。
要是乐意我也可以改改变成3.3,你看里面语法基本都是3.3的。。。
我的意思是如果是Python 2的话,所有除法都要注意一下,先乘以 1.0 再除。
(因为Python 3修了这个bug了所以只有Python 2要注意一下)
多测试,攒一些问题后一起push上去,版本号往后加一个。
我之前用过这方法战渣浪。。
结果是某同性交友网站av551994,半分钟不到,坚持看完有惊喜(
明白了,
你接上去那段是无效流,拖时间拖码率但是不能解码
我接上去那段是有效流,拖时间不拖码率能解码
话说可以现场搞个空音频啊,用lavfi和ffmpeg的原装AAC编码器
我那段是有效流啊。。。
AU录制的,不是无效的。
我认为吧,真的不能指望大家电脑上有lavfi。很多人ffmpeg都编译不明白。。。。。。
不能解码是因为视频流长度小于音频流,乐视按视频流的时间算,后面的音频被忽略了。
那真是被玩坏了。。
其实直接用原来的音频流就行了。。
接AAC跟接H264差不多,要相同采样率、声道数和Profile才能解码
因为要文件小。
我这东西1s才300字节,几小时后黑也不碍事啊。
我记得当年渣浪开始是按音频流的,后来改用最短流。看来乐视封杀这个方法改用最短流也不远了。
那我们起码还有VFR可以用。
如果连VFR都不能用了就麻烦一些了,Linux弄AVS费劲。
可能弄一堆1s的各种分辨率文件往上安?或者另想办法?
但是乐视正常传,码率也可以达到6M。其实大点没有问题,只要不是10M+的无脑后黑就行,但是1080P弄10+M也不大容易。。。
ffmpeg -filter_complex ‘color=black:s=640×480:d=1’ -c:v libx264 black480p.mp4
我得看看常见binary里面带不带 测试下。
好办法 如果有一天乐视封了 那么可以用这个加上现在的audioblacker做后黑。
ffmpeg -filter_complex 'color=black:s=640×480:d=1' -c:v libx264 black480p.mp4
ffmpeg version 2.3.git Copyright (c) 2000-2014 the FFmpeg developers
built on Aug 3 2014 13:42:36 with gcc 4.6 (Ubuntu/Linaro 4.6.3-1ubuntu5)
configuration: --prefix=/root/ffmpeg_build --extra-cflags=-I/root/ffmpeg_build/include --extra-ldflags=-L/root/ffmpeg_build/lib --bindir=/root/bin --enable-gpl --enable-libass --enable-libfdk-aac --enable-libfreetype --enable-libmp3lame --enable-libx264 --enable-nonfree
libavutil 52. 94.100 / 52. 94.100
libavcodec 55. 71.100 / 55. 71.100
libavformat 55. 50.100 / 55. 50.100
libavdevice 55. 13.102 / 55. 13.102
libavfilter 4. 11.102 / 4. 11.102
libswscale 2. 6.100 / 2. 6.100
libswresample 0. 19.100 / 0. 19.100
libpostproc 52. 3.100 / 52. 3.100
[color @ 0x24a9380] Unable to parse option value "640×480" as image size
Last message repeated 1 times
[color @ 0x24a9380] Error setting option s to value 640×480.
[Parsed_color_0 @ 0x24a8e40] Error applying options to the filter.
[AVFilterGraph @ 0x24a9b80] Error initializing filter 'color' with args 'black:s=640×480:d=1'
Error configuring filters.
啊拉。。。。。。
好像是WordPress把乘号也转义了。
你自己手动打一下吧。
注意引号和乘号。
果然。
恩 的确可以 我等下写个。
OK,写完了。
https://github.com/cnbeining/videoblacker
音频视频都处理,看他怎么封杀。不信邪了。。。。。
(引号被Wordpress自动转了……乃手动打一下命令吧……)
没想到这个办法又活过来了。
屏蔽也不是完全不行,看情况吧。
但是还是很有价值的。
那个libavbuggyduration应该能用了
(不过编译可能有点麻烦https://github.com/dantmnf/libavbuggyduration
我一直watch呢。
我想想怎么拿Python写出来。。。。
直接调用了FFmpeg的API,好像libav*系列还没有Python binding(不过可以看一下LLVM的黑科技,把C编译成Python什么的。。)
话说你这站不用梯子又上不了了。。
我看一看有没有造好的轮子。。。。。。。
有可能部分地区封锁吧,因为我前几天发了篇反党文章?
你看这种东西放在OpenShift上就没事(斜眼笑)
Openshift是AWS的IP,一般来说投鼠忌器。。。
那我该说啥还说啥。GFW认证也不是什么坏事。
被GFW认证代表我已经让人害怕了 那也不错啊。
找了一圈没看见python有啥好的处理flv的库。。。这就麻烦了。
我又是语言苦手,C什么的只能靠猜,一个字写不出,读懂都费劲。。。
ffmpeg与python好久之前有个封装,估计早不能用了。
只能继续碰碰运气了。。。
现在的这个libavbuggyduration(为什么我们都喜欢把程序的名字起得那么长呢)的3倍速原理是和之前的FlvPatcher的原理是一样的么?传乐视正常么?
经过测试,乐视的处理顺序应该是:
1.Mediainfo???看信息,决定是不是二压原画
2.demux,压,remux
3.YAMDI(雅蠛蝶)写进去metadata。
FYI。
这个倍速才是正确的实现,乐视正常,下载(手机)党骂娘。FlvPatcher那个不能用的。
而且说不定哪天FFmpeg一更新好心不让这样玩了就杯具了,尽快编译个静态版吧。。
这个东西目前只在我的Arch Linux上编译成功过,VPS上的Debian不行(LibAV的libavutil太新,没错,就是太!新!),交叉编译的话MinGW-w64链接失败,Windows上编译速度太慢configure ffmpeg的时候就掐掉了。。
其实你也可以像FlvBugger一样自己处理封装,只不过Python的效率肯定比不上.NET。
话说渣浪和乐视怎么都在用YAMDI。。
找了几圈死活看不见有什么好的python的对得起人的flv库。
FlvPatcher的实现我又读了一下,和libavbuggyduration到底差在哪里呢?原谅我C实在是不会。。。
应该就是所有的timecode都乘上一个数,最后一帧保留?还有别的我没看见的坑么?
(我也不指望能make出来了。。。看样坑很大)
倍速需要处理音频流,把所有帧的时间码都乘上一个数,然后Flash还是能按原来的速度播放(这跟VLC不跳过后黑但是Flash跳过是一个道理)。音频也是一帧一帧地放着,所以就能动手脚了。
FlvPatcher只能处理视频流,当时从blacker.sh改了几行就变成3xspeed.sh了,然后传上渣浪发现不行。。
还有FFmpeg API的一些坑,导致只能处理相同封装格式(原型是FFmpeg的范例程序),还有av_copy_packet和av_copy_packet_side_data什么的。。坑了我几小时,就差重构了。。。(不过跟用户也没什么关系)
构建的话,我到时写个脚本,先拖个FFmpeg的git版下来编译一下。。
ffmpeg有Linux binary:
http://ffmpeg.gusari.org/static/
# ./ffmpeg
ffmpeg version N-60696-g38a08e0 Copyright (c) 2000-2014 the FFmpeg developers
built on Feb 17 2014 15:07:16 with gcc 4.6 (Debian 4.6.3-1)
configuration: --prefix=/root/ffmpeg-static/64bit --extra-cflags='-I/root/ffmpeg-static/64bit/include -static'
--extra-ldflags='-L/root/ffmpeg-static/64bit/lib -static' --extra-libs='-lxml2 -lexpat -lfreetype'
--enable-static --disable-shared --disable-ffserver --disable-doc --enable-bzlib --enable-zlib
--enable-postproc --enable-runtime-cpudetect --enable-libx264 --enable-gpl --enable-libtheora
--enable-libvorbis --enable-libmp3lame --enable-gray --enable-libass --enable-libfreetype --enable-libopenjpeg
--enable-libspeex --enable-libvo-aacenc --enable-libvo-amrwbenc --enable-version3 --enable-libvpx
libavutil 52. 64.100 / 52. 64.100
libavcodec 55. 52.102 / 55. 52.102
libavformat 55. 33.100 / 55. 33.100
libavdevice 55. 10.100 / 55. 10.100
libavfilter 4. 1.102 / 4. 1.102
libswscale 2. 5.101 / 2. 5.101
libswresample 0. 17.104 / 0. 17.104
libpostproc 52. 3.100 / 52. 3.100
Hyper fast Audio and Video encoder
usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...
Use -h to get full help or, even better, run 'man ffmpeg'
那么理论上,如果用ffmpeg导出所有帧的timecode,然后统一扩大,那么不就可以了么?blacker是只管视频,那么修改应该也不大。。。
需要库和头文件。。
我看看能不能给FlvPatcher做点手术。。。
如果能导出音频时间码还能封进去就行。。之前Google翻了十几页也找不到。。。
或者试试音频偏移?
不对。。你要的是倍速啊。。
那几个倍速都是直接搞FLV的(FLV格式还算是比较简单的,Google一下就能找到Adobe的文档)
MP4不也弄了么。。。
但是真就找不到合适的工具了。
我现在也在考虑怎么弄音频timecode,但是不大成功。。。。
https://www.bunkus.org/videotools/mkvtoolnix/doc/mkvextract.html
2.7节 导出可以做。
但是意义不大就是了。。。移动端死的很惨。
BPS上搞了一下,大概是这样?//cirno.xyz/videos/test3.mp4 和 //cirno.xyz/videos/test3.reencode.mp4
确实是处理了两个时间码,不过三压版的音频是连续的(二压版手机播放不能)
恩。。。
从videospeeder(是的,我重新写了一个倍速)来看,貌似因为时间码,怎么着二压后都会不正常。
那么 再加一次remux会有变化么?
手癌。。VPS
要是时间码不对了,那么怎么二压肯定都不行了。
所以这个就当立此存照吧。
然后我把小丸的办法搬到了Linux:
https://github.com/cnbeining/videoblacker
但是我音频视频都处理,小丸只处理视频(之前没拆代码还真不知道这回事。。。。。)
不信邪了,看他怎么封杀。。。上人工审核不算本事。
GFW封SSH隧道也不用人工介入(歪了
恩。。。因为音频可以用ffmpeg检测是不是后面有后黑,视频也可以检测是不是是黑的,所以这个办法有可能失效。
但是无妨,我们还可以给他接一段正弦波或者白噪音/粉红噪音上去。。。或者加上一张漏尿图或者小圆本子什么的。
骗机器比骗人容易的多啊。。。
编译了OS X版和Cygwin版,放在GitHub的releases里,麻烦帮忙测试一下。
It works!
(OSX ver.)