1#!/usr/local/bin/python3.8
2
3# python-gphoto2 - Python interface to libgphoto2
4# http://github.com/jim-easterbrook/python-gphoto2
5# Copyright (C) 2018-19  Jim Easterbrook  jim@jim-easterbrook.me.uk
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20"""Simple time lapse script.
21
22This works OK with my Canon SLR, but will probably need changes to work
23with another camera.
24
25"""
26
27from __future__ import print_function
28
29from contextlib import contextmanager
30import os
31import subprocess
32import sys
33import time
34
35import gphoto2 as gp
36
37
38# time between captures
39INTERVAL = 10.0
40# temporary directory
41WORK_DIR = '/tmp/time_lapse'
42# result
43OUT_FILE = 'time_lapse.mp4'
44
45
46@contextmanager
47def configured_camera():
48    # initialise camera
49    camera = gp.Camera()
50    camera.init()
51    try:
52        # adjust camera configuratiuon
53        cfg = camera.get_config()
54        capturetarget_cfg = cfg.get_child_by_name('capturetarget')
55        capturetarget = capturetarget_cfg.get_value()
56        capturetarget_cfg.set_value('Internal RAM')
57        # camera dependent - 'imageformat' is 'imagequality' on some
58        imageformat_cfg = cfg.get_child_by_name('imageformat')
59        imageformat = imageformat_cfg.get_value()
60        imageformat_cfg.set_value('Small Fine JPEG')
61        camera.set_config(cfg)
62        # use camera
63        yield camera
64    finally:
65        # reset configuration
66        capturetarget_cfg.set_value(capturetarget)
67        imageformat_cfg.set_value(imageformat)
68        camera.set_config(cfg)
69        # free camera
70        camera.exit()
71
72
73def empty_event_queue(camera):
74    while True:
75        type_, data = camera.wait_for_event(10)
76        if type_ == gp.GP_EVENT_TIMEOUT:
77            return
78        if type_ == gp.GP_EVENT_FILE_ADDED:
79            # get a second image if camera is set to raw + jpeg
80            print('Unexpected new file', data.folder + data.name)
81
82
83def main():
84    if not os.path.exists(WORK_DIR):
85        os.makedirs(WORK_DIR)
86    template = os.path.join(WORK_DIR, 'frame%04d.jpg')
87    next_shot = time.time() + 1.0
88    count = 0
89    with configured_camera() as camera:
90        while True:
91            try:
92                empty_event_queue(camera)
93                while True:
94                    sleep = next_shot - time.time()
95                    if sleep < 0.0:
96                        break
97                    time.sleep(sleep)
98                path = camera.capture(gp.GP_CAPTURE_IMAGE)
99                print('capture', path.folder + path.name)
100                camera_file = camera.file_get(
101                    path.folder, path.name, gp.GP_FILE_TYPE_NORMAL)
102                camera_file.save(template % count)
103                camera.file_delete(path.folder, path.name)
104                next_shot += INTERVAL
105                count += 1
106            except KeyboardInterrupt:
107                break
108    subprocess.check_call(['ffmpeg', '-r', '25',
109                           '-i', template, '-c:v', 'h264', OUT_FILE])
110    for i in range(count):
111        os.unlink(template % i)
112    return 0
113
114
115if __name__ == "__main__":
116    sys.exit(main())
117