{"id":300,"date":"2017-04-03T04:05:43","date_gmt":"2017-04-03T04:05:43","guid":{"rendered":"http:\/\/www.piboxproject.com\/?p=300"},"modified":"2017-04-03T04:05:43","modified_gmt":"2017-04-03T04:05:43","slug":"kiosk-mode-for-videofe","status":"publish","type":"post","link":"https:\/\/www.piboxproject.com\/index.php\/2017\/04\/03\/kiosk-mode-for-videofe\/","title":{"rendered":"Kiosk mode for videofe"},"content":{"rendered":"<div id=\"dslc-theme-content\"><div id=\"dslc-theme-content-inner\"><p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" data-attachment-id=\"222\" data-permalink=\"https:\/\/www.piboxproject.com\/index.php\/gallery-view\/pibox-media-center\/videofe\/\" data-orig-file=\"https:\/\/i0.wp.com\/www.piboxproject.com\/wp-content\/uploads\/2016\/10\/videofe.png?fit=1264%2C704&amp;ssl=1\" data-orig-size=\"1264,704\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"videofe\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/www.piboxproject.com\/wp-content\/uploads\/2016\/10\/videofe.png?fit=300%2C167&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/www.piboxproject.com\/wp-content\/uploads\/2016\/10\/videofe.png?fit=1024%2C570&amp;ssl=1\" class=\"size-medium wp-image-222 alignleft\" src=\"https:\/\/i0.wp.com\/www.piboxproject.com\/wp-content\/uploads\/2016\/10\/videofe.png?resize=300%2C167&#038;ssl=1\" alt=\"\" width=\"300\" height=\"167\" srcset=\"https:\/\/i0.wp.com\/www.piboxproject.com\/wp-content\/uploads\/2016\/10\/videofe.png?resize=300%2C167&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.piboxproject.com\/wp-content\/uploads\/2016\/10\/videofe.png?resize=768%2C428&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.piboxproject.com\/wp-content\/uploads\/2016\/10\/videofe.png?resize=1024%2C570&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.piboxproject.com\/wp-content\/uploads\/2016\/10\/videofe.png?resize=660%2C368&amp;ssl=1 660w, https:\/\/i0.wp.com\/www.piboxproject.com\/wp-content\/uploads\/2016\/10\/videofe.png?resize=450%2C251&amp;ssl=1 450w, https:\/\/i0.wp.com\/www.piboxproject.com\/wp-content\/uploads\/2016\/10\/videofe.png?w=1264&amp;ssl=1 1264w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/>One of the first apps to be developed for the PiBox Media Center was <a href=\"https:\/\/gitlab.com\/pibox\/videofe\">VideoFE<\/a>.\u00a0 This app provides an interface for users to select a video to play from a list of videos read from a database and also wraps the hardware accelerated <a href=\"https:\/\/github.com\/popcornmix\/omxplayer\">omxplayer<\/a>.\u00a0 The UI is klunky in the current version.\u00a0 It&#8217;s just a simple GTK+ list.\u00a0 But moving up and down the list will display a poster for videos (or a poster for a TV series and a screen shot from the specific episode) along with a description.\u00a0 Posters and video metadata are read from a JSON database collected from <a href=\"https:\/\/www.themoviedb.org\/?language=en\">TheMovieDB.org<\/a> and <a href=\"http:\/\/thetvdb.com\/\">TheTVDB.com<\/a> using the <a href=\"https:\/\/gitlab.com\/pibox\/videolib\">VideoLib<\/a> Java desktop application.<\/p>\n<p>VidoeFE was the main reason for the media center implementation.\u00a0 My wife and I wanted to have some night time entertainment while <a href=\"http:\/\/www.rpawd.com\">camping in our small trailer<\/a>.\u00a0 The side of the trailer was just the right size for projecting a video inside the <a href=\"https:\/\/www.rpawd.com\/wp-content\/gallery\/2014_west_coast\/img_20140717_192147.jpg\">attached enclosed tent\/awning<\/a>. So I wrote VideoFE as the app for selecting and playing videos.\u00a0 Hooking a handheld pico-projector to the Raspberry Pi handled the projection issue. We could then have <a href=\"https:\/\/www.rpawd.com\/wp-content\/gallery\/2014_west_coast\/img_20140716_215225.jpg\">drive-in movie night<\/a> while camping without seriously annoying the neighbors at the campsite.<\/p>\n<h3>Kiosk Mode Extension<\/h3>\n<p>VideoFE works fine for the use case for which it was designed.\u00a0 But the passing of my oldest dog in February gave me a reason to extend it&#8217;s use cases by one: a <a href=\"http:\/\/www.piboxproject.com\/index.php\/2017\/03\/29\/pipics-slideshow-app-with-touchscreen-support\/\">digital photo frame<\/a>.\u00a0 One feature of the photo frame is playing videos.\u00a0 I needed an app that would play any and all videos found and continue to play them in a loop until stopped by the user.\u00a0 I also needed to integrate touchscreen support to allow skipping videos or navigating back and forth in the playing video.\u00a0 Stepping back from this use case it seems the general purpose here is a kiosk mode:\u00a0 play videos (or images) until interrupted.<\/p>\n<p>Since the photo frame use case needs to play videos it seemed like a variation of VideoFE, but with no user interaction for choosing which video to play.\u00a0 VideoFE works by reading all VideoLib generated databases from a directory tree, normally found on USB mounted media sticks.\u00a0 The databases are found under a <em>dbtop<\/em> directory, which is configurable, that specifies where the USB stick mount points reside.\u00a0 Searching for database files is by filename and extension.\u00a0 The JSON data is parsed and kept in memory since there isn&#8217;t that much of it per video and there aren&#8217;t likely to be 10&#8217;s-of-thousands of videos on a couple of USB sticks.\u00a0 Even if there are it still won&#8217;t take up that much memory.<\/p>\n<p>In kiosk mode there would be no databases.\u00a0 Videos are simply dropped on a USB stick in one of a number of formats (omxplayer supports a variety of file formats via <a href=\"https:\/\/ffmpeg.org\/\">ffmpeg<\/a>).\u00a0 So the search just needs to change to look for specific file types.\u00a0 For simplicity, the types are specified by filename extension.\u00a0 Omxplayer will simply not play any files with proper extensions that aren&#8217;t really video files.\u00a0 VideoFE would simply reap the omxplayer child and then start it again on the next file in its list of filenames.<\/p>\n<p>Setting the file types is already supported by VideoFE.\u00a0 A config file can be made that specifies which file types are supported by a given player.\u00a0 VideoFE is designed to work with players other than omxplayer so it could, for example, be used on the desktop.\u00a0 However, for kiosk mode on the Raspberry Pi the default configuration used by VideoFE is sufficient.<\/p>\n<p>In the end kiosk mode just does two things.\u00a0 The first is to remove the video selection UI.\u00a0 The first video is started as soon as the list of videos is generated.\u00a0 The second change is a tie in to the new touchscreen support in libpibox.\u00a0 The latter is also peripheral to the use case.\u00a0 The FAVI keyboard is still supported and will work whether the touchscreen is in use or not.<\/p>\n<p>With these two features integrated kiosk mode can be enabled by simply using the <em>-k<\/em> option to the <strong>videofe<\/strong> command.<\/p>\n<h3>Controlling Video Playback<\/h3>\n<p>The digital photo frame use case has a requirement to allow users to jump forward and back in a video.\u00a0 Movement to the next or previous video is handled by VideoFE&#8217;s touchscreen support by simply killing the current child process of omxplayer and starting a new one.\u00a0 But moving back and forth in the current video stream requires sending navigation commands to omxplayer directly.<\/p>\n<p>Omxplayer provides support for external control through the use of a FIFO.\u00a0 If omxplayer is started with standard input directed from a file then omxplayer uses that as the FIFO. The program will then accept any commands sent through that FIFO.\u00a0 VideoFE starts omxplayer with standard input redirection.\u00a0 When a touchscreen event is caught for navigating forward or backward in the video, VideoFE opens the FIFO and submits the command.\u00a0 Generally there is a short delay before the command is processed by omxplayer but this delay is outside the scope of VideoFE.<\/p>\n<pre>\u00a0\u00a0\u00a0 char\u00a0\u00a0\u00a0 right_arrow[3] = {0x1b, 0x5b, 0x44};\r\n\r\n\u00a0\u00a0\u00a0 write(fifo_fd, right_arrow, 3);\r\n\u00a0\u00a0\u00a0 usleep(250000);\r\n\u00a0\u00a0\u00a0 sprintf(buf, \"p\");\r\n\u00a0\u00a0\u00a0 write(fifo_fd, buf, 1);\r\n\u00a0\u00a0\u00a0 usleep(250000);\r\n\u00a0\u00a0\u00a0 write(fifo_fd, buf, 1);<\/pre>\n<p>In this case a three byte sequence is sent to the FIFO followed by the character <em>p<\/em> twice.\u00a0 The latter seemed to be required to force omxplayer to actually change file position.\u00a0 It&#8217;s unclear at this point if that is the correct solution, but it works.\u00a0 The characters to send are based on the official <a href=\"https:\/\/github.com\/popcornmix\/omxplayer\">key bindings<\/a> and a discussion on <a href=\"http:\/\/apsvr.com\/blog\/?p=122\">how to use the FIFO in a shell script<\/a>.\u00a0 A similar sequence is used for fast forward<\/p>\n<pre>\u00a0\u00a0\u00a0 char\u00a0\u00a0\u00a0 left_arrow[3] = {0x1b, 0x5b, 0x43};\r\n\r\n\u00a0\u00a0\u00a0 write(fifo_fd, left_arrow, 3);\r\n\u00a0\u00a0\u00a0 usleep(250000);\r\n\u00a0\u00a0\u00a0 sprintf(buf, \"p\");\r\n\u00a0\u00a0\u00a0 write(fifo_fd, buf, 1);\r\n\u00a0\u00a0\u00a0 usleep(250000);\r\n\u00a0\u00a0\u00a0 write(fifo_fd, buf, 1);<\/pre>\n<h3>Still a Problem<\/h3>\n<p>The original VideoFE playback via omxplayer requires launching an xterm that then runs omxplayer.\u00a0 This is done so that the xterm will send the proper X.org notification when omxplayer exits that causes the X display to get redrawn.\u00a0 Since omxplayer and X.org both write to the framebuffer (and in this case the same framebuffer) the latter must be told to do a screen refresh after omxplayer is done munging the buffer.\u00a0 The xterm is also used to clear the buffer to black before omxplayer starts to render what might be only a partial framebuffer update.<\/p>\n<p>But even using xterm as a handler for omxplayer isn&#8217;t enough as X.org doesn&#8217;t actually do the screen refresh xterm tells it to do.\u00a0 In order to get X.org to really do the update VideoFE has to switch virtual terminals (aka VTs) once to an empty VT and then back to where X.org is being displayed.\u00a0 Then an X refresh has to be issued manually.\u00a0 Only then do we get back to a visible X.org managed display.<\/p>\n<p>All of this finagling to get the framebuffer updated causes noticeable blinking of the display.\u00a0 It&#8217;s not clean by any means.\u00a0 But I&#8217;ve not found any other way to make it all work.\u00a0 So for now, the technique stays.\u00a0 This includes under the new kiosk mode because even though VideoFE has no X.org components (there is no UI to select videos in kiosk mode) we still need it to do all this so X.org will show the launcher properly once VideoFe exits.<\/p>\n<h3>Future Work<\/h3>\n<p>I have plans to give VideoFE a much nicer UI for selecting videos in non-kiosk mode.\u00a0 Now that I have a much better grasp of using gdk_pixbuf and Cairo it shouldn&#8217;t be difficult to implement a carousal of posters and descriptions.\u00a0 But kiosk mode has no need for this.\u00a0 The only possible updates may be to order videos using a prescribed naming scheme or to allow blending from one video into the next.\u00a0 But the latter will only happen after fixing the vt-switching problem.<\/p>\n<\/div><\/div>","protected":false},"excerpt":{"rendered":"<p>One of the first apps to be developed for the PiBox Media Center was VideoFE.\u00a0 This app provides an interface for users to select a video to play from a list of videos read from a database and also wraps the hardware accelerated omxplayer.\u00a0 The UI is klunky in the current version.\u00a0 It&#8217;s just a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":344,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"footnotes":"","jetpack_publicize_message":"Kiosk mode for videofe","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[1],"tags":[],"class_list":{"0":"post-300","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-uncategorized","8":"czr-hentry"},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/www.piboxproject.com\/wp-content\/uploads\/2017\/03\/film-roll.png?fit=1322%2C713&ssl=1","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p8du2Y-4Q","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/www.piboxproject.com\/index.php\/wp-json\/wp\/v2\/posts\/300","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.piboxproject.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.piboxproject.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.piboxproject.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.piboxproject.com\/index.php\/wp-json\/wp\/v2\/comments?post=300"}],"version-history":[{"count":8,"href":"https:\/\/www.piboxproject.com\/index.php\/wp-json\/wp\/v2\/posts\/300\/revisions"}],"predecessor-version":[{"id":346,"href":"https:\/\/www.piboxproject.com\/index.php\/wp-json\/wp\/v2\/posts\/300\/revisions\/346"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.piboxproject.com\/index.php\/wp-json\/wp\/v2\/media\/344"}],"wp:attachment":[{"href":"https:\/\/www.piboxproject.com\/index.php\/wp-json\/wp\/v2\/media?parent=300"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.piboxproject.com\/index.php\/wp-json\/wp\/v2\/categories?post=300"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.piboxproject.com\/index.php\/wp-json\/wp\/v2\/tags?post=300"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}