Skip to content

Commit

Permalink
change behaviour so next image runs at end of video rather than looping
Browse files Browse the repository at this point in the history
  • Loading branch information
paddywwoof committed Nov 23, 2023
1 parent 25c5fbb commit 902fcf5
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 19 deletions.
6 changes: 3 additions & 3 deletions src/picframe/image_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import logging
import threading
from picframe import get_image_meta
from picframe.video_streamer import get_dimensions
from picframe.video_streamer import VideoInfo


class ImageCache:
Expand Down Expand Up @@ -466,8 +466,8 @@ def __purge_missing_files_and_folders(self):
def __get_exif_info(self, file_path_name):
ext = os.path.splitext(file_path_name)[1].lower()
if ext in ImageCache.VIDEO_EXTENSIONS: # no exif info available
dimensions = get_dimensions(file_path_name)
return {'width': dimensions[0], 'height': dimensions[1]} # return early with min info for videos
video_info = VideoInfo(file_path_name) # TODO video info may contain rubbish if ffprobe failed
return {'width': video_info.width, 'height': video_info.height} # return early with min info for videos TODO duration available in video_info
exifs = get_image_meta.GetImageMeta(file_path_name)
# Dict to store interesting EXIF data
# Note, the 'key' must match a field in the 'meta' table
Expand Down
34 changes: 21 additions & 13 deletions src/picframe/video_streamer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,32 @@
import time
import json


def get_dimensions(video_path):
probe_cmd = f'ffprobe -v error -show_entries stream=width,height,avg_frame_rate -of json "{video_path}"'
probe_result = subprocess.check_output(probe_cmd, shell=True, text=True)
video_info_list = [vinfo for vinfo in json.loads(probe_result)['streams'] if 'width' in vinfo]
if len(video_info_list) > 0:
video_info = video_info_list[0] # use first if more than one!
return(video_info['width'], video_info['height'])
else:
return None
class VideoInfo:
def __init__(self, video_path):
probe_cmd = f'ffprobe -v error -show_entries stream=width,height,avg_frame_rate,duration -of json "{video_path}"'
probe_result = subprocess.check_output(probe_cmd, shell=True, text=True)
video_info_list = [vinfo for vinfo in json.loads(probe_result)['streams'] if 'width' in vinfo]
if len(video_info_list) > 0:
video_info = video_info_list[0] # use first if more than one!
self.width = int(video_info['width'])
self.height = int(video_info['height'])
self.fps = eval(video_info['avg_frame_rate']) #TODO this is string in form '24/1' converted to float using eval - try/catch this?
self.duration = float(video_info['duration'])
else:
self.width = self.height = self.fps = self.duration = None

class VideoStreamer:
def __init__(self, video_path):
self.flag = False # use to signal new texture
self.kill_thread = False
self.command = [ 'ffmpeg', '-i', video_path, '-f', 'image2pipe',
'-pix_fmt', 'rgb24', '-vcodec', 'rawvideo', '-']
dimensions = get_dimensions(video_path)
if dimensions is not None:
(self.W, self.H) = dimensions
video_info = VideoInfo(video_path)
if video_info.width is not None:
self.W = video_info.width
self.H = video_info.height
self.fps = video_info.fps
self.duration = video_info.duration
self.P = 3
self.image = np.zeros((self.H, self.W, self.P), dtype='uint8')
self.t = threading.Thread(target=self.pipe_thread)
Expand All @@ -33,6 +39,8 @@ def __init__(self, video_path):
self.W = 240
self.H = 180
self.P = 3
self.fps = 1.0
self.duration = 0.0
self.image = np.zeros((self.H, self.W, self.P), dtype='uint8')
self.t = None

Expand Down
12 changes: 9 additions & 3 deletions src/picframe/viewer_display.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ def __init__(self, config):
self.__sbg = None # slide for foreground
self.__next_tm = 0.0
self.__name_tm = 0.0
self.__start_tm = 0.0
self.__in_transition = False
self.__matter = None
self.__prev_clock_time = None
Expand Down Expand Up @@ -481,10 +482,12 @@ def slideshow_is_running(self, pics=None, time_delay=200.0, fade_time=10.0, paus
self.__draw_clock()

loop_running = self.__display.loop_running()
skip_image = False
tm = time.time()
if pics is not None:
new_sfg = self.__tex_load(pics, (self.__display.width, self.__display.height))
tm = time.time()
self.__start_tm = tm
self.__next_tm = tm + time_delay
self.__name_tm = tm + fade_time + self.__show_text_tm # text starts after slide transition
if new_sfg is not None: # this is a possible return value which needs to be caught
Expand Down Expand Up @@ -543,8 +546,11 @@ def slideshow_is_running(self, pics=None, time_delay=200.0, fade_time=10.0, paus
self.__in_transition = False

if self.__video_streamer is not None and self.__video_streamer.flag is True:
self.__sfg.update_ndarray(self.__video_streamer.image, 0)
self.__video_streamer.flag = False
if (tm - self.__start_tm) > self.__video_streamer.duration: # move on to next image at end of video TODO alow repeat behaviour?
skip_image = True
else:
self.__sfg.update_ndarray(self.__video_streamer.image, 0)
self.__video_streamer.flag = False

self.__slide.draw()

Expand Down Expand Up @@ -572,7 +578,7 @@ def slideshow_is_running(self, pics=None, time_delay=200.0, fade_time=10.0, paus
if block is not None:
block.sprite.draw()

return (loop_running, False) # now returns tuple with skip image flag added
return (loop_running, skip_image) # now returns tuple with skip image flag added

def slideshow_stop(self):
if self.__video_streamer is not None:
Expand Down

0 comments on commit 902fcf5

Please sign in to comment.