pax_global_header00006660000000000000000000000064136032175070014516gustar00rootroot0000000000000052 comment=3d0af528268c04327595ea23ecafabb0c882abc6 ffcvt-1.5.05/000077500000000000000000000000001360321750700127165ustar00rootroot00000000000000ffcvt-1.5.05/.gitignore000066400000000000000000000004231360321750700147050ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof ffcvt *~ ffcvt-1.5.05/.gitlab-ci.yml000066400000000000000000000012241360321750700153510ustar00rootroot00000000000000image: golang:1.10 stages: - build - test before_script: # Create a symbolic link under $GOPATH, this is needed for local build - cd $GOPATH/src - mkdir -p gitlab.com/$CI_PROJECT_NAMESPACE - cd gitlab.com/$CI_PROJECT_NAMESPACE - ln -s $CI_PROJECT_DIR - cd $CI_PROJECT_NAME - go get ./... build-test: script: # == build # - godep restore # - godep go build - go build -v -ldflags="-X main.date=`date -I$TIMESPEC`"; date -I$TIMESPEC # == test - $CI_PROJECT_NAME - $CI_PROJECT_NAME -version # - godep restore # - godep go test -v -cover ./... - go test -v -cover ./... - ( pwd; cd test; pwd; ls -l; ./test-all.sh; ) ffcvt-1.5.05/.travis.yml000066400000000000000000000040541360321750700150320ustar00rootroot00000000000000# -*- yaml -*- language: go env: global: # Package setup (Ref: http://pkg-go.alioth.debian.org/packaging.html) - VERSION="${TRAVIS_TAG:=0.0~git$(date +%Y%m%d)-1}" - PKG_NAME="ffcvt" - PKG_URL="https://github.com/suntong/ffcvt" - PKG_CAT=utils - PKG_ARCH=amd64 - PKG_DESC="ffmpeg convert wrapper tool" - PKG_VEND="suntong" - PKG_MAINT='Tong Sun ' - PKG_LICNS="MIT" # Build time setup - TZ=America/Toronto - DATE_BUILD=`date -I` script: - date - echo $DATE_BUILD $VERSION - echo - go get -t -v ./... - go build -v -ldflags="-X main.date=$DATE_BUILD" - ffcvt - go test -v ./... - ( cd test; ./test-all.sh; ) - go get github.com/mitchellh/gox - gox -ldflags="-X main.date=$DATE_BUILD" -osarch="linux/386 linux/amd64 darwin/amd64 windows/amd64" -output="out/{{.Dir}}-{{.OS}}-{{.Arch}}" # linux/386 linux/amd64 linux/arm darwin/amd64 darwin/386 windows/amd64 windows/386 # e.g.: out/ffcvt-linux-amd64 # Create Debian Package - mkdir -p build - cp -v out/${PKG_NAME}-linux-amd64 build/${PKG_NAME} - gem install fpm --no-document - mkdir -p pkg - >- fpm --verbose -s dir -t deb --name ${PKG_NAME} --package pkg/${PKG_NAME}.deb --force --deb-compression bzip2 --url "${PKG_URL}" --category ${PKG_CAT} --description "${PKG_DESC}" --maintainer "${PKG_MAINT}" --vendor "${PKG_VEND}" --license "${PKG_LICNS}" --version ${VERSION} --architecture ${PKG_ARCH} --depends apt --deb-compression gz ./build/=/usr/bin/ # --deb-compression gz: https://unix.stackexchange.com/questions/441032/ - ar t pkg/${PKG_NAME}.deb - sed -i -e "s/\$VERSION/$VERSION/" bintray-bin.json bintray-pkg.json - sed -i -e "s/\$DATE/$DATE_BUILD/" bintray-bin.json bintray-pkg.json deploy: - provider: bintray user: suntong key: ${BINTRAY_API_KEY} file: bintray-bin.json skip_cleanup: true - provider: bintray user: suntong key: $BINTRAY_API_KEY file: bintray-pkg.json skip_cleanup: true on: # tags: true ffcvt-1.5.05/LICENSE000066400000000000000000000021051360321750700137210ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015 Tong SUN Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.ffcvt-1.5.05/README.e.md000066400000000000000000000133511360321750700144230ustar00rootroot00000000000000 # {{.Name}} {{render "license/shields" . "License" "MIT"}} {{template "badge/godoc" .}} {{template "badge/goreport" .}} {{template "badge/travis" .}} ## {{toc 5}} ## {{.Name}} - ffmpeg convert wrapper tool ## Introduction - The next-generation codec like [High Efficiency Video codec (HEVC), H.265](https://goo.gl/IZrDH2) or [VP9](https://developers.google.com/media/vp9/) can produce videos visually comparable to H.264's result, but in [about half the file size](https://trac.ffmpeg.org/wiki/Encode/H.265). - Meanwhile the [Opus](https://goo.gl/BPUkTf) [audio codec](https://goo.gl/IZrDH2) is becoming the best thing ever for compressing audio -- A 64K Opus audio stream is comparable to mp3 files of 128K to 256K bandwidth. - Such fantastic high efficiency audio/video codec/encoding capability has long been available in `ffmpeg`, but fewer people know it or use it, partly because the `ffmpeg` command line is not that simple for every one. - The `ffcvt` is designed to take the burden from normal Joe -- All you need to do to encode a video is to give one parameter to `ffcvt`, i.e., the path and file name of the video to be encoded, and `ffcvt` will take care of the rest, using the recommended values for both audio/video encoding to properly encode it for you. - It can't be more simpler than that. However, beneath the simple surface, `ffcvt` is versatile and powerful enough to allow you to touch every corner of audio/video encoding. There is a huge list of environment variables (or command-line parameters) which will allow you tweak the encoding methods and parameters to exactly what you prefer instead. - Moreover, to encode a directory full of video files, including under its sub-directories, you need just to give `ffcvt` one single parameter, the directory location, and `ffcvt` will go ahead and encode all video files under that directory, including all its sub-directories as well. ## Quick Usage There is a quick usage help that comes with `ffcvt`, produced when it is invoked without any parameters: ### $ {{exec "ffcvt" | color "sh"}} ## Environment Variables For each `ffcvt` command line parameter, there is a environment variable corresponding to it. For example you can use `export FFCVT_FFMPEG=avconv` to use `avconv` instead of `ffmpeg` (Don't, I use it for my [CommandLineArgs](https://github.com/suntong001/lang/blob/master/lang/Go/src/sys/CommandLineArgs.go) to develop/test `ffcvt` without invoking `ffmpeg` each time). ## Encoding Help The detailed guide to choose/provide proper parameters to `ffcvt` have been moved to [wiki](https://github.com/suntong/ffcvt/wiki/). For example, - [HEVC vs VP9](https://github.com/suntong/ffcvt/wiki/WebM-(VP9)-Encoding#hevc-vs-vp9) - [Preset Method Comparison](https://github.com/suntong/ffcvt/wiki/HEVC-(x265)-Encoding#preset-method-comparison) - [The CRF Comparison](https://github.com/suntong/ffcvt/wiki/HEVC-(x265)-Encoding#the-crf-comparison) - [Example 1: YouTube Encoding](https://github.com/suntong/ffcvt/wiki/Example-1:-YouTube-Encoding) - [Example 2: Talk Encoding](https://github.com/suntong/ffcvt/wiki/Example-2:-Talk-Encoding) Please check them out in the [wiki](https://github.com/suntong/ffcvt/wiki/). ## Download/Install ### Using `apt` The `ffcvt` is now officially in Debian repository, so the installation is now as simple as a `apt install`/`apt-get install`: apt install ffcvt ### Download binaries - The latest binary executables are available under https://bintray.com/suntong/bin/{{.Name}}/latest as the result of the Continuous-Integration process. - I.e., they are built right from the source code during _every_ git commit _automatically_ by [travis-ci](https://travis-ci.org/). - Pick & choose the binary executable that suits your OS and its architecture. E.g., for Linux, it would most probably be the `{{.Name}}-linux-amd64` file. If your OS and its architecture is not available in the download list, please let me know and I'll add it. - You may want to rename it to a shorter name instead, e.g., `{{.Name}}`, after downloading it. ### Debian package Debian package _repo_ is available at https://dl.bintray.com/suntong/deb. The _browse-able_ repo view is at https://bintray.com/suntong/deb. ``` echo "deb [trusted=yes] https://dl.bintray.com/suntong/deb all main" | sudo tee /etc/apt/sources.list.d/suntong-debs.list sudo apt-get update sudo chmod 644 /etc/apt/sources.list.d/suntong-debs.list apt-cache policy {{.Name}} sudo apt-get install -y {{.Name}} ``` ### Install Source If you prefer to compile and install `ffcvt` from source, although a manual process, it's pretty straightforward and simple. 0. Get the source via `git clone` or [`go get`](https://golang.org/cmd/go/#hdr-Download_and_install_packages_and_dependencies). 0. Do `cd ffcvt`, then issue [`go build`](https://golang.org/cmd/go/#hdr-Compile_packages_and_dependencies) without any other parameters. 0. Copy the generated executable somewhere in the PATH That's it, it's ready to roll. ## Tools Choices As suggested before, don't use `avconv`, use `ffmpeg` instead (the `avconv` fork was more for political reasons. I personally believe `ffmpeg` is technically superior although might not be politically). As for video/movie play back, use [mpv](http://mpv.io/). It is a fork of mplayer2 and MPlayer, and is a true *modern* *all-in-one* movie player that can play ANYTHING, and one of the few movie players being actively developed all the time. Download link is in [mpv.io](http://mpv.io/), from which Ubuntu repo I get my Ubuntu `ffmpeg` package as well. If you are unsatisfied with mpv's simple user interface, check out https://wiki.archlinux.org/index.php/Mpv#Front_ends. ## Author(s) Tong SUN ![suntong from cpan.org](https://img.shields.io/badge/suntong-%40cpan.org-lightgrey.svg "suntong from cpan.org") All patches welcome. ffcvt-1.5.05/README.md000066400000000000000000000232701360321750700142010ustar00rootroot00000000000000 # ffcvt [![MIT License](http://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![GoDoc](https://godoc.org/github.com/suntong/ffcvt?status.svg)](http://godoc.org/github.com/suntong/ffcvt) [![Go Report Card](https://goreportcard.com/badge/github.com/suntong/ffcvt)](https://goreportcard.com/report/github.com/suntong/ffcvt) [![travis Status](https://travis-ci.org/suntong/ffcvt.svg?branch=master)](https://travis-ci.org/suntong/ffcvt) ## TOC - [ffcvt - ffmpeg convert wrapper tool](#ffcvt---ffmpeg-convert-wrapper-tool) - [Introduction](#introduction) - [Quick Usage](#quick-usage) - [$ ffcvt](#-ffcvt) - [Environment Variables](#environment-variables) - [Encoding Help](#encoding-help) - [Download/Install](#downloadinstall) - [Using `apt`](#using-`apt`) - [Download binaries](#download-binaries) - [Debian package](#debian-package) - [Install Source](#install-source) - [Tools Choices](#tools-choices) - [Author(s)](#author(s)) ## ffcvt - ffmpeg convert wrapper tool ## Introduction - The next-generation codec like [High Efficiency Video codec (HEVC), H.265](https://goo.gl/IZrDH2) or [VP9](https://developers.google.com/media/vp9/) can produce videos visually comparable to H.264's result, but in [about half the file size](https://trac.ffmpeg.org/wiki/Encode/H.265). - Meanwhile the [Opus](https://goo.gl/BPUkTf) [audio codec](https://goo.gl/IZrDH2) is becoming the best thing ever for compressing audio -- A 64K Opus audio stream is comparable to mp3 files of 128K to 256K bandwidth. - Such fantastic high efficiency audio/video codec/encoding capability has long been available in `ffmpeg`, but fewer people know it or use it, partly because the `ffmpeg` command line is not that simple for every one. - The `ffcvt` is designed to take the burden from normal Joe -- All you need to do to encode a video is to give one parameter to `ffcvt`, i.e., the path and file name of the video to be encoded, and `ffcvt` will take care of the rest, using the recommended values for both audio/video encoding to properly encode it for you. - It can't be more simpler than that. However, beneath the simple surface, `ffcvt` is versatile and powerful enough to allow you to touch every corner of audio/video encoding. There is a huge list of environment variables (or command-line parameters) which will allow you tweak the encoding methods and parameters to exactly what you prefer instead. - Moreover, to encode a directory full of video files, including under its sub-directories, you need just to give `ffcvt` one single parameter, the directory location, and `ffcvt` will go ahead and encode all video files under that directory, including all its sub-directories as well. ## Quick Usage There is a quick usage help that comes with `ffcvt`, produced when it is invoked without any parameters: ### $ ffcvt ```sh Usage: ffcvt [flags] Flags: -t target type: webm/x265-opus/x264-mp3/youtube (FFCVT_T) -aes audio encoding method set (FFCVT_AES) -ves video encoding method set (FFCVT_VES) -aea audio encoding method append (FFCVT_AEA) -vea video encoding method append (FFCVT_VEA) -abr audio bitrate (64k for opus, 256k for mp3) (FFCVT_ABR) -crf the CRF value: 0-51. Higher CRF gives lower quality (28 for x265, ~ 23 for x264) (FFCVT_CRF) -d directory that hold input files (FFCVT_D) -f input file name (either -d or -f must be specified) (FFCVT_F) -sym symlinks will be processed as well (FFCVT_SYM) -exts extension list for all the files to be queued (FFCVT_EXTS) -suf suffix to the output file names (FFCVT_SUF) -ext extension for the output file (FFCVT_EXT) -w work directory that hold output files (FFCVT_W) -ac copy audio codec (FFCVT_AC) -vc copy video codec (FFCVT_VC) -an no audio, output video only (FFCVT_AN) -vn no video, output audio only (FFCVT_VN) -vss video: same size (FFCVT_VSS) -o more options that will pass to ffmpeg program (FFCVT_O) -ato-opus audio encode to opus, using -abr (FFCVT_ATO_OPUS) -vto-x265 video video encode to x265, using -crf (FFCVT_VTO_X265) -p par2create, create par2 files (in work directory) (FFCVT_P) -nc no clobber, do not queue those already been converted (FFCVT_NC) -n no exec, dry run (FFCVT_N) -force overwrite any existing none-empty file (FFCVT_FORCE) -debug debugging level (FFCVT_DEBUG) -ffmpeg ffmpeg program executable name (FFCVT_FFMPEG) -version print version then exit (FFCVT_VERSION) Details: -abr string audio bitrate (64k for opus, 256k for mp3) -ac copy audio codec -aea string audio encoding method append -aes string audio encoding method set -an no audio, output video only -ato-opus audio encode to opus, using -abr -crf string the CRF value: 0-51. Higher CRF gives lower quality (28 for x265, ~ 23 for x264) -d string directory that hold input files -debug int debugging level (default 1) -ext string extension for the output file -exts string extension list for all the files to be queued (default ".3GP.3G2.ASF.AVI.DAT.DIVX.FLV.M2TS.M4V.MKV.MOV.MPEG.MP4.MPG.RMVB.RM.TS.VOB.WEBM.WMV") -f string input file name (either -d or -f must be specified) -ffmpeg string ffmpeg program executable name (default "ffmpeg") -force overwrite any existing none-empty file -n no exec, dry run -nc no clobber, do not queue those already been converted -o string more options that will pass to ffmpeg program -p par2create, create par2 files (in work directory) -suf string suffix to the output file names -sym symlinks will be processed as well -t string target type: webm/x265-opus/x264-mp3/youtube (default "webm") -vc copy video codec -vea string video encoding method append -version print version then exit -ves string video encoding method set -vn no video, output audio only -vss video: same size (default true) -vto-x265 video video encode to x265, using -crf -w string work directory that hold output files To reduce output, use `-debug 0`, e.g., `ffcvt -force -debug 0 -f testf.mp4 ...` ``` ## Environment Variables For each `ffcvt` command line parameter, there is a environment variable corresponding to it. For example you can use `export FFCVT_FFMPEG=avconv` to use `avconv` instead of `ffmpeg` (Don't, I use it for my [CommandLineArgs](https://github.com/suntong001/lang/blob/master/lang/Go/src/sys/CommandLineArgs.go) to develop/test `ffcvt` without invoking `ffmpeg` each time). ## Encoding Help The detailed guide to choose/provide proper parameters to `ffcvt` have been moved to [wiki](https://github.com/suntong/ffcvt/wiki/). For example, - [HEVC vs VP9](https://github.com/suntong/ffcvt/wiki/WebM-(VP9)-Encoding#hevc-vs-vp9) - [Preset Method Comparison](https://github.com/suntong/ffcvt/wiki/HEVC-(x265)-Encoding#preset-method-comparison) - [The CRF Comparison](https://github.com/suntong/ffcvt/wiki/HEVC-(x265)-Encoding#the-crf-comparison) - [Example 1: YouTube Encoding](https://github.com/suntong/ffcvt/wiki/Example-1:-YouTube-Encoding) - [Example 2: Talk Encoding](https://github.com/suntong/ffcvt/wiki/Example-2:-Talk-Encoding) Please check them out in the [wiki](https://github.com/suntong/ffcvt/wiki/). ## Download/Install ### Using `apt` The `ffcvt` is now officially in Debian repository, so the installation is now as simple as a `apt install`/`apt-get install`: apt install ffcvt ### Download binaries - The latest binary executables are available under https://bintray.com/suntong/bin/ffcvt/latest as the result of the Continuous-Integration process. - I.e., they are built right from the source code during _every_ git commit _automatically_ by [travis-ci](https://travis-ci.org/). - Pick & choose the binary executable that suits your OS and its architecture. E.g., for Linux, it would most probably be the `ffcvt-linux-amd64` file. If your OS and its architecture is not available in the download list, please let me know and I'll add it. - You may want to rename it to a shorter name instead, e.g., `ffcvt`, after downloading it. ### Debian package Debian package _repo_ is available at https://dl.bintray.com/suntong/deb. The _browse-able_ repo view is at https://bintray.com/suntong/deb. ``` echo "deb [trusted=yes] https://dl.bintray.com/suntong/deb all main" | sudo tee /etc/apt/sources.list.d/suntong-debs.list sudo apt-get update sudo chmod 644 /etc/apt/sources.list.d/suntong-debs.list apt-cache policy ffcvt sudo apt-get install -y ffcvt ``` ### Install Source If you prefer to compile and install `ffcvt` from source, although a manual process, it's pretty straightforward and simple. 0. Get the source via `git clone` or [`go get`](https://golang.org/cmd/go/#hdr-Download_and_install_packages_and_dependencies). 0. Do `cd ffcvt`, then issue [`go build`](https://golang.org/cmd/go/#hdr-Compile_packages_and_dependencies) without any other parameters. 0. Copy the generated executable somewhere in the PATH That's it, it's ready to roll. ## Tools Choices As suggested before, don't use `avconv`, use `ffmpeg` instead (the `avconv` fork was more for political reasons. I personally believe `ffmpeg` is technically superior although might not be politically). As for video/movie play back, use [mpv](http://mpv.io/). It is a fork of mplayer2 and MPlayer, and is a true *modern* *all-in-one* movie player that can play ANYTHING, and one of the few movie players being actively developed all the time. Download link is in [mpv.io](http://mpv.io/), from which Ubuntu repo I get my Ubuntu `ffmpeg` package as well. If you are unsatisfied with mpv's simple user interface, check out https://wiki.archlinux.org/index.php/Mpv#Front_ends. ## Author(s) Tong SUN ![suntong from cpan.org](https://img.shields.io/badge/suntong-%40cpan.org-lightgrey.svg "suntong from cpan.org") All patches welcome. ffcvt-1.5.05/VP9-CRF.png000066400000000000000000000726571360321750700144730ustar00rootroot00000000000000PNG  IHDRHY|sBITOtEXtSoftwaremate-screenshotȖJ IDATxy\4tHDNR \ˮv{&k-ʹۏuZ! jj׎$$h}|3~̚KT}&.@0vFH  ;#``$@0vFH  NddϯWFٲe@ ]ZTY,\.7tcyݸqy7p8cƌQ(={lڴK+*Wpe2(,Ng%Z y󦫫kaa!͖)))T\C770fal6RSSY,֎;lmm5jH$nذP(l߾gψСC,kҤI_}H$rppطo񼼼aÆYZZJ$]1=С@ hԨю;X,֗_~jm{qss .,H̙caaѫWb}yaaaPPPZBÇvJ5yZj //#G0k׮eXӦMk߾@ hРSnfffmmf"aX۷;w\.df[%$$~|>_.4(''FbfϞmccS^=Jj?@ Sμy_xubZjCb[hbbjj駟>z>CSZYYQCBB" Y&9;;3xSvЁ KZpQ\.ɓ':nӦM_~3gn޼ID5kLOOt۶m#"C:.## v˻vJDǏ8yhذNeˢt:ݡC/}2dM6-!!ÇNbωh…:.//Ã>6nܨ颣3PlFDRܜ 4mĄnw޹sG޸qC( +VQLLLLL lْEe:^um"jѢ:t5'$$dddԩSɦ߾}_xx8u҅9/FDDhWԔyyY&W) I??]viӦW^Wݻ7͞;wMn_)D$zMD.]ҿaÆDTZb{d[p\"bXD 2E)JfB311a5k1j׮} ")B1:N5"g^\rNK`u:Fruo}dzjժٳĂ۵knݺcǎEEEEEE=x`Ŋdh |>dl$0ӧOѱcLjɩA&&&hڴ7nܘߠA":uT~~>ٳ ljƍgL666fff={.ZJ",Xӓ: ܹSV7i,*55ٳQj?p׮]+WlԨJƍׯ_Cf ˕+W)rDϜf͚Bʁ;㔑ѨQ#P.;|p^z޽y[n[dI:u7n|U ׯ8p 00p̅kb?~͛7|xĉӧOڶm1kBqӧO֭g"Zvɓ}o5d{iժU|| 33T?ײem۶988?^*.ZhСTɓN/\o>ҴݻwO8\xQFGm۶;mVZAAA׮]rgffΜ9cǎ2e%ɥKf͚\R8gΜ?=K"rppxlDVܹY3gΨQʣRSSvVwsǎS(;waw`1 ޴i_ >ɓ_W+dž lmm/]Rv4#G2KE_ڵkw6mڒ%KN>: |x^^޻??}4101ڷo߄ K桻{=ܹӠAW#C":qD*T17"/d[~s,KdggK$]~0..M"ԩS'..^zV0`@ bHqΒ*컑 (o|>ܸq﹑]6t||3gx?f{/m =v#>cC-[ԬY 9Ĭk׮֭[ڵkԱc6nܸA;wx"5jرO>|p"zٰa\]][h`jhhhv\\\&MV_-!22RDFF֯_/_^M׏N]:5m]ね(F*z=z8;;waϞ=DgϞA888 6l^WիW322}t-44kg̘}aÆթSgժU zKqRKR[j ߽{y;v|W*jǎ˗/g3~TTTffs֬Y_?~AǎcV8vXl޼y޼yӦM{Ν{ĉmێ1BT-o'O_ݫhjvرcǎ'OX諚4i/ܾ}FEڶm[.]]ֲe!C$$$;wn?sJJ -Y$,,lʕv}]aaav̙-Zz2_=9Zn]PP˗Mw'NڵٳR׭[w…5k0o>C~9::nݺuڵ\.2eJn݊#F8993V^?p…;w0D k۶= 4W^[& .iҥK;wmƌ͞=o߾&Mڽ{w}GDӦM_=@SSӐ˗ϙ3;wX,vvv.3MOX+ů2n:b"?;vpf<k1RSSCCCCCCWXcggE o:%~xiʕ+[ldDTXXx)BqA >>D}ҥf͚鷐޽zxv_=9T+ѳgO`gU̧㙘?~˫f͚k^fMv:u|8>R>>>>>>QQQ۶mW|=x###UTgΜ6l2au0`@hh-[bcc_NDZV t!44M6Gm߾=Ͽ~AA7eNh+a옅-Z~...ڵӧgeF$5z~ᠹy:u߿dfAW,ښYx\.9ppT*ǏU*w}b=yyy>,҈ %w*cdKy;#G=z[jg}gaF-A }t֮]l2"211iԨQFbccOz( gϞO͚5߰{]xq&Lҥ s{MLL֯_hs֭}egg/^1**J;w`O:eaab_)r.nYϾ|׉~nuֽ{w׮]yU'Y,{rN>~iX{{tڵkGU^dgg3&&&L\{.]>}8,)˗/_wڴiN*vQi:uX,uޕΎf'$$05W^}… &X%ckIxu:ݢEvڠÇ_^4|cqpp9rd===CCC{_'77wС>>>mڴ泱Fwȑ͛73%K}feeL`WlvNVXѥK͛;::3f֬Y?@ ۷-[BBB:wwޘ-_|L:.&&&!!ɩaEs#/6;KҪsnwRΝ;gϞ?twwׯ냂 ùs2% ]v&MԣG2㏼/~R\3 e݉Ӕ)S&LzǷnݺF&L?~|zzzPPP@@opBNmi d2__ߨTWWWfff{9ŝrssz\"(--ԩS|IφP(ꫯ,X`aaQvŋ_~X/stts玧.g5kdnZyڵ'N01ǏܹsgbEEEEEE͘1:uewׯ_@ }.\nݺoܸܹ丘4ǧ~#Fx]I&رc===7lؠAkݺkQXYfwܸq{%"XܻwEx.\8cƌ޽{k-Z6233)E[Pu=<<0.o˗/?]a5vP[jU林HV۷7t!;(gϞ=oݪe۶mqqqSL1t!``$0 `$@0vFH  ;#``$@0vFH  Ҋ֭[і˗/w'NLJJҷܹO>]v]dIAAAW P 80::Z5rȀtsy%))iԩ!!! 9{,B{g ¢޽ĉ>}ED{ӧѣ9N;Ǝ92%%hcXXX5 Pf6mtBQvowʕ!C 2hctt;,  N IDAT>|owqqQT]1@UpM.Yhc֭'MT^[iVCP7^Z1--M&ZXX(B};555U(Y-@UѣG"jEUVZ5f933| 曷cWF\.WT*fvPY[[ky W =veΥP<Y..Jوr,yyyvJ3RSS,Yye_ryzzaZZL&cXDVUyPuN4IT.YD5Z7 pa(\\\n޼,=xٙ֫WO~->_n]Õ PΜ9`E;GJ5P.ؕ?goo7֪U͍urJ;;;33e˖ QQQcƌw"]\\^ E!ؕiVZaWWYfX,"رcrr… Z ])@Ur9NW(?^ Epfk@0vFH  ;#``$@0vFH  U~T3'5[t:kO:zAjRP,$bV񖘍(bK5ZU&i=CW!A^ϗyf$&&T͋yA+"\c%zŪ)5@)W(_J UK $oL$"yc֭b`1"/Fm6ųY) DPeJJ^3#<+_2Sye|(>F"R#)5_z^`EVTݗ|ʗ!A}JHR\g|x3o@VT͇Iֈ8BU `lSeJDɗ)54/bɼ+yq%+jCJIrRg$kDrO{ԁe$;0(oQj$^ԫzy1=I迨pTvy|ySDRV,Qϧ dT͛^T͋,7bx>`liQWCVdN25"U|(\hi6vPei(*FPj$)"  Y83Y<_0oB* uJEi7GֱlH2wքySf^"@BUN7)=oSJEOm55$ *Tiv1RmJIi7)E2r2o@zdVܑ,=JTv3RQ%dj_|TNi7)-nPU_GZ ;y2C!mC髇3AxYf )S Jh~X:&\*To찏WB`F|J;q2)>e= uV kp$HdMBkYki+n![+ˆ⍺-GBdZuHR$v+P ;Um'U}B$K"e)(1e?$򵛒:6k&m_WT @$c(:eCjٴ~yɔG);(1SNKU$!Q <_$auYȦ\hKʧOyLO) >yimrZؖVχwŵ0 B i))))72ITx˥$J>f&:I*z0 ;)+û)'-} 7o'Ejχzx0t */Ce1tP&|i(|J /s>&MePփnYbO$%j&IlIlKw0 %%55"eJ;LA)(/E_޳y>6$!qlO(va_,zgN"c;-oI.%?ɣL'Ӟ2r)'S~2)ZQ#`KO2(bP @!;S2/7>%e2P^vRc2~f:dF< > 3ufRj)tF,\̑+IYrc`c\F9^z5ju쇔(FP()5͝ɼ;;;qM+:;Shٮ#+('2PʸCw)))#2_ZQ`|XuŮCB0+*L""9%\RDQ=ʌhʼKJ^Ӳ!Y8;YIGbr NGY).eܥ;q22Z+YY *b"i]֥ZhSeQ JIѤN7)?RPp$$ Wt# Wt'UWP IEK^2ߢvoSZEzvȫ,H|̝H * Ȧ͋ǔzTppdNfO0w"sʯ "I-%>&Eߤ{zY= k(3uHX˯ZdkH!GCZv3[|BrQ#_z-ό,҃,IAĕT|X$M/i)+(eQ}~HYʤtŚ;2w!I-=ؽ]WTeǑ={qog`P[@.dR=1"uJۤF9_$K$CEe^OReh鰏컗G>Z^(Sv,eǓ2Rcʉ'e%Q^Kqf$u $G("@a nve1L1C55:В$IlK$&5 Țz`Lʕԁ5JʌK9`'_'< b∉+&xfė@N9 d$,H #%fu|*GDF/~3WC1_ZSM e"=#e%2T!M;NhM|KXGDlq[HϜx7oxHF5PΣ- ɦkWe&4Q:9LTF)J4*H#u~e ̈oN\)eKb #zP,b+ZQY5x jZHD)+;J3( )ћ"ē FtR64/'M>( TΡTRePAiHN2йFDDJ([kfiYi4K+J5L4K#-jŹR'֘nkv*ǡ6桓讣09׾vb푮lD6$*SV~*2II,ReXVFm^чIyJ]vZvԩnnnF 9sUfz2rqyqcquرED#[[[r Ź*9 Z-a|{w=3ŠlI7f9 sn9;Âf4ds294/i1kkZЊ6$DIXV$,U͛7ccclbeeED|͎;ڵkwҥQFx~]zѣ|WXXXLL̔)Sj2lIUZfųg'QbAYqbVj+{Dl'SjebL v*)TGa&e)޸$%-Ij-Ij~r9>..NTFGG;99x<-::peV1vk2^xJ5tgϞ9;;1SMDW⣱ԊZQ"x:WVyQv%S^2%Q^2)Q3K&U:))ѥ^/N"$ mITD6$!qM`аT333 |>={ߪDdaaP( VeU`^nܸWxH4d6e˖~i͚5E@L) <'r<_}_{F^h#'inLUStNǪCJE"ˇ P(vED@,~1FrU*ʬbɓ'=<<-+Wp8Be˖`DD@>LJ}DNDN$ בS%q)1 5x6Z|/ߊ_})'BXj՗_~oDmjjx}?[O[!ؕ9lbbRqĉV>}zAAϔ)SX,\$ \oWSvmү,k֬YK.ﭭNADgΜ9/6lٳO ?)v7r燪)Z8 z8PZ@9 ?^d܃_)09Z7AՅX*&Gk:+n֬Y.>80vFH  ;#``$@0vFHb{HKx7WVyz@0vFH  ;#``$@0vFH  ;#``$@0vFHp ]@eaٕU^. ;#``$@0vFH  ;#``$@0vFH  ;#``$|,BCCϜ9?{lVknn^G@e ={L&;yd~~~= qBCC'O|xڵ帋 vLjժ,X`˖-帋 vLf͚Yhezzz9b]%$S*aG8p`^^޵k7rۗ.*6UB2lmm9,gΜٰaàrEd_|Ž{do2*~駟~Ĥ*614$$$...00P(vaƌS޽{׬Y#4h,q?޾} M?<|P_~iذ!ܹs޽mڴ åj׮]{–-[>|%KܹcmmظqcCWZ>Ν;`@qƇX,cǎ.*6 6e˖K.533cR]ZZڮ]ZO<=z Rn]":qΝ;'O,H-ZvÇWB=C"*a/*/Cvs7ZvԩnnnF 9sŬD"ȑ#l60//Ν;o.]TxZbbb=ݻ>>>ΣG>rHAA_?߿OD.]5j]~=jbǗ_~Y Bӳ_~帋 vVrppի+z_)>>B,m,((x𡻻;ER@۷y<~M6 .$h'''ǴEGGrնm%K9ȑ#%">z%K5k׮Lr5j <+##P&1p\SSSBaR>@'Oܼys^^^˖- ߤDdaaa4ߤÆ _~FF322]\\\\\&O\^`GD,tuu?~|xxx%gggo믿>uԩSCD\.WUT+o߾1cXp̘1EČ477wǎ5v o߾}[q֭[gff,wM0F5dTJD...111GωHVWS49"́(H p~ pެ˫slvnniӘi:nΜ9#GxM!?w\6mƦo[!iӦǏSSSkժbiq/zڵk+ LbӭHVgggO~*7{iTC8Eof8?oSfp~d2\^զrK"*62[eggOÆ ڵkT3f0Ӓg̘P($uV;dǏwss8p \.^z7otvv&[n|6(PZ#G 333CjҦ7o}8\._`ܹst.kCEuܙY|rrr[oݺu̙Gq;wT~+SӦM7ohggwO2BurJ;;;33e˖VVV~~~GVTVϸ\ŋ{O2ž۳X,o**&&̙3!!!QQQ嵯.//ܹsVVVVVV(czVWX^^ 2};vLNN^pV}Se͚5׮]JE|PRxÝtVc{ܖ4$0B+;7#QοmҏI?4EHc*J6p@ hԨQFZ666qGTھ)9=K_[t޼y<˾aY[fjq*Di$ܬ5S#frfׯ_~rUA1̏Syf_nq+;ygU,^%VW%yl+0033/5wYⲴWvϾu7o{CY+f9lSCW `dʁ`F^^ s6 ɼ}+er[YKf-298!A+d\7nftMߌ0 >]#v 7kIα5tF*P!Ϛ)f5ɼ़ggM$R'%~"߶,Е|b"6f7c=w|N,_ZYD>Dly io=-R^9{X~Jy!Ty!7ʱeJ> vA3H%{K:&JyGG]ʏ}g|Ɔ젊Dt}ґ o\=w8Qûw7ʖ[[t,nE\k0 ;jLL 6{p#weߘ#K $n 0^ ,Ӧ&?vTy\Cg%p$jщWЕT;0l@i|ܰc߸blMҦb y{wTd߻%oi@)(8 n328 PP@EA@N[J[4MIekiy晹s/{nXB#|k#t^p`h5!LW CAA~5yjEsCZ9I?.S4$kH/Ah. ؁c?yT$nJelؿJ8X<~w 'K88kuawu]`}ν50BH8RjCcEOfDpp'v.PE$Q 8cA^nosܺwBB/"ПƎMbp\@T H"BZцXC԰v] TOȇ#IljK'"\Y72v=|恄KY9?\m.ʵ56^=Muqxdv`*8qI4^w!jvthTjR^h)5昋n ۚM7.n\vgq1r,-z} ;aGQ2OS6u$\|Rg.UZ+muU*#TЋ#Uqq1|%;;7 al1gYJRTiʻf׵/4^>I-eHٱIY 'F pQp_ xNNѯbS~)9jV՟9L-E8'?'FabWr]U6t ;OƊcEĉ 5k.6ZnK6 !B)'sc ^ @C8 9 sI(\]{)Po( bqxqEy)_VW0}]V7; |?%QhcL'r s3ӷS)ɪ5p`hdJEkԬԪQ[SR#W΋)Ɨqu_!9RZ)HQ Uvp{V'HBbVEK%HcЮh !DG E|E@^K觻:j6U x+v)tvi 7Jō:oQG c 1Ƣ(cЮKmvN:q8W_%=lk3+쀋#!41dLo 2S0S9a(@?Ah܈jn~! /wm,ޡTW S)e8 ~@7|бBc+tW!f'_#J.L[`/=lحR[}>GKٴgl[>y”QZ ֧k!@૲f <~?SXVr#~lJ_Ki]norfXB)Q RrE407`xXrjaTȓo(t Jaxˉ-'59+^~_zpŔd !r .+B4EK"~b 5O_)z*}E=֌C^!?ސ?Y''+@@W @oTt򿤓mMڮ$b[B] #-Wka{w,!$\-P]4k[._(:F0=33ȑ#?uv]׿ulJ梢^?=#3tq㖲|S%SΥƭ0${?h/tu/00pǎAAAԬn>Ie2ͦړ]VAHtVVJ߿?!DRY,ٳgW_}588eU naskj iokqw돻 M:?t '.h3pBb9sLff5k!bWպJw`G֮Z'!T*>?k,{zk۶m\.em0^O f5fedpܪ*1e7eoW0haTۏӧ777EDDBf@ p.eXuչ?DR[2W_Zld2111SNrq׮]_2}gO E䡉䡉z23*04i?;H/6GzC4w7&8w?u_^zҥ| ͶZΥVG]ו-^8%%eɒ% j7H$ſrï7ӮqCp~=>הatp9?+Te*а-LVc~~~ZD")..v.teUCCg2z~ĉlssFn w쥡;~kw9_wX2s3Vl:cmtun&;;{ڴiˬ:N \^XX# !Ad]V }w{[NBEiy~d=LF׭[7}tF>vX.&֮]Ϟ;wdɒ%.m ufȰK.u6N/Xm( 3WD!EfqUNU͍kY/z/;V}UȦƒ ^R# Ԫ4A0so(78h=;Po`ճ4 z;а }XV _rk7+C͕aƊ0SEϦ 5BͪN떍BXa1(Vh4+,J.CpFK¶-~ֆKآ J-jNdlZsVxfP8+4 dGb\+p_ 1 FQگOJUe֚rZ]j*7kE9ίVa# c3™=m<'qd:6: :KeVeՔ[o嶺*Ʀ!Y6 `G0BYAa̠pVP?у@_A 9N֚r[MVWe.ެթڛl[0Bp$mlӲ-L[;@OBX!Q(-"ZSaTk7ڵvڬ׉:VȔjYR-_ײvUI-uRat+"kVkuU6uM]m.*[5<1ZhuSF:71~,I3˯%ֲjmn曬5~s[1;.y?BxU-jVآZbKئ F&Rs 61X l +@t1B*zY v= qGt !^f_[Ϫ5|6RkkgtxAk#OjF>CFviV/֋- sM.KlkgD#A _Բ5, ; ˩9AjNsV|Q>D$ @@Mԅhzv%հ @`R/0Ey1kioZkR'%Ԫ6m #0y,/_`o|zhz :c֌l<*B4,~9*nd7*LMbUK-ZbVKRZbQmocKc/d2Øa_'B\w`Q0w/l4f;ҩFVԢZ|73|aY ,ed1!̀V@5 e$rvȒ4$DѱgۛluU*k]U*{[˝u3Q?t`s+zQ _ WIЩa6nlk}M]cqdV[+o]g#;`8!Dg,`\p30=l!\]:8c!<@vC x;`!<@vC x;`1 LIDAT!<@vC x;`!<@vC x;`!<xof&;w.quEdOϟ?pN:i$WWpƮ?~oYhч~xƍ۷"^jӦMk׮ssι"`3 4(11_?|lvuQNkk_{#FL2wuQn;djV.[,2V 1 LF&%%8VSssn,DZֵUBt/Qbt:VuՕb9[X,bq]ElIb&XVgjr/W3;u8Dwsw8> ||^z=lvOLBЄ[!u'XLњ !Vye^xpkph4BHcc#˽RlwbXl^^ÉvmUP||f+..fsss]`&LgϞK.|ǏxPD"ј1c>g~w'NtuQn犻ݮ]<>rW_} ϟ?/ MSO"`!p)C x;`!<޽{?`^>999'N'NqㆳԩScǎ3f̨z{ׇP(222ԧaΜ9)))F:pN͓<Ӊ~]}?pRRܹsZ-!DbϞ==UxϹ!FlO<Ć -b,[gubuR]]|Egw}+3fTUUJc>mm455/6lÇ K/BΝ;}Dٳg{kt֭[sΔ;y7 Á.\d;t<޽{oOߩ˗,Y`C B`ƌ"hȑ=X{O!g;g1:zݻbZd`pΞ8qbҥ\kv?+r8l6GGGޥ7|3|pp8wañbŊ^x Ņ =mҤI;vKJjv̙|G3gμ{tnnntttCCC _Uν 1JqqAS-bLѣGO:uڴiT X'|ͤId2dʔ)15]SS3rHFs b:XB{222>k4Cۛ7o6lBȓO>9eʔgv\= &L2dE~4nBGMr<;;{С=]gX>CY,QF-_Gy'' Fcmmmvv]>ɓ'wʕ+LrpnvBȝ{rʪU BBB.\c_}Uhhɓ'ccc!111Ν=zbO>nݺe˖L&:8iƍB2!vz79\!FYrԩS !֭KIIdOa_!DVYf&L欬e˖QN}`'K~mccyƌC9r֭[9իBQRR2{[`لAinn޸q#ϧ;;K$Zݣ{Xٳׯoe˨_vZf :tԩS^xl6zXtt4N%#GdddPtHuu //]… ?HΎNOO 6mpRI"B !*jժUF)f޽n-5!;wp8য়~M0i4dl6;--F szZvĈqqq[9p@TTŋ !QQQ---Fbۗ,YBe5A9!dNwϞ=.ڴiS>_upp󀻑bm1! j[󎟟߭ !~PTFҥK͛aÆ/׿LdS@#2~xBF!Pv/:!$<<<77WTΙ3dnjbx2IIIԬ\.ԴjGYYYwND矛|͙3g~Mu:negb!̙3RYYE}ttD'N8sݹs>HcǎEzLobOzꬬ+Wvq/RRR ƒ%Kϟ?bŊ~鸹iӦnܸz߾}Nr^?]Fu֓'OVTT|%%%7r$&&vk=[w R)8%::y||\.gXbHGFEDDPaz̙֭;ydqq… e2Yjj}p=h4Zzz;~x??_~gn]lٲv5kք}O=!$**O?]j'|2p-[S .X,/2!dرw9r/\bń |y;77m۶+WGFFn޼9..n_4˖-kjjR({u$h4ꂚ;!v'bw!On2y睖x`۶mn#חA !<@vC x;`!<@vC x;`!<@vC x;`!<@vC x;p'111sԾy昘Ce'NB Cll7PHII9sL(JVQQѱ/鉉wZt̙ׅT*^W(]X~CwR:6n۶-((di`BRr]( ??_,wa] ܉R8phZKB! !d޽cƌINN1cun>Z`AmmСC !yyy2lӦM _ Kz}tR|RLNNv{AAB`2 jj?>lwڕHz| NRB͛7>}ѻwCņiΝ;~:<}4Ś={cccs zR  80%%nOJJoD"QƍKKK;88BOOnBDm۶=s .̙cii) ]\\~>oK,ѣݻw/ n߾M)**bXz Ƌ-OFO_"ҋgX/633k޼ŋ[rYBaӦM.],֭[ݻwmԨwAA!buqfffbxܸq2_9 Q!>>>EݿҼys#wwwBHdd$vƌ''' F~:EQ7n$UY2=G߿;Q@>m4Hr?NQԄ !nnnÇr͛7dgذaݻw'?(*##C$BرcGEٺukJ/_N:t{EQ#F q\6}9FE100Xti5jrK M={5!dE-ZҦM1cBn߾MQ=;ԩӨQ =tP֯_Oׯ!刺>O% !K.rOp8mڴ P ϩ;wB Œ%K!gϦ?󜕕}ƍXCi=~<>Li߾=w[lEQŅ-ZՠABL&S湔/:QSP9:RU9M42o޼˗/Uѣw+W(pBș3goݺ秪s|ꫯ,--cbbN:E;ٚݻ-Zlذ%}ٹs':qĉgW3f߿b DJ:vf !;w&<{,>>^.?zH$D͛7B?BȖ-[VTT$%%xBN6MUߴiSsssBѣ77hBȀ !#FxrUV:lْn\YYܜk۶H$;w<{vڭYV_a8NHH٠AOPH=z4!D(ât'koԨQ952dBcbb$kOR'OV?>99933$iӦzU޽=== !mڴ :r!MJJJhͦ_tv%Ç*7oޜ>JIro5m[-\8}ҳlEQ5m,+00otR~FYe]t@=::["<|ptWW)e ~p95Bԣ۲e }}2gϞ'hҤILLӧ\)6055UNBΝ;Gkٲ%NLLtrrرcdd}R!$99cǎ...k׮+a3Bȭ[/̬A/_|!dzzz˗/o۶-!F۷׮]#\|m׮]޽{˖-G*.߾}wNNN,!E8p"J;FԩWP; Ure̺u떲,KOOUٰaLSSScccѣGcVVVcX<>ئM&SkkRTJ_A#FPӠA7tPz46l|)޽;p8/_~ٳ?r(>YXXH_?f @۷(}7nOnܸ_~^T%ϝ;H }BΟ?i&um|}˖-ys̒Z?"ףGZdCQTmkQ@0}/\HW__jjիWa-.^Ep8Æ ۶mիkτzM$)_gee8::ve2n?tPn=<<_N̴y=Axx!C*/cǎ77'OVnرc\\\̙Cx(ϩM0bcc !ӧϱcj7x=뇴1nkEژoBkׯ[nݱc 6Ѝm۶uqqYhQYY!ٳ^rW_}5/^ؤ3yyϟ?'=z{Æ >=A^֯_߹s>}TTTU>(JCCC;w8qČ BHnnͯ4v*g䣣Lacc.\`___GGnݺ]~}۷wuuݻw/=L&[tk۶m}}}߼y~>|͍J;ʌ,o֭^^^?w*{69s&??z @5!/ ÇVԩ=8bN8v˗B={rŞ={|r-ttx+/^ 22r׮]GxxxOݻw޽SN:tpvv;vٳgOlٲϫG>BQ񍳕[ ~=TcJ_uڵ8rHYY/Ɏ9qƫW.]Ç޽~zxxov-[;wܹs-Z9s3gz=zLz,]t޼y/^nΜ9.]Zv+**&L 鏎9rȑK.eggo޼\_}ի̞>}ڤI>|xڵI222_>e˖eggB֭[wƍ[=zT ?^PT鴫Wv|sޟTk׮wϛ7?mD"e_[%K,Y~rvJ;w>|X(B/^w͞=;--XXXXXXtЁ>?!--:< lS !z:rȴiD"g̘ҠA{ٳ}+V޹sSN%H҄͛{j`ggWy!C;zcǎ}k?enѢÇ|9eĉ[n-**Z|X,&$&&ғQUQQի.]8::}UBX)x9*m:X˾mhhX{cy~133kݺ5!m۶ p8rU&{ŋO8ǏW͝ϟ?r[jemmMO?c wwwM# \NQ\ Py7ܷoi 6|9%jV;z_mBcL=%-[v޽B5kk@ H$Iaa5k ݻwwݡCy]|YGG͛ꅅ,RVZUPP0jԨ;w9sRǧsƍS66kٳgVVVtaѣGUķmÇߌ-$333//~sɓ'7oŋ޻wͦS 0p}ҬY$<Z6mڔb)/OIIi֬l'YYYq8 f+W*o>QOcuc;v`W9]vC]~}vvvΝmmmLɓYf B6rʓ'Offf^|۷ 6477ߴiS||#G.^Xeх ^~ldX>\paBBBJJ˗gQis}ݔ)S^|B _zrʕSm3]qrUq`Ѹ ˽Wy}vvv?sRRRtt;tҽ{&M̜9311? yxx(?~c>~MVߝ  6l…111 3f055ussͽ|Doܸ:{H$|[[_ }lǮ?}ߎj\bBCC UVV".\0,,G+VXdIvX,֊+|ܹ饫;lذUVUuʕBpذa<oʕ?ׯ_Ϟ=#""4ik׮o&M;vlmw߶u> '̪X,֖-[<<nܸÇspL6p@??^zr5jdffFн}^z8qb'~w'?~&N8d>oq۷h߿0{>}L:{}ݻwR>cWޟ?۷SRR޽{_3EPjLP!~+-%%+::Zmܸ1--]TsF$InN:t!*P^^~ĉ'2]h?z7n܉'8)))?3ӅCl8 ِ4fCls y@!h69͆<ِ4fCls y@!h6.Ժ:t(77aڴiTv-@0bĈ!C?czzuMMM}}}۵kG߽{w_vttT.qqTڣG___@PgAlPصk BR#/(i\tt ƌuV@d}ӦM)))k֬۳g͛7(Νkjje˖=z,\0;;ի`OO͛7.Z(Bŋ#""fΜbŊGܹ@#( (ϝ;ݻ;v ?BeZ92 //ŋ666ݺu6l؉'xΝɓ'[YY5ٳH'''///DCBLJ޾}{{{26@%&&&%%I$֭[7ʕ+G^LL&֭q022z9ñ[j_%|4qqqt{֭FHdccWVVlwppdIIIuuIQM!/:V 177_n>W[U;m~.++KP988ed2YQQQ}+77X(''c BIoѯe ߄sM-E0[h]]VZѯ):yd6mH5u[RBȆ /^,Ν+x鵉2)H%Ó~'R#oݗy|BFN?ß,mA-8pJSD"QuyZΟ?/ ܘ.DDNݵeсLW%oơokcZR(.]ߟ5{kאf\S=w/4{LP!pQ9qR@To1טBMNMy|*(PijnQ2-LPO!LC/%tk0n` xrn` n`9P7F0yTFA4{kG@KXQS1 ρ*qĦ '!1!ρo;Z9Po۳7F9P=SCALVt􊯟)}Z شYSRfsP[ O7xcӵh395N !d/2] BZ$ok0dQ(, t9 yjwaZ.xj(!$gbyNh!9uz^:ݩf-<uѬu,Lm.pMNEyHʘ.@ A1Ώ̾"eLU砮8C_&0] @#ok5+, `e_GIYpLY\'n]1]l]Pv%ubAb苧,#lZam9kzFR}9{\ۘ.cCniA=a|h:rsyxj|˳_..i,aAc,'a|QnALt9 y\b\"I_t- ymICkTsb3BOjBt9 yv˰6˳9t- y|EoZJS@ M.r(o*.@ ρZd\>ר4w)k0sJ9:恄_6,eM<"Ơ]E@ ρeP}Uk-ksFy #LL 0]f@rx`aE׻@3 ρzkL97TL@ %,}+.@!ρ::7<K˼@!ρ:*gZ Y]2rm!7K@!ρg1j$}Sprӵ/9P_%FWBn/b5<jM P٫@M!ρkD.gP_܍7z|{ޕL>Yg̘1` &_w?#((Ç8pݺuee47gLQޡL5WVV6f̘oټysyAtu0,,rKjjÏ?Hӫ2\.;wnV&O|ƍ ޽QF^ 8q}-ZuVuň9sZjΝ~~~uy op뫉}sw.ɳa 6T^155ӳK.&MB>veh5V/6oleeU˗-[l7[[*ܹs'??VVVF={,!$22K"?|rÇo>000** CtG`7( !t9P=IIIU_|<:ycG^Lܝ;wF]155_抋VZqqq[E"M\\\YYYrrA&%%%~co󸦖eOcZz֞P(<O__j K 2Y%3gbݮpX}zP&y[[jj*!$"""::ZGGgРAC aX;"CeZ>>cǎ;;;Wn|T*%̝;ݻk֬2cYYSx2cNG`(4k/ӵ󜩩ҥKvui#2Ts߿sΝ;9rȈf ¹sN<@9 ///W-// l722O~p[͍/gX]_޿hc7uVv^WKб}[KTұ..._wwwz(.''ԩS<~Ẵ67nЃ޽{Ϛ5W^Gn% !$''r ʷ^XWؘb噚B +⓾!-=S-cʷ'w8ӰqTKT}!-[tlAXp;?xe>[m "l۶C111^^^d<Fٳg<~{?~L7xޞ5o\@ЬYzNU>RoBjn޽3fPMLLM#/3%1msbo}}}Pf͚͛78>=gϞϟB\]]׬YC%&&׏_;v,%%eʕZ" 4СCw܉ |jUl?.]8t-PC:uzё#G222"##N>~ʴ9} VX6qDÇ'&&B\%K233}||]xbXL7o^ddIIɢEGwС+W={v֭'L7 \M^;[.r&.\xʕ &=ztʔ);w&?Be, cB͍BjuR]];lUlܫ:2g~WLBvغ}[{oѱ}[Kԡc Q(.]RB/?3] @B6oF4l,fYr?p}wy^?3] @Ab2o#K[K+LPG@pBBb sm v}v6ӵ9B&7Dgܾt-y8` !Mrjh'EyoW y}ֵ1u<ZȬe>Zt9y賮oMfڂ<Zdf~K'V ρ42O %d!fC;νo1] !AxF~I³G@Ő^5O_I^3[6rT y ~u:J }@iv32T^0+. A=%k.%> _t-_y)_h8Xy֗t95< E^0I.^30gm[q!ӵoohKAXfhQt9<oΝO4MKLspQK~i+>Ab_+''rB~3!f)Ma@,wt԰?*2Gɘ.>^3LyYML?s_cp{?9jHJB|^n,bBD/B:PsնrkD<6}3ӵ T_[J%p;5y&^ Z 2]ks5te~lfBt9P! 4iyOjku9sL:0??_Gr$-Tpwium۶ŋ_tI*|FEEWHT΀=t9%))) kJ=j#GV~H$j۶QT۷ :… *,H֯_ߵkWBxscggGj*>>J؏i֭[Ӎ"&..,99Y ɒj@}mAޮ tqݺuuタPϞ=׭[Yy;v3foXX kRƍ(O?~_~\###5FFF2򌹹ʷFFF999kW(vOO #F r~ckP?~| ͫu䭳RUǧEҥѣCCCUAcXӦMstt1cFttjRe˖]vqƝ:u"x뮮U ]]]UXܗ+**ھ}۷)j׮7]vIIoݺ7rH///z޽{O:5k$$$XXX:;;ܺuk999SMLL|xWRRҨQ#uddWfΜIaXÆ Qae@: gqVIE6I3LWuMzy޽{LqAYYYrVŤlRɊ&ei _LGJiiiueѣG/]4--ɓ'yyyӦɨsr 7](iUYO6Ѥ,)E$@UBCCCCChcc[?Ϟ=kiijffFw۷n:w\r5[$)J<9m8́(| E".++ZQÇ^%1$ IDAT<<ǏTU@=otΉk1JBAzr<))T" mٲPo e76J!sZhѢE*T z7nhРAݬ yaټ7!>P7muz+ְDW4 Z,)It(yP{%xӻ3R6`tuBNs ~gp/360D:Vutt6i E<@}!+FVHBX 3Qs~6qؖ/MoTtEZfnM SYvw|SAW=yѬdlRLjy@uYe c94DtQ.4cϹ7e$U'uzw@- hTa-FtPeSR(L C0Rhmd,~K+&IJ. <|c&TE@LWATכ z[&MMEl)e y6a}q0y@]7=6+T|}h1]9mot9\qɳST3]9qנTݑrk"u@B*el&H(Jgl M& y@ Zk|zǠ4qy_rSY:u@@Na]iwߍ([랍~5ӥ!hbviAc; #ºgczָ<@e_Jɒm6=s{޹ ?f):m<P_б iraEM|gL/DvL vq66B}i]寒-#$A׿ :u_ddN38U:)H>@N\ e!9א^'W&ˁ,슅G0-cpBoP&C W'}c74ѷfw?ڃt^nObt}B!mlhu9W/ǯD,OW_.PkDSj ǜ[4rQ-x Px.Ů8Fsl Ņ*1.ʜS$p~֧$6Lʸ;දFH Zx͡\4=γF%rI;1uH|\9^_?,M5`9c1Ȓ_Z`5?43K8P]p5>7];ֳgϞ9s4iJJʂ .̙3Z^^^DDɓ{߿FFٳgg̘֮]nݺ!CL<ǧw c"|ZiHUmj)ߘmA{Z<hC/7⊮>W'Nl)))IHHx衇ڳgw}w˖-S([n]vg/\rʔ)n|O"Z>&eZ8̢e{o Q:#.9 _n4lxy3/rVVVHHȅ=zo߾iӦi|СC7o0aƍSRRF%5k}woqݺuw_>}ӧOg'M):s)o pT 4_![To)N葲o7W~ -sYr3/Z矿hv~}n߿c={:UUU͋q\d2y /n8bL=bLo\ehwk~Vq{pڎkՁRdrf^K*//ollBG*xNsM6ϯyVp8Nx``%o=bñm Pdo2dpZVoZO>u{+!;oVضñm#r`{5/7 _nEK\}Nqݨ(!Dee}.$$y$pHHHuu a6/W? k# y۟^er{bVmvgpSA;Pj-qlȵ?/7%NjFZ'Nh4:\NBBB~~~/ YYY,Ϡj-,,h4>>>h\C'=<;>^ɖo{,f-[׷—ycKHHt ,8}tff%K~_{NǏBL Yĉwy"==СC~iQQK/$׬Yo߾E_x;/cSt_b^B[lt :ՠϵ[plFY|( N:⧞yٺz𗶍_zz9.뫯jMP||FV7;Sţ{M_gx󭗤T*ΝVsLRt=ΘgپnXء 1?CNQRg=8?9H7F񯮟 |uD|.vez9hs]sϾtksxꎘiʔ: yyK_붹 ŷ wk>cwYꥦ@ךBc68l\cryZ[V0hq]c HFi w'nGöU_tnrqDch tzG;.`[Q|' ,s'@P56=X6!Dۯ׿dLjRpioM#~7hپaǙSի^^&*4l{}/dJR};Q_koxhp (~F>¼m5sT~ՊyU+iv7 0 M*H\ws 'Ji8q.se?,[r)>^"e@uݏ{ٔ:Fs KJS]5~צlwTL! 1M~SH@ۢ)~c7a=~ e˼ q~+u:,6AoR~*ݮɖCq Κ;Bv222dVI@KR(Ov?}C{CNPpxnvR߮\CJ!F B4( Ek>/Rmmzg}BÝl##o6"WgH5&vB 2̂g:j;}T(F׆vp(65sH3`EB(ka,][i;*.zZU9sڰJuymX6Q{M9϶4rf!%QnpZ*aBתRp{ypw!sᎳto..z[ҷRz^v^Z 3*:u@ʟ?>;haa9/υ˃*Bl!ঊ{yg[%ߧ4BT!J@/@ R*TA*@UH_c@HWkaoL.Am:d>9msڎ?7:!rjgTTmr r:k*5ӅW|s)@7(tޠ5(| J_נzWW:W M;5[;X4,|sŢ2Y|M?wkWmY[ sYWv՛] nYU(;U=_Fצ5tOB$MJuBTInRl&Ii&InBӤT_C!#*?o.sB_9HRiZ\ֻmwk]Ze1;]Zg]R2zmw768.z[Zw7~~W}l62d>~J6q՛ݍ emp7ֻ -qt.eS>.J4MjCv۩v;nTC㶫MWZ8%( &a0~8gMxЇʖ‘s"> ߠG1{@F8?@{Ѡ6N{pA3p8'9ڑ@ q@sF7> o9y}@sF7> o9y}@sF7> o9y}@sF7M-uvu5662d>>>R'=jll\h޽{}||ѣGKH8?:nݺvڙ3gΟ?رc+W:ŋ,X0eʔ~{Ϟ=R'=\Xn}קOӧoڴfI vn֭SN8p1c>sC}lSN%''{vɓ'M@;tqJYLJJsҦ;\+q\EFc2*++M@;TUUT~@vb6ZҪFih4v]DS6S VjyptCjjjjS6?GvFF8mv8mUlfff j͘B5is 88XPTWWGDD!ln-gԸnB!tz^\Vhbcc<>>>Ҧ޽{SSSAAg1++GnFkw}5kۗhѢ o&iذajAAݻ?{GP­eׯw: z's\RCC… k4ǎ;j(}@޸ o9y}@sFϰ'Ϛ5ٳR66͕:Wٸq?|]wM2ѣRN73fѣWXt:NmNO<{I@CKΙ3箻Zd`={6iE/3gUvoN0a}yg=|ᇻv={_;v|R'6}Qaa) 9ƍSRRF5k֬3gpV8v_}￿SNRgR!!!͋]~ڧ'OΘ1#>>^PTR6zd2M2RǑ#G\rÇ\z z+Z*!!!++jN4IHO;Yf)jǏ?{LIDATDϢ:L˗7/.Z[nܛϡ{O?455wߍLJJ:S.]v|("""22RT^@%$$,^駟VT+WLII:) oAAA]t0>ܹ?;$&&Ξ=uў555}./Ko~\T^c̙>ի3 o9y}@sF7> o9y}@sF7> o9y}@sF7> o9yɓ'_4dɒ 6Ķ۷o?~!66رcWvڵ*F 999 Aټj*R }Ѱ0!D^^B"@III}}}bbUl m>@KJJ.\bEjuLL6رc@@"''[n:*憅_Ŷsd ''wV3R]];$&&ũT*!ć~8lذ{K3f(++۷";;;..n}曷lyGy$11[o]lڵ+---))iΜ9999 ~%sd '''%%%<<3|ofyj[olٲo;wLJJ2ebƌӦM{n' 6W^BTTT;k׮;vXp[og !ݢh***Ο?sk֬1cÇkkk,Xp¾}=SgϞUZ)??:ujTTTJJRB]t={vhhhjjرc7o,7o޸qƌ=k,s- Je\\\s[t;vXZZf=͛ӧOfyB>vX ݻwB|3gld2TTT:t_ zr~@EDGGtO>dÆ YYY G{IMM]x[oݺ5(((""B֥Kϟfeevm6"66yΝ;(By~h?U^^bŊ(^o0Ck޼yRi~INNNrrKLLT*3^YYm۶Çzm o9y}@sF7> o9y}@EꃄIENDB`ffcvt-1.5.05/bintray-bin.json000066400000000000000000000013271360321750700160320ustar00rootroot00000000000000{ "package": { "name": "ffcvt", "repo": "bin", "subject": "suntong", "desc": "ffmpeg convert wrapper tool", "website_url": "https://github.com/suntong/ffcvt", "issue_tracker_url": "https://github.com/suntong/ffcvt/issues", "vcs_url": "https://github.com/suntong/ffcvt.git", "licenses": ["MIT"], "public_download_numbers": false }, "version": { "name": "$VERSION", "desc": "Release $VERSION", "released": "$DATE", "gpgSign": false }, "files": [{ "includePattern": "out/(.*)", "uploadPattern": "$VERSION/$1", "matrixParams": { "override": 1 } }], "publish": true } ffcvt-1.5.05/bintray-pkg.json000066400000000000000000000016251360321750700160440ustar00rootroot00000000000000{ "package": { "name": "ffcvt", "repo": "deb", "subject": "suntong", "desc": "ffmpeg convert wrapper tool", "website_url": "https://github.com/suntong/ffcvt", "issue_tracker_url": "https://github.com/suntong/ffcvt/issues", "vcs_url": "https://github.com/suntong/ffcvt.git", "licenses": ["MIT"], "public_download_numbers": false }, "version": { "name": "$VERSION", "desc": "Release $VERSION", "released": "$DATE", "vcs_tag": "$VERSION", "gpgSign": true }, "files": [{ "includePattern": "pkg/(.*)\\.deb", "uploadPattern": "pool/main/f/$1_$VERSION_amd64.deb", "matrixParams": { "deb_distribution": "all", "deb_component": "main", "deb_architecture": "amd64", "override": 1 } }], "publish": true } ffcvt-1.5.05/config.go000066400000000000000000000227131360321750700145170ustar00rootroot00000000000000// !!! !!! // WARNING: Code automatically generated. Editing discouraged. // !!! !!! package main import ( "flag" "fmt" "os" ) //////////////////////////////////////////////////////////////////////////// // Constant and data type/structure definitions const progname = "ffcvt" // os.Args[0] // The Options struct defines the structure to hold the commandline values type Options struct { Target string // target type: webm/x265-opus/x264-mp3/youtube Encoding // anonymous field to hold encoding values Directory string // directory that hold input files File string // input file name (either -d or -f must be specified) Links bool // symlinks will be processed as well Exts string // extension list for all the files to be queued Suffix string // suffix to the output file names WDirectory string // work directory that hold output files AC bool // copy audio codec VC bool // copy video codec AN bool // no audio, output video only VN bool // no video, output audio only VSS bool // video: same size Lang string // language selection for audio stream extraction OptExtra string // more options that will pass to ffmpeg program A2Opus bool // audio encode to opus, using -abr V2X265 bool // video video encode to x265, using -crf Par2C bool // par2create, create par2 files (in work directory) NoClobber bool // no clobber, do not queue those already been converted NoExec bool // no exec, dry run Force bool // overwrite any existing none-empty file Debug int // debugging level FFMpeg string // ffmpeg program executable name FFProbe string // ffprobe program execution PrintV bool // print version then exit } //////////////////////////////////////////////////////////////////////////// // Global variables definitions // Opts holds the actual values from the command line parameters var Opts Options //////////////////////////////////////////////////////////////////////////// // Commandline definitions func init() { // set default values for command line parameters flag.StringVar(&Opts.Target, "t", "webm", "target type: webm/x265-opus/x264-mp3/youtube") flag.StringVar(&Opts.VES, "ves", "", "video encoding method set") flag.StringVar(&Opts.AES, "aes", "", "audio encoding method set") flag.StringVar(&Opts.SES, "ses", "", "subtitle encoding method set") flag.StringVar(&Opts.VEP, "vep", "", "video encoding method prepend") flag.StringVar(&Opts.AEP, "aep", "", "audio encoding method prepend") flag.StringVar(&Opts.SEP, "sep", "", "subtitle encoding method prepend") flag.StringVar(&Opts.VEA, "vea", "", "video encoding method append") flag.StringVar(&Opts.AEA, "aea", "", "audio encoding method append") flag.StringVar(&Opts.ABR, "abr", "", "audio bitrate (64k for opus, 256k for mp3)") flag.StringVar(&Opts.CRF, "crf", "", "the CRF value: 0-51. Higher CRF gives lower quality\n\t (28 for x265, ~ 23 for x264)") flag.StringVar(&Opts.Directory, "d", "", "directory that hold input files") flag.StringVar(&Opts.File, "f", "", "input file name (either -d or -f must be specified)") flag.BoolVar(&Opts.Links, "sym", false, "symlinks will be processed as well") flag.StringVar(&Opts.Exts, "exts", ".3GP.3G2.ASF.AVI.DAT.DIVX.FLV.M2TS.M4V.MKV.MOV.MPEG.MP4.MPG.RMVB.RM.TS.VOB.WEBM.WMV", "extension list for all the files to be queued") flag.StringVar(&Opts.Suffix, "suf", "", "suffix to the output file names") flag.StringVar(&Opts.Ext, "ext", "", "extension for the output file") flag.StringVar(&Opts.WDirectory, "w", "", "work directory that hold output files") flag.BoolVar(&Opts.AC, "ac", false, "copy audio codec") flag.BoolVar(&Opts.VC, "vc", false, "copy video codec") flag.BoolVar(&Opts.AN, "an", false, "no audio, output video only") flag.BoolVar(&Opts.VN, "vn", false, "no video, output audio only") flag.BoolVar(&Opts.VSS, "vss", true, "video: same size") flag.StringVar(&Opts.Lang, "lang", "eng", "language selection for audio stream extraction") flag.StringVar(&Opts.OptExtra, "o", "", "more options that will pass to ffmpeg program") flag.BoolVar(&Opts.A2Opus, "ato-opus", false, "audio encode to opus, using -abr") flag.BoolVar(&Opts.V2X265, "vto-x265", false, "video video encode to x265, using -crf") flag.BoolVar(&Opts.Par2C, "p", false, "par2create, create par2 files (in work directory)") flag.BoolVar(&Opts.NoClobber, "nc", false, "no clobber, do not queue those already been converted") flag.BoolVar(&Opts.NoExec, "n", false, "no exec, dry run") flag.BoolVar(&Opts.Force, "force", false, "overwrite any existing none-empty file") flag.IntVar(&Opts.Debug, "debug", 1, "debugging level") flag.StringVar(&Opts.FFMpeg, "ffmpeg", "ffmpeg", "ffmpeg program executable name") flag.StringVar(&Opts.FFProbe, "ffprobe", "ffprobe -print_format flat", "ffprobe program execution") flag.BoolVar(&Opts.PrintV, "version", false, "print version then exit") // Now override those default values from environment variables if len(Opts.Target) == 0 || len(os.Getenv("FFCVT_T")) != 0 { Opts.Target = os.Getenv("FFCVT_T") } if len(Opts.VES) == 0 || len(os.Getenv("FFCVT_VES")) != 0 { Opts.VES = os.Getenv("FFCVT_VES") } if len(Opts.AES) == 0 || len(os.Getenv("FFCVT_AES")) != 0 { Opts.AES = os.Getenv("FFCVT_AES") } if len(Opts.SES) == 0 || len(os.Getenv("FFCVT_SES")) != 0 { Opts.SES = os.Getenv("FFCVT_SES") } if len(Opts.VEP) == 0 || len(os.Getenv("FFCVT_VEP")) != 0 { Opts.VEP = os.Getenv("FFCVT_VEP") } if len(Opts.AEP) == 0 || len(os.Getenv("FFCVT_AEP")) != 0 { Opts.AEP = os.Getenv("FFCVT_AEP") } if len(Opts.SEP) == 0 || len(os.Getenv("FFCVT_SEP")) != 0 { Opts.SEP = os.Getenv("FFCVT_SEP") } if len(Opts.VEA) == 0 || len(os.Getenv("FFCVT_VEA")) != 0 { Opts.VEA = os.Getenv("FFCVT_VEA") } if len(Opts.AEA) == 0 || len(os.Getenv("FFCVT_AEA")) != 0 { Opts.AEA = os.Getenv("FFCVT_AEA") } if len(Opts.ABR) == 0 || len(os.Getenv("FFCVT_ABR")) != 0 { Opts.ABR = os.Getenv("FFCVT_ABR") } if len(Opts.CRF) == 0 || len(os.Getenv("FFCVT_CRF")) != 0 { Opts.CRF = os.Getenv("FFCVT_CRF") } if len(Opts.Directory) == 0 || len(os.Getenv("FFCVT_D")) != 0 { Opts.Directory = os.Getenv("FFCVT_D") } if len(Opts.File) == 0 || len(os.Getenv("FFCVT_F")) != 0 { Opts.File = os.Getenv("FFCVT_F") } if len(Opts.Exts) == 0 || len(os.Getenv("FFCVT_EXTS")) != 0 { Opts.Exts = os.Getenv("FFCVT_EXTS") } if len(Opts.Suffix) == 0 || len(os.Getenv("FFCVT_SUF")) != 0 { Opts.Suffix = os.Getenv("FFCVT_SUF") } if len(Opts.Ext) == 0 || len(os.Getenv("FFCVT_EXT")) != 0 { Opts.Ext = os.Getenv("FFCVT_EXT") } if len(Opts.WDirectory) == 0 || len(os.Getenv("FFCVT_W")) != 0 { Opts.WDirectory = os.Getenv("FFCVT_W") } if len(Opts.Lang) == 0 || len(os.Getenv("FFCVT_LANG")) != 0 { Opts.Lang = os.Getenv("FFCVT_LANG") } if len(Opts.OptExtra) == 0 || len(os.Getenv("FFCVT_O")) != 0 { Opts.OptExtra = os.Getenv("FFCVT_O") } if len(Opts.FFMpeg) == 0 || len(os.Getenv("FFCVT_FFMPEG")) != 0 { Opts.FFMpeg = os.Getenv("FFCVT_FFMPEG") } if len(Opts.FFProbe) == 0 || len(os.Getenv("FFCVT_FFPROBE")) != 0 { Opts.FFProbe = os.Getenv("FFCVT_FFPROBE") } } const USAGE_SUMMARY = " -t\ttarget type: webm/x265-opus/x264-mp3/youtube (FFCVT_T)\n -ves\tvideo encoding method set (FFCVT_VES)\n -aes\taudio encoding method set (FFCVT_AES)\n -ses\tsubtitle encoding method set (FFCVT_SES)\n -vep\tvideo encoding method prepend (FFCVT_VEP)\n -aep\taudio encoding method prepend (FFCVT_AEP)\n -sep\tsubtitle encoding method prepend (FFCVT_SEP)\n -vea\tvideo encoding method append (FFCVT_VEA)\n -aea\taudio encoding method append (FFCVT_AEA)\n -abr\taudio bitrate (64k for opus, 256k for mp3) (FFCVT_ABR)\n -crf\tthe CRF value: 0-51. Higher CRF gives lower quality\n\t (28 for x265, ~ 23 for x264) (FFCVT_CRF)\n\n -d\tdirectory that hold input files (FFCVT_D)\n -f\tinput file name (either -d or -f must be specified) (FFCVT_F)\n -sym\tsymlinks will be processed as well (FFCVT_SYM)\n -exts\textension list for all the files to be queued (FFCVT_EXTS)\n -suf\tsuffix to the output file names (FFCVT_SUF)\n -ext\textension for the output file (FFCVT_EXT)\n -w\twork directory that hold output files (FFCVT_W)\n\n -ac\tcopy audio codec (FFCVT_AC)\n -vc\tcopy video codec (FFCVT_VC)\n -an\tno audio, output video only (FFCVT_AN)\n -vn\tno video, output audio only (FFCVT_VN)\n -vss\tvideo: same size (FFCVT_VSS)\n -lang\tlanguage selection for audio stream extraction (FFCVT_LANG)\n -o\tmore options that will pass to ffmpeg program (FFCVT_O)\n -ato-opus\taudio encode to opus, using -abr (FFCVT_ATO_OPUS)\n -vto-x265\tvideo video encode to x265, using -crf (FFCVT_VTO_X265)\n\n -p\tpar2create, create par2 files (in work directory) (FFCVT_P)\n -nc\tno clobber, do not queue those already been converted (FFCVT_NC)\n -n\tno exec, dry run (FFCVT_N)\n\n -force\toverwrite any existing none-empty file (FFCVT_FORCE)\n -debug\tdebugging level (FFCVT_DEBUG)\n -ffmpeg\tffmpeg program executable name (FFCVT_FFMPEG)\n -ffprobe\tffprobe program execution (FFCVT_FFPROBE)\n -version\tprint version then exit (FFCVT_VERSION)\n\nDetails:\n\n" // Usage function shows help on commandline usage func Usage() { fmt.Fprintf(os.Stderr, "\nUsage:\n %s [flags] \n\nFlags:\n\n", progname) fmt.Fprintf(os.Stderr, USAGE_SUMMARY) flag.PrintDefaults() fmt.Fprintf(os.Stderr, "\nTo reduce output, use `-debug 0`, e.g., `ffcvt -force -debug 0 -f testf.mp4 ...`\n") os.Exit(0) } ffcvt-1.5.05/ffcvt.1.ronn000066400000000000000000000031651360321750700150700ustar00rootroot00000000000000# ffcvt -- ffmpeg convert wrapper tool ## SYNOPSIS ffcvt [flags] [video_filename] ## OPTIONS For `flags`, run `ffcvt` without parameters to see the comprehensive list and explanation. ## DESCRIPTION Command `ffcvt` is an easy to use video converter that takes the burden of such daunting task from normal Joe, to harness the fantastic high efficiency audio/video codec/encoding capability long been available in `ffmpeg`, by simplifying the convoluted `ffmpeg` command line parameters. To encode a video, all you need to do is to give one parameter to `ffcvt`, i.e., the path and file name of the video to be encoded, and `ffcvt` will take care of the rest, using the recommended values for both audio/video encoding to properly encode it for you. It can't be more simpler than that. However, beneath the simple surface, `ffcvt` is versatile and powerful enough to allow you to touch every corner of audio/video encoding. There is a huge list of environment variables (or command-line parameters) which will allow you tweak the encoding methods and parameters to exactly what you prefer instead. Moreover, to encode a directory full of video files, including under its sub-directories, you need just to give `ffcvt` one single parameter, the directory location, and `ffcvt` will go ahead and encode all video files under that directory, including all its sub-directories as well. ## EXAMPLES `ffcvt` comes with comprehensive online documents. For further details, please go to: https://github.com/suntong/ffcvt#encoding-help https://github.com/suntong/ffcvt/wiki ## SEE ALSO `ffmpeg(1)` ## AUTHORS Tong Sun ffcvt-1.5.05/ffcvt.go000066400000000000000000000311401360321750700143540ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////// // Porgram: FfCvt // Purpose: ffmpeg convert wrapper tool // Authors: Tong Sun (c) 2015-2019, All rights reserved //////////////////////////////////////////////////////////////////////////// /* Transcodes all videos in the given directory and all of it's subdirectories using ffmpeg. */ //go:generate sh -x ffcvt_cli.sh //////////////////////////////////////////////////////////////////////////// // Program start package main import ( "bytes" "flag" "fmt" "log" "os" "os/exec" "path" "path/filepath" "regexp" "strings" "time" ) //////////////////////////////////////////////////////////////////////////// // Constant and data type/structure definitions const _encodedExt = "_.mkv" //////////////////////////////////////////////////////////////////////////// // Global variables definitions var ( version = "1.5.05" date = "2020-01-01" sprintf = fmt.Sprintf encodedExt string = _encodedExt totalOrg int64 = 1 totalNew int64 = 1 videos []string workDirs []string ) //////////////////////////////////////////////////////////////////////////// // Main func main() { flag.Usage = Usage flag.Parse() if Opts.PrintV { fmt.Fprintf(os.Stderr, "%s\nVersion %s built on %s\n", progname, version, date) os.Exit(0) } // One mandatory arguments, either -d or -f if len(Opts.Directory)+len(Opts.File) < 1 { Usage() } getDefault() encodedExt = Opts.Ext // Sanity check if Opts.WDirectory != "" { // To error on the safe side -- when -d is not given but -f is, // path.Clean(Opts.Directory) will return ".", thus forcing // the work directory cannot be the same as pwd // because the encodedExt might be conflicting with the source file encodedExt = encodedExt[1:] // now ".mkv" Opts.Directory = path.Clean(Opts.Directory) Opts.WDirectory = path.Clean(Opts.WDirectory) absd, _ := filepath.Abs(Opts.Directory) // The basename of the source directory will be created under the work //directory, which will become the new work directory if Opts.File == "" { Opts.WDirectory += string(os.PathSeparator) + filepath.Base(absd) } absw, _ := filepath.Abs(Opts.WDirectory) if absd == absw { log.Fatalf("[%s] Error: work directory\n\t\t (%s)\n\t\t is the same as the source directory\n\t\t (%s).", progname, absw, absd) } debug("Transcoding to "+Opts.WDirectory, 2) err := os.MkdirAll(Opts.WDirectory, os.ModePerm) checkError(err) } else { Opts.Par2C = false } startTime := time.Now() // transcoding if Opts.File != "" { fmt.Printf("\n== Transcoding: %s\n", Opts.File) transcodeFile(Opts.File) } else if Opts.Directory != "" { filepath.Walk(Opts.Directory, visit) transcodeVideos(startTime) } // par2 creating if Opts.Par2C { filepath.Walk(Opts.WDirectory, visitWDir) createPar2s(workDirs) } // reporting fmt.Printf("\nTranscoding completed in %s\n", time.Since(startTime)) fmt.Printf("Org Size: %d MB\n", totalOrg/1024) fmt.Printf("New Size: %d MB\n", totalNew/1024) fmt.Printf("Saved: %d%%\n", (totalOrg-totalNew)*100/totalOrg) } //////////////////////////////////////////////////////////////////////////// // Function definitions //========================================================================== // Directory & files handling func visit(path string, f os.FileInfo, err error) error { if f.IsDir() { return nil } appendVideo(Opts.Directory + string(os.PathSeparator) + path) return nil } // Append the video file to the list, unless it's encoded already func appendVideo(fname string) { if Opts.WDirectory == "" && fname[len(fname)-5:] == encodedExt { debug("Already-encoded file ignored: "+fname, 1) return } fext := strings.ToUpper(fname[len(fname)-4:]) if strings.Index(Opts.Exts, fext) < 0 { debug("None-video file ignored: "+fname, 3) return } if !Opts.Links && isSymlink(fname) { debug("Skip symlink file: "+fname, 1) return } if Opts.NoClobber && fileExist(getOutputName(fname)) { debug("Encoded file exist for: "+fname, 1) return } videos = append(videos, fname) } func visitWDir(path string, f os.FileInfo, err error) error { if !f.IsDir() { return nil } debug(path, 2) workDirs = append(workDirs, path) return nil } func createPar2s(workDirs []string) { fmt.Printf("\n== Creating par2 files\n\n") for ii, dir := range workDirs { if ii == 0 && len(workDirs) > 1 { // skip the root folder, if there are sub folders continue } os.Chdir(dir) dirName := filepath.Base(dir) cmd := []string{"par2create", "-u", "zz_" + dirName + ".par2", "*" + encodedExt} debug(strings.Join(cmd, " "), 1) out, err := exec.Command(cmd[0], cmd[1:]...).CombinedOutput() if err != nil { log.Printf("%s: Exec error - %s", progname, err.Error()) } fmt.Printf("%s\n", out) } } //========================================================================== // Transcode handling // Transcode videos in the global videos array func transcodeVideos(startTime time.Time) { videosTotal := len(videos) for i, inputName := range videos { videoNdx := i + 1 fmt.Printf("\n== Transcoding [%d/%d]: '%s'\n under %s\n", videoNdx, videosTotal, filepath.Base(inputName), filepath.Dir(inputName)) transcodeFile(inputName) fmt.Printf("Time taken so far %s\n", time.Since(startTime)) fmt.Printf("Finishing the remaining %d%% in %s\n", (videosTotal-videoNdx)*100/videosTotal, time.Duration(int64(float32(time.Since(startTime))* float32(videosTotal-videoNdx)/float32(videoNdx)))) } } func transcodeFile(inputName string) { startTime := time.Now() outputName := getOutputName(inputName) debug(outputName, 4) os.MkdirAll(filepath.Dir(outputName), os.ModePerm) var oldAEP, oldVEP, oldSEP string oldEPUsed := false if !Opts.NoExec { // probe the file stream info first, only when not using -n fsinfo, err := probeFile(inputName) if err != nil { log.Printf("%s: Probe error - %s", progname, err.Error()) return } debug(fsinfo, 4) // if there are more than one audio stream allAudioStreams := regexp.MustCompile(`Stream #0:.+: Audio: (.+)`). FindAllStringSubmatch(fsinfo, -1) if len(allAudioStreams) > 1 { // then find the designated audio stream language audioStreams := regexp. MustCompile(`Stream #(.+)\(` + Opts.Lang + `\): Audio: (.+)`). FindStringSubmatch(fsinfo) if len(audioStreams) >= 1 { // and use the 1st audio stream of the designated language // via *temporarily* tweaking AEP/VEP/SEP setting oldAEP, oldVEP, oldSEP = Opts.AEP, Opts.VEP, Opts.SEP oldEPUsed = true debug(audioStreams[1], 3) Opts.AEP += " -map " + audioStreams[1] dealSurroundSound(audioStreams[2]) // when `-map` is used (for audio), then all else need mapping as well videoStreams := regexp.MustCompile(`Stream #(.+?)(\(.+\))*: Video: `). FindStringSubmatch(fsinfo) Opts.VEP += " -map " + videoStreams[1] subtitleStreams := regexp.MustCompile(`Stream #(.+)\(.+\): Subtitle: `). FindAllStringSubmatch(fsinfo, -1) // keep all subtitle streams for _, subtitleStream := range subtitleStreams { Opts.SEP += " -map " + subtitleStream[1] } } // else: designated audio language not found, use `default` instead } else { debug(inputName+" has single audio stream", 2) dealSurroundSound(allAudioStreams[0][1]) } } args := encodeParametersS(encodeParametersA(encodeParametersV( []string{"-i", inputName}))) if Opts.Force { args = append(args, "-y") } args = append(args, strings.Fields(Opts.OptExtra)...) args = append(args, flag.Args()...) args = append(args, outputName) debug(Opts.FFMpeg+" "+strings.Join(args, " "), 1) if Opts.NoExec { fmt.Printf("%s: to execute -\n %s %s\n", progname, Opts.FFMpeg, strings.Join(args, " ")) } else { //fmt.Printf("] %#v\n", args) cmd := exec.Command(Opts.FFMpeg, args...) var out, errOut bytes.Buffer cmd.Stdout = &out cmd.Stderr = &errOut err := cmd.Run() if err != nil { log.Printf("%s: Exec error - %s\n\n%s", progname, err.Error(), string(errOut.Bytes())) } fmt.Printf("%s\n", out.String()) timeTake := time.Since(startTime) if err != nil { fmt.Println("Failed.") // == remove zero-sized output file file, err := os.Open(outputName) checkError(err) // get the file size stat, err := file.Stat() file.Close() checkError(err) //fmt.Println("File size is ", stat.Size()) if stat.Size() == 0 { err := os.Remove(outputName) checkError(err) } debug("Zero-sized output file '"+outputName+"' removed.", 1) } else { originalSize := fileSize(inputName) transcodedSize := fileSize(outputName) sizeDifference := originalSize - transcodedSize totalOrg += originalSize totalNew += transcodedSize fmt.Println("Done.") fmt.Printf("Org Size: %d KB\n", originalSize) fmt.Printf("New Size: %d KB\n", transcodedSize) fmt.Printf("Saved: %d%% with %d KB\n", sizeDifference*100/originalSize, sizeDifference) fmt.Printf("Time: %v at %v\n\n", timeTake, time.Now().Format("2006-01-02 15:04:05")) } if oldEPUsed { // restored *temporarily* tweaked AEP/VEP/SEP setting Opts.AEP, Opts.VEP, Opts.SEP = oldAEP, oldVEP, oldSEP } } return } // dealSurroundSound will append to Opts.AEP proper setting to encode // 5.1 surround sound channels func dealSurroundSound(channelFeatures string) { if regexp.MustCompile(`, 5.1\(side\), `).MatchString(channelFeatures) { Opts.AEP += " -ac 2" } } func probeFile(inputName string) (string, error) { out := &bytes.Buffer{} cmd := exec.Command("sh", "-c", Opts.FFProbe+" "+inputName+ " 2>&1 | grep 'Stream #'") cmd.Stdout = out cmd.Stderr = out err := cmd.Run() return string(out.Bytes()), err } // Returns the encode parameters for Subtitle func encodeParametersS(args []string) []string { if Opts.SEP != "" { args = append(args, strings.Fields(Opts.SEP)...) } if Opts.SES != "" { args = append(args, strings.Fields(Opts.SES)...) } return args } // Returns the encode parameters for Audio func encodeParametersA(args []string) []string { if Opts.AEP != "" { args = append(args, strings.Fields(Opts.AEP)...) } if Opts.AC { args = append(args, "-c:a", "copy") return args } if Opts.AN { args = append(args, "-an") return args } if Opts.A2Opus { Opts.AES = "libopus" } if Opts.AES != "" { args = append(args, "-c:a", Opts.AES) } if Opts.ABR != "" { args = append(args, "-b:a", Opts.ABR) } if Opts.AEA != "" { args = append(args, strings.Fields(Opts.AEA)...) } return args } // Returns the encode parameters for Video func encodeParametersV(args []string) []string { if Opts.VEP != "" { args = append(args, strings.Fields(Opts.VEP)...) } if Opts.VC { args = append(args, "-c:v", "copy") return args } if Opts.VN { args = append(args, "-vn") return args } if Opts.V2X265 { Opts.VES = "libx265" } if Opts.VES != "" { args = append(args, "-c:v", Opts.VES) } if Opts.CRF != "" { if Opts.VES == "libvpx-vp9" { // -b:v 0 -crf 37 args = append(args, "-b:v", "0", "-crf", Opts.CRF) } if Opts.VES[:6] == "libx26" { args = append(args, "-"+Opts.VES[3:]+"-params", "crf="+Opts.CRF) } } if Opts.VEA != "" { args = append(args, strings.Fields(Opts.VEA)...) } return args } //========================================================================== // Dealing with Files // Returns true if the file is symbolic link func isSymlink(fname string) bool { fi, err := os.Lstat(fname) checkError(err) return fi.Mode()&os.ModeSymlink != 0 } // Returns true if the file exist func fileExist(fname string) bool { _, err := os.Stat(fname) return err == nil } // Returns the file size func fileSize(fname string) int64 { stat, err := os.Stat(fname) checkError(err) return stat.Size() / 1024 } // Replaces the file extension from the input string with _.mkv, and optionally // Opts.Suffix as well. If "-w" is defined, use it for output name. func getOutputName(input string) string { index := strings.LastIndex(input, ".") if index > 0 { input = input[:index] } r := input + Opts.Suffix + encodedExt //fmt.Printf("] (r, od, owd) %+v, %+v, %+v\n", r, Opts.Directory, Opts.WDirectory) if Opts.WDirectory != "" { // transcoding single file if Opts.File != "" { r = Opts.WDirectory + "/" + filepath.Base(input) + Opts.Suffix + encodedExt } else { r = strings.Replace(r, Opts.Directory, Opts.WDirectory, 1) } } return r } //========================================================================== // Support functions func debug(input string, threshold int) { if !(Opts.Debug >= threshold) { return } print("] ") print(input) print("\n") } func checkError(err error) { if err != nil { log.Printf("%s: Fatal error - %s", progname, err.Error()) os.Exit(1) } } ffcvt-1.5.05/ffcvt_cli.sh000077500000000000000000000010441360321750700152130ustar00rootroot00000000000000templateFile=$GOPATH/src/github.com/go-easygen/easygen/test/commandlineFlag [ -s $templateFile.tmpl ] || templateFile=/usr/share/gocode/src/github.com/go-easygen/easygen/test/commandlineFlag [ -s $templateFile.tmpl ] || templateFile=/usr/share/doc/easygen/examples/commandlineFlag [ -s $templateFile.tmpl ] || { echo No template file found exit 1 } easygen $templateFile ffcvt_cli | sed '/\tVES\t\tstring/{ N; N; N; N; N; N; N; N; N; s|^.*$|\tEncoding\t// anonymous field to hold encoding values|; }; /\tExt\t\tstring/d; ' | gofmt > config.go ffcvt-1.5.05/ffcvt_cli.yaml000066400000000000000000000134551360321750700155510ustar00rootroot00000000000000# easygen data driven file for ffcvt commandline handling # # easygen -tf $GOPATH/src/github.com/go-easygen/easygen/test/commandlineFlag ffcvt_cli | sed '/\tAES\t\tstring/{ N; N; N; N; N; s|^.*$|\tEncoding\t// anonymous field to hold encoding values|; }; /\tExt\t\tstring/d; ' | gofmt > config.go # # Ref, old code log: # ... | sed -n '/ The Options struct /{N; N; N; N; N; N; N; p; q; }' | tee -a structEnc.go # program name, name for the executable ProgramName: ffcvt # package name # - For standalone program that does not belong to any package, e.g., # https://github.com/suntong001/easygen/blob/7791e4f0e5605543d27da1671a21376cdb9dcf2a/easygen/easygen.go # just ignore the first line, the `package` output, and copy the rest # - If you don't mind using a separated file to handle commandline paramters, # then name the package as "main". see the spin-out "TF-minus1.go" file under # https://github.com/suntong001/easygen/tree/d1ab0b5fe80ddac57fe9ef51f6ccb3ab998cd5ee # - If you are using it in a pacakge, look no further than # https://github.com/suntong001/easygen/blob/master/easygenapi/config.go # which was a direct dump: easygen test/commandlineFlag > easygenapi/config.go # PackageName: main # Name of the structure to hold the values for/from commandline StructName: Options # The actual variable that hold the commandline paramter values StructVar: Opts Options: # Basic fields for encoding - Name: Target Type: string Flag: t Value: '"webm"' Usage: "target type: webm/x265-opus/x264-mp3/youtube" - Name: VES Type: string Flag: ves Value: '""' Usage: "video encoding method set" - Name: AES Type: string Flag: aes Value: '""' Usage: "audio encoding method set" - Name: SES Type: string Flag: ses Value: '""' Usage: "subtitle encoding method set" - Name: VEP Type: string Flag: vep Value: '""' Usage: "video encoding method prepend" - Name: AEP Type: string Flag: aep Value: '""' Usage: "audio encoding method prepend" - Name: SEP Type: string Flag: sep Value: '""' Usage: "subtitle encoding method prepend" - Name: VEA Type: string Flag: vea Value: '""' Usage: "video encoding method append" - Name: AEA Type: string Flag: aea Value: '""' Usage: "audio encoding method append" - Name: ABR Type: string Flag: abr Value: '""' Usage: "audio bitrate (64k for opus, 256k for mp3)" - Name: CRF Type: string Flag: crf Value: '""' Usage: "the CRF value: 0-51. Higher CRF gives lower quality\\n\\t (28 for x265, ~ 23 for x264)" - Name: SEPARATOR # Optional parameters that controls the encoding - Name: Directory Type: string Flag: d Value: '""' Usage: "directory that hold input files" - Name: File Type: string Flag: f Value: '""' Usage: "input file name (either -d or -f must be specified)" - Name: Links Type: bool Flag: sym Value: false Usage: symlinks will be processed as well # - Name: File # Type: string # Flag: fs # Value: '""' # Usage: "file supplements, more files to encode (in form of: -i f2 -i f3...)" - Name: Exts Type: string Flag: exts Value: '".3GP.3G2.ASF.AVI.DAT.DIVX.FLV.M2TS.M4V.MKV.MOV.MPEG.MP4.MPG.RMVB.RM.TS.VOB.WEBM.WMV"' Usage: "extension list for all the files to be queued" - Name: Suffix Type: string Flag: suf Value: '""' Usage: "suffix to the output file names" - Name: Ext Type: string Flag: ext Value: '""' Usage: "extension for the output file" - Name: WDirectory Type: string Flag: w Value: '""' Usage: "work directory that hold output files" - Name: SEPARATOR - Name: AC Type: bool Flag: ac Value: false Usage: copy audio codec - Name: VC Type: bool Flag: vc Value: false Usage: copy video codec - Name: AN Type: bool Flag: an Value: false Usage: no audio, output video only - Name: VN Type: bool Flag: vn Value: false Usage: no video, output audio only - Name: VSS Type: bool Flag: vss Value: true Usage: "video: same size" - Name: Lang Type: string Flag: lang Value: '"eng"' Usage: "language selection for audio stream extraction" - Name: OptExtra Type: string Flag: o Value: '""' Usage: "more options that will pass to ffmpeg program" - Name: A2Opus Type: bool Flag: ato-opus Value: false Usage: "audio encode to opus, using -abr" - Name: V2X265 Type: bool Flag: vto-x265 Value: false Usage: "video video encode to x265, using -crf" - Name: SEPARATOR - Name: Par2C Type: bool Flag: "p" Value: false Usage: "par2create, create par2 files (in work directory)" - Name: NoClobber Type: bool Flag: nc Value: false Usage: "no clobber, do not queue those already been converted" - Name: NoExec Type: bool Flag: "n" Value: false Usage: "no exec, dry run" - Name: SEPARATOR - Name: Force Type: bool Flag: force Value: false Usage: overwrite any existing none-empty file - Name: Debug Type: int Flag: debug Value: 1 Usage: debugging level - Name: FFMpeg Type: string Flag: ffmpeg Value: '"ffmpeg"' Usage: "ffmpeg program executable name" - Name: FFProbe Type: string Flag: ffprobe Value: '"ffprobe -print_format flat"' Usage: "ffprobe program execution" - Name: PrintV Type: bool Flag: "version" Value: false Usage: "print version then exit" # Use the USAGE_SUMMARY in Usage help UsageSummary: "TRUE" UsageLead: "\\nUsage:\\n %s [flags] \\n\\nFlags:\\n\\n" UsageEnd: "\\nTo reduce output, use `-debug 0`, e.g., `ffcvt -force -debug 0 -f testf.mp4 ...`\\n" ffcvt-1.5.05/ffcvt_proj.yaml000066400000000000000000000002221360321750700157400ustar00rootroot00000000000000Wireframe: Proj: ffcvt Desc: ffmpeg convert wrapper tool Lang: Go Vendor: suntong Author: Tong Sun License: MIT ffcvt-1.5.05/preset-large.png000066400000000000000000000457301360321750700160270ustar00rootroot00000000000000PNG  IHDR_ gAMA a cHRMz&u0`:pQ<bKGDtIME.JIDATxy|EU=dI&$1$ @#{躮ouuW]EtQ[rpʍH df92Ww1GB&-Vw}[UߪBRp8YjJr8Ngpp8*p8Up:$tWI \%93Jr8Ng\F*(,˔P(DH.uEQ%"q8}tf#('C';hr?۟Nl?19c:?>8sYL#V^?gݷo &Ca kJq)u9"~?K!;Sz>D3|pٲe_}Up?}_%zkK,PJ!DQ`0466ʲbg`0^! }>B555˲|ĉP( B c1gΜ:Ƹ#1m z.KQ.N'>R,?,o6%zn78s*p.1BAXn]yyyKKW_}[om޼9&&FV}wqGVV_|M6 87:c~[njkkx͛7O<^_dIzzK/{̗_~Gٿ5\3t/^'D-\W^1͋//_{{矯kkk޿W^yj>䓿/kjjn/Xছnh4|… ĉ>`(z[֤_gks83}I1̜9sO<ĵ^{5$%%]y?f{饗EO|ɥK1b׮]ߏ=rʄ g|߮k}g}vԨQeee+WQ%??hŊcǎ裏222  |>kx_Ǐ_cǎqƽ n;vdovZә_Yr\nfKLL|WnwCCñcsrr4O?Ͼ=322lܸ7sA}_AV#AD^ǺdYx'2!;֮ (ʈ#RRRz=ٳ{fsaaa|||\\ B,KB].Ƙ)TR%''K !crZ 6mڔ Yj@o}F1}1VjZ,U8}IB`00d1VT^/I,?Os=7k֬W^yes>|=RBHLL̟^xWKy䑿;wLII)--mjj*((;G?tfddjr-O<~ႂm۶dV%IAtΜ9s'OhbEEŎ;rrrL裏>ӿկz) p.˨zu:] `bG)E1 J$bqqO{l~Q` ZB6-!!ARɲFfhdYjmmULZZZ4FikkSղ,Lj4'|N0TT---V1ƄV5MSSZ6L^Bh ,ǣPr8OG:=JB( ̗$1Ʊcǎ9z==j޼ys18??l6+RDQJNcrqLL c^gyE%LJrȺ222!VhKĒERj04 b.3!.H'ʸ|paĎ™'N~~Q{Z1m"\TP 3K)( b0C B1!a srd9/r.*˭9$<.ߪb!FJACv= L6Xǥ(Ӑ͢a& !b'rBEQ|E/JٻlU懲Yy[o5 mݺp555 _tnٻwozzΝ;[ZZZ[[-[ ڿej` l߾h֭{YvmRRhٳg/^h4t:YmV]]vF={***:xرc?^[[kZWZUPPPRRSJǏ+V(((8|p}}򪪪|>_VVV(zg̘۷رc6j۷"55ѣqqq999RRR֯_R.]zX^^Jrotȑ#V0`U*UbbbLLٳ[[[!`2XbIIIN7gΜCnJ+Ç?WTTAZ`TO)ill2eʍ7)))cƌIJJ?~ȑ#`G=|p~~~yy(92??ot8 ,6jٳfͪSL+Y$IfYѣG4(//@} v{JeZǏ߿5*77w̘1iii>`0]uU@@hZJhjkk QСC^ݎVhp./" Q@8 ׿kȑ# .6lZmEEĉ |ĉo￷Zx<={644L2eC 1L<ŒبjϞitW]m^?3N뉳Z%%%~?455m߾aNl6[kkkeY~222hdz92iҤ/Aׯʕ+M&Srrjkkkkkc*z=ʆF#k#mZCg4nw0lkk r<%9!~ ƍ+++YVWWgee{^IN81eʔEvmn#:Kd늭vMi3H38ai̠$)55l6577_wu{ \sF)))3fٳ)555SL̴Zknn8pJjkk۳g-ҿ6mcI&-[L:bUHUd DJgߪ2*2%#Aٳh4vmf֭ׯhZ(feeAfgg**33SՖ?~ĉ3g>|q$]ql6'''^x<NIIIMMeݑٳg9ra֬Y:ѣGnjcZ ZgeeLZLIIZqqqZWz3f_>--m„ t뭷&&&Yf̙l؝ %\~@g-H +FO\jR: ]D^,G7|s8l{a9ey޼y,[Ly%%%Ν;4͂ lٲ}v|\СCϏtr8[nݶmnhiiYzN W;S3S]QQQVVv}ÇBٲeÆ $iÆ sY~}mm󋋋ڸ{B.]СCUUU=Peeemmc~_游9 BСCsQT;v8~w•, ',Bz—dt:kkk-Z-lZzZa "l6[aa`p\xEQ8^WVt:ŲcTDbbRp.-*W_ ;v:theehl_yMkqu^_Tv,l[ak(#L&~N>B* :q].WxYӽ ,'Nܽ{7Ũ"s* .77۷o(F*))EQK8p-[88Z\\jsssC=Onnft֭.,,ܺukqqqyyٳBvvv\ҺH!j =Q $$$b~ izʏ=W IWVI(b 48pOn:e`DaWNdG(@#Gt{a @>QUpPa=C pD7wIAJA"H X;UV|psK_$'Z #fP-QC@@@!IƢ5įU|:œ+Mbe'qlPN+8Jr>1C"J1@)A #! V!:ū%%_c k͡f 1/6I 5jH.UJ( ~,D ioBȑWZu!{B&`hvJb!UJ'-nUڸ#ypp" @ %  c@hު̶-1ؠ4Yak " T(]xʄCX%$vF1\%9\82"y4Vm >shu]|s1M ^A&BHhH!ʘ-i+ѓA%m !"*) Tin ::V+iҳu3"(~: 4$PbT\R 6R@Nepp.)#lo۶!p`Ul;!$$2rtk*s'ǿ=4įU(E( K_OUn(B`B@7+847HiY>t1Z0PtA5͉BJr8-0!c+?dA޽!fi¿͏ 8"Np7R !EQ'B( v(J(Ic19( `_&f49ŹZ/G?] m^xF(p%VÕ7<LG!`?>'RPc O*W>Ѯ-v)ayvI4ʢ&5kB, !g9FFa7s*Ʉ2pիWL2Bgtk׮^{-tʕZv,UVY777]+>|xmmMƎۿvH-'*ak !iguKy- #d$7. Q )!UYY*1\sJZbE^^ްazy9doNk\yŔ6(yA§RA-!%>iTRzΧ,vuD.Ȯ5!acǎؑ#Gj%K 4$!!!557 e$+ 6 0 99ĉNرcdѣGl3f~pm544lٲe„ >宻2۶m# øq******1'SiU9]Nb@Vmew+Ӥ9j2$-SúǮ;zǏ:h ?~,//* [ܷo_eejkkf%''@SSSVVVuu58x9j4Qt޼yPO>$+**JMM6m믿n4͛7妛nꫯ^~̬,pA8瀚P$B/B*JvC˫vSp[wo|/Z?'ݮSL>ω ZA%fW7]v 'NxWA/'&&ԣ7|J$I>.gNJgv]8UN<[HJ_m&*svB* (CSV#sy XMc9㑙s8gDJv迫1uį QC||KJV{9Mձ+v390("Msxe}d]%>BF$b9r 1ws?/e>%vr Erz"#1T<=ijw<+?sßNSToc#c.wp2 VH/G@/*pJr,L"kՙO{EEA>Jù 雜HVi'5 T&\ ki'TisAq#K$ Q"EE:k$O) bDr ’D:P5HN7%9}D 3K &JrRR?S񈌤?eS\"9WING0fMg:(wNBoW>|P;v.X{oȑpQ^//|7 .⪲,vv Gs!N'z.\.L'# c~( 7N~C!D8De8KDWҡCN8qҤI_%Y{E`0xW B2d/^p8F=qDp\K,x<3gLMMdY7o(˖-$i޼yIIIs΢"F`-[l߾l6{+W|?w}W\\ܾy睂Н^޽`Ν[o/@l6ے%Kx ~ʄ裻v|PZZگ_ |wk׮0a7޸iӦoyرEEE999V:tУ>z꺺{pTVVBW>~ݺuՅ[n-...//={7|R^;ϧPQ@zCJ(BȒhkn΍2X$d䌡?,_A ^1$$ju_E)u`2֯__UU555_=tpkfKHHHKKO`Ν{ѩ[b˗/ᇧO(J~穩ƍ۲eܹs:rȺ;73f3&!!ARM4iʔ)1cl߾?n4hЀfϞ][[{UWeff^s5^{h< z^хw*/>de'Y{]ޟ*2th8s`nE]gH!0atMUTڭsB;vl@`0$%%Y,$x-{믯yw222mֿegE0bĈ#FB5jԨQqaa!L81\R3g1݇柇 ``Ga[v( Il؇w??_նHt]wAw*TQ ~Ȼ˴w7CQL566:t ^@ZR{SS#] MCܳ)_.Zl;D+(.X@ <2YTۻ8)lbC][}Q3(' /|d]@xsR'9fΝٷHNwv%ꀻA)._=lt8} b!_Xwr7D.WU bgx}hE>p8TAض[Ϥ9,H%Hg9+\%9=%HR^-qw0'T6USPAyOW:R!PE4_kz왿?%vIvrD/\%9 K)C}h?nh϶}k/g<%7O0@@PsW[/d>T%71 K0s?~釘d'HN߀?ǜ.) a)5{fr߮Sg.>9@6AS,--۶mׯ͛M&ի bŊh4v|YS:)'}^pYf)ЮEIi;ߖHYJwo2;U$h]ٝv @x`)tձ1!4}?V&)///Z<%B,2lNرc ѣG|866$I}d,!&%%%^W vb444řL&Bzt:]0|6-99tC_ш9IR"5V"&ɨdBR]L c9dc[q+ -4VvƇln`\XG% *ۍEBPJFL8$ ],zBgrE5j`(--ep8FJjJEQW:u… w=k,SJ͛ >IᄁiӦF߼y/lXn馯_ʂ7@s @(.!RDIh7iWXHjV6ٹ&ߵ'I[;% T"jرR@Tj%ɔ Aݠ}.֞kmm}Bonn~7M&\%;Dn`_^7!!AV{' Oac IBh)))ZV¼<^뮺*wK䥡]9PX-Gi-1+=1HW<&IO:@y<`-)S >\$rWh4V \%U&&&Z,tz 8k2oG:(f3=5qW7"̢(  !$FQn)woM6֫ӊo1MlTTA)eqqqFDBqb%.,PX? N),xdlǑA,Ho X$CIb,R(@ ԩ36N3ΦJ%^`X9j bi<-D%$GpdŹӢ!8Ct!=9#@N $9yH(@0q'Mq@ArT7`*mNī%mi9p.^UI/&Pfk{gIwԫS5)7"@6lT`L)rJHO ]]}C V{x\_>"7Mhq@IvAn㘲u[ b%Q\@)E#,н'(pxٶ|BH,PI !2d$OAmHd?R?J* i($ϫ8VlVM[׭:hĉ"UYՅ[-}sKdEM" iI^NNw<pNP5 $Hi_@iC V k1%KhdPPax\"B4 ^`L>hBFac, 1PLJRńd!͕ "z!{Ha>#P@|L9'\% ć&/-,N& PܢS2($Ґ9dG@)B@*iWתB)P$hIb^OH:@ @` 'G8U 5Ŀ4nwLj?5" (P@ (db72uL}M)P¼R ,@` S8膫dwB/ܥHaP&W?V,n[VhLHD Vh}, |8ùtpf:KAa:=ØD c Fs8wB83Jr8Ngpp8*p8Up:$tWI \%93Jr8Ngpp8*p8Up:$tWI \%93Jr8Ngpp8S*I)%uD{;*I)EEpbB4keQI턐HBry^u;о,{YX,==}g;Ɯ,sŕOߴ dz 'Ki78Lki:*#GVZ%¼y󒒒®e* n?coVeeevvvǛq{þǂ(JjQGD(,ܹ>4] #DI-J(h(a,,3`X_ϛ7ĉEEE# P@p8L&*\.WKK Bcu͍ud5ЉǏ:AQ!}.nSl5HI+pB+$np.jm/c YTTPBJv7duu;t:]ADDV"[1}.Mۅa„O>( jhh``eee(\˗YFL0z޽&iҤIO=o- lnn>qDLL̻,Xh"Po;aE?fwJyoȐ![nE1##cرUUU>>eʔIPE.\pܸqM2@EV 7l0qD6gժUz^SJ͛h/^ʚM )w޷ojU%++ߵkך5k cΜ9l6@Ԩ@'N_l6k4мyZm;a$I2 $c|xks*iֲMk !}Y^^yw_~~ĉsWM6qC EQ"mUӣvss6lG}tW:xNgXnwKKˁ@vv?͛7̑p.5|?nNZ`0&&&//`07NiӦ\9sfǓ ӦM;pvmYYY{*,,4Q8'sA<rRGUEv-gBNbLm.#8K%93 tWI \%93Jr8Ngpp8a[RHLH%tEXtdate:create2015-08-02T00:14:56-04:00G%tEXtdate:modify2015-08-02T00:14:56-04:00tIENDB`ffcvt-1.5.05/preset-small.png000066400000000000000000000535741360321750700160520ustar00rootroot00000000000000PNG  IHDRJxgAMA a cHRMz&u0`:pQ<bKGDtIME nOVIDATxy|]so&$,($l  EpRj+y*}Zj ""[HX%$$!ΜInv/5;s QJp8]v85pP:\C9p p85pP:\C9p p85pP:\C9p p85pP:\C9p p834TeB(,VzhY "Zig3mᠮNC0D&l7ame/ ;)k)bZ1S"!{ZgzSJ !_DŽY/_̒ԮȶNQIOzii)RihTo? g@1(4ׯ_zn_bE}}X,v؈r\nl63q8cvl]. JettZ,(FaVkMMG=N)8C׳ب( %r577ffi-b3OƸ (OP6l2VpಲcǞ:uھ};xŋ/~Ǜx &u]CۺukXX{Ç>hѢE߶m۷~?g1 ?OF˲9rd߾}O쳏?3gn'xbٲeqqqgΜٲeʕ+Nguu/_z%ñz/rͿ򪪪^{W_}__vmLL̺uV\p8~_=ۏ ";7n+w/ꫯFEE-\Ro߾;;qj=e6ZHVc)cv ;ٱJbEZrjZx&v7m R&Ol2Xz$I,٬wHRlF&NǎU*kp8b١"[W?ÁР3Cۄ:Imۤ[?5__;*JYe&XȌpR|*,-wDzl^; 3,J>[dSDQVP gGtX,&γB! n&˲̆yOaLcN.rSWƺS B@)`|K(c7 ^-sѲ ,% ;p 4 3ҽnrrZpXU:=h4M*B[>; ^̞$I,,%|*4JaOW;5*L5⊄ReEcİ̙3gΜڵkWZZZ!xEJ J~!(DhϑeN<)¸quj=vXjjSfϞ"srrBCCHrqq__7o^t QF?pHNp:]'O|o-[$%%7j4#Gl߾=,,TQu:O:500P]v:thС,;m۶=z$))iƍaa/hC)*Vm9ZPPn:/>|8BWя~骫WXXXUUuѣG[,כaÆB0_|EJJFEĉhjjg6rff޽{M&^ϊRRRf'|R]]pС[577ܹرca&>>~#GpBsss\\׸p е{2F@?JPX>; B֭߳gOhhɓx/Roܸq̘1 8qBV˲|A^t:ΝR3j(Qݛp 7lݺd2>}… &L`RM8i;ۑq-?u]p? W؎vdgZrX,oɓKKKNgxxÇ/\F_]x1///>>~VuϞ=۷ogSf͚;7c\PPPYY1f̘\r-&)<vqI}vZZZZRRmΞ=ߦرjvA6 lZ^a#F9sFQZP]]lٲ'NTp6_5J{<44t{oeeEκ:ܹsSSSA5k͛YkkkZmbb(3f̼y[á,(gϞ;wnnn1c&M&jژJe2f̘1bĈ)SxX6?rɲVZ-xǏ8eʔ\yPLL MMMwye˚N:{lFSYY9w)SPJ ,YtRV{-X,r6px961` Xc}'O?~~aÆy6f}ףFܝv|rxx ;w >x㏗$$$DDD&@OV>E,Mo?/Udm@鐡Cfsff¶nD)eK.Y駟~.^R\.l1cΝ;222N|```ZZZDDDJJ(**"""88o!Bmmmss%Krss-}`~E@ kuXBei @VeggqfV111F`0 :4<<|„ jo>}z\\h2dHSSS^^ˇ5jԨnR:l0Qj0 ?bĈCDEEϜ93###((hcc+IR\\N ,**jhhxnƜ3w1c9r$>>?1;?(zn)..SNMKK۵kWJJJll,PN1h[mVQ۱MWk5M}s_˗/Xy|뭷͛WTTdX!l6Bh4&l6B*D*bرlWKָ~H8~ یJill+<!QSSK!QQQz-zg=~SL=z4dffE*o,eYf{ާR jݵ8[{d8!,,$ɲ>ER_"++˪^gUzGC1,KZZZmm-[痿eeeO8qႂ n۶y?###iӦCLݮVSSS:tҥvݧp,Ub L&s={.]Z`>lXbccB+jPTTy̙!C>--- h4?0bnwUUСC}XejkU~Di5]&ୗ;cǭ/cmzmks̗;plA{ ~vߟ~p8Wr8N?p8]k(tur8Np8]k(tuzg;研`` Q{:Mn9p67o[pr7~]U(r{APEA.8<+`.hZQNGp M&{dtgOɦ]U*2DwA^㋂\i'HJ y'&Fn١H7?9?;B{޸衖 .5ݭ(7@9 +ۊ' }"#,N t0uq8}+z,r҈gO׻2EVB 9fyϳ3eEJ3W@\4⹿nk_; b9s'O?ozڵyyyk+Byyy֭Alذb ۥ-~gGٳRkjj6lp!'%%%.K^z%+W_}l6x㍊`G?:v^߷o_bbbvvvDDĎ;F9vXIo>bĈlN{)Yϟ?t̙ѣG3:>Ƭں&$ #t9? &%#BP?+EAxEa{(V_qҤI=://OÇ>ѣ_ȑ#322ƍ'IRoO !vt\\Ç1x-KFFdJKK;|yyyRRRAAA\\ܴiӊǍ7eʔ5k?~|ƌoV67.R0BH:GOL29CA]g\lzn]He%b}ƌ xҥaaa%%%(N6f8p ,,,--+))IIIa6loj"(cǎe<͚|NGEnc,Hfa) XVqE_WWקz0YPhvz@=#ؠb#@vYV| Hd}K$ ڍO B#Ѭ1أ zk(HoDg<@6vKE\_ߢ aaax+;tϞ=ޓaaaw6ͷ~֭[Yuv8IXep:1v\uuurakjjRRR0\ZZ1ZC avcbbjjjY6hkyApwDRI%Avvk [&?,$! >+fNPO_zʌ%)޺BQF*7wF>_(v; ΩA*;2{СC}O4i53pce #% ZP,( =SFНlI ׿Oh*{(׼aپnȿ3![ \C9 4d; 0BVbs(~H1ېL@CA \C9 $ A0D( ̤`SlGԿl;_@QLk(gAtwk80nB$μ=bٜͨ08G'd.\anl* ,N@mW_xp.>\C9Ggr;q}@$v"NquPp|ZQJd,ln+S Eٰ&>zVgݩ̝2"VdN䦨q+n" ]xoVDžߜ=>GlD͆ -֕WyzFD՚ݑ:>ٕ2p8@MѨ赖A*Hpc SV]6~oVQ FARt( Qa跳P:"ڞ J=X1]m˝b~*n4I?IH,{+/ORJMPF?uѶZR O[\|'P1:/[ ->PODuc/kKQ8= os8)h{.# RX&Nʭ>P(ߣmV&(hCNobZN, o4FIAo)p8 IC-ȇ(2#r8&,rMܦexӰG B3DtQJ !~4w$^1v7#>7?{ܲ?Կ;!$a x0w\zo>,5'`u[,[~CxIz8D=Y?Bn L4(/MXٳv2Ν5jԬYyDP!ynn}]L)5:kwJ!PY"U>D,[a-KhhhLL̼y:|Wnx| Bk.oƘ(n);fv91SbZO.f vc]W1gee}ᇓ'OJtZCB-:{;3?qDhO| JQ׻n;泮3z,ft:xOςW>|nNG=5i3gLOOV]LݧsPߙ+V0LfYRA5I;|AYAضm[qq ˗/?qDnnndde˾ꫢÇy睔RY7lP]]755͜9399O>q\=z=BoR{gc,[6T,s9~V<5?ȷ/!j}iXxqQQx={d2-[0 =yduuQΝ;g6.]Gs*$,77W^tRiiCXI!!TXXxa&cB ?x\\޽{ VZ1hll\jUiiiee%8//jժ'|̙3KMM]bž}:)>8؇nP/QkB~Daqoj/ʸ>Ȣ Ygw=D*w+avY_M]Vl?>44ŋ'O\redd}._j*w%511l6 z讻C%I3f?0t1<?pNN0,- !$"""///>>b4f33~CCC !婩 TcF"ڀvNJ_$ Rvydg]H!(õBE? 9E.:4 ABQn/Qŧ:4B"$ v&_1 5#9n/OR\.r݂~!0m}vءhF)IB(<<ٳ=eULV;w=zҥKʲWXXh6SRRl6ۓO>vZ]uIEa(`? `eYxF(?!q{,͍NOQj l6')Zf[x2BA%()B ˊѧ %2B~h۲OusStiKpbъ+C mfDen(aX\gX==vǼoVdvJt:̙xbչ `8~h,.][oBv(*((Xpm>p8"##iӦCLݮVSSS:tҥv"z!D(tXG/7"hڐH R tW"T ~JD@^RRB;qB A!B$IaᝈzjUnox_;qzx ݗQ@!$(0($4ė)#G3,++… g:tPiik/͛7;#F,\ЏQ%aފ;w&<<<((^ 4i$8ydEEŨQsrrnҥKn游y:&馛n*..^`AJJkjj,X0nܸxӹh"hߍ^?$ RJePcDPB)J)%O(R"5z`;̸F-Q&*2q9,jͅAE鉳)G(׊e˖UVVFEE͘1c&MJJJZpaqqܹshs:yd]]0Lײv(3N8q…{NgiiĉFcgKVXaaa,?iii)))yR:|Ç[`̘1cƌaNeʔիW?.\ػw?c1i?+[ӯu>P+CH&lЪ:Eٴi4iҤ3fQ;ѧjnJZpaJJJS|?AB5ŏ)6ٍ,Ʈ\v6>R!f͂2v7}; \W.i4+V(VcbbbbbQ`f3(=ms8 @p͟~tϵI(¼l%;-3ù7ح( F/m+{;` ߼7žR^zc#Ez_^3 <( T~mmf([nr8~(<ŦW?a6iOup;JCm;/?4&.I3%8ޖpQ ̭Į;p gJ63XRo'p p!qͫդN\-t DA8u8vQֳ\'pKS߇n`  r8݃+&Z.x[u6gᡟV`?oP KSk j[NlVӓ 3y+~N@8(ԝmNC?htB@K.5}: 0oFkԷy0wq@bp:@f)xaOBA N'؄1ܻ*?`ZKj?TAV*~3CuRtPPW%6Ax+C7E<@&1xA#mgފ}VMNMawY S7P) *BiR꽒=sqo3@@e+̦r( ˃vkUmvC}J!ASJ[ggpPԉ5H@٬`AV=ۭ츷|vi6lؐ 555k׮C]!u rrr6l`X`_| q%MbȊzj7B9(,:t,?Zv B>7&&&644?߷o˗w1lذ/n#*++322bccmwߝDk6vqߣ,Mj:7O8b'- ЖϹP)A鉳 ߼vcZQ_N16mZcc>} 7pV>tBWSUWWFB(v=<<{<eYEB 6 cL)jzi{v{EC#l7>|0YG@18jB@-ACc ݷ(Une7nNBnڧ %p\0 PQjO]~o 4(PxqJAVR0nljl8zA ksڴiԩSO8Q__VY=JbU_w! 2e)++s:㚚2qssspp0bV!C2pBژFF~(** B-/7J*` (THKBEB)꾌RJ F/+otSF K,H)EθR&Wqл'-DO*`0X@YQJu:0 P}E!:`hek`(!77ǏgPmm!CXEOLLBPJZ:u[o%}ݗzoy˖-WNII ߸qwqիWO0!--m͚5oY>裣GΟ?XT*UFpEM J* B/ TR YVU*(ZVԾ"c' X\?ԠFq_^*Q'OM*#J=j?t7RJTjѷMjʓ$IlLu:?LQT'Oe/KppߟŪyrr2]}BCYM6mԨQ*[n0aBHHBhɒ%uuuaaa.h4JtPXbba&꣏>r3PܑJ}{}/B _& @ p/t.zkԭ2>RIkʺ*ӖeZ ,$B)YB1FUCWʜ=,ys$-'|rJizzȑ#A7oĉYE ePJCBB кdE9s0q eFh43 dҽEgc1(nƔh ECzDF=DVgYC[]@Oi(BSRȎ[Wz1;d۹kA@\RQ>ӟx9sT>};{%!l==%|%#IM"gUؾu c2K!3{,5Q},P6S@1ӗ` fp_{k>y#Cs< [_Tqb P'|8 u ptާ@Zڪk}WZb'h ?  8؊XmkzM5|vK1  ~Y8Qa *J^ӧ# 53(Ef{ڏ1\[EXΈ5ӏA@Uf;ћJsC+@ (L[6`J nP4@I[sݏ.d򘛟k(?"Jl  3s>~(ۅ5Aw?lXp/b vGosz>  - 1)jrƬ9c/V12+q\_r"$ p#SI(i#QǃȰI7EB1%\=9>"#NbR8K&7t SSMVUjIq61nwN5f;5?^ 7˓4qA3ΪT@=Hnh0?n;tkP Kg(PzeP(`T(PI.T1(͉Wg$.ߴ>QhH-#JUԍ"tQ#X,J3Hn`( ʡZ7R s^ZX9AxDzcH=j@JYK5Uh@%1),R #H!mAh4$Łټ+2;!NPP c@! W||JH%8r:.+00_aR@UlƌXgQy%Vk,r<#hLX鮤M|*ʅ5tf)ԉ2fIx/!R@Q:⯵% t]BIѨN>n6mr8=z4!cCj7`+ta¿8rV](S*@弋e)J!R)H4(MTs#_[,Q)A@0wH\jG#d{o) q:4 R دSʕ-v#j*fSVw/B(ߋ/+y3U3gdddh4K\}Yf h(!D#G;nXfѣZMTDE 2 w.$A,).J݉&4FE%[u< )xd$F [Z܈j-%ɇ8YǓJ%({$1BP6 DI-*QI7!Q%ǨY%ZqkIR#5QR?CHJA%OVO{e bJKRG]`(Z` h({N%%%h4"}H0iՕŵ5.u QZhյzZV&nV5ѕmjF@FVVVJ:߇Jꪋet[CmNeuVP!'BRUn,+|PU^T_豈݉* LMs]sYWUۏ&b`e>quYX~SZbB[Gͪ(&!#^ ^}Lyu+qQ"b }x* /{'2FJA/E}7KR. ,af^B{466^ɲ\[[ (vaw۷o׮]}b Nk.]VWW_,uuuΛ6I)eٴX,999~mqqqm}_2}w\ޔx.jʼn'~8;ޟb ͽ|% H]x<`jVVVbeYZV;O>`0755wDQsox<]x5mll|!/_e`A`+**, 2R__Rgc˖- ,ńw}+vWWW@mm-ˬ,//g֊jTբ(ndYe¾+8Bcm6+++Bn97U!URR:|pii)0%e( kTKKK{t:Z, "ȲxGرc!0$T ~.īlͫV?1uǏ;iӦ>~Сwy[խXUUU&)((%88nv}qq޳jz̙۶m$)==X8pc|w+WX`!EDDddd{uuu111&//fv9Fp,**zkjj"##B˗/OEILL{=rEѸy'xb111YYYeee oz}wsĉ{8o޼膆O>b;yܹs-KHHȔ)S3eBVWWfЄ ؼÆ t#FU)))L """N/Ϟ=ll9v 6;(.\ghhhssǏ#fsjjj``(֭;wСCCBBZRRԔ.[lK/i5X&((â(666՝?>&&̙3oq_5?b&ܹs!!!,O4)&&!4}.T0VCCCovw٤'ZiӦ}j Wkr&&&JTXXO4)**JSRJ#"+Wn߾_t򀀀+Wn۶MRY,q]]ݬYZ-tύv튏0aBuuuQQQsss=w1.rAAp:/=zS$IlfB$8qbh4 ľgQŋ)))N4iRmmmqqqMM /pYL)**ZVu̘1l8=tmyz0a' 4siӦDQ ڰa̙3VW_}%BPP5kѣ?Ӣ"+t:eY> \^^yfc%I?~ܹsZmCnw8۶me944tr-IIIׯ|2ˣ_ t8lEt͘1oVaV(*Rj4_cѡC}Ν%Iv}'ܹsҤI.\xwܐ蔿1))yϞ=iii,O8q޼yÇjgԩ8q⭷Gn33m6ۘ1ct:]nn.N=P]b{ RSSY+n0~x1:. pTg^p!66v.]*))w/cjz=HR566fff#BCC8`ÇJh4FԩSCMLL$,,k}JjM&7_j˥ã ++fĈ0f̘^xjΜ9SVL0I_ʡRʺJ(6Rr<|wnJq8{v˲L)-))a=;i`777WUU)RQQA)Ul6SJ,śRf<455މn(b=uތrvc2f}J,FݤƛÊǏXY޼{<EQEaO)-++cװ\w]UUUURj !?|YYKOqq7,a6 PJCаsŋ҇ONvù:Uisڔu(>999fyܹ~ + cީ@{㟽5@z"FJ:(i{}e? uz;!NOɓ'#߿iӦaÆߞӫ%:\C9p p85pP:\C9p p85pP:\C9p p85p ^ՠh%tEXtdate:create2015-08-02T00:10:48-04:00{%tEXtdate:modify2015-08-02T00:10:48-04:00BIENDB`ffcvt-1.5.05/structEnc.go000066400000000000000000000042021360321750700152150ustar00rootroot00000000000000package main import "log" //////////////////////////////////////////////////////////////////////////// // Constant and data type/structure definitions // The Encoding struct defines the structure to hold encoding values type Encoding struct { VES string // video encoding method set AES string // audio encoding method set SES string // subtitle encoding method set VEP string // video encoding method prepend AEP string // audio encoding method prepend SEP string // subtitle encoding method prepend VEA string // video encoding method append AEA string // audio encoding method append ABR string // audio bitrate CRF string // the CRF value: 0-51. Higher CRF gives lower quality Ext string // extension for the output file } //////////////////////////////////////////////////////////////////////////// // Global variables definitions //////////////////////////////////////////////////////////////////////////// // Global variables definitions var Defaults map[string]Encoding func init() { Defaults = map[string]Encoding{ "webm": { AES: "libopus", VES: "libvpx-vp9", SES: "-c:s copy", ABR: "64k", CRF: "42", Ext: "_.mkv", }, "x265-opus": { AES: "libopus", VES: "libx265", ABR: "64k", CRF: "28", Ext: _encodedExt, }, "x264-mp3": { AES: "libmp3lame", AEA: "-q:a 3", VES: "libx264", ABR: "256k", CRF: "23", Ext: _encodedExt, }, "youtube": { // https://trac.ffmpeg.org/wiki/Encode/YouTube // https://trac.ffmpeg.org/wiki/Encode/HighQualityAudio AES: "libvorbis", AEA: "-q:a 5", VES: "libx264", VEA: "-pix_fmt yuv420p", ABR: "", CRF: "20", Ext: "_.avi", }, } } func getDefault() { // preserve command line values abr, crf := Opts.ABR, Opts.CRF if encDefault, ok := Defaults[Opts.Target]; ok { // debug(encDefault.Ext, 2) Opts.Encoding = encDefault // debug(Opts.Encoding.Ext, 2) // debug(Opts.Ext, 2) } else { log.Fatal(progname + " Error: Wrong target option passed to -t.") } // restore command line values if abr != "" { Opts.ABR = abr } if crf != "" { Opts.CRF = crf } if Opts.Suffix != "" { Opts.Suffix = "_" + Opts.Suffix } } ffcvt-1.5.05/test/000077500000000000000000000000001360321750700136755ustar00rootroot00000000000000ffcvt-1.5.05/test/StreamSample.mkv000066400000000000000000000213721360321750700170160ustar00rootroot00000000000000Eߣ#BBBBBmatroskaBBSg"Mt@JMSIfSMSTkS|MSCpSMSTgSMSSkS"If*ױB@{Євротур / EuroTrip (2004) BDRip-AVC [2xUkr/Eng | Sub Eng] [Hurtom]MLavf57.48.102WALavf57.48.102svw@uo³ҩD@zTk1xׁsŁ"undV_MPEG4/ISO/AVC#ツ|k-@TT@cd)gd)R l@NLK@# bh<<ׁsŁSnУкраїна [багатоголосий закадровий] - AC3 2.0 @ 192kbps"ukrA_AC3 @pׁsŁSnНовий [багатоголосий закадровий] - AC3 2.0 @ 192kbps"ukrA_AC3 @pSׁsŁSnOriginal - AC3 5.1 @ 640kbps"engA_AC3 @p*ׁsŁSneng"engS_TEXT/UTF8CpMECEہE2sĄ -1-EChapter 01C|undTg +ss.cgEENCODERDLavf57.48.102ssccŁgEBPSDzengD2049372g&EDURATIONDzengD01:30:05.855000000g"ENUMBER_OF_FRAMESDzengD129611g%ENUMBER_OF_BYTESDzengD1384826152gXE_STATISTICS_WRITING_APPDzengDmkvmerge v35.0.0 ('All The Love In The World') 64-bitg;E_STATISTICS_WRITING_DATE_UTCDzengD2019-10-19 11:23:08gIE_STATISTICS_TAGSDzengDBPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTESssccŁgEBPSDzengD192000g&EDURATIONDzengD01:30:05.728000000g"ENUMBER_OF_FRAMESDzengD168929g$ENUMBER_OF_BYTESDzengD129737472gXE_STATISTICS_WRITING_APPDzengDmkvmerge v35.0.0 ('All The Love In The World') 64-bitg;E_STATISTICS_WRITING_DATE_UTCDzengD2019-10-19 11:23:08gIE_STATISTICS_TAGSDzengDBPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTESssccŁgEBPSDzengD192000g&EDURATIONDzengD01:30:05.728000000g"ENUMBER_OF_FRAMESDzengD168929g$ENUMBER_OF_BYTESDzengD129737472gXE_STATISTICS_WRITING_APPDzengDmkvmerge v35.0.0 ('All The Love In The World') 64-bitg;E_STATISTICS_WRITING_DATE_UTCDzengD2019-10-19 11:23:08gIE_STATISTICS_TAGSDzengDBPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTESssccŁgEBPSDzengD640000g&EDURATIONDzengD01:30:05.824000000g"ENUMBER_OF_FRAMESDzengD168932g$ENUMBER_OF_BYTESDzengD432465920gXE_STATISTICS_WRITING_APPDzengDmkvmerge v35.0.0 ('All The Love In The World') 64-bitg;E_STATISTICS_WRITING_DATE_UTCDzengD2019-10-19 11:23:08gIE_STATISTICS_TAGSDzengDBPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTESssccŁgEBPSDzengD66g&EDURATIONDzengD01:27:40.296000000g ENUMBER_OF_FRAMESDzengD1324g ENUMBER_OF_BYTESDzengD43878gXE_STATISTICS_WRITING_APPDzengDmkvmerge v35.0.0 ('All The Love In The World') 64-bitg;E_STATISTICS_WRITING_DATE_UTCDzengD2019-10-19 11:23:08gIE_STATISTICS_TAGSDzengDBPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTESss:ccŁg"EDURATIOND00:00:00.416000000ss:ccŁg"EDURATIOND00:00:00.032000000ss:ccŁg"EDURATIOND00:00:00.032000000ss:ccŁg"EDURATIOND00:00:00.032000000ss:ccŁg"EDURATIOND00:00:00.000000000CuMCgd)R l@NLK@# bh<<EH, #x264 - core 157 r2935 545de2f - H.264/MPEG-4 AVC codec - Copyleft 2003-2018 - http://www.videolan.org/x264.html - options: cabac=1 ref=9 deblock=1:-1:-1 analyse=0x3:0x113 me=umh subme=11 psy=1 psy_rd=1.00:0.15 mixed_ref=1 me_range=48 chroma_me=1 trellis=2 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=0 chroma_qp_offset=-3 threads=18 lookahead_threads=3 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=8 b_pyramid=2 b_adapt=2 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=240 keyint_min=23 scenecut=40 intra_refresh=0 rc_lookahead=60 rc=2pass mbtree=1 bitrate=2050 ratetol=1.0 qcomp=0.60 qpmin=10 qpmax=69 qpstep=4 cplxblur=20.0 qblur=0.5 vbv_maxrate=50000 vbv_bufsize=62500 nal_hrd=none filler=0 ip_ratio=1.40 aq=1:1.00e 6VF܍էg0K0 _*`=5tAA P0 wA[ݿ0 A!!C w`@Cb W>|ϟ>|ϟ>|ϟ>|ϟ>|u|ϟ>|ϟ>|ϟ>|ϟ>|_>|ϟ>|ϟ>|ϟ>|ϟ>H 6mx㻻www6o5kZֵkZֵkZֵ6mx㻻www6o5kZֵmǏ;wwwxmZֵkZֵkZֵkZmǏ;wwwxmZֵkZ`6mx㻻www6o5kZֵkZֵkZֵ6mx㻻www6o5kZֵmǏ;wwwxmZֵkZֵkZֵkZmǏ;wwwxmZֵkZ`6mx㻻www6o5kZֵkZֵkZֵ6mx㻻www6o5kZֵmǏ;x|kZֵkZֵkZֵmǏ;x|kZֵ(C w`@Cb W>|ϟ>|ϟ>|ϟ>|ϟ>|u|ϟ>|ϟ>|ϟ>|ϟ>|_>|ϟ>|ϟ>|ϟ>|ϟ>H 6mx㻻www6o5kZֵkZֵkZֵ6mx㻻www6o5kZֵmǏ;wwwxmZֵkZֵkZֵkZmǏ;wwwxmZֵkZ`6mx㻻www6o5kZֵkZֵkZֵ6mx㻻www6o5kZֵmǏ;wwwxmZֵkZֵkZֵkZmǏ;wwwxmZֵkZ`6mx㻻www6o5kZֵkZֵkZֵ6mx㻻www6o5kZֵmǏ;x|kZֵkZֵkZֵmǏ;x|kZֵ(J wɒ$@}*0 ?Wϟ>|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>|_>|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>|u|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>|Ͽϟ>|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>Wϟ>|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>|ϟ>|rH"Dǎmm浭kZϟ>|ϟ>||ϟ>|;Ǐ;wwwmmϚֵk_>|ϟ>|πxwwwwmZֵkϟ>|ϟ>|kZֵ|ϟ>|ϟ>>Ǐ;mkZֵ>|ϟ>|x㻻wwvm|kZֵϟ>|ϟ>|w|ϟǎmm浭kZϟ>|ϟ>||ϟ>|;|;Ǐ;wwwmmϚֵk_>|ϟ>|πxwwwwmZֵkϟ>|ϟ>|kZֵ|ϟ>|ϟ>Ǐ;mkZֵ>|ϟ>|x㻻wwvm|kZֵϟ>|ϟ>|w$vG2B41K;Ǐ;wwwmmϚֵk_>|ϟ>|πxwwwwmZֵkϟ>|ϟ>|kZֵ|ϟ>|ϟ>Ǐ;mkZֵ>|ϟ>|x㻻wwvm|kZֵϟ>|ϟ>|w@ ( /0X崘30M9GzfcNn}I=26V %yֻgɢ7oWeT@+2.;Ǐ;wwwmmϚֵk_>|ϟ>|πxwwwwmZֵkϟ>|ϟ>|kZֵ|ϟ>|ϟ>Ǐ;mkZֵ>|ϟ>|x㻻wwvm|kZֵϟ>|ϟ>|wNϨN;Ǐ;wwwmmϚֵk_>|ϟ>|πxwwwwmZֵkϟ>|ϟ>|kZֵ|ϟ>|ϟ>Ǐ;mkZֵ>|ϟ>|x㻻wwvm|kZֵϟ>|ϟ>|w>SkIffcvt-1.5.05/test/ffcvt_test.txt000066400000000000000000000205301360321750700166050ustar00rootroot00000000000000 Usage: ffcvt [flags] Flags: -t target type: webm/x265-opus/x264-mp3/youtube (FFCVT_T) -ves video encoding method set (FFCVT_VES) -aes audio encoding method set (FFCVT_AES) -ses subtitle encoding method set (FFCVT_SES) -vep video encoding method prepend (FFCVT_VEP) -aep audio encoding method prepend (FFCVT_AEP) -sep subtitle encoding method prepend (FFCVT_SEP) -vea video encoding method append (FFCVT_VEA) -aea audio encoding method append (FFCVT_AEA) -abr audio bitrate (64k for opus, 256k for mp3) (FFCVT_ABR) -crf the CRF value: 0-51. Higher CRF gives lower quality (28 for x265, ~ 23 for x264) (FFCVT_CRF) -d directory that hold input files (FFCVT_D) -f input file name (either -d or -f must be specified) (FFCVT_F) -sym symlinks will be processed as well (FFCVT_SYM) -exts extension list for all the files to be queued (FFCVT_EXTS) -suf suffix to the output file names (FFCVT_SUF) -ext extension for the output file (FFCVT_EXT) -w work directory that hold output files (FFCVT_W) -ac copy audio codec (FFCVT_AC) -vc copy video codec (FFCVT_VC) -an no audio, output video only (FFCVT_AN) -vn no video, output audio only (FFCVT_VN) -vss video: same size (FFCVT_VSS) -lang language selection for audio stream extraction (FFCVT_LANG) -o more options that will pass to ffmpeg program (FFCVT_O) -ato-opus audio encode to opus, using -abr (FFCVT_ATO_OPUS) -vto-x265 video video encode to x265, using -crf (FFCVT_VTO_X265) -p par2create, create par2 files (in work directory) (FFCVT_P) -nc no clobber, do not queue those already been converted (FFCVT_NC) -n no exec, dry run (FFCVT_N) -force overwrite any existing none-empty file (FFCVT_FORCE) -debug debugging level (FFCVT_DEBUG) -ffmpeg ffmpeg program executable name (FFCVT_FFMPEG) -ffprobe ffprobe program execution (FFCVT_FFPROBE) -version print version then exit (FFCVT_VERSION) Details: -abr string audio bitrate (64k for opus, 256k for mp3) -ac copy audio codec -aea string audio encoding method append -aep string audio encoding method prepend -aes string audio encoding method set -an no audio, output video only -ato-opus audio encode to opus, using -abr -crf string the CRF value: 0-51. Higher CRF gives lower quality (28 for x265, ~ 23 for x264) -d string directory that hold input files -debug int debugging level (default 1) -ext string extension for the output file -exts string extension list for all the files to be queued (default ".3GP.3G2.ASF.AVI.DAT.DIVX.FLV.M2TS.M4V.MKV.MOV.MPEG.MP4.MPG.RMVB.RM.TS.VOB.WEBM.WMV") -f string input file name (either -d or -f must be specified) -ffmpeg string ffmpeg program executable name (default "ffmpeg") -ffprobe string ffprobe program execution (default "ffprobe -print_format flat") -force overwrite any existing none-empty file -lang string language selection for audio stream extraction (default "eng") -n no exec, dry run -nc no clobber, do not queue those already been converted -o string more options that will pass to ffmpeg program -p par2create, create par2 files (in work directory) -sep string subtitle encoding method prepend -ses string subtitle encoding method set -suf string suffix to the output file names -sym symlinks will be processed as well -t string target type: webm/x265-opus/x264-mp3/youtube (default "webm") -vc copy video codec -vea string video encoding method append -vep string video encoding method prepend -version print version then exit -ves string video encoding method set -vn no video, output audio only -vss video: same size (default true) -vto-x265 video video encode to x265, using -crf -w string work directory that hold output files To reduce output, use `-debug 0`, e.g., `ffcvt -force -debug 0 -f testf.mp4 ...` == Transcoding: StreamSample.mkv ffcvt: to execute - ffmpeg -i StreamSample.mkv -c:v libvpx-vp9 -b:v 0 -crf 42 -c:a libopus -b:a 64k -c:s copy /tmp/StreamSample.mkv Org Size: 0 MB New Size: 0 MB Saved: 0% ] Skip symlink file: ./test1.avi ] Skip symlink file: ./test2.avi ] Skip symlink file: ./test3.webm == Transcoding [1/1]: 'StreamSample.mkv' under . ] ffmpeg -i ./StreamSample.mkv -c:v libx265 -x265-params crf=28 -c:a libopus -b:a 64k ./StreamSample_.mkv ffcvt: to execute - ffmpeg -i ./StreamSample.mkv -c:v libx265 -x265-params crf=28 -c:a libopus -b:a 64k ./StreamSample_.mkv Org Size: 0 MB New Size: 0 MB Saved: 0% == Transcoding [1/4]: 'StreamSample.mkv' under . ] ffmpeg -i ./StreamSample.mkv -c:v libx265 -x265-params crf=28 -c:a libopus -b:a 64k ./StreamSample_.mkv ffcvt: to execute - ffmpeg -i ./StreamSample.mkv -c:v libx265 -x265-params crf=28 -c:a libopus -b:a 64k ./StreamSample_.mkv == Transcoding [2/4]: 'test1.avi' under . ] ffmpeg -i ./test1.avi -c:v libx265 -x265-params crf=28 -c:a libopus -b:a 64k ./test1_.mkv ffcvt: to execute - ffmpeg -i ./test1.avi -c:v libx265 -x265-params crf=28 -c:a libopus -b:a 64k ./test1_.mkv == Transcoding [3/4]: 'test2.avi' under . ] ffmpeg -i ./test2.avi -c:v libx265 -x265-params crf=28 -c:a libopus -b:a 64k ./test2_.mkv ffcvt: to execute - ffmpeg -i ./test2.avi -c:v libx265 -x265-params crf=28 -c:a libopus -b:a 64k ./test2_.mkv == Transcoding [4/4]: 'test3.webm' under . ] ffmpeg -i ./test3.webm -c:v libx265 -x265-params crf=28 -c:a libopus -b:a 64k ./test3_.mkv ffcvt: to execute - ffmpeg -i ./test3.webm -c:v libx265 -x265-params crf=28 -c:a libopus -b:a 64k ./test3_.mkv Org Size: 0 MB New Size: 0 MB Saved: 0% ] Skip symlink file: ./test1.avi ] Skip symlink file: ./test2.avi ] Skip symlink file: ./test3.webm == Transcoding [1/1]: 'StreamSample.mkv' under . ] ffmpeg -i ./StreamSample.mkv -c:v libvpx-vp9 -b:v 0 -crf 42 -c:a libopus -b:a 64k -c:s copy ./StreamSample_.mkv ffcvt: to execute - ffmpeg -i ./StreamSample.mkv -c:v libvpx-vp9 -b:v 0 -crf 42 -c:a libopus -b:a 64k -c:s copy ./StreamSample_.mkv Org Size: 0 MB New Size: 0 MB Saved: 0% == Transcoding [1/4]: 'StreamSample.mkv' under . ] ffmpeg -i ./StreamSample.mkv -c:v libvpx-vp9 -b:v 0 -crf 42 -c:a libopus -b:a 64k -c:s copy ./StreamSample_.mkv ffcvt: to execute - ffmpeg -i ./StreamSample.mkv -c:v libvpx-vp9 -b:v 0 -crf 42 -c:a libopus -b:a 64k -c:s copy ./StreamSample_.mkv == Transcoding [2/4]: 'test1.avi' under . ] ffmpeg -i ./test1.avi -c:v libvpx-vp9 -b:v 0 -crf 42 -c:a libopus -b:a 64k -c:s copy ./test1_.mkv ffcvt: to execute - ffmpeg -i ./test1.avi -c:v libvpx-vp9 -b:v 0 -crf 42 -c:a libopus -b:a 64k -c:s copy ./test1_.mkv == Transcoding [3/4]: 'test2.avi' under . ] ffmpeg -i ./test2.avi -c:v libvpx-vp9 -b:v 0 -crf 42 -c:a libopus -b:a 64k -c:s copy ./test2_.mkv ffcvt: to execute - ffmpeg -i ./test2.avi -c:v libvpx-vp9 -b:v 0 -crf 42 -c:a libopus -b:a 64k -c:s copy ./test2_.mkv == Transcoding [4/4]: 'test3.webm' under . ] ffmpeg -i ./test3.webm -c:v libvpx-vp9 -b:v 0 -crf 42 -c:a libopus -b:a 64k -c:s copy ./test3_.mkv ffcvt: to execute - ffmpeg -i ./test3.webm -c:v libvpx-vp9 -b:v 0 -crf 42 -c:a libopus -b:a 64k -c:s copy ./test3_.mkv Org Size: 0 MB New Size: 0 MB Saved: 0% ] Transcoding to /tmp/test == Transcoding [1/4]: 'StreamSample.mkv' under . ] ffmpeg -i ./StreamSample.mkv -c:v libvpx-vp9 -b:v 0 -crf 42 -c:a libopus -b:a 64k -c:s copy /tmp/test/StreamSample.mkv ffcvt: to execute - ffmpeg -i ./StreamSample.mkv -c:v libvpx-vp9 -b:v 0 -crf 42 -c:a libopus -b:a 64k -c:s copy /tmp/test/StreamSample.mkv == Transcoding [2/4]: 'test1.avi' under . ] ffmpeg -i ./test1.avi -c:v libvpx-vp9 -b:v 0 -crf 42 -c:a libopus -b:a 64k -c:s copy /tmp/test/test1.mkv ffcvt: to execute - ffmpeg -i ./test1.avi -c:v libvpx-vp9 -b:v 0 -crf 42 -c:a libopus -b:a 64k -c:s copy /tmp/test/test1.mkv == Transcoding [3/4]: 'test2.avi' under . ] ffmpeg -i ./test2.avi -c:v libvpx-vp9 -b:v 0 -crf 42 -c:a libopus -b:a 64k -c:s copy /tmp/test/test2.mkv ffcvt: to execute - ffmpeg -i ./test2.avi -c:v libvpx-vp9 -b:v 0 -crf 42 -c:a libopus -b:a 64k -c:s copy /tmp/test/test2.mkv == Transcoding [4/4]: 'test3.webm' under . ] ffmpeg -i ./test3.webm -c:v libvpx-vp9 -b:v 0 -crf 42 -c:a libopus -b:a 64k -c:s copy /tmp/test/test3.mkv ffcvt: to execute - ffmpeg -i ./test3.webm -c:v libvpx-vp9 -b:v 0 -crf 42 -c:a libopus -b:a 64k -c:s copy /tmp/test/test3.mkv Org Size: 0 MB New Size: 0 MB Saved: 0% ffcvt-1.5.05/test/test-all.sh000077500000000000000000000015711360321750700157650ustar00rootroot00000000000000#! /bin/sh #env FFCVT=../ffcvt # During Debian building, it is at obj-x86_64-linux-gnu/bin/ffcvt # while the source is at obj-x86_64-linux-gnu/src/github.com/suntong/ffcvt/test [ -s $FFCVT ] || FFCVT=../../../../../bin/ffcvt $FFCVT -version echo '- Test (config.go) cli help output' $FFCVT > /tmp/ffcvt_test.txt 2>&1 echo - Test transcoding single file $FFCVT -n -debug 0 -f StreamSample.mkv -w /tmp >> /tmp/ffcvt_test.txt 2>&1 echo - Test -sym control $FFCVT -t x265-opus -n -d . >> /tmp/ffcvt_test.txt 2>&1 $FFCVT -t x265-opus -n -d . -sym >> /tmp/ffcvt_test.txt 2>&1 $FFCVT -n -d . >> /tmp/ffcvt_test.txt 2>&1 $FFCVT -n -d . -sym >> /tmp/ffcvt_test.txt 2>&1 $FFCVT -n -sym -debug 2 -d . -w /tmp >> /tmp/ffcvt_test.txt 2>&1 echo - Compare test results sed -i '/ [0-9.]*[mµ]*s$/d' /tmp/ffcvt_test.txt diff -wU 1 ffcvt_test.txt /tmp/ffcvt_test.txt ret=$? echo $ret exit $ret ffcvt-1.5.05/test/test1.avi000077700000000000000000000000001360321750700205452StreamSample.mkvustar00rootroot00000000000000ffcvt-1.5.05/test/test2.avi000077700000000000000000000000001360321750700171732test1.aviustar00rootroot00000000000000ffcvt-1.5.05/test/test3.webm000077700000000000000000000000001360321750700173472test1.aviustar00rootroot00000000000000ffcvt-1.5.05/test2/000077500000000000000000000000001360321750700137575ustar00rootroot00000000000000ffcvt-1.5.05/test2/ffcvt_test.txt000077700000000000000000000000001360321750700227642../test/ffcvt_test.txtustar00rootroot00000000000000ffcvt-1.5.05/test2/subdir/000077500000000000000000000000001360321750700152475ustar00rootroot00000000000000ffcvt-1.5.05/test2/subdir/test_s1.avi000077700000000000000000000000001360321750700243052../../test/subdir/test_s1.aviustar00rootroot00000000000000ffcvt-1.5.05/test2/test-sym.sh000077700000000000000000000000001360321750700214062../test/test-sym.shustar00rootroot00000000000000ffcvt-1.5.05/test2/test1.avi000077700000000000000000000000001360321750700204462../test/test1.aviustar00rootroot00000000000000ffcvt-1.5.05/test2/test2.avi000077700000000000000000000000001360321750700204502../test/test2.aviustar00rootroot00000000000000ffcvt-1.5.05/test2/test3.webm000077700000000000000000000000001360321750700210002../test/test3.webmustar00rootroot00000000000000ffcvt-1.5.05/video-crf.png000066400000000000000000000525731360321750700153160ustar00rootroot00000000000000PNG  IHDRM(gAMA a cHRMz&u0`:pQ<bKGDtIME k)(TIDATxy|U3gMn=%DA\pCĊ[Z[ҧc>>.VEEda N"[HB&\ "7 d/^p8˜{s3D)6p.g@E hr8 A3"p4\9΀f@(UUESJY0Gqr8 b!D)Euv࿁;9%H;ZuMw|p8kfLUUE1(C)e"; PZ[[_{۷@ K cqUVVBWjp#72Y|믿r~馦&p8\.!!z}>_ss3Ԅ1FnzBMMM!UUn?[oi4B 'Պ1&|UUnfu:Nݫf1\.x<(RJ6ne9}m@+FcaaaeeN{BCC+++:;lݺu͚5||l6ۏ~ѣGIII k֬ kmmo߾~x/Œ3o0Z-Bg=yO>c=ϟgyРA555'NXl=PSS׿kn7jժ'O,..~饗G_g?ٖ-[?G?zGUUù=x`ȑZrr ~_Č3fΜ9Vr:999+VXrڌ?ٳ?544޽jhh }}ѱcfff">cЮ]O1zpnFܹs111*¡#F0 7˲p8L&:>>=NSSSxx88NVKaOܨ"xU֬Yc2X6Z 1⒠.+]B?~xxx74cùV27t˄@wN btCWI.w>Ds󋠪^ Y3Xڴ$'RJAҕ(ұzqUp8EYoJlNU=)JۣMzP8!k1TU0C C= l(R566 `X<aff|O1U0ĔhϞ=qqq#;S4yKsl߾}LϞ=kZǍH!Ğ\=77@YryFBWvy)|_~~򓟜?`0lذ!77wĈEEEG5k h4Zرc+VHIIIJJ7n{"##vx̙石{WuǐpѯCZmMXkyr.`/ҠA~HHȺu*++[[[x≊Ϙ1#11*wI9 ,f v5BW_=#---YYY&MZ~}]]СCE>|֭[nj_|ؾ}3gN8a^$ۏ92w\JΝ;[[[ND)]tiBB¬YZ[[7mTUU5dȐI&޽x֬Yqqqc6'<}tiiNwG-..$)**̙3s΍lhh8tP}}ɓzfKOO?|pQQ7|3|SJ|Aպzjt=L۷Ϙ1a^y啾!|UBۣLz!XtS6m?)%%%??`0\233SȲ( Cdd1c,˅6l>|(6m|sjkk M׿;\~Vϒ-[6eF~EQ֭[WWWW]]e˖ &{RSSS[[kXN8qYSs=PZZbŊ4RQQQ^^r\.ɔw9qD77myQ 1yyyv=33RZWWRRR#G|>Q-lfL!>>`0PJG9tУGh T__#߿_HӢɧ!lm wxElȃEӥ+rKӧg͚5k֬˲}„ *444))d2I4jԨ:tܸqQQQGUEզ~`O-˲`vۄ XK%DDD 6l&Lp:&IǏ5h4|p`2fsrrٳg)QQQfo>`0xor:, jux5g 4hPbbbcc#*77wڵ#F(,,6Ξ=[SSV!ºu,ˎ;,Y /TTT <8::Z]XY}O,Ԏd?ł;zfYQk Jq|||RRRmm-iuYE2nEC`o^z dddlڴu֝;wfee;vM/f2c \Iѥ!2~=^L~~ӣ/2==}СYbżyx /= лP:d;ݕco@@:h 66ʅ;Nu . ױC~SLA:G>QܥoM:Hcc4oDn~갹p88zq \|p4\9΀D0P\rz&Wm]WzCp8LZ'r:vl6qִdt1>=PQ˥e:39Et$knnfbw+W8p ,,iŊǏOMMe ڵkřׯ/-->|UnZ__?tP6g߲evv/^\TT$Ih\x}X%a_O`%믿޵kWvvvQQ8Y1gطdbm۶ɓ'?(n޼{ !zwӟ466ٳ .o޼e…ϟh ._2sbJibbO?]XXHihh/DQ2e <<<Ak~pE=W\i6EQdB$&[l7`Ee$r`_zǁP`&q8 ;m۶mۦYAfݻwxѣGI KJJ㎂;v}ݫWf-ѧONMMvrss \.FޱcǙ3gbcc. B899ٳ#G_mmmbb5r8Nw%8S`sv(0-R`WY츔bm `3uYa ӗ`:q8 A:Ӈ wp .=9$B}K_6\r8m=BqJ+"PNKR&r ^ `={5d= 96R] C}>p@wv}HChwHT, BL9.QpW` @)Q{n݅AЂrE/2҄v}u8>E@R&m8 %0]PmAHh+҂&h9xKI!>C9r?h[#Ƅ@U@V ~I90m"$ &@5 vp^TitW@7j*(ޖ..Un6D9@!&" P h A6% Rǁ&Q@v=`A @K5mnZ؟(d7 o X,Iv paEZ*7Җ3hk{FA(.8k`k0iPmK T] ~ |-,W5Po U}P]w m*J&X9ݟՀ&4PF6}0-P JȘ Cl8R~ T |YPHЄU&J@9pAŰ@K!bԵ*(mw˾jl2?NC]W@@P  &(~;zUVsT\nB2mUm@Z3E!@-]W^9o_+.u"Pyyk,swj\ƵGcׇ)1ނT*ERWJ͹"ÿ}\WvJ0 HQ4z48gHEr`0jVZ(v޶+tٍ_7#of=i@=p.+rByM {2{un`;\{B^0*@Px38M~6ݹ2YvDU 4]fKx.!-uH";Z̰~yOay})1U ]{ភz1PDD`c]M_$Cnjz4!ޘ\ \`"nW`?4^?տǫ }8s.D nq8^A'Pb? 6[VwrJC5`0J|~"t`XKzOrC$.|W>3<B@\ 9^wAP*(3/>{91"|;udŬwaC"^[mYw&65 c.}mM y&~XW~oF?> BW[e^SAJ)!H'NU߽ ^`0h<ù'HJza.h<}С4$MZ|T<:_Nl*̹!^h['1~Ji J)n(Hf=@4.?~q<8#' yw +!_RL^yɋ;w744|G ݾj*_WW/bTTԹs֮]Joܸ1::h4۷oǎСCk7Y֪u?G2zIj$h:8b|wVf6ڄ*B2!|Xomm-))ihhXzusssrrr}}}~~ QQQA.LݻhѢxHQ &jZJrȑקEEE]vذaYYY$֮YfСEEEz())СC=ztĈKCbm ȈAB)!@`0s?%E:}џ<'cY6.>BgZ_Ɯ?pĈ|߹swܙb4\[fV7L2RZQQA)_^^^CCĉ6m>O&^h4B$Ir\QEEQDQ$t:1ƔRAZ[[]fcc㕻MU ~]bn۴)%qӎ-쫗>v:ntDBvthdeN!""466k޴iScc}ݗ r? 0 |rrrdY>vz )))eeeJn ryqkkkBB6___ cVhlr3ʲl2jU*|(QQa?Cl-#/Qx;K@|>P$i#2'\Ώnt;v(..v].Ƹ)%%QW 6̒%K~'N`zcǎ9|۶m=XaaѣG͛jժٳgsYbE}}ѣsss/^p8n>Ϛ5kEoFV~7:6G fF>Վ4CGg3LVzpxtرG}5=S^^o߾~X!, g1VU[fdd655ݦ0/^w֭ӧOpX,x^/k#Q{zPpV@IԔ9,k-\@EJ/=" H!Nbx%Ir:n[QŢh:> 4۱(5uš.I; ,O{|zK]k)Qc$Xե8lq?!>>v[=("eZ( ̵sKas2] AlcgiNJ!N+LF۔93T/jlbՓuvL&t%Q?[~"b(`9X`\L΀'l߯ l\nZϼYqUSQT\q*mZ-LK}ˠ:'!ȭRѶvƹtC'0O` Z-!E#W9.7r j+LF${Jl᳹uKN75j[ (*$CM ("$EB7}}өms>} Cfa|w:AnM0WCMP&^Vp0iAu$x'ڶm_?x'uhM3L-&M]@U! | "4ģS]**O3P =T㷥T}Ƽ!5Uɜ.j(SA4);U;YƵ QQ gjPBǹ"ȹ HE!*(PU HlȼgYɵgK{ L3LCP̹"  z0¦Pӌs9ǹsC˲X;99]7va,)1{HTJmCEsEP%P(e!I֍3϶qj[`fO4fCm@{pth( AS- ~lYcڽٽO/Qů͞ϝ.&up ӿ"ȹv` X`UUws:[UЎ4Cuzw.s\9=VYQ1R1Tյg{֦?x= ]DzUX$vR\9׉Εe,!a+-q\޿ſYθE7&O3U0[.ԗ:ns88כ ePUBٜ_(eeRfڳiE4sjG@?J!6]u4B . "e"Oa2^ }KÇVv*l8 '()`t#KIo"QDc'[KN')z~ok:d_/9D3%n*U)RDwR)sMp6uMu[~*%GêIpܠQATU(`7j3i3yEޒCKh)a&=K7zNN" 6 wod!оUORJ !co3E "% =cg-MŘD)afh1R\ hQ&FlW[Va=qĺuL&SIIIFFƴi]uuE#|ϟx< , tm:}6gr8 !\I$>R]9{cgFJLStY4# aQX8z1*ٝ:0e}RHGxxxTTTvvҥKNzv˭s\ɷrKIIɞ={fΜIX3 l_9:!8mC{'A5p6 cY#)im|.{v_iqZ!R MZc28O.  9+`1N0yyy+E!t}[۷oOJJr8(t:lZVZV,"B),,8Jj EQbz"@M Hà--8vtJ(+VΞ4iҒ%Kl6ۭޚ{ޙ3g1ʕ>{31:]~iP@DIQX[">s͟Z3F&9Y $ꆔ4N:% \Q"Afݻw>|xGyDd"xС'NX_w(rСuֽ⋭ųgְGٳwޚgyEEEwuݽ{O5k-\pҥ7oniiYp;SSS{1B… }SO-^2;;;33>1bDp~ܟ^^Чf-ӗaYE޲(Ev_Q!׍uB'Q$}-FK [X tiVg@EBnDV=sȑ#N:u_|q͚5("A@*6 RP -ڨ]B!PETG|t6{Ad2FĽ7ypQԡ`$SRU8UDRq$''[N :T$blmVX,^zذa=cYZZܜr^|ŏ?866k!vSRRݻwcY $YBzco4E+"2BHEPUUef!DvUU`! .2!AU` ![-^?M("(_Ls UQCp8OV@@T~ |AmBHq>DAu;_m?ie- ~^ 'aQ,9-SJfH}^P{hAX}1!dϞ=7|eD :H%Ix<~>؝&ȫa4Y|jfs Ӛ5k"""\.dB}׵G.//2ͅ%%%wqGAA;JKKիWܹvGGG>}:55>۱c-((p\&;;{ǎgΜR /y? "to$Y)[2H"jڰok,(u B,G~+k^5t7$t RE~D*XSGIa`VTK9;Q >SaQrJgΜ+_uYdVFEE}G/?kV"={ƍeY3gꫯRSSG駟?;v!C ͛M@)aX.Rm%0 Vmn3S+VzhI!f( G rr,:ޓG\Nڋ6+ H$1:^6J,Q/4,ގ2mׯ[v5kƍ7dȐFG̝;m憅|;@)]`NMMMMM7}tdGsrrrrrX:SNO,mLGA{f-M,ڃPoAƠRm @ `ǧH)fWqi~gjB)&QI. f ` PBnĶF(<c6y䑎G(---3gΌ-+++--W*aݞ~3gμ&-g/v@PUm'$$\r6X夤$ PJYcb]"NF:| 6!5YQ-3޳%ΝlE6!,sOFF_Ss鏰셠B6 %<*2FӤ$0t ǽgN?>쯫XeN>,R*Q g| ?OEijj*..n ʲLaMo|.w 1nXqMH$JM6v8ο T.Fn_jRl]EE5Tʽ"zE֛ȲOSJ5M\\\\\\w,7q8Bݩ4^bׄ_Lo;-@+EU)7Wsϫ6uwRpz( ᲵԶa-mC y>$ wB[Jw8T7|Tƃ}"Dt_ݸKn zXE}7G׋.pp8.g@E hr8 A3"p4\9΀ pp8.g@E hr8 A3"p4\9΀ pp8.g@E hr8M/ 6TUUU/t|TծZ }Kl2B\բ跳iLҀ={/c^Klذaɒ%bŊ@1Gqe "<τ fֆv:yyy#Gܵk,˓&MJMMݼysLLLnn`B={699yhȑSNz4iٳkjjWM mDM ~P`L!m \;y ߴRYC@A-{ (_MtL2f#F={rVf%BRO8cƌ8qf͞= FB$I.+22"(((AN'ƘR*Bkkk`Rhllr*J1nTУO0~m@1F^XCZ\ YχPpJ1~Χ_Phh#ퟰW{&P J?pfmR qNϷrʜ655i4ލlPJ].Wɑeرc~?444a322*++1vք&m>/>>>220ƄKA|eʲl2jU*7 4A-T$hm~k*)$T%=A榔""D(&sHf&:PBt:ݕK<BL&ѣGߟ( 9,,%}Ko BHYF=C6l9rIx{_6mڪU^ȕ+WΙ3ȑ#ѣsss/^?nKKK裏v=k֬.{e-+|UI'МB)`eY#z,C1uPʬ6h4 *˲$kĞ-h4$"@kzoi'|}M'L@)}7-eUtd9bXq뮻VV'O$?>55544T3f3&,, !4wƈk6%IZ`Asssxx8<b=8\wBCOڤP*RB ;,o îIµ RTD|yJĉ322f[ݧGF)e0tʔ)!6kh$;`ΜmQ- Vjl?ΰ]OϮߧceso崷&;ڃ'坷1Ɓ0ˎ9ȶar8 ~_r)}Py \nZp8~[Hi \9΀ pp8.g@E hr8 A3"p4\9΀ pp8.g@E hr8 A3"p4\9΀ pp8.g@E hr8 A3"p4\9΀&AJi_p.(7\F (!RxË Bl6l^M 9;g3g11'f_sXF; ٌRUs.ԨzFzVF$h/QCrUVRУF k.mpETj압=Pj^S[j]Rb7황eݍu: k"FVr\ ٛ@)  rA@AuE21KkY!66`M&Sxxxeee0֏&j\f޽px9|r"BtJA텅e2y֊LadV: vR[aaIsH3YK~; yt[(% *XUU`* XY޽ܹsRxufffB7!d֭wu,˝ @^omnY{]Ԡ_Y{@^ի###z֞=M 4Bd{ Zf!{e;n9R>ti-;߬h ۃb'!X>Do|(L'bw#Zr Wv;lIsyu0'7˗:u [n]hQEEY޳lQ򗌜aͣ|IEEEZBȪU>a}駟~i|Zn>Zz5455ꫯz.=wҥKנ?ܰa-NMKt !7,]K[]]hѢ}!y۷C^ZA+ Ji]]hTUno߾}ڵSLq8n[lYv=qСCɓ'_:H&fl6͛mj]vt'OVTT444|aÆrޛvۭnf[lYuuuVVjZL _PPTVVАֶ|>VvVᆱV+x111'O|)))W^~0A (---¢VkKK ;v V\9y$$$~޴}N8|rILVRRqԩC@ZZ}ݧj~mAy%KnE/Y{fҤIϟ[|pLLLEE4inMYv;v5jɒ%~{MM̈́  TU={C׻u֦&YYY3nu9ew݄ jjj{ʼn%ID?###sssYDoZy欬g?<0a„XQ $I!!!VuϞ=,SJE}үYfܹկf,?'M"˲^El6={VM6=z;dPiڵk{챟zh4g?ɑ$It:Af#GVG}[WWt:{H-^w۶moz)ϗ`Ǐ7Nt:V+IdڶmnSN]̙3s" ^kj$h4v8vXIdYvoƌ3rss-Z9mڴu)hzF)fY$p8"##njX,{INNk%$$l6JVezކ0p\cСcƌ=֭j7noj{[x"##)n;55l6@||MQ?[ٳ4++7FX$Iuuu---QQQV?l0I)5 6lxNݻGu뭷Ԥ@g`cݻ fX!,h4'Nܼy֭[ZmYYٝw'Μ9SګϬ6m{w1cFBFajdd$;_DQ-Z$IO<޿yw._\ь9Rbbbbbb9gΜyWA?o18k֬r{ٳ,F 6pw׫hTU%LB^7<<XWdkYzHHj~c=&YM&p\~b ޷YEĬ|(v/F566t::EeOPYٛpLjkk%IbQQQP\N7+]W%!c7}[A&k{K%|"q pW>,y/Ok۾tpp8 p8 .g@E hr8 A3"p4\9΀ pp8.>Sr+TerzUU}>/z !t.~6el~0w9nE{0Z|/K6s+W{vZ;HAv^[oF8oY{0!Cݻ駟...޵kל9sN>=66j.Y$33sԨQV2 ~>zE{` !~cƍ'N,//ߵkWvv?񏜜3faÆ3gl+WDQBH֛ xuKF=j՘1c V;x'NL&Q322Vɓkjj͛K9y3=--m߾}ckq\ *R&g1,tF](Blfu{g@;F8΀ pp8.g@E hr8 A3"p4<+l%tEXtdate:create2015-08-04T23:08:31-04:00i%tEXtdate:modify2015-08-04T23:08:31-04:00;IENDB`