Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a49846cf0a | ||
|
|
abb32c50e0 | ||
|
|
6640769595 | ||
|
|
337dbbc11f | ||
|
|
681bcb37e4 | ||
|
|
6c5aaeb20b | ||
|
|
fae5db9f75 | ||
|
|
2d4c88da9e | ||
|
|
b08c30cd69 |
51
README.md
51
README.md
@@ -1,21 +1,34 @@
|
|||||||
# video-thumbnail-generator
|
# Video thumbnail generator
|
||||||
Generate thumbnail sprites from videos.
|
> Generate thumbnail sprites from videos.
|
||||||
|
|
||||||
|
## Why
|
||||||
|
|
||||||
### Why?
|
|
||||||

|

|
||||||
|
|
||||||
Almost all video players enhances user's seekbar navigation by providing a thumbnail preview of the moments where the user can seek to. This is a python script that, given a video, generate a thumbnail sprite image from it.
|
Generate a thumbnail sprite shouldn't be hard, because almost all video players enhances user's seekbar navigation by providing a thumbnail preview of the moments where the user want to seek. This is a python script that, given a video, generate a thumbnail sprite image from it.
|
||||||
|
|
||||||
### Build
|
## Build
|
||||||
|
|
||||||
Clone this repository. On project folder:
|
1. Clone it:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ git clone git@github.com:flavioribeiro/video-thumbnail-generator.git
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Then go to the project's folder:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ cd video-thumbnail-generator
|
||||||
|
```
|
||||||
|
|
||||||
|
3. And finally run:
|
||||||
```shell
|
```shell
|
||||||
$ chmod a+x build && ./build
|
$ chmod a+x build && ./build
|
||||||
```
|
```
|
||||||
|
|
||||||
### Run
|
## Run
|
||||||
```shell
|
```shell
|
||||||
$ chmod a+x generator && ./generator --help
|
$ ./generator --help
|
||||||
Video Thumbnail Generator
|
Video Thumbnail Generator
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
@@ -34,9 +47,9 @@ Options:
|
|||||||
<output> Output.
|
<output> Output.
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example
|
## Example
|
||||||
```shell
|
```shell
|
||||||
$ ./generator videos/27467_1_milkbots_wg_720p.mp4 2 126 73 10 27467_1_milkbots_wg_with_script.jpg
|
$ ./generator videos/27467_1_milkbots_wg_720p.mp4 2 126 73 10 thumbnails.jpg
|
||||||
Extracting 101 frames
|
Extracting 101 frames
|
||||||
.................................................................. Frames extracted.
|
.................................................................. Frames extracted.
|
||||||
Saved!
|
Saved!
|
||||||
@@ -44,6 +57,22 @@ Saved!
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
#### License
|
|
||||||
|
## Browser Support
|
||||||
|
|
||||||
|
 |  |  |  | 
|
||||||
|
--- | --- | --- | --- | --- |
|
||||||
|
IE 9+ ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ |
|
||||||
|
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
1. Fork it!
|
||||||
|
2. Create your feature branch: `git checkout -b my-awesome-new-feature`
|
||||||
|
3. Commit your changes: `git commit -m 'Add some awesome feature'`
|
||||||
|
4. Push to the branch: `git push origin my-awesome-new-feature`
|
||||||
|
5. Submit a pull request :]
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
This code is under [Apache License](https://github.com/flavioribeiro/video-thumbnail-generator/blob/master/LICENSE).
|
This code is under [Apache License](https://github.com/flavioribeiro/video-thumbnail-generator/blob/master/LICENSE).
|
||||||
|
|||||||
1
build
1
build
@@ -6,3 +6,4 @@ if [ "$UNAME_S" == "Darwin" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
chmod a+x generator
|
||||||
|
|||||||
20
generator
20
generator
@@ -21,10 +21,11 @@ Options:
|
|||||||
from docopt import docopt
|
from docopt import docopt
|
||||||
from moviepy.editor import VideoFileClip
|
from moviepy.editor import VideoFileClip
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import glob, os, random, sys, shutil, math
|
from click import progressbar
|
||||||
|
import glob, os, random, shutil, math, tempfile
|
||||||
|
|
||||||
|
|
||||||
TMP_FRAMES_PATH="/tmp/frames/"
|
TMP_FRAMES_PATH = tempfile.mkstemp()[1]
|
||||||
|
|
||||||
def generate_video_thumbnail(args):
|
def generate_video_thumbnail(args):
|
||||||
videoFileClip = VideoFileClip(args['<video>'])
|
videoFileClip = VideoFileClip(args['<video>'])
|
||||||
@@ -35,29 +36,28 @@ def generate_video_thumbnail(args):
|
|||||||
|
|
||||||
columns = int(args['<columns>'])
|
columns = int(args['<columns>'])
|
||||||
output = args['<output>']
|
output = args['<output>']
|
||||||
generate_sprite_from_images(outputPrefix, columns, size, output)
|
generate_sprite_from_frames(outputPrefix, columns, size, output)
|
||||||
|
|
||||||
def generate_frames(videoFileClip, interval, outputPrefix, size):
|
def generate_frames(videoFileClip, interval, outputPrefix, size):
|
||||||
print "Extracting", int(videoFileClip.duration / interval), "frames"
|
print "Extracting", int(videoFileClip.duration / interval), "frames"
|
||||||
frameCount = 0
|
frameCount = 0
|
||||||
for i in range(0, int(videoFileClip.duration), interval):
|
with progressbar(range(0, int(videoFileClip.duration), interval)) as items:
|
||||||
|
for i in items:
|
||||||
extract_frame(videoFileClip, i, outputPrefix, size, frameCount)
|
extract_frame(videoFileClip, i, outputPrefix, size, frameCount)
|
||||||
frameCount += 1
|
frameCount += 1
|
||||||
print "Frames extracted."
|
print "Frames extracted."
|
||||||
|
|
||||||
def extract_frame(videoFileClip, moment, outputPrefix, size, frameCount):
|
def extract_frame(videoFileClip, moment, outputPrefix, size, frameCount):
|
||||||
sys.stdout.write(".")
|
|
||||||
sys.stdout.flush()
|
|
||||||
output = outputPrefix + ("%05d.png" % frameCount)
|
output = outputPrefix + ("%05d.png" % frameCount)
|
||||||
videoFileClip.save_frame(output, t=int(moment))
|
videoFileClip.save_frame(output, t=int(moment))
|
||||||
resize_image(output, size)
|
resize_frame(output, size)
|
||||||
|
|
||||||
def resize_image(filename, size):
|
def resize_frame(filename, size):
|
||||||
image = Image.open(filename)
|
image = Image.open(filename)
|
||||||
image = image.resize(size, Image.ANTIALIAS)
|
image = image.resize(size, Image.ANTIALIAS)
|
||||||
image.save(filename)
|
image.save(filename)
|
||||||
|
|
||||||
def generate_sprite_from_images(framesPath, columns, size, output):
|
def generate_sprite_from_frames(framesPath, columns, size, output):
|
||||||
framesMap = sorted(glob.glob(framesPath + "*.png"))
|
framesMap = sorted(glob.glob(framesPath + "*.png"))
|
||||||
images = [Image.open(filename) for filename in framesMap]
|
images = [Image.open(filename) for filename in framesMap]
|
||||||
masterWidth = size[0] * columns
|
masterWidth = size[0] * columns
|
||||||
@@ -86,6 +86,6 @@ def get_output_prefix():
|
|||||||
return TMP_FRAMES_PATH + ("%032x_" % random.getrandbits(128))
|
return TMP_FRAMES_PATH + ("%032x_" % random.getrandbits(128))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
arguments = docopt(__doc__, version='0.0.1')
|
arguments = docopt(__doc__, version='0.0.2')
|
||||||
generate_video_thumbnail(arguments)
|
generate_video_thumbnail(arguments)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user