Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Wisketchy Dobrov 2020-10-26 20:50:21 +03:00
commit 56612d7143
8 changed files with 5980 additions and 35 deletions

View File

@ -37,12 +37,16 @@ Linux/OSX
```
fvid -i [input file] -e
fvid -i [input file] --framerate 30 -e
fvid -i [input file] --password "wow fvid is cool" -e
```
Windows
```
py -m fvid -i [input file] -e
py -m fvid -i [input file] --framerate 30 -e
py -m fvid -i [input file] --password "wow fvid is cool" -e
```
Retrieving data from videos
@ -59,6 +63,7 @@ Windows
py -m fvid -i [input video] -d
```
If the file was encoded with a non-default password, it'll prompt you to enter the password upon decoding.
How to Contribute
-----------------

View File

@ -1,2 +1,2 @@
__version__ = "0.0.2"
__version__ = "1.0.0"

View File

@ -1,5 +1,28 @@
import sys
from fvid import main
# leaving this here in case the try/except thing doesn't work
"""
import platform
import distro # to check linux distributions
try:
linux_distro = distro.linux_distribution()[0].lower()
except:
linux_distro = "n/a"
# fvid
if platform.system().lower() in ('linux', 'darwin') and linux_distro not in ('artix linux',):
# this used to work for every distro but something changed in the Cython/Password PR
from fvid import main
else:
# windows and artix linux need this because of something in the Cython/Password PR, unknown if more OSes need it
from fvid.fvid import main
"""
try:
from fvid import main
except:
from fvid.fvid import main
if __name__ == '__main__':
sys.exit(main())
sys.exit(main())

6
fvid/cythonizer.py Normal file
View File

@ -0,0 +1,6 @@
#cython: language_level = 3
from distutils.core import Extension, setup
from Cython.Build import cythonize
ext = Extension(name="fvid_cython", sources=["fvid_cython.pyx"])
setup(ext_modules=cythonize(ext, compiler_directives={'language_level': 3, 'infer_types': True}))

View File

@ -1,19 +1,12 @@
from bitstring import Bits, BitArray
from PIL import Image
import glob
from operator import sub
import numpy as np
from tqdm import tqdm
import binascii
import argparse
import sys
import os
import getpass
import getpass
import io
import gzip
import pickle
@ -23,6 +16,11 @@ from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from Crypto.Cipher import AES
try:
from fvid_cython import cy_get_bits_from_image as cy_gbfi
use_cython = True
except (ImportError, ModuleNotFoundError):
use_cython = False
FRAMES_DIR = "./fvid_frames/"
SALT = '63929291bca3c602de64352a4d4bfe69'.encode() # It need be the same in one instance of coding/decoding
@ -54,8 +52,6 @@ def get_password(password_provided):
key = kdf.derive(password)
return key
def get_bits_from_file(filepath, key):
print('Reading file...')
bitarray = BitArray(filename=filepath)
@ -87,6 +83,10 @@ def less(val1, val2):
return val1 < val2
def get_bits_from_image(image):
if use_cython:
bits = cy_gbfi(image)
return bits, False
width, height = image.size
done = False
@ -94,11 +94,10 @@ def get_bits_from_image(image):
px = image.load()
bits = ""
pbar = range(height)
white = (255, 255, 255)
black = (0, 0, 0)
for y in pbar:
for y in range(height):
for x in range(width):
pixel = px[x, y]
@ -111,14 +110,9 @@ def get_bits_from_image(image):
elif pixel == black:
pixel_bin_rep = "0"
else:
white_diff = tuple(map(abs, map(sub, white, pixel)))
# min_diff = white_diff
black_diff = tuple(map(abs, map(sub, black, pixel)))
# if the white difference is smaller, that means the pixel is closer
# to white, otherwise, the pixel must be black
if all(map(less, white_diff, black_diff)):
if abs(pixel[0] - 255) < abs(pixel[0] - 0) and abs(pixel[1] - 255) < abs(pixel[1] - 0) and abs(pixel[2] - 255) < abs(pixel[2] - 0):
pixel_bin_rep = "1"
else:
pixel_bin_rep = "0"
@ -128,7 +122,6 @@ def get_bits_from_image(image):
return (bits, done)
def get_bits_from_video(video_filepath):
# get image sequence from video
print('Reading video...')
@ -143,6 +136,8 @@ def get_bits_from_video(video_filepath):
bits = ""
sequence_length = len(image_sequence)
print('Bits are in place')
if use_cython:
print('Using Cython...')
for index in tqdm(range(sequence_length)):
b, done = get_bits_from_image(image_sequence[index])
@ -153,7 +148,6 @@ def get_bits_from_video(video_filepath):
return bits
def save_bits_to_file(file_path, bits, key):
# get file extension
@ -203,7 +197,6 @@ def split_list_by_n(lst, n):
for i in range(0, len(lst), n):
yield lst[i : i + n]
def make_image_sequence(bitstring, resolution=(1920, 1080)):
width, height = resolution
@ -213,7 +206,6 @@ def make_image_sequence(bitstring, resolution=(1920, 1080)):
# bit_sequence = []
print('Making image sequence')
print('Cutting...')
#bitlist = list(tqdm(split_list_by_n(bitstring, set_size)))
bitlist = list(split_list_by_n(bitstring, set_size))
del bitstring
@ -225,8 +217,6 @@ def make_image_sequence(bitstring, resolution=(1920, 1080)):
print('Saving frames...')
for _ in tqdm(range(len(bitlist))):
bitl = bitlist.pop()
# for bitl in tqdm(bitlist):
# image_bits = list(map(int, tqdm(bitl)))
image_bits = list(map(int, bitl))
# print(image_bits)
@ -237,7 +227,6 @@ def make_image_sequence(bitstring, resolution=(1920, 1080)):
)
index += 1
def make_video(output_filepath, framerate="1/5"):
if output_filepath == None:
@ -262,7 +251,6 @@ def setup():
if not os.path.exists(FRAMES_DIR):
os.makedirs(FRAMES_DIR)
def main():
parser = argparse.ArgumentParser(description="save files as videos")
parser.add_argument(

5859
fvid/fvid_cython.c Normal file

File diff suppressed because it is too large Load Diff

38
fvid/fvid_cython.pyx Normal file
View File

@ -0,0 +1,38 @@
# distutils: language=c
# cython: boundscheck=False
# cython: cdivision=True
# cython: wraparound=False
cpdef str cy_get_bits_from_image(image):
cdef int width, height, x, y
cdef str pixel_bin_rep, bits
cdef (int, int, int) pixel
width, height = image.size
px = image.load()
bits = ""
for y in range(height):
for x in range(width):
pixel = px[x, y]
pixel_bin_rep = <str>"0"
# for exact matches, indexing each pixel individually is faster in cython for some reason
if pixel[0] == 255 and pixel[1] == 255 and pixel[2] == 255:
pixel_bin_rep = <str>"1"
elif pixel[0] == 0 and pixel[1] == 0 and pixel[2] == 0:
pixel_bin_rep = <str>"0"
else:
# if the white difference is smaller (comparison part 1), that means the pixel is closer
# to white, otherwise, the pixel must be black
if abs(pixel[0] - 255) < abs(pixel[0] - 0) and abs(pixel[1] - 255) < abs(pixel[1] - 0) and abs(pixel[2] - 255) < abs(pixel[2] - 0):
pixel_bin_rep = <str>"1"
else:
pixel_bin_rep = <str>"0"
# adding bits
bits += pixel_bin_rep
return bits

View File

@ -1,7 +1,28 @@
import os
import codecs
from setuptools import setup
from setuptools import Extension
from setuptools.command.build_ext import build_ext as _build_ext
try:
from Cython.Build import cythonize
except ImportError:
use_cython = False
ext = 'c'
else:
use_cython = True
ext = 'pyx'
if not use_cython:
extensions = Extension("fvid.fvid_cython", ["fvid/fvid_cython.c"], include_dirs=["./fvid", "fvid/"])
else:
extensions = Extension("fvid.fvid_cython", ["fvid/fvid_cython.pyx"], include_dirs=["./fvid", "fvid/"])
extensions = cythonize(extensions, compiler_directives={'language_level': "3", 'infer_types': True})
class build_ext(_build_ext):
def finalize_options(self):
_build_ext.finalize_options(self)
with open("README.md", "r") as fh:
long_description = fh.read()
@ -41,10 +62,9 @@ setup(
"Intended Audience :: End Users/Desktop",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Operating System :: Microsoft :: Windows :: Windows 10",
"Operating System :: Microsoft :: Windows :: Windows 8",
"Operating System :: Microsoft :: Windows :: Windows 8.1",
@ -53,14 +73,20 @@ setup(
],
license="MIT",
packages=["fvid"],
setup_requires=[
"cython >= 3.0a6"
],
install_requires=[
"bitstring",
"python-magic",
"pillow",
"numpy",
"tqdm",
"ffmpeg-python",
"cryptography >= 3.1.1",
"pycryptodome >= 3.9.8"
],
python_requires=">=3.6",
entry_points={"console_scripts": ["fvid = fvid.fvid:main"]},
ext_modules=extensions,
cmdclass={'build_ext': build_ext},
include_package_data=True,
zip_safe=False,
)