audioblacker发布:不加时间的过乐视不二压方法

庆祝期末考试结束的最好办法就是不歇气写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)

 

48 thoughts on “audioblacker发布:不加时间的过乐视不二压方法”

    1. Beining Post author

      本身就已经不精确了。
      因为
      1)音频是拿Audition弄的,但是其实是1s69
      2)音频不是300字节,封装后变成1.02k
      所以肯定会有差别。
      但是不碍事。

      Reply ↓
    2. Beining Post author

      当时想用一个FLV解析的包,但是发现不行,还不如ffprobe自己算。
      这个包是2.7的,就这样了。
      要是乐意我也可以改改变成3.3,你看里面语法基本都是3.3的。。。

      Reply ↓
    1. dant

      明白了,
      你接上去那段是无效流,拖时间拖码率但是不能解码
      我接上去那段是有效流,拖时间不拖码率能解码
      话说可以现场搞个空音频啊,用lavfi和ffmpeg的原装AAC编码器

      Reply ↓
      1. Beining Post author

        我那段是有效流啊。。。
        AU录制的,不是无效的。
        我认为吧,真的不能指望大家电脑上有lavfi。很多人ffmpeg都编译不明白。。。。。。

        Reply ↓
        1. dant

          那真是被玩坏了。。
          其实直接用原来的音频流就行了。。
          接AAC跟接H264差不多,要相同采样率、声道数和Profile才能解码

          Reply ↓
          1. Beining Post author

            那我们起码还有VFR可以用。
            如果连VFR都不能用了就麻烦一些了,Linux弄AVS费劲。
            可能弄一堆1s的各种分辨率文件往上安?或者另想办法?
            但是乐视正常传,码率也可以达到6M。其实大点没有问题,只要不是10M+的无脑后黑就行,但是1080P弄10+M也不大容易。。。

          2. Beining Post author

            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.

            啊拉。。。。。。

      1. dant

        直接调用了FFmpeg的API,好像libav*系列还没有Python binding(不过可以看一下LLVM的黑科技,把C编译成Python什么的。。)
        话说你这站不用梯子又上不了了。。

        Reply ↓
          1. Beining Post author

            Openshift是AWS的IP,一般来说投鼠忌器。。。
            那我该说啥还说啥。GFW认证也不是什么坏事。
            被GFW认证代表我已经让人害怕了 那也不错啊。

    1. Beining Post author

      找了一圈没看见python有啥好的处理flv的库。。。这就麻烦了。
      我又是语言苦手,C什么的只能靠猜,一个字写不出,读懂都费劲。。。
      ffmpeg与python好久之前有个封装,估计早不能用了。
      只能继续碰碰运气了。。。
      现在的这个libavbuggyduration(为什么我们都喜欢把程序的名字起得那么长呢)的3倍速原理是和之前的FlvPatcher的原理是一样的么?传乐视正常么?
      经过测试,乐视的处理顺序应该是:
      1.Mediainfo???看信息,决定是不是二压原画
      2.demux,压,remux
      3.YAMDI(雅蠛蝶)写进去metadata。
      FYI。

      Reply ↓
      1. dant

        这个倍速才是正确的实现,乐视正常,下载(手机)党骂娘。FlvPatcher那个不能用的。
        而且说不定哪天FFmpeg一更新好心不让这样玩了就杯具了,尽快编译个静态版吧。。
        这个东西目前只在我的Arch Linux上编译成功过,VPS上的Debian不行(LibAV的libavutil太新,没错,就是太!新!),交叉编译的话MinGW-w64链接失败,Windows上编译速度太慢configure ffmpeg的时候就掐掉了。。
        其实你也可以像FlvBugger一样自己处理封装,只不过Python的效率肯定比不上.NET。
        话说渣浪和乐视怎么都在用YAMDI。。

        Reply ↓
        1. Beining Post author

          找了几圈死活看不见有什么好的python的对得起人的flv库。
          FlvPatcher的实现我又读了一下,和libavbuggyduration到底差在哪里呢?原谅我C实在是不会。。。
          应该就是所有的timecode都乘上一个数,最后一帧保留?还有别的我没看见的坑么?
          (我也不指望能make出来了。。。看样坑很大)

          Reply ↓
          1. dant

            倍速需要处理音频流,把所有帧的时间码都乘上一个数,然后Flash还是能按原来的速度播放(这跟VLC不跳过后黑但是Flash跳过是一个道理)。音频也是一帧一帧地放着,所以就能动手脚了。
            FlvPatcher只能处理视频流,当时从blacker.sh改了几行就变成3xspeed.sh了,然后传上渣浪发现不行。。
            还有FFmpeg API的一些坑,导致只能处理相同封装格式(原型是FFmpeg的范例程序),还有av_copy_packet和av_copy_packet_side_data什么的。。坑了我几小时,就差重构了。。。(不过跟用户也没什么关系)
            构建的话,我到时写个脚本,先拖个FFmpeg的git版下来编译一下。。

          2. Beining Post author

            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是只管视频,那么修改应该也不大。。。

          3. dant

            如果能导出音频时间码还能封进去就行。。之前Google翻了十几页也找不到。。。
            或者试试音频偏移?

          4. dant

            不对。。你要的是倍速啊。。
            那几个倍速都是直接搞FLV的(FLV格式还算是比较简单的,Google一下就能找到Adobe的文档)

          5. Beining Post author

            MP4不也弄了么。。。
            但是真就找不到合适的工具了。
            我现在也在考虑怎么弄音频timecode,但是不大成功。。。。

          6. dant

            BPS上搞了一下,大概是这样?//cirno.xyz/videos/test3.mp4 和 //cirno.xyz/videos/test3.reencode.mp4
            确实是处理了两个时间码,不过三压版的音频是连续的(二压版手机播放不能)

          7. Beining Post author

            恩。。。
            从videospeeder(是的,我重新写了一个倍速)来看,貌似因为时间码,怎么着二压后都会不正常。
            那么 再加一次remux会有变化么?

          8. Beining Post author

            要是时间码不对了,那么怎么二压肯定都不行了。
            所以这个就当立此存照吧。
            然后我把小丸的办法搬到了Linux:
            https://github.com/cnbeining/videoblacker
            但是我音频视频都处理,小丸只处理视频(之前没拆代码还真不知道这回事。。。。。)
            不信邪了,看他怎么封杀。。。上人工审核不算本事。

          9. Beining Post author

            恩。。。因为音频可以用ffmpeg检测是不是后面有后黑,视频也可以检测是不是是黑的,所以这个办法有可能失效。
            但是无妨,我们还可以给他接一段正弦波或者白噪音/粉红噪音上去。。。或者加上一张漏尿图或者小圆本子什么的。
            骗机器比骗人容易的多啊。。。

Leave a Reply

Your email address will not be published. Required fields are marked *