├── .gitignore ├── AUTHORS.md ├── LICENSE.md ├── MANIFEST ├── MANIFEST.in ├── README.md ├── batch.sh ├── docs ├── INSTALL.md └── notes.txt ├── gomoshion.py ├── moshion ├── __init__.py ├── clip.py ├── core.py ├── extractframes │ ├── Rat.py │ ├── __init__.py │ ├── framesource.py │ ├── multirange.py │ ├── newmath.py │ ├── rateconverter.py │ └── timespec.py ├── pymosh │ ├── __init__.py │ ├── avi.py │ ├── mpeg4.py │ └── riff.py ├── scripts │ └── gomoshion.py ├── seqls.py ├── sequence.py └── util.py ├── output └── frame_list.txt ├── setup.cfg ├── setup.py └── tests ├── __init__.py └── footage ├── input ├── Users │ └── rob │ │ └── Code │ │ └── python-moshtion │ │ └── tests │ │ └── footage │ │ └── output │ │ └── frame_list.txt ├── input_ftg.0001.jpg ├── input_ftg.0002.jpg ├── input_ftg.0003.jpg ├── input_ftg.0004.jpg ├── input_ftg.0005.jpg ├── input_ftg.0006.jpg ├── input_ftg.0007.jpg ├── input_ftg.0008.jpg ├── input_ftg.0009.jpg ├── input_ftg.0010.jpg ├── input_ftg.0011.jpg ├── input_ftg.0012.jpg ├── input_ftg.0013.jpg ├── input_ftg.0014.jpg ├── input_ftg.0015.jpg ├── input_ftg.0016.jpg ├── input_ftg.0017.jpg ├── input_ftg.0018.jpg ├── input_ftg.0019.jpg ├── input_ftg.0020.jpg ├── input_ftg.0021.jpg ├── input_ftg.0022.jpg ├── input_ftg.0023.jpg ├── input_ftg.0024.jpg ├── input_ftg.0025.jpg ├── input_ftg.0026.jpg ├── input_ftg.0027.jpg ├── input_ftg.0028.jpg ├── input_ftg.0029.jpg ├── input_ftg.0030.jpg ├── input_ftg.0031.jpg ├── input_ftg.0032.jpg ├── input_ftg.0033.jpg ├── input_ftg.0034.jpg ├── input_ftg.0035.jpg ├── input_ftg.0036.jpg ├── input_ftg.0037.jpg ├── input_ftg.0038.jpg ├── input_ftg.0039.jpg ├── input_ftg.0040.jpg ├── input_ftg.0041.jpg ├── input_ftg.0042.jpg ├── input_ftg.0043.jpg ├── input_ftg.0044.jpg ├── input_ftg.0045.jpg ├── input_ftg.0046.jpg ├── input_ftg.0047.jpg ├── input_ftg.0048.jpg ├── input_ftg.0049.jpg ├── input_ftg.0050.jpg ├── input_ftg.0051.jpg ├── input_ftg.0052.jpg ├── input_ftg.0053.jpg ├── input_ftg.0054.jpg ├── input_ftg.0055.jpg ├── input_ftg.0056.jpg ├── input_ftg.0057.jpg ├── input_ftg.0058.jpg ├── input_ftg.0059.jpg ├── input_ftg.0060.jpg ├── input_ftg.0061.jpg ├── input_ftg.0062.jpg ├── input_ftg.0063.jpg ├── input_ftg.0064.jpg ├── input_ftg.0065.jpg ├── input_ftg.0066.jpg ├── input_ftg.0067.jpg ├── input_ftg.0068.jpg ├── input_ftg.0069.jpg ├── input_ftg.0070.jpg ├── input_ftg.0071.jpg ├── input_ftg.0072.jpg ├── input_ftg.0073.jpg ├── input_ftg.0074.jpg ├── input_ftg.0075.jpg ├── input_ftg.0076.jpg ├── input_ftg.0077.jpg ├── input_ftg.0078.jpg ├── input_ftg.0079.jpg ├── input_ftg.0080.jpg ├── input_ftg.0081.jpg ├── input_ftg.0082.jpg ├── input_ftg.0083.jpg ├── input_ftg.0084.jpg ├── input_ftg.0085.jpg ├── input_ftg.0086.jpg ├── input_ftg.0087.jpg ├── input_ftg.0088.jpg ├── input_ftg.0089.jpg ├── input_ftg.0090.jpg ├── input_ftg.0091.jpg ├── input_ftg.0092.jpg ├── input_ftg.0093.jpg ├── input_ftg.0094.jpg ├── input_ftg.0095.jpg ├── input_ftg.0096.jpg ├── input_ftg.0097.jpg ├── input_ftg.0098.jpg ├── input_ftg.0099.jpg └── input_ftg.0100.jpg └── moshtex ├── moshtex_ftg.0001.jpg ├── moshtex_ftg.0002.jpg ├── moshtex_ftg.0003.jpg ├── moshtex_ftg.0004.jpg ├── moshtex_ftg.0005.jpg ├── moshtex_ftg.0006.jpg ├── moshtex_ftg.0007.jpg ├── moshtex_ftg.0008.jpg ├── moshtex_ftg.0009.jpg ├── moshtex_ftg.0010.jpg ├── moshtex_ftg.0011.jpg ├── moshtex_ftg.0012.jpg ├── moshtex_ftg.0013.jpg ├── moshtex_ftg.0014.jpg ├── moshtex_ftg.0015.jpg ├── moshtex_ftg.0016.jpg ├── moshtex_ftg.0017.jpg ├── moshtex_ftg.0018.jpg ├── moshtex_ftg.0019.jpg ├── moshtex_ftg.0020.jpg ├── moshtex_ftg.0021.jpg ├── moshtex_ftg.0022.jpg ├── moshtex_ftg.0023.jpg ├── moshtex_ftg.0024.jpg ├── moshtex_ftg.0025.jpg ├── moshtex_ftg.0026.jpg ├── moshtex_ftg.0027.jpg ├── moshtex_ftg.0028.jpg ├── moshtex_ftg.0029.jpg ├── moshtex_ftg.0030.jpg ├── moshtex_ftg.0031.jpg ├── moshtex_ftg.0032.jpg ├── moshtex_ftg.0033.jpg ├── moshtex_ftg.0034.jpg ├── moshtex_ftg.0035.jpg ├── moshtex_ftg.0036.jpg ├── moshtex_ftg.0037.jpg ├── moshtex_ftg.0038.jpg ├── moshtex_ftg.0039.jpg ├── moshtex_ftg.0040.jpg ├── moshtex_ftg.0041.jpg ├── moshtex_ftg.0042.jpg ├── moshtex_ftg.0043.jpg ├── moshtex_ftg.0044.jpg ├── moshtex_ftg.0045.jpg ├── moshtex_ftg.0046.jpg ├── moshtex_ftg.0047.jpg ├── moshtex_ftg.0048.jpg ├── moshtex_ftg.0049.jpg ├── moshtex_ftg.0050.jpg ├── moshtex_ftg.0051.jpg ├── moshtex_ftg.0052.jpg ├── moshtex_ftg.0053.jpg ├── moshtex_ftg.0054.jpg ├── moshtex_ftg.0055.jpg ├── moshtex_ftg.0056.jpg ├── moshtex_ftg.0057.jpg ├── moshtex_ftg.0058.jpg ├── moshtex_ftg.0059.jpg ├── moshtex_ftg.0060.jpg ├── moshtex_ftg.0061.jpg ├── moshtex_ftg.0062.jpg ├── moshtex_ftg.0063.jpg ├── moshtex_ftg.0064.jpg ├── moshtex_ftg.0065.jpg ├── moshtex_ftg.0066.jpg ├── moshtex_ftg.0067.jpg ├── moshtex_ftg.0068.jpg ├── moshtex_ftg.0069.jpg ├── moshtex_ftg.0070.jpg ├── moshtex_ftg.0071.jpg ├── moshtex_ftg.0072.jpg ├── moshtex_ftg.0073.jpg ├── moshtex_ftg.0074.jpg ├── moshtex_ftg.0075.jpg ├── moshtex_ftg.0076.jpg ├── moshtex_ftg.0077.jpg ├── moshtex_ftg.0078.jpg ├── moshtex_ftg.0079.jpg ├── moshtex_ftg.0080.jpg ├── moshtex_ftg.0081.jpg ├── moshtex_ftg.0082.jpg ├── moshtex_ftg.0083.jpg ├── moshtex_ftg.0084.jpg ├── moshtex_ftg.0085.jpg ├── moshtex_ftg.0086.jpg ├── moshtex_ftg.0087.jpg ├── moshtex_ftg.0088.jpg ├── moshtex_ftg.0089.jpg ├── moshtex_ftg.0090.jpg ├── moshtex_ftg.0091.jpg ├── moshtex_ftg.0092.jpg ├── moshtex_ftg.0093.jpg ├── moshtex_ftg.0094.jpg ├── moshtex_ftg.0095.jpg ├── moshtex_ftg.0096.jpg ├── moshtex_ftg.0097.jpg ├── moshtex_ftg.0098.jpg ├── moshtex_ftg.0099.jpg ├── moshtex_ftg.0100.jpg └── moshtex_ftg.0101.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | tests/footage/output 2 | *~ 3 | *.db 4 | *.orig 5 | *.pyc 6 | *.pyo 7 | *.rej 8 | .installed.cfg 9 | __minitage__* 10 | bin 11 | python_dirtt.egg-info 12 | build 13 | _build 14 | develop-eggs 15 | downloads 16 | eggs 17 | log 18 | parts 19 | tmp 20 | .DS_Store 21 | .hg 22 | src/*.egg-info 23 | dist 24 | pip-log.txt 25 | .Python 26 | lib 27 | include 28 | .mr.developer.cfg 29 | src 30 | ._* 31 | -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | # Author(s) 2 | 3 | Robert Moggach 4 | Fabio Piparo 5 | 6 | # Maintainers 7 | 8 | Robert Moggach 9 | 10 | # Contributors 11 | 12 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License 2 | =============== 3 | 4 | Copyright (c) 2014 Robert Moggach, Fabio Piparo & contributors. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | AUTHORS.md 2 | docs/INSTALL.md 3 | docs/notes.txt 4 | gomoshion.py 5 | LICENSE.md 6 | MANIFEST 7 | MANIFEST.in 8 | moshion/__init__.py 9 | moshion/core.py 10 | moshion/pymosh 11 | moshion/pymosh/__init__.py 12 | moshion/pymosh/avi.py 13 | moshion/pymosh/mpeg4.py 14 | moshion/pymosh/riff.py 15 | moshion/seqls.py 16 | moshion/sequence.py 17 | moshion/util.py 18 | moshion/scripts/gomoshion.py 19 | README.md 20 | setup.cfg 21 | setup.py 22 | tests/__init__.py 23 | tests/footage/input/input_ftg.0001.jpg 24 | tests/footage/input/input_ftg.0002.jpg 25 | tests/footage/input/input_ftg.0003.jpg 26 | tests/footage/input/input_ftg.0004.jpg 27 | tests/footage/input/input_ftg.0005.jpg 28 | tests/footage/input/input_ftg.0006.jpg 29 | tests/footage/input/input_ftg.0007.jpg 30 | tests/footage/input/input_ftg.0008.jpg 31 | tests/footage/input/input_ftg.0009.jpg 32 | tests/footage/input/input_ftg.0010.jpg 33 | tests/footage/input/input_ftg.0011.jpg 34 | tests/footage/input/input_ftg.0012.jpg 35 | tests/footage/input/input_ftg.0013.jpg 36 | tests/footage/input/input_ftg.0014.jpg 37 | tests/footage/input/input_ftg.0015.jpg 38 | tests/footage/input/input_ftg.0016.jpg 39 | tests/footage/input/input_ftg.0017.jpg 40 | tests/footage/input/input_ftg.0018.jpg 41 | tests/footage/input/input_ftg.0019.jpg 42 | tests/footage/input/input_ftg.0020.jpg 43 | tests/footage/input/input_ftg.0021.jpg 44 | tests/footage/input/input_ftg.0022.jpg 45 | tests/footage/input/input_ftg.0023.jpg 46 | tests/footage/input/input_ftg.0024.jpg 47 | tests/footage/input/input_ftg.0025.jpg 48 | tests/footage/input/input_ftg.0026.jpg 49 | tests/footage/input/input_ftg.0027.jpg 50 | tests/footage/input/input_ftg.0028.jpg 51 | tests/footage/input/input_ftg.0029.jpg 52 | tests/footage/input/input_ftg.0030.jpg 53 | tests/footage/input/input_ftg.0031.jpg 54 | tests/footage/input/input_ftg.0032.jpg 55 | tests/footage/input/input_ftg.0033.jpg 56 | tests/footage/input/input_ftg.0034.jpg 57 | tests/footage/input/input_ftg.0035.jpg 58 | tests/footage/input/input_ftg.0036.jpg 59 | tests/footage/input/input_ftg.0037.jpg 60 | tests/footage/input/input_ftg.0038.jpg 61 | tests/footage/input/input_ftg.0039.jpg 62 | tests/footage/input/input_ftg.0040.jpg 63 | tests/footage/input/input_ftg.0041.jpg 64 | tests/footage/input/input_ftg.0042.jpg 65 | tests/footage/input/input_ftg.0043.jpg 66 | tests/footage/input/input_ftg.0044.jpg 67 | tests/footage/input/input_ftg.0045.jpg 68 | tests/footage/input/input_ftg.0046.jpg 69 | tests/footage/input/input_ftg.0047.jpg 70 | tests/footage/input/input_ftg.0048.jpg 71 | tests/footage/input/input_ftg.0049.jpg 72 | tests/footage/input/input_ftg.0050.jpg 73 | tests/footage/moshtex/moshtex_ftg.0001.jpg 74 | tests/footage/moshtex/moshtex_ftg.0002.jpg 75 | tests/footage/moshtex/moshtex_ftg.0003.jpg 76 | tests/footage/moshtex/moshtex_ftg.0004.jpg 77 | tests/footage/moshtex/moshtex_ftg.0005.jpg 78 | tests/footage/moshtex/moshtex_ftg.0006.jpg 79 | tests/footage/moshtex/moshtex_ftg.0007.jpg 80 | tests/footage/moshtex/moshtex_ftg.0008.jpg 81 | tests/footage/moshtex/moshtex_ftg.0009.jpg 82 | tests/footage/moshtex/moshtex_ftg.0010.jpg 83 | tests/footage/moshtex/moshtex_ftg.0011.jpg 84 | tests/footage/moshtex/moshtex_ftg.0012.jpg 85 | tests/footage/moshtex/moshtex_ftg.0013.jpg 86 | tests/footage/moshtex/moshtex_ftg.0014.jpg 87 | tests/footage/moshtex/moshtex_ftg.0015.jpg 88 | tests/footage/moshtex/moshtex_ftg.0016.jpg 89 | tests/footage/moshtex/moshtex_ftg.0017.jpg 90 | tests/footage/moshtex/moshtex_ftg.0018.jpg 91 | tests/footage/moshtex/moshtex_ftg.0019.jpg 92 | tests/footage/moshtex/moshtex_ftg.0020.jpg 93 | tests/footage/moshtex/moshtex_ftg.0021.jpg 94 | tests/footage/moshtex/moshtex_ftg.0022.jpg 95 | tests/footage/moshtex/moshtex_ftg.0023.jpg 96 | tests/footage/moshtex/moshtex_ftg.0024.jpg 97 | tests/footage/moshtex/moshtex_ftg.0025.jpg 98 | tests/footage/moshtex/moshtex_ftg.0026.jpg 99 | tests/footage/moshtex/moshtex_ftg.0027.jpg 100 | tests/footage/moshtex/moshtex_ftg.0028.jpg 101 | tests/footage/moshtex/moshtex_ftg.0029.jpg 102 | tests/footage/moshtex/moshtex_ftg.0030.jpg 103 | tests/footage/moshtex/moshtex_ftg.0031.jpg 104 | tests/footage/moshtex/moshtex_ftg.0032.jpg 105 | tests/footage/moshtex/moshtex_ftg.0033.jpg 106 | tests/footage/moshtex/moshtex_ftg.0034.jpg 107 | tests/footage/moshtex/moshtex_ftg.0035.jpg 108 | tests/footage/moshtex/moshtex_ftg.0036.jpg 109 | tests/footage/moshtex/moshtex_ftg.0037.jpg 110 | tests/footage/moshtex/moshtex_ftg.0038.jpg 111 | tests/footage/moshtex/moshtex_ftg.0039.jpg 112 | tests/footage/moshtex/moshtex_ftg.0040.jpg 113 | tests/footage/moshtex/moshtex_ftg.0041.jpg 114 | tests/footage/moshtex/moshtex_ftg.0042.jpg 115 | tests/footage/moshtex/moshtex_ftg.0043.jpg 116 | tests/footage/moshtex/moshtex_ftg.0044.jpg 117 | tests/footage/moshtex/moshtex_ftg.0045.jpg 118 | tests/footage/moshtex/moshtex_ftg.0046.jpg 119 | tests/footage/moshtex/moshtex_ftg.0047.jpg 120 | tests/footage/moshtex/moshtex_ftg.0048.jpg 121 | tests/footage/moshtex/moshtex_ftg.0049.jpg 122 | tests/footage/moshtex/moshtex_ftg.0050.jpg 123 | tests/footage/moshtex/moshtex_ftg.0051.jpg 124 | tests/footage/moshtex/moshtex_ftg.0052.jpg 125 | tests/footage/moshtex/moshtex_ftg.0053.jpg 126 | tests/footage/moshtex/moshtex_ftg.0054.jpg 127 | tests/footage/moshtex/moshtex_ftg.0055.jpg 128 | tests/footage/moshtex/moshtex_ftg.0056.jpg 129 | tests/footage/moshtex/moshtex_ftg.0057.jpg 130 | tests/footage/moshtex/moshtex_ftg.0058.jpg 131 | tests/footage/moshtex/moshtex_ftg.0059.jpg 132 | tests/footage/moshtex/moshtex_ftg.0060.jpg 133 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS.md 2 | include LICENSE.md 3 | include README.md 4 | recursive-include docs *.md *.html *.jpg *.png *.js *.css *.gif 5 | recursive-exclude docs/_build * 6 | recursive-include tests *.py 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # python-moshion - Datamoshing Motion 2 | 3 | > **moshion** is a command line interface to [ffmpeg](https://www.ffmpeg.org "ffmpeg.org") 4 | > used to [datamosh](http://knowyourmeme.com/memes/datamoshing "Datamoshing") 5 | > two video sequences to purposely create encoding artifacts. 6 | 7 | 8 | **This software is in alpha state and no where near production ready.** 9 | 10 | **Try it out but all the usual caveats apply. Use at your own risk etc.** 11 | 12 | 13 | 14 | ## Status and License 15 | 16 | Copyright (c) 2014 Robert Moggach, Fabio Piparo & contributors. 17 | 18 | Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php 19 | 20 | 21 | 22 | 23 | ## About 24 | 25 | Traditional 'datamoshing' involves removing I-frames from encoded videos to create encoding 26 | artifacts that appear to make frames melt into one another by inheriting the motion of the 27 | incoming footage. 28 | 29 | This is cool but the result is a moving still frame - we want a moving outgoing picture. 30 | By progressively deleting frames from the outgoing clip along with the I-frame of the incoming clip, 31 | we hope to create a series of frames that represent the outgoing clip moshed by the motion of the 32 | incoming clip. Give it a try. 33 | 34 | This has all been done before but usually only produces another video and without alot of flexibility 35 | for what we need. We work with discrete frames so **moshion** accordingly takes two image sequences, 36 | splices them together, encodes them, deletes the I-frames to create a moshed video and then extracts 37 | the *moshed* frames as a new image sequence. 38 | 39 | 40 | ## Contributing 41 | 42 | All kinds of contributions are welcome - code, tests, documentation, bug reports, ideas, etc. 43 | 44 | Currently we need to implement the following: 45 | 46 | * testing 47 | * optimization 48 | * more encoding options, codecs, tricks to make it better 49 | * enhanced portability 50 | * better code all around instead of the rushed hack this is now 51 | * other mosh techniques 52 | 53 | Check out the issues to see what we're focused on. 54 | 55 | * [GitHub Issue Tracker](https://github.com/mogga/python-moshion/issues "Issues") 56 | 57 | 58 | ### Forking through GitHub 59 | 60 | First of all, you need to fork from the official repository... 61 | 62 | [Fork python-moshion](https://github.com/mogga/python-moshion/fork "Fork") 63 | 64 | Now you can change whatever you want, commit, push to your fork and when 65 | your contribution is done, follow the pull request link and explain what you did and why. 66 | 67 | 68 | 69 | ### Running the tests 70 | 71 | Patience. Tests are important and will be implemented. 72 | 73 | 74 | 75 | ## Documentation 76 | 77 | This is admittedly sparse but will get better. For now: 78 | 79 | ### Installation 80 | 81 | We don't have any installer at the moment so you kinda need to know what you're doing. 82 | 83 | #### Prerequisites 84 | 85 | Without question you need ffmpeg but there are a ton of other libraries you may need as well depending on what images, videos you want to use. 86 | 87 | Here are some links: 88 | 89 | ##### Mac OSX 90 | 91 | Everyone loves homebrew. Getting it to install **ffmpeg** is not always easy. 92 | 93 | brew install ffmpeg --with-fdk-aac --with-ffplay --with-freetype --with-frei0r \ 94 | --with-libass --with-libass --with-libbluray --with-libcaca --with-libquvi \ 95 | --with-libvo-aacenc --with-libvorbis --with-libvpx --with-opencore-amr \ 96 | --with-openjpeg --with-openssl --with-opus --with-rtmpdump --with-schroedinger \ 97 | --with-speex --with-theora --with-tools --with-libmp3lame 98 | 99 | This is easier... 100 | 101 | [static FFmpeg binaries for Mac OS X Intel 64bit](http://www.evermeet.cx/ffmpeg/) 102 | 103 | #### Clone the repo 104 | 105 | Start by cloning the repo: 106 | 107 | git clone https://github.com/mogga/python-moshion.git 108 | 109 | #### Command Line Tool 110 | 111 | From within the repo run the included command line script to get a feel for it. 112 | 113 | cd python-moshion 114 | ./gomoshion.py -s 1 -e 20 -f 5 --input `pwd`/tests/footage/input/input_ftg.%04d.jpg --mosh `pwd`/tests/footage/input/input_ftg.%04d.jpg -o `pwd`/tests/footage/output 115 | 116 | or use the interactive mode... 117 | 118 | ./gomoshion.py -q 119 | 120 | 121 | 122 | ## Acknowledgements 123 | 124 | We use a couple great packages to get this working: 125 | 126 | First and foremost is [pymosh](https://github.com/grampajoe/pymosh "PyMosh") so a big thank you for that headstart. 127 | 128 | Being VFX/CG artists we also rely on [cgkit](http://cgkit.sourceforge.net) which we use for it's sequence parsing bits. 129 | 130 | The really great [Ruby AviGlitch](http://ucnv.github.io/aviglitch/) is great too although this is python so it was more of an inspiration than anything else. 131 | 132 | For our tests we use a few bits from the [internet archive](https://archive.org/) specifically this clip: 133 | 134 | [InternetArchive35mmStockFootageSampleReel](https://archive.org/details/InternetArchive35mmStockFootageSampleReel) 135 | 136 | 137 | ## Links 138 | 139 | Here are some great places to learn about datamoshing, glitch art, pixel sorting. 140 | It's not comprehensive by any stretch... just the links we found as we did our research. 141 | 142 | * [pymosh](https://github.com/grampajoe/pymosh "PyMosh") 143 | * [Perl Autodatamosh](https://github.com/grampajoe/Autodatamosh) 144 | * [Ruby AviGlitch](http://ucnv.github.io/aviglitch/) 145 | * [PixelSorting](https://github.com/jeffThompson/PixelSorting) 146 | * [Le_DataMoshing](http://wiki.labomedia.org/index.php/Le_DataMoshing) 147 | * [Databend Gist](https://gist.github.com/adrn/4090186) 148 | * [Databend](https://github.com/cschlisner/Databend) 149 | * [Quartz Composer Datamosh](http://kriss.cx/tom/datamosh/) 150 | * [GL PBO Glitch](https://github.com/bangnoise/GL-PBO-Glitch) 151 | * [Echobender](http://www.hellocatfood.com/echobender/) 152 | * [Glitch Things](http://www.hellocatfood.com/tag/glitch/) 153 | * [Processing Glitch](http://www.xradiograph.com/Processing/Glitch) 154 | * [dataswitch](https://github.com/dataswitch/Experimental/tree/master/databend) 155 | * [imageglitch](http://www.sun-art.org/creativecoding/imageglitch/) 156 | * [imageglitcher](http://www.airtightinteractive.com/2011/02/glitch-your-images-with-imageglitcher/) 157 | * [Databending](http://www.jackhagley.com/Experimental-Databending) 158 | * [Encoding Explained](http://objavi.booki.cc/books/alookatopenvideo-en-2013.01.10-12.43.09/ch010_encoding-explained.html) 159 | 160 | -------------------------------------------------------------------------------- /docs/INSTALL.md: -------------------------------------------------------------------------------- 1 | Coming soon... -------------------------------------------------------------------------------- /docs/notes.txt: -------------------------------------------------------------------------------- 1 | 2 | # Moving Mosh Procedure 3 | 4 | ## INPUT IMAGE SEQUENCE 5 | 6 | src.%04d.jpg 1-5 7 | 8 | ## INPUT MOSH TEXTURE SEQUENCE 9 | 10 | tex.%04d.jpg 1-10 11 | 12 | 13 | ## Concat sequences to create full size AVI 14 | 15 | src.0001.jpg I 16 | src.0002.jpg 17 | src.0003.jpg 18 | src.0004.jpg 19 | src.0005.jpg 20 | tex.0001.jpg I 21 | tex.0002.jpg 22 | tex.0003.jpg 23 | tex.0004.jpg 24 | tex.0005.jpg 25 | 26 | 27 | ## Iterative Frame Dropping 28 | 29 | 1) Delete frames up to I-frame 30 | 31 | src.0001.jpg I 32 | src.0002.jpg X 33 | src.0003.jpg X 34 | src.0004.jpg X 35 | src.0005.jpg X 36 | tex.0001.jpg I X 37 | tex.0002.jpg 38 | tex.0003.jpg 39 | tex.0004.jpg 40 | tex.0005.jpg 41 | tex.0006.jpg 42 | 43 | 2) Export Desired Frame 44 | 45 | src.0001.jpg I 46 | ... deleted ... 47 | tex.0002.jpg -> mosh.0001.jpg 48 | tex.0003.jpg 49 | tex.0004.jpg 50 | tex.0005.jpg 51 | tex.0006.jpg 52 | 53 | ## Advance to next frame and repeat 54 | 55 | 3) Delete frames up to I-frame 56 | 57 | src.0001.jpg I 58 | src.0002.jpg 59 | src.0003.jpg X 60 | src.0004.jpg X 61 | src.0005.jpg X 62 | tex.0001.jpg I X 63 | tex.0002.jpg 64 | tex.0003.jpg 65 | tex.0004.jpg 66 | tex.0005.jpg 67 | tex.0006.jpg 68 | 69 | 4) Export Desired Frame 70 | 71 | src.0001.jpg I 72 | src.0002.jpg 73 | ... deleted ... 74 | tex.0002.jpg 75 | tex.0003.jpg -> mosh.0002.jpg 76 | tex.0004.jpg 77 | tex.0005.jpg 78 | tex.0006.jpg 79 | 80 | ## Advance to next frame and repeat 81 | 82 | 5) Delete frames up to I-frame 83 | 84 | src.0001.jpg I 85 | src.0002.jpg 86 | src.0003.jpg 87 | src.0004.jpg X 88 | src.0005.jpg X 89 | tex.0001.jpg I X 90 | tex.0002.jpg 91 | tex.0003.jpg 92 | tex.0004.jpg 93 | tex.0005.jpg 94 | tex.0006.jpg 95 | 96 | 6) Export Desired Frame 97 | 98 | src.0001.jpg I 99 | src.0002.jpg 100 | src.0003.jpg 101 | ... deleted ... 102 | tex.0002.jpg 103 | tex.0003.jpg 104 | tex.0004.jpg -> mosh.0003.jpg 105 | tex.0005.jpg 106 | tex.0006.jpg 107 | 108 | 109 | ## Advance to next frame and repeat 110 | 111 | 7) Delete frames up to I-frame 112 | 113 | src.0001.jpg I 114 | src.0002.jpg 115 | src.0003.jpg 116 | src.0004.jpg 117 | src.0005.jpg X 118 | tex.0001.jpg I X 119 | tex.0002.jpg 120 | tex.0003.jpg 121 | tex.0004.jpg 122 | tex.0005.jpg 123 | tex.0006.jpg 124 | 125 | 8) Export Desired Frame 126 | 127 | src.0001.jpg I 128 | src.0002.jpg 129 | src.0003.jpg 130 | src.0004.jpg 131 | ... deleted ... 132 | tex.0002.jpg 133 | tex.0003.jpg 134 | tex.0004.jpg 135 | tex.0005.jpg -> mosh.0004.jpg 136 | tex.0006.jpg 137 | 138 | 139 | ## Advance to next frame and repeat 140 | 141 | 9) Delete frames up to I-frame 142 | 143 | src.0001.jpg I 144 | src.0002.jpg 145 | src.0003.jpg 146 | src.0004.jpg 147 | src.0005.jpg 148 | tex.0001.jpg I X 149 | tex.0002.jpg 150 | tex.0003.jpg 151 | tex.0004.jpg 152 | tex.0005.jpg 153 | tex.0006.jpg 154 | 155 | 10) Export Desired Frame 156 | 157 | src.0001.jpg I 158 | src.0002.jpg 159 | src.0003.jpg 160 | src.0004.jpg 161 | src.0005.jpg 162 | ... deleted ... 163 | tex.0002.jpg 164 | tex.0003.jpg 165 | tex.0004.jpg 166 | tex.0005.jpg 167 | tex.0006.jpg -> mosh.0005.jpg -------------------------------------------------------------------------------- /gomoshion.py: -------------------------------------------------------------------------------- 1 | moshion/scripts/gomoshion.py -------------------------------------------------------------------------------- /moshion/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | python-moshion - Datamoshing Motion 3 | (c) 2014 Robert Moggach, Fabio Piparo and contributors 4 | Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php 5 | 6 | __init__.py 7 | 8 | moshion is a command line interface to ffmpeg used to datamosh two 9 | video sequences to purposely create encoding artifacts. 10 | 11 | """ 12 | 13 | #v0.0.1b 14 | VERSION = (0, 0, 1, 'beta', 1) 15 | 16 | STATUSES = {'alpha': 'a', 'beta': 'b', 'releasecandidate': 'rc' } 17 | 18 | 19 | def get_version(): 20 | version = '%s.%s' % (VERSION[0], VERSION[1]) 21 | if VERSION[2]: 22 | version = '%s.%s' % (version, VERSION[2]) 23 | if VERSION[3:] == ('alpha', 0): 24 | version = '%s pre-alpha' % version 25 | else: 26 | if VERSION[3] != 'final': 27 | version = '%s%s%s' % (version, STATUSES[VERSION[3]], VERSION[4]) 28 | return version 29 | 30 | __version__ = get_version() 31 | __all__ = ['util'] 32 | 33 | -------------------------------------------------------------------------------- /moshion/clip.py: -------------------------------------------------------------------------------- 1 | """ 2 | python-moshion - Datamoshing Motion 3 | (c) 2014 Robert Moggach, Fabio Piparo and contributors 4 | Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php 5 | 6 | moshClassic.py 7 | 8 | moshion is a command line interface to ffmpeg used to datamosh two 9 | video sequences to purposely create encoding artifacts. 10 | 11 | """ 12 | 13 | 14 | 15 | class Clip(): 16 | """ 17 | Clip Object 18 | 19 | this class defines the clip object which is represents 20 | an image sequence object and provides methods for passing 21 | the sequence to other methods programmatically and performing 22 | I/O functions. 23 | """ 24 | 25 | def __init__(self): 26 | pass 27 | -------------------------------------------------------------------------------- /moshion/core.py: -------------------------------------------------------------------------------- 1 | """ 2 | python-moshion - Datamoshing Motion 3 | (c) 2014 Robert Moggach, Fabio Piparo and contributors 4 | Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php 5 | 6 | core.py 7 | 8 | moshion is a command line interface to ffmpeg used to datamosh two 9 | video sequences to purposely create encoding artifacts. 10 | 11 | """ 12 | 13 | 14 | import sys 15 | import os 16 | import glob 17 | import copy 18 | import subprocess 19 | 20 | from .pymosh import Index 21 | from .pymosh.mpeg4 import is_iframe 22 | #from .extractframes.timespec import time_to_frame 23 | #from .extractframes.multirange import multirange 24 | from .util import IS_TTY, HR, hilite 25 | import sequence 26 | import readline 27 | 28 | # pattern=os.path.abspath(pattern) 29 | # fseqs = sequence.glob(pattern) 30 | 31 | 32 | class Moshion(): 33 | 34 | def __init__(self, inseq, moshseq, start, end, outdir, moshstart=None, bitrate="8000", keyframe="999", threshold="100000000", interval="9", avionly=False, uber=False): 35 | self.uber = uber 36 | self.inseq = os.path.normpath(inseq.replace('\\', os.sep)) 37 | self.filebase = self.inseq.split('.')[0].split(os.sep)[-1] 38 | self.fileext = self.inseq.split('.')[-1] 39 | self.moshseq = os.path.normpath(moshseq.replace('\\', os.sep)) 40 | self.start = int(start) 41 | self.end = int(end) 42 | self.avionly=avionly 43 | if moshstart is None: 44 | self.moshstart = int(self.start) 45 | else: 46 | self.moshstart = int(moshstart) 47 | self.input_frame_list = list(range(int(self.start), int(self.end)+1)) 48 | self.mosh_frame_list = list(range(int(self.moshstart), int(self.moshstart)+len(self.input_frame_list)+1)) 49 | self.bitrate = bitrate 50 | self.keyframe = keyframe 51 | self.threshold = threshold 52 | self.interval = interval 53 | self.outdir = os.path.normpath(outdir.replace('\\', os.sep)) 54 | self.to_mosh = [] 55 | self.moshed = [] 56 | if not os.path.isdir(self.outdir): 57 | os.makedirs(self.outdir, 0755) 58 | self.outfiledir = os.path.join(self.outdir, self.fileext) 59 | if not os.path.isdir(self.outfiledir) and not self.avionly: os.makedirs(self.outfiledir, 0755) 60 | outfilename = "{2}{0}{1}_moshed.%04d.{2}".format( os.sep, self.filebase, self.fileext ) 61 | self.outseq = os.path.join(self.outdir, outfilename) 62 | # self.moshed = os.path.join(self.outdir, "mosh_encode.avi") 63 | self.file_list_dict = self.get_file_list_dict() 64 | self.write_file_list() 65 | 66 | def get_file_list_dict(self): 67 | files = {} 68 | if not self.uber: 69 | file_list_name = 'frame_list.txt' 70 | file_list = ['ffconcat version 1.0'] 71 | for frame in self.input_frame_list: 72 | file_list.append("file %s" % self.inseq % frame) 73 | for frame in self.mosh_frame_list: 74 | file_list.append("file %s" % self.moshseq % frame) 75 | files[file_list_name] = file_list 76 | else: 77 | file_list_name = 'frame_list.%04d.txt' 78 | uber_frame_list = list(self.input_frame_list) 79 | while uber_frame_list: 80 | file_list = ['ffconcat version 1.0'] 81 | for frame in uber_frame_list: 82 | file_list.append("file %s" % self.inseq % frame) 83 | for frame in self.mosh_frame_list: 84 | file_list.append("file %s" % self.moshseq % frame) 85 | files[file_list_name % uber_frame_list.pop()] = file_list 86 | return files 87 | 88 | def write_file_list(self): 89 | for ffile, flist in self.file_list_dict.iteritems(): 90 | file_path = os.path.join(self.outdir, ffile) 91 | out_file = file(file_path, 'w') 92 | out_file.write('\n'.join(flist)) 93 | out_file.close() 94 | 95 | def get_encode_opts(self, list_file, avi): 96 | opts = ['ffmpeg'] 97 | opts.extend(['-safe', '0']) 98 | opts.extend(['-i']) 99 | opts.extend([list_file]) 100 | opts.extend(['-nostdin']) 101 | opts.extend(['-hide_banner']) 102 | opts.extend(['-pattern_type', 'sequence']) 103 | opts.extend(['-g', self.keyframe]) 104 | opts.extend(['-sc_threshold', self.threshold]) 105 | opts.extend(['-an']) 106 | opts.extend(['-vf', 'fps=25']) 107 | opts.extend(['-vcodec', 'libxvid']) 108 | opts.extend(['-f', 'avi']) 109 | opts.extend(['-y']) 110 | opts.extend([avi]) 111 | return opts 112 | 113 | def write_movie(self): 114 | self.to_mosh=[] 115 | if not self.uber: 116 | msg = '\n\nCreating initial movie\n\n' 117 | if IS_TTY: print hilite(msg,7) 118 | for key, value in self.file_list_dict.iteritems(): 119 | list_file = os.path.join(self.outdir, key) 120 | avi_filename = "{0}.avi".format(self.filebase) 121 | self.to_mosh.append(avi_filename) 122 | avi = os.path.join(self.outdir, avi_filename) 123 | #, shell=False, stdin=PIPE, stdout=PIPE, stderr=PIPE 124 | return subprocess.call(self.get_encode_opts(list_file, avi), close_fds=True) 125 | else: 126 | msg = '\n\nCreating initial movies\n\n' 127 | if IS_TTY: print hilite(msg,7) 128 | print hilite(self.input_frame_list,30) 129 | file_list_name = 'frame_list.%04d.txt' 130 | for frame in self.input_frame_list: 131 | list_file = os.path.join(self.outdir, file_list_name % frame) 132 | avi_filename = "{0}_fr{1}.avi".format(self.filebase, '%04d'%frame) 133 | self.to_mosh.append(avi_filename) 134 | avi = os.path.join(self.outdir, avi_filename) 135 | #, shell=False, stdin=PIPE, stdout=PIPE, stderr=PIPE 136 | subprocess.call(self.get_encode_opts(list_file, avi), close_fds=True) 137 | 138 | def mosh(self): 139 | if self.to_mosh is None: 140 | return False 141 | else: 142 | for avi_filename in self.to_mosh: 143 | moshed_avi_filename = avi_filename.replace('.avi','_moshed.avi') 144 | msg = '{0}Creating moshed movie:\n{1}{0}'.format(HR, moshed_avi_filename) 145 | if IS_TTY: print hilite(msg,15) 146 | input_avi = os.path.join(self.outdir, avi_filename) 147 | moshed_avi = os.path.join(self.outdir, moshed_avi_filename) 148 | # by johannesgj 149 | # https://github.com/grampajoe/pymosh/blob/master/examples/moshmotion.py 150 | # loads in the index of frames in the given avi file 151 | f = Index(input_avi) 152 | # So I can assign to the closed-over buffer 153 | buf = [None] 154 | 155 | def process_frame(frame): 156 | """Process a frame, holding onto one P-frame at a time, 157 | which is used to replace any I-frames encountered.""" 158 | # if there is no frame in buf or the frame is not i-frame 159 | if buf[0] == None or not is_iframe(frame): 160 | # then buf is the seen p-frame 161 | buf[0] = frame 162 | else: 163 | # if it IS an iframe then use the buf'ers pframe 164 | frame = buf[0] 165 | # return the frame 166 | return frame 167 | 168 | # we use the list of frames in the loaded file 169 | for stream in f.video: 170 | # make a new list to put in frames YOU decide 171 | newstream = [] 172 | # append it with a i-frame to make it load fine in video player 173 | newstream.append(stream[0]) 174 | # two variables for counting frames and interval 175 | ix = 0 176 | jx = 0 177 | # stream is reduced by one since we have allready added one frame above 178 | for i in stream[1:]: 179 | ix += 1 180 | jx += 1 181 | # if ix the counter of interval is < interval select normal frames 182 | if ix < self.interval: 183 | newstream.append(process_frame(stream[jx])) 184 | # else bleed the reached frame for interval time 185 | else: 186 | newstream.append(newstream[-1]) 187 | # init interval 188 | if ix > self.interval * 2: 189 | ix = 0 190 | # replace original stream with same length newstream 191 | stream.replace(newstream) 192 | 193 | # Call rebuild to recombine the modified streams and perform any other 194 | # maintenance the file format needs for clean output. 195 | f.rebuild() 196 | 197 | # Finally, write the modified file . 198 | f.write(moshed_avi) 199 | self.moshed.append(moshed_avi_filename) 200 | 201 | def get_export_opts(self, seekto_str, fcount, moshed_avi): 202 | framerate = 25.0 # irrelevant - just needs to be constant 203 | # endframe = float(self.end+1) 204 | # exportsecs = endframe/framerate 205 | # fftime = "%05.2f" % exportsecs 206 | opts = ['ffmpeg'] 207 | opts.extend(['-nostdin']) 208 | opts.extend(['-hide_banner']) 209 | opts.extend(['-i', moshed_avi]) 210 | opts.extend(['-ss', seekto_str]) 211 | opts.extend(['-frames:v',str(fcount)]) 212 | opts.extend(['-vf', 'fps=25']) 213 | # opts.extend(['-ss', '00:00:%s' % fftime]) 214 | opts.extend(['-f', 'image2']) 215 | opts.extend([self.outseq]) 216 | print " ".join(opts) 217 | return opts 218 | 219 | def write_sequence(self): 220 | framerate = 25.0 # irrelevant - just needs to be constant 221 | seekto_frame = float(len(self.input_frame_list)+1.0) 222 | seekto_secs = seekto_frame/framerate 223 | seekto_str = "%05.2f" % seekto_secs 224 | if not self.uber: 225 | fcount = len(self.input_frame_list) 226 | for key, fname in enumerate(self.moshed): 227 | msg = '{0}Exporting {2} frame image sequence from {3}: {1}{0}'.format(HR, self.outseq, fcount, fname) 228 | if IS_TTY: print hilite(msg,11) 229 | avi = os.path.join(self.outdir, fname) 230 | subprocess.call(self.get_export_opts(seekto_str, fcount, avi), close_fds=True) 231 | else: 232 | uber_frame_list = list(self.moshed) 233 | while uber_frame_list: 234 | fcount = len(uber_frame_list) 235 | fname = uber_frame_list.pop(0) 236 | avi = os.path.join(self.outdir, fname) 237 | msg = '{0}Exporting {2} frame image sequence from {3}: {1}{0}'.format(HR, self.outseq, fcount, fname) 238 | if IS_TTY: print hilite(msg,11) 239 | subprocess.call(self.get_export_opts(seekto_str, fcount, avi), close_fds=True) 240 | 241 | def do_full_mosh(self): 242 | self.write_movie() 243 | self.mosh() 244 | self.write_sequence() 245 | 246 | -------------------------------------------------------------------------------- /moshion/extractframes/Rat.py: -------------------------------------------------------------------------------- 1 | '''\ 2 | This module implements rational numbers. 3 | 4 | The entry point of this module is the function 5 | rat(numerator, denominator) 6 | If either numerator or denominator is of an integral or rational type, 7 | the result is a rational number, else, the result is the simplest of 8 | the types float and complex which can hold numerator/denominator. 9 | If denominator is omitted, it defaults to 1. 10 | Rational numbers can be used in calculations with any other numeric 11 | type. The result of the calculation will be rational if possible. 12 | 13 | There is also a test function with calling sequence 14 | test() 15 | The documentation string of the test function contains the expected 16 | output. 17 | ''' 18 | 19 | # Contributed by Sjoerd Mullender 20 | 21 | # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Python 22 | # Software Foundation; All Rights Reserved 23 | 24 | from types import * 25 | 26 | def gcd(a, b): 27 | '''Calculate the Greatest Common Divisor.''' 28 | while b: 29 | a, b = b, a%b 30 | return a 31 | 32 | def rat(num, den = 1): 33 | # must check complex before float 34 | if isinstance(num, complex) or isinstance(den, complex): 35 | # numerator or denominator is complex: return a complex 36 | return complex(num) / complex(den) 37 | if isinstance(num, float) or isinstance(den, float): 38 | # numerator or denominator is float: return a float 39 | return float(num) / float(den) 40 | # otherwise return a rational 41 | return Rat(num, den) 42 | 43 | class Rat: 44 | '''This class implements rational numbers.''' 45 | 46 | def __init__(self, num, den = 1): 47 | if den == 0: 48 | raise ZeroDivisionError, 'rat(x, 0)' 49 | 50 | # normalize 51 | 52 | # must check complex before float 53 | if (isinstance(num, complex) or 54 | isinstance(den, complex)): 55 | # numerator or denominator is complex: 56 | # normalized form has denominator == 1+0j 57 | self.__num = complex(num) / complex(den) 58 | self.__den = complex(1) 59 | return 60 | if isinstance(num, float) or isinstance(den, float): 61 | # numerator or denominator is float: 62 | # normalized form has denominator == 1.0 63 | self.__num = float(num) / float(den) 64 | self.__den = 1.0 65 | return 66 | if (isinstance(num, self.__class__) or 67 | isinstance(den, self.__class__)): 68 | # numerator or denominator is rational 69 | new = num / den 70 | if not isinstance(new, self.__class__): 71 | self.__num = new 72 | if isinstance(new, complex): 73 | self.__den = complex(1) 74 | else: 75 | self.__den = 1.0 76 | else: 77 | self.__num = new.__num 78 | self.__den = new.__den 79 | else: 80 | # make sure numerator and denominator don't 81 | # have common factors 82 | # this also makes sure that denominator > 0 83 | g = gcd(num, den) 84 | self.__num = num / g 85 | self.__den = den / g 86 | # try making numerator and denominator of IntType if they fit 87 | try: 88 | numi = int(self.__num) 89 | deni = int(self.__den) 90 | except (OverflowError, TypeError): 91 | pass 92 | else: 93 | if self.__num == numi and self.__den == deni: 94 | self.__num = numi 95 | self.__den = deni 96 | 97 | def __repr__(self): 98 | return 'Rat(%s,%s)' % (self.__num, self.__den) 99 | 100 | def __str__(self): 101 | if self.__den == 1: 102 | return str(self.__num) 103 | else: 104 | return '(%s/%s)' % (str(self.__num), str(self.__den)) 105 | 106 | # a + b 107 | def __add__(a, b): 108 | try: 109 | return rat(a.__num * b.__den + b.__num * a.__den, 110 | a.__den * b.__den) 111 | except OverflowError: 112 | return rat(long(a.__num) * long(b.__den) + 113 | long(b.__num) * long(a.__den), 114 | long(a.__den) * long(b.__den)) 115 | 116 | def __radd__(b, a): 117 | return Rat(a) + b 118 | 119 | # a - b 120 | def __sub__(a, b): 121 | try: 122 | return rat(a.__num * b.__den - b.__num * a.__den, 123 | a.__den * b.__den) 124 | except OverflowError: 125 | return rat(long(a.__num) * long(b.__den) - 126 | long(b.__num) * long(a.__den), 127 | long(a.__den) * long(b.__den)) 128 | 129 | def __rsub__(b, a): 130 | return Rat(a) - b 131 | 132 | # a * b 133 | def __mul__(a, b): 134 | try: 135 | return rat(a.__num * b.__num, a.__den * b.__den) 136 | except OverflowError: 137 | return rat(long(a.__num) * long(b.__num), 138 | long(a.__den) * long(b.__den)) 139 | 140 | def __rmul__(b, a): 141 | return Rat(a) * b 142 | 143 | # a / b 144 | def __div__(a, b): 145 | try: 146 | return rat(a.__num * b.__den, a.__den * b.__num) 147 | except OverflowError: 148 | return rat(long(a.__num) * long(b.__den), 149 | long(a.__den) * long(b.__num)) 150 | 151 | def __rdiv__(b, a): 152 | return Rat(a) / b 153 | 154 | # a % b 155 | def __mod__(a, b): 156 | div = a / b 157 | try: 158 | div = int(div) 159 | except OverflowError: 160 | div = long(div) 161 | return a - b * div 162 | 163 | def __rmod__(b, a): 164 | return Rat(a) % b 165 | 166 | # a ** b 167 | def __pow__(a, b): 168 | if b.__den != 1: 169 | if isinstance(a.__num, complex): 170 | a = complex(a) 171 | else: 172 | a = float(a) 173 | if isinstance(b.__num, complex): 174 | b = complex(b) 175 | else: 176 | b = float(b) 177 | return a ** b 178 | try: 179 | return rat(a.__num ** b.__num, a.__den ** b.__num) 180 | except OverflowError: 181 | return rat(long(a.__num) ** b.__num, 182 | long(a.__den) ** b.__num) 183 | 184 | def __rpow__(b, a): 185 | return Rat(a) ** b 186 | 187 | # -a 188 | def __neg__(a): 189 | try: 190 | return rat(-a.__num, a.__den) 191 | except OverflowError: 192 | # a.__num == sys.maxint 193 | return rat(-long(a.__num), a.__den) 194 | 195 | # abs(a) 196 | def __abs__(a): 197 | return rat(abs(a.__num), a.__den) 198 | 199 | # int(a) 200 | def __int__(a): 201 | return int(a.__num / a.__den) 202 | 203 | # long(a) 204 | def __long__(a): 205 | return long(a.__num) / long(a.__den) 206 | 207 | # float(a) 208 | def __float__(a): 209 | return float(a.__num) / float(a.__den) 210 | 211 | # complex(a) 212 | def __complex__(a): 213 | return complex(a.__num) / complex(a.__den) 214 | 215 | # cmp(a,b) 216 | def __cmp__(a, b): 217 | diff = Rat(a - b) 218 | if diff.__num < 0: 219 | return -1 220 | elif diff.__num > 0: 221 | return 1 222 | else: 223 | return 0 224 | 225 | def __rcmp__(b, a): 226 | return cmp(Rat(a), b) 227 | 228 | # a != 0 229 | def __nonzero__(a): 230 | return a.__num != 0 231 | 232 | # coercion 233 | def __coerce__(a, b): 234 | return a, Rat(b) 235 | 236 | def test(): 237 | '''\ 238 | Test function for rat module. 239 | 240 | The expected output is (module some differences in floating 241 | precission): 242 | -1 243 | -1 244 | 0 0L 0.1 (0.1+0j) 245 | [Rat(1,2), Rat(-3,10), Rat(1,25), Rat(1,4)] 246 | [Rat(-3,10), Rat(1,25), Rat(1,4), Rat(1,2)] 247 | 0 248 | (11/10) 249 | (11/10) 250 | 1.1 251 | OK 252 | 2 1.5 (3/2) (1.5+1.5j) (15707963/5000000) 253 | 2 2 2.0 (2+0j) 254 | 255 | 4 0 4 1 4 0 256 | 3.5 0.5 3.0 1.33333333333 2.82842712475 1 257 | (7/2) (1/2) 3 (4/3) 2.82842712475 1 258 | (3.5+1.5j) (0.5-1.5j) (3+3j) (0.666666666667-0.666666666667j) (1.43248815986+2.43884761145j) 1 259 | 1.5 1 1.5 (1.5+0j) 260 | 261 | 3.5 -0.5 3.0 0.75 2.25 -1 262 | 3.0 0.0 2.25 1.0 1.83711730709 0 263 | 3.0 0.0 2.25 1.0 1.83711730709 1 264 | (3+1.5j) -1.5j (2.25+2.25j) (0.5-0.5j) (1.50768393746+1.04970907623j) -1 265 | (3/2) 1 1.5 (1.5+0j) 266 | 267 | (7/2) (-1/2) 3 (3/4) (9/4) -1 268 | 3.0 0.0 2.25 1.0 1.83711730709 -1 269 | 3 0 (9/4) 1 1.83711730709 0 270 | (3+1.5j) -1.5j (2.25+2.25j) (0.5-0.5j) (1.50768393746+1.04970907623j) -1 271 | (1.5+1.5j) (1.5+1.5j) 272 | 273 | (3.5+1.5j) (-0.5+1.5j) (3+3j) (0.75+0.75j) 4.5j -1 274 | (3+1.5j) 1.5j (2.25+2.25j) (1+1j) (1.18235814075+2.85446505899j) 1 275 | (3+1.5j) 1.5j (2.25+2.25j) (1+1j) (1.18235814075+2.85446505899j) 1 276 | (3+3j) 0j 4.5j (1+0j) (-0.638110484918+0.705394566962j) 0 277 | ''' 278 | print rat(-1L, 1) 279 | print rat(1, -1) 280 | a = rat(1, 10) 281 | print int(a), long(a), float(a), complex(a) 282 | b = rat(2, 5) 283 | l = [a+b, a-b, a*b, a/b] 284 | print l 285 | l.sort() 286 | print l 287 | print rat(0, 1) 288 | print a+1 289 | print a+1L 290 | print a+1.0 291 | try: 292 | print rat(1, 0) 293 | raise SystemError, 'should have been ZeroDivisionError' 294 | except ZeroDivisionError: 295 | print 'OK' 296 | print rat(2), rat(1.5), rat(3, 2), rat(1.5+1.5j), rat(31415926,10000000) 297 | list = [2, 1.5, rat(3,2), 1.5+1.5j] 298 | for i in list: 299 | print i, 300 | if not isinstance(i, complex): 301 | print int(i), float(i), 302 | print complex(i) 303 | print 304 | for j in list: 305 | print i + j, i - j, i * j, i / j, i ** j, 306 | if not (isinstance(i, complex) or 307 | isinstance(j, complex)): 308 | print cmp(i, j) 309 | print 310 | 311 | 312 | if __name__ == '__main__': 313 | test() 314 | -------------------------------------------------------------------------------- /moshion/extractframes/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import shutil 3 | from framesource import VideoFrameSource 4 | import tempfile 5 | import decimal 6 | import rateconverter 7 | import os 8 | 9 | """ 10 | extractframes package - extract frames from a video. 11 | 12 | The top level module contains only one function, extract() which is the main 13 | way you'd accomplish frame extractions. 14 | """ 15 | 16 | # maybe refactor this part so that the file movement is also testable 17 | # separately from the extraction? 18 | 19 | def extract(infile, outfile, ratio=None, in_frames=None, quiet=True, 20 | out_count=None, out_offset=0): 21 | outdir = os.path.dirname(outfile) 22 | if len(outdir) == 0: 23 | outdir = '.' 24 | if not os.path.isdir(outdir): 25 | raise IOError('Destination directory %s does not exist!' % os.path.dirname(outfile)) 26 | 27 | if ratio is not None and out_count is not None: 28 | raise ValueError('You can only specify one of ratio and out_count') 29 | elif ratio is None and out_count is None: 30 | ratio = 1 31 | 32 | frame_source = VideoFrameSource(infile, quiet=quiet) 33 | 34 | if not in_frames: 35 | # xrange is half-open interval. For closed interval, would be 36 | # [0, get_num_frames() - 1] 37 | in_frames = xrange(0, frame_source.get_num_frames()) 38 | 39 | if in_frames[0] < 0 or in_frames[-1] > frame_source.get_num_frames() - 1: 40 | raise ValueError("Requested bounds %s don't fit in %d-frame video file" 41 | % (in_frames, frame_source.get_num_frames())) 42 | 43 | in_count = in_frames[-1] - in_frames[0] + 1 44 | 45 | if out_count is not None: 46 | ratio = rateconverter.ratio_for_number(in_count, out_count) 47 | 48 | iterator = rateconverter.convert_integers_by_iterator_ratio(ratio, in_frames, 49 | dest_offset=out_offset) 50 | if not quiet: 51 | try: 52 | import progressbar 53 | pbar = progressbar.ProgressBar(widgets=['Copying frames to destination', 54 | progressbar.Bar(), progressbar.ETA()]) 55 | test = pbar([1]) 56 | iterator = pbar(list(iterator)) 57 | except (ImportError, TypeError): 58 | print "(For a progress bar, install python-progressbar v. 2.3)" 59 | for src, dst in iterator: 60 | source = frame_source.get_frame_file(src) 61 | dest = outfile % dst 62 | 63 | shutil.copy(source, dest) 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /moshion/extractframes/framesource.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import with_statement 3 | import shutil 4 | import subprocess 5 | import extractframes 6 | import tempfile 7 | import atexit 8 | import re 9 | import os 10 | 11 | class VideoFrameSource(object): 12 | def __init__(self, vid_file, index_from=0, permanent=False, quiet=True): 13 | self.source_video = vid_file 14 | self.index_from = index_from 15 | self.permanent = permanent 16 | self.quiet = quiet 17 | self._extract_frames() 18 | 19 | def _extract_frames(self): 20 | self.temp_path = tempfile.mkdtemp() 21 | 22 | def delete_temp(): 23 | shutil.rmtree(self.temp_path) 24 | if not self.permanent: 25 | atexit.register(delete_temp) 26 | 27 | tmp_fmt = os.path.join(self.temp_path, '%010d.jpg') 28 | do_extraction(self.source_video, tmp_fmt, quiet=self.quiet) 29 | # returned sorted 30 | self.frame_name_list = sorted(os.listdir(self.temp_path)) 31 | 32 | def get_frame_file(self, frame_num): 33 | """Gets the frame referred to by the frame number supplied. 34 | 35 | This function is tricksy! If you call obj.get_frame_file(N), you'll 36 | get a file with a name that looks like it's N+1. This is intentional! 37 | FFmpeg extracts starting with 1, but VirtualDub starts with 0. This is 38 | for compatibility with VirtualDub. 39 | """ 40 | if frame_num < len(self.frame_name_list): 41 | return os.path.join(self.temp_path, self.frame_name_list[frame_num]) 42 | else: 43 | return None 44 | 45 | def get_num_frames(self): 46 | return len(self.frame_name_list) 47 | 48 | 49 | 50 | 51 | 52 | if os.name == 'nt': 53 | devnull_fname = 'nul' 54 | else: 55 | devnull_fname = '/dev/null' 56 | 57 | 58 | 59 | 60 | def do_extraction(infile, outfile, quiet=True): 61 | source_spec = ['-i', infile] 62 | dest_spec = [outfile] 63 | other_args = ['-qmax', '1'] 64 | kwargs = {} 65 | 66 | # be quiet, ffmpeg!! 67 | with open(devnull_fname, 'w') as devnull: 68 | if quiet: 69 | kwargs['stderr'] = devnull 70 | 71 | ffmpeg = subprocess.Popen(['ffmpeg'] + source_spec + other_args + dest_spec, **kwargs) 72 | ret = ffmpeg.wait() 73 | if ret != 0: 74 | raise IOError('Ffmpeg returned code %d' % ret) 75 | 76 | 77 | -------------------------------------------------------------------------------- /moshion/extractframes/multirange.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import itertools 3 | 4 | class multirange(object): 5 | def __init__(self, range_str, parser=int): 6 | """Take string like '1-10,12-40', and return the indicated integers""" 7 | 8 | self.range_str = range_str 9 | 10 | sections = range_str.split(',') 11 | self.ranges = [] 12 | self.expanded = None 13 | last_end = float('-inf') 14 | for section in sections: 15 | parts = [parser(x) for x in section.split('-')] 16 | 17 | if parts[0] <= last_end: 18 | raise ValueError('Ranges must not overlap') 19 | if len(parts) != 2: 20 | raise ValueError('Ranges must have exactly two parts, "start-end"') 21 | 22 | last_end = parts[1] 23 | 24 | self.ranges.append(xrange(parts[0], parts[1] + 1)) 25 | 26 | 27 | def __iter__(self): 28 | return itertools.chain(*self.ranges) 29 | 30 | def _ensure_expanded(self): 31 | if self.expanded == None: 32 | self.expanded = list(iter(self)) 33 | 34 | def __getitem__(self, idx): 35 | self._ensure_expanded() 36 | return self.expanded[idx] 37 | 38 | def __len__(self): 39 | self._ensure_expanded() 40 | return len(self.expanded) 41 | 42 | def __str__(self): 43 | return self.range_str 44 | 45 | def __repr__(self): 46 | return "multirange(%s)" % str(self) 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /moshion/extractframes/newmath.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import tempfile 3 | import contextlib 4 | import math 5 | def float_range(a, b, inc): 6 | """ 7 | Returns a list containing an arithmetic progression of floats. 8 | This is simply a float version of the built-in range(a, b, step) 9 | function. The result is [ , ) as always in Python. 10 | """ 11 | try: 12 | x = [float(a)] 13 | except: 14 | raise ValueError("float value required") 15 | for i in range(1, int(math.ceil((b - a ) / inc))): 16 | x.append(a + i * inc) 17 | return x 18 | 19 | @contextlib.contextmanager 20 | def temp_dir(**kwargs): 21 | tempdir = tempfile.mkdtemp(**kwargs) 22 | yield tempdir 23 | subprocess.check_call(['rm', '-rf', tempdir]) 24 | 25 | -------------------------------------------------------------------------------- /moshion/extractframes/rateconverter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import math 3 | #import fractions 4 | import Rat 5 | import itertools 6 | 7 | def old_convert_integers_by_ratio(ratio, num_inputs, src_offset=0, dest_offset=0): 8 | """Given an out:in ratio and a number of inputs, give the reassignments 9 | that will result in the correct number of output frames taken linearly from 10 | input frames. 11 | 12 | You can also specify a src_offset or dest_offset, which are added to the 13 | source or dest numbers. 14 | 15 | >>> list(convert_integers_by_ratio(0.5, 4)) 16 | [(1, 0), (3, 1)] 17 | >>> 18 | """ 19 | max_taken = -1 20 | for in_frame in xrange(0, num_inputs): 21 | out_frame = int(math.floor((in_frame + 1) * ratio)) - 1 22 | if out_frame > max_taken: 23 | for copy in xrange(max_taken + 1, out_frame + 1): 24 | yield (in_frame + src_offset, copy + dest_offset) 25 | max_taken = out_frame 26 | 27 | def convert_integers_by_ratio(ratio, num_inputs, src_offset=0, dest_offset=0): 28 | return convert_integers_by_iterator_ratio(ratio, 29 | xrange(src_offset, src_offset + num_inputs), 30 | dest_offset=dest_offset) 31 | 32 | def argh(ratio, source, dest_offset=0): 33 | """Given a source of frame numbers and a ratio, gives the reassignments 34 | that will result in the best assignment of input to output frames.""" 35 | 36 | if len(source) == 0: 37 | raise StopIteration() 38 | 39 | first_frame = source[0] 40 | 41 | for in_frame in source: 42 | rel_in_frame = in_frame - first_frame 43 | 44 | first_rel_out_frame = int(math.floor(rel_in_frame * ratio)) 45 | bound_rel_out_frame = int(math.floor((rel_in_frame + 1) * ratio)) 46 | 47 | # Confusing, argh: 48 | # Uncomment this to let the program use e.g. even-numbered frames when 49 | # the ratio is 1/2. Unfortunately, this breaks everything else! See 50 | # testSkipRatioBad in test_rateconverter.py. You'll also need to use 51 | # take_last_assignment down in convert_integers_by_iterator_ratio. 52 | #bound_rel_out_frame = max( 53 | #int(math.floor((rel_in_frame + 1) * ratio)), 54 | #first_rel_out_frame + 1) 55 | 56 | for rel_out_frame in xrange(first_rel_out_frame, bound_rel_out_frame): 57 | yield (in_frame, rel_out_frame + dest_offset) 58 | 59 | def convert_integers_by_iterator_ratio(ratio, source, dest_offset=0): 60 | #return take_last_assignment(argh(ratio, source, dest_offset)) 61 | return argh(ratio, source, dest_offset) 62 | 63 | def take_last_assignment(source): 64 | first = True 65 | last = None 66 | for assn in source: 67 | if first: 68 | last = assn 69 | first = False 70 | if assn[1] != last[1]: 71 | yield last 72 | last = assn 73 | if last is not None: 74 | yield last 75 | 76 | 77 | 78 | 79 | def expected_number(ratio, num_inputs): 80 | return math.floor(ratio * num_inputs) 81 | 82 | def ratio_for_number(num_inputs, num_outputs): 83 | return Rat.rat(num_outputs, num_inputs) 84 | 85 | def frames_in_range(bounds): 86 | return bounds[1] + 1 - bounds[0] 87 | 88 | def convert_range_to_range(in_bounds, out_bounds): 89 | num_outs = frames_in_range(out_bounds) 90 | num_ins = frames_in_range(in_bounds) 91 | ratio = ratio_for_number(num_ins, num_outs) 92 | return convert_integers_by_ratio(ratio, num_ins, 93 | src_offset=in_bounds[0], 94 | dest_offset=out_bounds[0]) 95 | 96 | -------------------------------------------------------------------------------- /moshion/extractframes/timespec.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import Rat 4 | 5 | # 29.97 is apparently only an approximation 6 | DEFAULT_FRAME_RATE = Rat.rat(30 * 1000, 1001) 7 | 8 | def time_to_frame(fnum, rate=DEFAULT_FRAME_RATE): 9 | return int(fnum * rate) 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /moshion/pymosh/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | __all__ = ['Index'] 4 | 5 | 6 | class Index(object): 7 | def __init__(self, filename): 8 | self.filename = filename 9 | self.index = None 10 | 11 | # Just do this for now 12 | import avi 13 | self.index = avi.AVIFile(filename) 14 | 15 | def __getattr__(self, index): 16 | return getattr(self.index, index) 17 | 18 | def __iter__(self): 19 | return iter(self.index) 20 | -------------------------------------------------------------------------------- /moshion/pymosh/avi.py: -------------------------------------------------------------------------------- 1 | import riff 2 | import struct 3 | import sys 4 | from mpeg4 import is_iframe 5 | 6 | 7 | class Stream(object): 8 | def __init__(self, num, stream_type): 9 | self.num = int(num) 10 | self.type = stream_type 11 | self.chunks = [] 12 | 13 | def add_frame(self, chunk): 14 | self.chunks.append(chunk) 15 | 16 | def __getitem__(self, index): 17 | return self.chunks.__getitem__(index) 18 | 19 | def __iter__(self): 20 | return self.chunks.__iter__() 21 | 22 | def __len__(self): 23 | return len(self.chunks) 24 | 25 | def append(self, *args): 26 | return self.chunks.append(*args) 27 | 28 | def extend(self, *args): 29 | return self.chunks.extend(*args) 30 | 31 | def replace(self, chunks): 32 | self.chunks = chunks 33 | 34 | 35 | class AVIFile(object): 36 | """A wrapper for AVI files.""" 37 | def __init__(self, filename): 38 | self.riff = riff.RiffIndex(filename=filename) 39 | 40 | header = self.riff.find('LIST', 'hdrl') 41 | # Get stream info 42 | stream_lists = header.find_all('LIST', 'strl') 43 | self.streams = [] 44 | for l in stream_lists: 45 | strh = l.find('strh') 46 | data = strh.data 47 | fccType, = struct.unpack('4s', data[:4]) 48 | stream = Stream(len(self.streams), fccType) 49 | self.streams.append(stream) 50 | 51 | self.frame_order = [] 52 | self.split_streams() 53 | 54 | def __iter__(self): 55 | return iter(self.streams) 56 | 57 | def add_frame(self, chunk): 58 | stream_num = int(chunk.header[:2]) 59 | if stream_num < len(self.streams): 60 | self.frame_order.append((stream_num, len(self.streams[stream_num]))) 61 | self.streams[stream_num].add_frame(chunk) 62 | 63 | def split_streams(self): 64 | movi = self.riff.find('LIST', 'movi') 65 | for chunk in movi: 66 | self.add_frame(chunk) 67 | 68 | def combine_streams(self): 69 | chunks = [] 70 | for frame_record in self.frame_order: 71 | stream_num, frame_num = frame_record 72 | stream = self.streams[stream_num] 73 | frame = stream[frame_num] 74 | chunks.append(frame) 75 | return chunks 76 | 77 | def _video(self): 78 | return filter(lambda stream: stream.type == 'vids', self.streams) 79 | video = property(_video) 80 | 81 | def _audio(self): 82 | return filter(lambda stream: stream.type == 'auds', self.streams) 83 | audio = property(_audio) 84 | 85 | def rebuild(self): 86 | """Rebuild RIFF tree and index from streams.""" 87 | movi = self.riff.find('LIST', 'movi') 88 | movi.chunks = self.combine_streams() 89 | self.rebuild_index() 90 | 91 | def rebuild_index(self): 92 | old_index = self.riff.find('idx1') 93 | movi = self.riff.find('LIST', 'movi') 94 | data = '' 95 | offset = 0 96 | flags = { 97 | 'base': 0x00000000, 98 | 'keyframe': 0x00000010, 99 | } 100 | for chunk in movi: 101 | length = len(chunk) 102 | frame_flags = flags['base'] 103 | # If it's a video keyframe or audio frame, use keyframe flag 104 | if (chunk.header[2] == 'd' and is_iframe(chunk)) or (chunk.header[2] == 'w'): 105 | frame_flags |= flags['keyframe'] 106 | data += struct.pack('<4sIII', chunk.header, frame_flags, offset, 107 | length+8) 108 | offset += length + 8 + (length % 2) 109 | new_index = riff.RiffDataChunk('idx1', data) 110 | self.riff.find('RIFF').replace(old_index, new_index) 111 | 112 | def write(self, fh): 113 | self.riff.write(fh) 114 | -------------------------------------------------------------------------------- /moshion/pymosh/mpeg4.py: -------------------------------------------------------------------------------- 1 | IFRAME_HEADER = '\x00\x00\x01\xb0' 2 | 3 | 4 | def is_iframe(frame): 5 | """Determine whether frame is an I frame.""" 6 | return frame[:4] == IFRAME_HEADER 7 | -------------------------------------------------------------------------------- /moshion/pymosh/riff.py: -------------------------------------------------------------------------------- 1 | import struct 2 | import os 3 | import sys 4 | 5 | 6 | list_headers = ('RIFF', 'LIST') 7 | 8 | 9 | class UnexpectedEOF(Exception): 10 | pass 11 | 12 | 13 | class RiffIndexChunk(object): 14 | def __init__(self, fh, header, length, position): 15 | self.file = fh 16 | self.header = header 17 | self.length = int(length) 18 | self.position = position 19 | 20 | @staticmethod 21 | def from_file(fh, position): 22 | pass 23 | 24 | def __str__(self): 25 | data = self.data 26 | return '{header}{length}{data}'.format(header=self.header, 27 | length=struct.pack(' self.length: 37 | end = self.length 38 | data = self.file.read(end-start) 39 | self.file.seek(current) 40 | return data 41 | else: 42 | return '' 43 | 44 | def __getitem__(self, index): 45 | return self[index:index+1] 46 | 47 | def _data(self): 48 | """Read data from the file.""" 49 | current_position = self.file.tell() 50 | self.file.seek(self.position) 51 | data = self.file.read(self.length) 52 | self.file.seek(current_position) 53 | if self.length % 2: 54 | data += '\x00' # Padding byte 55 | return data 56 | data = property(_data) 57 | 58 | def as_data(self): 59 | """Return a RiffDataChunk read from the file.""" 60 | 61 | 62 | class RiffIndexList(RiffIndexChunk): 63 | def __init__(self, header, list_type, *args, **kwargs): 64 | self.header = header 65 | self.type = list_type 66 | self.file = kwargs.get('file', None) 67 | self.position = kwargs.get('position', 0) 68 | self.chunks = kwargs.get('chunks', []) 69 | 70 | def __getitem__(self, index): 71 | return self.chunks[index] 72 | 73 | def __setitem__(self, index, value): 74 | return self.chunks.__setitem__(index, value) 75 | 76 | def __delitem__(self, index): 77 | return self.chunks.__delitem__(index) 78 | 79 | def __iter__(self): 80 | return iter(self.chunks) 81 | 82 | def __len__(self): 83 | """Return total data length of the list and its headers.""" 84 | return self.chunk_length() + len(self.type) + len(self.header) + 4 85 | 86 | def chunk_length(self): 87 | length = 0 88 | for chunk in self.chunks: 89 | chunk_len = len(chunk) 90 | length += chunk_len + 8 # Header and length bytes 91 | length += chunk_len % 2 # Pad byte 92 | return length 93 | 94 | def __str__(self): 95 | length = self.chunk_length() + len(self.type) 96 | return '{header}{length}{list_type}'.format(header=self.header, 97 | length=struct.pack(' ",16)) 29 | inseqs=sequence.glob(inseq_input.split('.')[0]) 30 | if len(inseqs) > 1: 31 | print hilite("\nPick a sequence:",6) 32 | for k,v in enumerate(inseqs): 33 | print "\t {0}) {1}".format(k+1, v) 34 | inseq_input = raw_input(hilite("input_seq (1) > ",16)) or 1 35 | inseq = inseqs[int(inseq_input)-1] 36 | else: 37 | inseq = inseqs[0] 38 | inseq_path = inseq.__str__().split(' ')[0] 39 | inseq_start = inseq.__str__().split(' ')[1] 40 | inseq_end = inseq.__str__().split(' ')[2] 41 | print hilite("\nEnter first frame of input sequence:",6) 42 | print "\nEg. 953\n" 43 | start=raw_input(hilite("first_fr ({0}) > ".format(inseq_start),16)) or inseq_start 44 | print hilite("\nEnter last frame of input sequence:",6) 45 | print "\nEg. 1002\n" 46 | end=raw_input(hilite("last_fr ({0}) > ".format(inseq_end),16)) or inseq_end 47 | # MOSH SEQUENCE 48 | print hilite("\nEnter the moshtex sequence path:",6) 49 | print "\nEg. /my/great/moshtex.%04d.jpg\n" 50 | moshseq_input = raw_input(hilite("moshtex_path > ", 16)) 51 | moshseqs=sequence.glob(moshseq_input.split('.')[0]) 52 | if len(moshseqs) > 1: 53 | print "Pick a sequence:" 54 | for k,v in enumerate(moshseqs): 55 | print " {0}) {1}".format(k+1, v) 56 | moshseq_input = raw_input(hilite("moshtex_path > ",16)) or 1 57 | moshseq = moshseqs[int(moshseq_input)-1] 58 | else: 59 | moshseq = moshseqs[0] 60 | moshseq_path = moshseq.__str__().split(' ')[0] 61 | moshseq_start = moshseq.__str__().split(' ')[1] 62 | moshseq_end = moshseq.__str__().split(' ')[2] 63 | print hilite("\nEnter the first frame of moshtex sequence:",6) 64 | print "\nEg. 5\n" 65 | moshfirst=raw_input(hilite("moshtex_first_fr ({0}) > ".format(moshseq_start),16)) or moshseq_start 66 | # OUTPUT 67 | print hilite("\nEnter the output directory path:",6) 68 | print "\nEg. /my/great/output\n" 69 | outdir = raw_input(hilite("output_path > ",16)) 70 | 71 | bitrate = raw_input(hilite("Bitrate (8000) > ",16)) or "8000" 72 | keyframe = raw_input(hilite("Keyframe (999) > ",16)) or "999" 73 | threshold = raw_input(hilite("Threshold (100000000) > ",16)) or "100000000" 74 | interval = raw_input(hilite("Interval (9) > ",16)) or "9" 75 | uber = raw_input(hilite("Uber Moshion? (N) > ",12)) or "N" 76 | if uber in ['Y','y','yes','YES','Yes']: 77 | uber = True 78 | else: 79 | uber = False 80 | return { 81 | 'inseq': inseq_path, 82 | 'start': start, 83 | 'end': end, 84 | 'moshseq': moshseq_path, 85 | 'moshstart': moshfirst, 86 | 'outdir': outdir, 87 | 'bitrate': bitrate, 88 | 'keyframe': keyframe, 89 | 'threshold': threshold, 90 | 'interval': interval, 91 | 'uber': uber 92 | } 93 | 94 | def main(): 95 | usage = "Usage: \n%prog --start 1 --end 10 -i /my/great/sequence.%04d.jpg -m /my/great/tex.%04d.jpg -f 1 -o /my/great/moshion_output" 96 | version=__import__('moshion').get_version() 97 | description="moshion v%s - Datamoshing Motion" % version 98 | parser = OptionParser(usage=usage, version=version, description=description) 99 | 100 | parser.add_option("-s", "--start", dest="start", help="first frame of input sequence") 101 | parser.add_option("-e", "--end", dest="end", help="last frame of input sequence") 102 | parser.add_option("-i", "--inseq", dest="inseq", help="A path to an image sequence. Use 'name.%04d.extension'.") 103 | parser.add_option("-m", "--moshseq", dest="moshseq", help="A path to a mosh sequence. Use 'name.%04d.extension'. This sequence will drive the motion of the i_frame.") 104 | parser.add_option("-f", "--moshstart", dest="moshstart", help="first frame of mosh sequence") 105 | parser.add_option("-b", "--bitrate", dest="bitrate", help="bitrate of encoded video") 106 | parser.add_option("-k", "--keyframe", dest="keyframe", help="Key frame interval, also known as GOP length. This determines the maximum distance between I-frames. It should be higher then len(inputs)+i_frame.") 107 | parser.add_option("-t", "--threshold", dest="threshold", help="Adjusts the sensitivity of x264's scene-cut detection. Recommended super high.") 108 | parser.add_option("-x", "--interval", dest="interval", help="spacing of p frames in moshion seq") 109 | parser.add_option("-o", "--outdir", dest="outdir", help="Full path to output directory") 110 | parser.add_option("-a", "--avionly", dest="avionly", help="If set to true, only generates the source AVI.", action="store_true", default=False) 111 | parser.add_option("-n", "--noseq", dest="noseq", help="If set to true, does not write image sequence.", action="store_true", default=False) 112 | parser.add_option("-w", "--writeseq", dest="writeseq", help="If set to true, tries to only write the image sequence from a pre-existing moshion AVI.", action="store_true", default=False) 113 | parser.add_option("-q", "--interactive", dest="interactive", help="Use prompts to enter info.", action="store_true", default=False) 114 | # special sauce, lettuce, cheese 115 | parser.add_option("-u", "--uber", dest="uber", help="If set to true, uses the UBER technique.", action="store_true", default=False) 116 | 117 | (options, args) = parser.parse_args() 118 | 119 | 120 | if options.interactive: 121 | moshion_options=interactive() 122 | moshion = Moshion(**moshion_options) 123 | moshion.do_full_mosh() 124 | else: 125 | if None in [options.start, options.end, options.inseq, options.moshseq, options.moshstart, options.outdir]: 126 | parser.print_help() 127 | sys.exit(1) 128 | 129 | if IS_TTY: print hilite("{1}moshion v{0}{1}For a list of available options use the -h flag".format(version, HR), 7) 130 | 131 | moshion_options = { 132 | 'start' : options.start, 133 | 'end' : options.end, 134 | 'inseq' : options.inseq, 135 | 'moshseq' : options.moshseq, 136 | 'moshstart' : options.moshstart, 137 | 'outdir' : options.outdir, 138 | 'avionly': options.avionly, 139 | 'uber': options.uber 140 | } 141 | 142 | moshion_options['bitrate'] = options.bitrate if options.bitrate else "8000" 143 | moshion_options['keyframe'] = options.keyframe if options.keyframe else "999" 144 | moshion_options['threshold'] = options.threshold if options.threshold else "100000000" 145 | moshion_options['interval'] = options.interval if options.interval else "8" 146 | 147 | if options.avionly and options.writeseq: 148 | if IS_TTY: print hilite("ERROR: you can't use avionly and writeseq options together!",10) 149 | parser.print_help() 150 | sys.exit(1) 151 | 152 | moshion = Moshion(**moshion_options) 153 | 154 | if not moshion_options['avionly'] and not options.noseq and not options.writeseq: 155 | moshion.do_full_mosh() 156 | 157 | if options.avionly: 158 | moshion.write_movie() 159 | 160 | if options.noseq: 161 | moshion.write_movie() 162 | moshion.mosh() 163 | 164 | if options.writeseq: 165 | moshion.write_sequence() 166 | 167 | echo_cmd = "gomoshion.py" 168 | echo_cmd = " ".join([echo_cmd, "--start {start} --end {end} --moshstart {moshstart}".format(start=moshion_options['start'],end=moshion_options['end'],moshstart=moshion_options['moshstart'])]) 169 | echo_cmd = " ".join([echo_cmd, "--inseq {inseq} --moshseq {moshseq}".format(inseq=moshion_options['inseq'],moshseq=moshion_options['moshseq'])]) 170 | echo_cmd = " ".join([echo_cmd, "--outdir {outdir}".format(outdir=moshion_options['outdir'])]) 171 | echo_cmd = " ".join([echo_cmd, "--bitrate {bitrate} --keyframe {keyframe} --threshold {threshold} --interval {interval}".format(bitrate=moshion_options['bitrate'],keyframe=moshion_options['keyframe'],threshold=moshion_options['threshold'],interval=moshion_options['interval'])]) 172 | if options.avionly: echo_cmd = " ".join([echo_cmd, "--avionly"]) 173 | if options.noseq: echo_cmd = " ".join([echo_cmd, "--noseq"]) 174 | if options.writeseq: echo_cmd = " ".join([echo_cmd, "--write"]) 175 | if moshion_options['uber']: echo_cmd = " ".join([echo_cmd, "--uber"]) 176 | 177 | 178 | if IS_TTY: print hilite("{0}COMMAND:\n{1}{0}".format(HR, echo_cmd),12) 179 | if IS_TTY: print hilite("{0}Moshion Complete!{0}".format(HR),3) 180 | sys.exit(0) 181 | 182 | 183 | if __name__ == "__main__": 184 | main() 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /moshion/seqls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # ***** BEGIN LICENSE BLOCK ***** 3 | # Version: MPL 1.1/GPL 2.0/LGPL 2.1 4 | # 5 | # The contents of this file are subject to the Mozilla Public License Version 6 | # 1.1 (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # http://www.mozilla.org/MPL/ 9 | # 10 | # Software distributed under the License is distributed on an "AS IS" basis, 11 | # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 12 | # for the specific language governing rights and limitations under the 13 | # License. 14 | # 15 | # The Original Code is the Python Computer Graphics Kit. 16 | # 17 | # The Initial Developer of the Original Code is Matthias Baas. 18 | # Portions created by the Initial Developer are Copyright (C) 2004 19 | # the Initial Developer. All Rights Reserved. 20 | # 21 | # Contributor(s): 22 | # 23 | # Alternatively, the contents of this file may be used under the terms of 24 | # either the GNU General Public License Version 2 or later (the "GPL"), or 25 | # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 26 | # in which case the provisions of the GPL or the LGPL are applicable instead 27 | # of those above. If you wish to allow use of your version of this file only 28 | # under the terms of either the GPL or the LGPL, and not to allow others to 29 | # use your version of this file under the terms of the MPL, indicate your 30 | # decision by deleting the provisions above and replace them with the notice 31 | # and other provisions required by the GPL or the LGPL. If you do not delete 32 | # the provisions above, a recipient may use your version of this file under 33 | # the terms of any one of the MPL, the GPL or the LGPL. 34 | # 35 | # ***** END LICENSE BLOCK ***** 36 | 37 | import optparse 38 | import sys, os, glob 39 | import os.path 40 | import time 41 | import sequence 42 | 43 | class SequenceInfo: 44 | """Obtains and stores info about a file sequence. 45 | """ 46 | def __init__(self, seq): 47 | """Constructor. 48 | 49 | seq is a Sequence object that contains the file names. 50 | """ 51 | # Get all the info... 52 | size = 0 53 | minMTime = None 54 | maxMTime = None 55 | for fileName in seq: 56 | try: 57 | fileInfo = os.stat(str(fileName)) 58 | except OSError: 59 | print >>sys.stderr, sys.exc_info()[1] 60 | continue 61 | size += fileInfo.st_size 62 | if minMTime is None or fileInfo.st_mtimemaxMTime: 65 | maxMTime = fileInfo.st_mtime 66 | 67 | self.size = size 68 | self.minMTime = minMTime 69 | self.maxMTime = maxMTime 70 | 71 | def sizeStr(self): 72 | """Return the sequence size as a human-readable string. 73 | """ 74 | size = self.size 75 | if size<1024: 76 | return "%dB"%size 77 | elif size<1024*1024: 78 | return "%dK"%(size/1024) 79 | else: 80 | #elif size<1024*1024*1024: 81 | return "%dM"%(size/(1024*1024)) 82 | # else: 83 | # return "%dG"%(size/(1024*1024*1024)) 84 | 85 | def minMTimeStr(self): 86 | """Return the mtime of the oldest file in the sequence. 87 | """ 88 | if self.minMTime is None: 89 | return "?" 90 | else: 91 | t = time.localtime(self.minMTime) 92 | return time.strftime("%d %b %H:%M", t) 93 | 94 | def maxMTimeStr(self): 95 | """Return the mtime of the newest file in the sequence. 96 | """ 97 | if self.maxMTime is None: 98 | return "?" 99 | else: 100 | t = time.localtime(self.maxMTime) 101 | return time.strftime("%d %b %H:%M", t) 102 | 103 | def timeSpanStr(self): 104 | """Return the time difference between the oldest and newest file in the sequence. 105 | """ 106 | if self.minMTime is None or self.maxMTime is None: 107 | return "0" 108 | else: 109 | dt = int(self.maxMTime-self.minMTime) 110 | d = int(dt/(60*60*24)) 111 | dt -= d*60*60*24 112 | h = int(dt/(60*60)) 113 | dt -= h*60*60 114 | m = int(dt/60) 115 | dt -= m*60 116 | s = dt 117 | if d>30: 118 | return ">1 month" 119 | if d>0: 120 | return "%dd %dh"%(d,h) 121 | elif h>0: 122 | return "%dh %dmin"%(h,m) 123 | elif m>0: 124 | return "%dmin %ds"%(m,s) 125 | else: 126 | return "%ss"%(s) 127 | 128 | 129 | def main(): 130 | parser = optparse.OptionParser(usage="%prog [options] paths") 131 | parser.add_option("-l", "--long", action="store_true", default=False, help="Print additional information per sequence") 132 | parser.add_option("-d", "--directories", action="store_true", default=False, help="List directories") 133 | parser.add_option("-V", "--version", action="store_true", default=False, help="Display version information") 134 | opts,args = parser.parse_args() 135 | 136 | if len(args)==0: 137 | args = ["*"] 138 | 139 | args.sort() 140 | 141 | # List directories first 142 | if opts.directories: 143 | for pattern in args: 144 | for name in glob.glob("%s*"%pattern): 145 | if os.path.isdir(name): 146 | if opts.long: 147 | print ("%53s/"%name) 148 | else: 149 | print ("%s/"%name) 150 | 151 | # List sequences 152 | for pattern in args: 153 | pattern=os.path.abspath(pattern) 154 | fseqs = sequence.glob(pattern) 155 | for fseq in fseqs: 156 | if opts.long: 157 | info = SequenceInfo(fseq) 158 | print ("%8s %12s - %12s %-12s %s [%d files]"%(info.sizeStr(), 159 | info.minMTimeStr(), 160 | info.maxMTimeStr(), 161 | "(%s)"%info.timeSpanStr(), 162 | fseq, 163 | len(fseq))) 164 | else: 165 | print (fseq) 166 | 167 | ########################################################################## 168 | 169 | main() 170 | 171 | -------------------------------------------------------------------------------- /moshion/util.py: -------------------------------------------------------------------------------- 1 | """ 2 | python-moshion - Datamoshing Motion 3 | (c) 2014 Robert Moggach, Fabio Piparo and contributors 4 | Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php 5 | 6 | util.py 7 | 8 | moshion is a command line interface to ffmpeg used to datamosh two 9 | video sequences to purposely create encoding artifacts. 10 | 11 | """ 12 | 13 | import sys 14 | 15 | 16 | COLOR_CODES={ 17 | 'none': '0', 18 | 'black': '30', 19 | 'red': '31', 20 | 'green': '32', 21 | 'brown': '33', 22 | 'blue': '34', 23 | 'magenta': '35', 24 | 'cyan': '36', 25 | 'light_gray': '37', 26 | 'dark_gray': '30;1', 27 | 'bright_red': '31;1', 28 | 'bright_green':'32;1', 29 | 'yellow': '33;1', 30 | 'bright_blue': '34;1', 31 | 'purple': '35;1', 32 | 'bright_cyan': '36;1', 33 | 'white': '37;1' 34 | } 35 | 36 | COLORS=[ 37 | 'none', # 0 38 | 'black', # 1 39 | 'red', # 2 40 | 'green', # 3 41 | 'brown', # 4 42 | 'blue', # 5 43 | 'magenta', # 6 44 | 'cyan', # 7 45 | 'light_gray', # 8 46 | 'dark_gray', # 9 47 | 'bright_red', # 10 48 | 'bright_green', # 11 49 | 'yellow', # 12 50 | 'bright_blue', # 13 51 | 'purple', # 14 52 | 'bright_cyan', # 15 53 | 'white' # 16 54 | ] 55 | 56 | 57 | def hilite(string, color=0): 58 | '''hilite a string in TTY terminals/shells''' 59 | color_code = COLOR_CODES[COLORS[color]] 60 | out_str = "\x1b[{color_code}m{string}\x1b[0m".format(color_code=color_code, string=string) 61 | return out_str 62 | 63 | 64 | IS_TTY = sys.stdout.isatty() 65 | 66 | 67 | HR=hilite("-"*64,4).join(["\n","\n"]) 68 | -------------------------------------------------------------------------------- /output/frame_list.txt: -------------------------------------------------------------------------------- 1 | ffconcat version 1.0 2 | file input/input_ftg.0001.jpg 3 | file input/input_ftg.0002.jpg 4 | file input/input_ftg.0003.jpg 5 | file input/input_ftg.0004.jpg 6 | file input/input_ftg.0005.jpg 7 | file input/input_ftg.0006.jpg 8 | file input/input_ftg.0007.jpg 9 | file input/input_ftg.0008.jpg 10 | file input/input_ftg.0009.jpg 11 | file input/input_ftg.0010.jpg 12 | file input/input_ftg.0011.jpg 13 | file input/input_ftg.0012.jpg 14 | file input/input_ftg.0013.jpg 15 | file input/input_ftg.0014.jpg 16 | file input/input_ftg.0015.jpg 17 | file input/input_ftg.0016.jpg 18 | file input/input_ftg.0017.jpg 19 | file input/input_ftg.0018.jpg 20 | file input/input_ftg.0019.jpg 21 | file input/input_ftg.0020.jpg 22 | file input/input_ftg.0005.jpg 23 | file input/input_ftg.0006.jpg 24 | file input/input_ftg.0007.jpg 25 | file input/input_ftg.0008.jpg 26 | file input/input_ftg.0009.jpg 27 | file input/input_ftg.0010.jpg 28 | file input/input_ftg.0011.jpg 29 | file input/input_ftg.0012.jpg 30 | file input/input_ftg.0013.jpg 31 | file input/input_ftg.0014.jpg 32 | file input/input_ftg.0015.jpg 33 | file input/input_ftg.0016.jpg 34 | file input/input_ftg.0017.jpg 35 | file input/input_ftg.0018.jpg 36 | file input/input_ftg.0019.jpg 37 | file input/input_ftg.0020.jpg 38 | file input/input_ftg.0021.jpg 39 | file input/input_ftg.0022.jpg 40 | file input/input_ftg.0023.jpg 41 | file input/input_ftg.0024.jpg 42 | file input/input_ftg.0025.jpg -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [build_sphinx] 2 | all_files = 1 3 | build-dir = docs/_build 4 | source-dir = docs 5 | 6 | [egg_info] 7 | tag_build = 8 | tag_date = 0 9 | tag_svn_revision = 0 10 | 11 | [upload_sphinx] 12 | upload-dir = docs/_build/html 13 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | from distutils.command.install_data import install_data 3 | from distutils.command.install import INSTALL_SCHEMES 4 | import os 5 | import sys 6 | from setup_commands import TestCommand, CleanCommand 7 | 8 | 9 | def return_version(): 10 | return __import__('moshion').get_version() 11 | 12 | 13 | class osx_install_data(install_data): 14 | # On MacOS, the platform-specific lib dir is /System/Library/Framework/Python/.../ 15 | # which is wrong. Python 2.5 supplied with MacOS 10.5 has an Apple-specific fix 16 | # for this in distutils.command.install_data#306. It fixes install_lib but not 17 | # install_data, which is why we roll our own install_data class. 18 | 19 | def finalize_options(self): 20 | # By the time finalize_options is called, install.install_lib is set to the 21 | # fixed directory, so we set the installdir to install_lib. The 22 | # install_data class uses ('install_data', 'install_dir') instead. 23 | self.set_undefined_options('install', ('install_lib', 'install_dir')) 24 | install_data.finalize_options(self) 25 | 26 | if sys.platform == "darwin": 27 | cmdclasses = {'install_data': osx_install_data} 28 | else: 29 | cmdclasses = {'install_data': install_data} 30 | 31 | cmdclasses['test'] = TestCommand 32 | cmdclasses['clean'] = CleanCommand 33 | 34 | 35 | def fullsplit(path, result=None): 36 | """ 37 | Split a pathname into components (the opposite of os.path.join) in a 38 | platform-neutral way. 39 | """ 40 | if result is None: 41 | result = [] 42 | head, tail = os.path.split(path) 43 | if head == '': 44 | return [tail] + result 45 | if head == path: 46 | return result 47 | return fullsplit(head, [tail] + result) 48 | 49 | 50 | # Tell distutils to put the data_files in platform-specific installation 51 | # locations. See here for an explanation: 52 | # http://groups.google.com/group/comp.lang.python/browse_thread/thread/35ec7b2fed36eaec/2105ee4d9e8042cb 53 | for scheme in INSTALL_SCHEMES.values(): 54 | scheme['data'] = scheme['purelib'] 55 | 56 | 57 | # Compile the list of packages available, because distutils doesn't have 58 | # an easy way to do this. 59 | packages, data_files = [], [] 60 | root_dir = os.path.dirname(__file__) 61 | if root_dir != '': 62 | os.chdir(root_dir) 63 | 64 | moshion_dir = 'moshion' 65 | 66 | for dirpath, dirnames, filenames in os.walk(moshion_dir): 67 | # Ignore dirnames that start with '.' 68 | for i, dirname in enumerate(dirnames): 69 | if dirname.startswith('.'): del dirnames[i] 70 | if '__init__.py' in filenames: 71 | packages.append('.'.join(fullsplit(dirpath))) 72 | elif filenames: 73 | data_files.append([dirpath, [os.path.join(dirpath, f) for f in filenames]]) 74 | 75 | # Small hack for working with bdist_wininst. 76 | # See http://mail.python.org/pipermail/distutils-sig/2004-August/004134.html 77 | if len(sys.argv) > 1 and sys.argv[1] == 'bdist_wininst': 78 | for file_info in data_files: 79 | file_info[0] = '\\PURELIB\\%s' % file_info[0] 80 | 81 | 82 | setup( 83 | name='python-moshion', 84 | packages=packages, 85 | cmdclass = cmdclasses, 86 | scripts=['moshion/scripts/gomoshion.py'], 87 | data_files = data_files, 88 | version=return_version(), 89 | description="Datamoshing Motion", 90 | long_description=""" 91 | python-moshion - Datamoshing Motion 92 | (c) 2014 Robert Moggach, Fabio Piparo & contributors. 93 | Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php 94 | 95 | moshion is a standalone tool and library used to datamosh 96 | two video sequences such that the motion of both clips is retained. 97 | 98 | """, 99 | classifiers=[ 100 | 'Development Status :: 4 - Beta', 101 | 'Intended Audience :: Developers', 102 | 'License :: OSI Approved :: MIT License', 103 | 'Programming Language :: Python', 104 | 'Natural Language :: English', 105 | 'Operating System :: POSIX :: Linux', 106 | 'Operating System :: MacOS :: MacOS X', 107 | ], 108 | keywords='image video encoding art', 109 | author='Robert Moggach', 110 | author_email='rob@moggach.com', 111 | maintainer='Robert Moggach', 112 | maintainer_email='rob@moggach.com', 113 | license='MIT' 114 | ) 115 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/__init__.py -------------------------------------------------------------------------------- /tests/footage/input/Users/rob/Code/python-moshtion/tests/footage/output/frame_list.txt: -------------------------------------------------------------------------------- 1 | ffconcat version 1.0 2 | file /Users/rob/Code/python-moshtion/tests/footage/moshtex/moshtex_ftg.0100.jpg 3 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0001.jpg 4 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0002.jpg 5 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0003.jpg 6 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0004.jpg 7 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0005.jpg 8 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0006.jpg 9 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0007.jpg 10 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0008.jpg 11 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0009.jpg 12 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0010.jpg 13 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0011.jpg 14 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0012.jpg 15 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0013.jpg 16 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0014.jpg 17 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0015.jpg 18 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0016.jpg 19 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0017.jpg 20 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0018.jpg 21 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0019.jpg 22 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0020.jpg 23 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0021.jpg 24 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0022.jpg 25 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0023.jpg 26 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0024.jpg 27 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0025.jpg 28 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0026.jpg 29 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0027.jpg 30 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0028.jpg 31 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0029.jpg 32 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0030.jpg 33 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0031.jpg 34 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0032.jpg 35 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0033.jpg 36 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0034.jpg 37 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0035.jpg 38 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0036.jpg 39 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0037.jpg 40 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0038.jpg 41 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0039.jpg 42 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0040.jpg 43 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0041.jpg 44 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0042.jpg 45 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0043.jpg 46 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0044.jpg 47 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0045.jpg 48 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0046.jpg 49 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0047.jpg 50 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0048.jpg 51 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0049.jpg 52 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0050.jpg 53 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0051.jpg 54 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0052.jpg 55 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0053.jpg 56 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0054.jpg 57 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0055.jpg 58 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0056.jpg 59 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0057.jpg 60 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0058.jpg 61 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0059.jpg 62 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0060.jpg 63 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0061.jpg 64 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0062.jpg 65 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0063.jpg 66 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0064.jpg 67 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0065.jpg 68 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0066.jpg 69 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0067.jpg 70 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0068.jpg 71 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0069.jpg 72 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0070.jpg 73 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0071.jpg 74 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0072.jpg 75 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0073.jpg 76 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0074.jpg 77 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0075.jpg 78 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0076.jpg 79 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0077.jpg 80 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0078.jpg 81 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0079.jpg 82 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0080.jpg 83 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0081.jpg 84 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0082.jpg 85 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0083.jpg 86 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0084.jpg 87 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0085.jpg 88 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0086.jpg 89 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0087.jpg 90 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0088.jpg 91 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0089.jpg 92 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0090.jpg 93 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0091.jpg 94 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0092.jpg 95 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0093.jpg 96 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0094.jpg 97 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0095.jpg 98 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0096.jpg 99 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0097.jpg 100 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0098.jpg 101 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0099.jpg 102 | file /Users/rob/Code/python-moshtion/tests/footage/input/input_ftg.0100.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0001.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0002.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0003.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0003.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0004.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0004.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0005.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0005.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0006.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0006.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0007.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0007.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0008.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0008.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0009.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0009.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0010.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0010.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0011.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0011.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0012.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0012.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0013.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0013.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0014.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0014.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0015.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0015.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0016.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0016.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0017.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0017.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0018.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0018.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0019.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0019.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0020.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0020.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0021.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0021.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0022.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0022.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0023.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0023.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0024.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0024.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0025.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0025.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0026.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0026.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0027.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0027.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0028.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0028.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0029.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0029.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0030.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0030.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0031.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0031.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0032.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0032.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0033.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0033.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0034.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0034.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0035.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0035.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0036.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0036.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0037.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0037.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0038.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0038.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0039.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0039.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0040.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0040.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0041.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0041.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0042.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0042.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0043.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0043.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0044.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0044.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0045.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0045.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0046.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0046.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0047.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0047.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0048.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0048.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0049.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0049.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0050.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0050.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0051.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0051.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0052.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0052.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0053.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0053.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0054.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0054.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0055.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0055.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0056.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0056.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0057.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0057.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0058.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0058.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0059.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0059.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0060.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0060.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0061.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0061.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0062.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0062.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0063.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0063.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0064.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0064.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0065.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0065.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0066.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0066.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0067.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0067.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0068.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0068.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0069.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0069.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0070.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0070.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0071.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0071.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0072.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0072.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0073.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0073.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0074.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0074.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0075.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0075.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0076.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0076.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0077.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0077.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0078.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0078.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0079.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0079.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0080.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0080.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0081.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0081.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0082.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0082.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0083.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0083.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0084.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0084.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0085.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0085.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0086.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0086.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0087.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0087.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0088.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0088.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0089.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0089.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0090.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0090.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0091.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0091.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0092.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0092.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0093.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0093.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0094.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0094.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0095.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0095.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0096.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0096.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0097.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0097.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0098.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0098.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0099.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0099.jpg -------------------------------------------------------------------------------- /tests/footage/input/input_ftg.0100.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/input/input_ftg.0100.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0001.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0002.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0003.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0003.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0004.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0004.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0005.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0005.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0006.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0006.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0007.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0007.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0008.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0008.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0009.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0009.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0010.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0010.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0011.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0011.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0012.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0012.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0013.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0013.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0014.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0014.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0015.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0015.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0016.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0016.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0017.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0017.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0018.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0018.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0019.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0019.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0020.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0020.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0021.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0021.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0022.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0022.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0023.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0023.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0024.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0024.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0025.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0025.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0026.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0026.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0027.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0027.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0028.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0028.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0029.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0029.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0030.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0030.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0031.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0031.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0032.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0032.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0033.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0033.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0034.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0034.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0035.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0035.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0036.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0036.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0037.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0037.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0038.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0038.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0039.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0039.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0040.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0040.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0041.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0041.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0042.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0042.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0043.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0043.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0044.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0044.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0045.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0045.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0046.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0046.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0047.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0047.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0048.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0048.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0049.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0049.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0050.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0050.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0051.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0051.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0052.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0052.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0053.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0053.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0054.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0054.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0055.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0055.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0056.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0056.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0057.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0057.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0058.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0058.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0059.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0059.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0060.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0060.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0061.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0061.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0062.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0062.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0063.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0063.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0064.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0064.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0065.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0065.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0066.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0066.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0067.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0067.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0068.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0068.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0069.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0069.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0070.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0070.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0071.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0071.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0072.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0072.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0073.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0073.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0074.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0074.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0075.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0075.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0076.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0076.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0077.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0077.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0078.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0078.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0079.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0079.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0080.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0080.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0081.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0081.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0082.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0082.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0083.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0083.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0084.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0084.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0085.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0085.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0086.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0086.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0087.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0087.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0088.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0088.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0089.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0089.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0090.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0090.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0091.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0091.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0092.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0092.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0093.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0093.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0094.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0094.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0095.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0095.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0096.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0096.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0097.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0097.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0098.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0098.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0099.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0099.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0100.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0100.jpg -------------------------------------------------------------------------------- /tests/footage/moshtex/moshtex_ftg.0101.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmoggach/python-moshion/75a5bb67ab12950adaed9049ce296f6488585477/tests/footage/moshtex/moshtex_ftg.0101.jpg --------------------------------------------------------------------------------