├── LICENSE.md
├── README.md
├── ffmpeg-appender-test.py
├── ffmpeg-appender-test.sh
├── ffmpeg-image-sequencer.sh
├── images
├── earth.jpg
├── picture1.jpg
├── picture2.jpg
└── picture3.jpg
└── video_space.avi
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Bertrand Martel
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FFmpeg image video sequencer
2 |
3 | Create videos from image and append images to existing videos using ffmpeg
4 |
5 | Project is available in Linux Bash script and in Python script
6 |
7 | ffmpeg 2.1+ is required
8 |
9 |
Bash
10 |
11 | create video from image or append image to video :
12 |
13 | `./ffmpeg-image-sequencer.sh -i file1:file2:file3 -f `
14 |
15 | Video must be encoded in mjpeg or mpeg4
16 | path_to_video_output may already exists if that is the case the image are appended to it (if the video format is correct)
17 |
18 | Exemple
19 |
20 | ``./ffmpeg-image-sequencer.sh -i ./image/picture1.jpg``
21 |
22 | This will create a MPEG4 video showing picutre1.jpg during 1 second
23 |
24 |
25 | ``./ffmpeg-image-sequencer.sh -i ./image/picture2.jpg -f video2.mpeg``
26 |
27 | This will append picture2.jpg to video2.mpeg
28 |
29 | Testing script
30 |
31 | `./ffmpeg-appender_test.sh`
32 |
33 | Python
34 |
35 | Testing script : `python ffmpeg-encoder_test.py`
36 |
37 | Testing script : what does it do ?
38 |
39 | * download images from WEB
40 | * create a video from image if no video existing
41 | * create a video from image and append to existing video
42 |
43 | The output is a video created in output directory which contains all 4 images getting from websites and with 1 second of frame rate.
44 |
45 | How does it work ?
46 |
47 | You can use ffmpeg create your video and append JPG image to it.
48 |
49 | To create the video from an existing image :
50 |
51 | ```
52 | ffmpeg -f image2 -pattern_type sequence -start_number 0 -r 1 -i $TEMPORARY_FILE_NAME.jpg -s 1920x1080 $TEMPORARY_FILE_NAME.avi
53 | ```
54 |
55 | * `-f image2` is Image file demuxer format
56 | * `pattern_type sequence` is for sequential pattern
57 | * `start_number` is the index of the sequence
58 | * `-r 1` is the frame rate, I put it to 1 frame/s to have time to see each picture
59 | * `-s 1920x1080` set the frame size
60 |
61 | To append an image to an existing a video, you will have to convert this image to a temporary video first, and then concat your former video to this newly created video. To concat videos :
62 |
63 | ```
64 | ffmpeg -i "concat:$OUTPUT_FILE_NAME.avi|$TEMPORARY_FILE_NAME.avi" -c copy $TEMPORARY_FILE_NAME_VIDEO.avi
65 | ```
66 |
67 | * `-i "concat:$OUTPUT_FILE_NAME.avi|$TEMPORARY_FILE_NAME.avi"` take videos to concat, you can add more if you like between |
68 | * `-c copy` will copy all video streams without reencoding
69 |
70 | You can find more information on ffmpg here https://ffmpeg.org/ffmpeg.html
71 |
72 |
--------------------------------------------------------------------------------
/ffmpeg-appender-test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #####################################################################################
3 | #####################################################################################
4 | #
5 | # title : ffmpeg-appender-test.py
6 | # authors : Bertrand Martel
7 | # copyrights : Copyright (c) 2015 Bertrand Martel
8 | # license : The MIT License (MIT)
9 | # date : 16/08/2015
10 | # description : create video if not exist and append a series of image to this video taken from WEB
11 | # usage : python ffmpeg-appender-test.py
12 | #
13 | #####################################################################################
14 | #####################################################################################
15 |
16 | import sys, getopt, os, subprocess
17 |
18 | def main(argv):
19 |
20 | output_file_name = "video_space"
21 | temporary_file_name = "temp_space"
22 | temporary_file_name_video = "temp_video"
23 |
24 | picture_array = [ "https://upload.wikimedia.org/wikipedia/commons/4/4e/Anttlers101.jpg", \
25 | "https://upload.wikimedia.org/wikipedia/commons/3/3b/NASA-SpiralGalaxyM101-20140505.jpg", \
26 | "https://upload.wikimedia.org/wikipedia/commons/b/b0/Supernova_in_M101_2011-08-25.jpg", \
27 | "http://1.1.1.5/bmi/images.nationalgeographic.com/wpf/media-live/photos/000/061/cache/earth-full-view_6125_990x742.jpg" ]
28 |
29 | this_dir = os.path.dirname(os.path.abspath(__file__))
30 | os.chdir(this_dir)
31 |
32 | output_file_path = ''.join([this_dir , "/",output_file_name,".avi"])
33 | temporary_file_path_avi = ''.join([this_dir,"/",temporary_file_name,".avi"])
34 | temporary_file_name_jpg = ''.join([this_dir,"/",temporary_file_name,".jpg"])
35 | temporary_file_name_video = ''.join([this_dir,"/",temporary_file_name_video,".avi"])
36 |
37 | #remove files
38 |
39 | try:
40 | os.remove(output_file_path)
41 | except OSError:
42 | pass
43 |
44 | try:
45 | os.remove(temporary_file_path_avi)
46 | except OSError:
47 | pass
48 |
49 | try:
50 | os.remove(temporary_file_name_jpg)
51 | except OSError:
52 | pass
53 |
54 | try:
55 | os.remove(temporary_file_name_video)
56 | except OSError:
57 | pass
58 |
59 | for picture in picture_array:
60 |
61 | subprocess.call(["wget", picture, "-O", temporary_file_name_jpg])
62 |
63 | subprocess.call(["ffmpeg -nostdin -v verbose -f image2 -pattern_type sequence -start_number 0 -r 1 -i " + temporary_file_name_jpg + " -s 1920x1080 " + temporary_file_path_avi],shell=True)
64 |
65 | try:
66 | os.remove(temporary_file_name_jpg)
67 | except OSError:
68 | pass
69 |
70 | if os.path.exists(output_file_path):
71 |
72 | # concat this video and former video
73 | subprocess.call(['cd ' + this_dir + ' | ffmpeg -nostdin -v verbose -i "concat:' + output_file_name + '.avi|' + temporary_file_name + '.avi" -c copy ' + temporary_file_name_video],shell=True)
74 |
75 | try:
76 | os.remove(temporary_file_path_avi)
77 | except OSError:
78 | pass
79 |
80 | try:
81 | os.remove(output_file_path)
82 | except OSError:
83 | pass
84 |
85 | os.rename(temporary_file_name_video, output_file_path)
86 |
87 | else:
88 | os.rename(temporary_file_path_avi, output_file_path)
89 |
90 | if __name__ == "__main__":
91 | main(sys.argv[1:])
92 |
93 | __author__ = "Bertrand Martel"
94 | __copyright__ = "Copyright 2015, Bertrand Martel"
95 | __credits__ = ["Bertrand Martel"]
96 | __license__ = "MIT"
97 | __version__ = "1.0.0"
98 | __maintainer__ = "Bertrand Martel"
99 | __email__ = "bmartel.fr@gmail.com"
100 | __status__ = "POC"
--------------------------------------------------------------------------------
/ffmpeg-appender-test.sh:
--------------------------------------------------------------------------------
1 | #/bin/bash
2 | #####################################################################################
3 | #####################################################################################
4 | #
5 | # title : ffmpeg-appender-test.sh
6 | # authors : Bertrand Martel
7 | # copyrights : Copyright (c) 2015 Bertrand Martel
8 | # license : The MIT License (MIT)
9 | # date : 16/08/2015
10 | # description : create a MPEG4 video from a sequence of images taken from the web
11 | # usage : ./ffmpeg-appender-test.sh
12 | #
13 | #####################################################################################
14 | #####################################################################################
15 |
16 | #set workign directory
17 | WORKING_DIR=./
18 |
19 | OUTPUT_FILE_NAME="video_space"
20 | OUTPUT_FILE_PATH="$WORKING_DIR/$OUTPUT_FILE_NAME.avi"
21 | TEMPORARY_FILE_NAME="temp_space"
22 | TEMPORARY_FILE_NAME_VIDEO="temp_video"
23 |
24 | #set a list of picture to download
25 | declare -a PICTURE_ARRAY=("https://upload.wikimedia.org/wikipedia/commons/4/4e/Anttlers101.jpg" \
26 | "https://upload.wikimedia.org/wikipedia/commons/3/3b/NASA-SpiralGalaxyM101-20140505.jpg" \
27 | "https://upload.wikimedia.org/wikipedia/commons/b/b0/Supernova_in_M101_2011-08-25.jpg" \
28 | "https://upload.wikimedia.org/wikipedia/commons/9/97/The_Earth_seen_from_Apollo_17.jpg")
29 |
30 | #change directory for ffmpeg processing
31 | cd $WORKING_DIR
32 |
33 | #remove temporary and output files if existing
34 | rm -rf $OUTPUT_FILE_PATH
35 | rm -rf $TEMPORARY_FILE_NAME.avi
36 | rm -rf $TEMPORARY_FILE_NAME.jpg
37 | rm -rf $TEMPORARY_FILE_NAME_VIDEO.avi
38 |
39 | for i in {0..3}
40 | {
41 | #get image from WEB path
42 | wget ${PICTURE_ARRAY[i]} -O $TEMPORARY_FILE_NAME.jpg
43 |
44 | #create a video from the image
45 | ffmpeg -nostdin -v verbose -f image2 -pattern_type sequence -start_number 0 -r 1 -i $TEMPORARY_FILE_NAME.jpg -s 1920x1080 $TEMPORARY_FILE_NAME.avi
46 |
47 | #remove jpg file we have just downloaded
48 | rm $TEMPORARY_FILE_NAME.jpg
49 |
50 | if [ -f $OUTPUT_FILE_PATH ];
51 | then
52 | # concat this video and former video into a new one
53 | ffmpeg -nostdin -v verbose -i "concat:$OUTPUT_FILE_NAME.avi|$TEMPORARY_FILE_NAME.avi" -c copy $TEMPORARY_FILE_NAME_VIDEO.avi
54 |
55 | #remove the former output and the video previously created
56 | rm $TEMPORARY_FILE_NAME.avi
57 | rm $OUTPUT_FILE_NAME.avi
58 |
59 | #rename to the output
60 | mv $TEMPORARY_FILE_NAME_VIDEO.avi $OUTPUT_FILE_NAME.avi
61 | else
62 | mv $TEMPORARY_FILE_NAME.avi $OUTPUT_FILE_NAME.avi
63 | fi
64 | }
65 |
--------------------------------------------------------------------------------
/ffmpeg-image-sequencer.sh:
--------------------------------------------------------------------------------
1 | #/bin/bash
2 | #####################################################################################
3 | #####################################################################################
4 | #
5 | # title : ffmpeg-image-sequencer.sh
6 | # authors : Bertrand Martel
7 | # copyrights : Copyright (c) 2015 Bertrand Martel
8 | # license : The MIT License (MIT)
9 | # date : 16/08/2015
10 | # description : create a MPEG4 video if not exist and append one or a list of JPG images to this video
11 | # usage : ./ffmpeg-image-sequencer.sh -i file1:file2:file3 -f
12 | #
13 | #####################################################################################
14 | #####################################################################################
15 |
16 | #default path is in current directory
17 |
18 | # A POSIX variable
19 | OPTIND=1 # Reset in case getopts has been used previously in the shell.
20 |
21 | # Initialize our own variables:
22 | output_file=""
23 | input_file=""
24 |
25 | verbose=0
26 |
27 | while getopts "h?i:f:" opt; do
28 | case "$opt" in
29 | h|\?)
30 | echo "Usage : ffmpeg-image-sequencer.sh ::.....:"
31 | exit 0
32 | ;;
33 | i) input_file=$OPTARG
34 | ;;
35 | f) output_file=$OPTARG
36 | ;;
37 | esac
38 | done
39 |
40 | shift $((OPTIND-1))
41 |
42 | [ "$1" = "--" ] && shift
43 |
44 | echo "Processing list of files : $input_file"
45 | echo "Processing to output file : $output_file"
46 |
47 | if [ -z $input_file ]; then
48 | echo "Usage : ffmpeg-image-sequencer.sh ::.....:"
49 | exit 0
50 | fi
51 |
52 | FILE_LIST="$input_file"
53 | VIDEO_INIT=""
54 |
55 | #set workign directory
56 | WORKING_DIR=./
57 |
58 | OUTPUT_FILE_NAME="video_output"
59 | OUTPUT_FILE_PATH="$WORKING_DIR/$OUTPUT_FILE_NAME.avi"
60 | TEMPORARY_FILE_NAME="temp"
61 | TEMPORARY_FILE_NAME_VIDEO="temp_video"
62 |
63 | #change directory for ffmpeg processing
64 | cd $WORKING_DIR
65 |
66 | if [ "$output_file" != "$OUTPUT_FILE_NAME.avi" ]; then
67 | rm -rf $OUTPUT_FILE_NAME.avi
68 | fi
69 |
70 | if [ -f $output_file ]; then
71 | cp $output_file $WORKING_DIR/$OUTPUT_FILE_NAME.avi
72 | fi
73 |
74 | IFS=':' read -ra ADDR <<< "$FILE_LIST"
75 |
76 | for i in "${ADDR[@]}"; do
77 |
78 | #create a video from the image
79 | ffmpeg -nostdin -v verbose -f image2 -pattern_type sequence -start_number 0 -r 1 -i $i -s 1920x1080 $TEMPORARY_FILE_NAME.avi
80 |
81 | if [ -f $OUTPUT_FILE_PATH ];
82 | then
83 | # concat this video and former video into a new one
84 | ffmpeg -nostdin -v verbose -i "concat:$OUTPUT_FILE_NAME.avi|$TEMPORARY_FILE_NAME.avi" -c copy $TEMPORARY_FILE_NAME_VIDEO.avi
85 |
86 | #remove the former output and the video previously created
87 | rm $TEMPORARY_FILE_NAME.avi
88 | rm $OUTPUT_FILE_NAME.avi
89 |
90 | #rename to the output
91 | mv $TEMPORARY_FILE_NAME_VIDEO.avi $OUTPUT_FILE_NAME.avi
92 | else
93 | mv $TEMPORARY_FILE_NAME.avi $OUTPUT_FILE_NAME.avi
94 | fi
95 |
96 | done
--------------------------------------------------------------------------------
/images/earth.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bertrandmartel/ffmpeg-image-sequencer/42145bc9079673e388e982bafe768d50cd5d8b13/images/earth.jpg
--------------------------------------------------------------------------------
/images/picture1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bertrandmartel/ffmpeg-image-sequencer/42145bc9079673e388e982bafe768d50cd5d8b13/images/picture1.jpg
--------------------------------------------------------------------------------
/images/picture2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bertrandmartel/ffmpeg-image-sequencer/42145bc9079673e388e982bafe768d50cd5d8b13/images/picture2.jpg
--------------------------------------------------------------------------------
/images/picture3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bertrandmartel/ffmpeg-image-sequencer/42145bc9079673e388e982bafe768d50cd5d8b13/images/picture3.jpg
--------------------------------------------------------------------------------
/video_space.avi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bertrandmartel/ffmpeg-image-sequencer/42145bc9079673e388e982bafe768d50cd5d8b13/video_space.avi
--------------------------------------------------------------------------------