Digicam-Card-Player

This script has a modified routine for loading files from the directory structure usually found on a digital camera’s memory card. It will sort the files by date, instead of filename. Find the Code on GitHub/juliusCode/mp4museum

Overview

This code is designed to run on a Raspberry Pi and utilizes the VLC media player to play media files (like videos and audio) from a USB drive or specific directories. It also listens for button presses on GPIO pins to control playback (pause and next).

Imports

import time, vlc, os, glob
import RPi.GPIO as GPIO
import subprocess
from datetime import datetime
  • time: Used for sleep functions and timing.
  • vlc: The VLC Python bindings to control media playback.
  • os: Provides functions to interact with the operating system (like file paths).
  • glob: Used for file pattern matching.
  • RPi.GPIO: A library to control GPIO pins on the Raspberry Pi.
  • subprocess: Allows running shell commands from Python.
  • datetime: Not used in the provided code but typically used for date and time manipulation.

Audio Device Configuration

audiodevice = "0"

if os.path.isfile('/boot/alsa.txt'):
    f = open('/boot/alsa.txt', 'r')
    audiodevice = f.read(1)
  • This section checks for a configuration file (/boot/alsa.txt) to determine which audio device to use. If the file exists, it reads the first character to set the audiodevice.

GPIO Setup

GPIO.setmode(GPIO.BOARD)
GPIO.setup(11, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)
GPIO.setup(13, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)
  • Sets up the GPIO pins using the BOARD numbering scheme.
  • Pins 11 and 13 are configured as input pins with pull-down resistors, meaning they will read low (0) when not pressed.

Button Event Handlers

def buttonPause(channel):
    # Code to filter interference
    inputfilter = 0
    for x in range(0,200):
        if GPIO.input(11):
            inputfilter += 1
        time.sleep(.001)
    if (inputfilter > 50):
        player.pause()

def buttonNext(channel):
    # Code to filter interference
    inputfilter = 0
    for x in range(0,200):
        if GPIO.input(13):
            inputfilter += 1
        time.sleep(.001)
    if (inputfilter > 50):
        player.stop()
  • These functions are called when the respective GPIO pins detect a rising edge (button press).
  • They implement a simple debounce mechanism to filter out noise or static discharges by counting the number of times the button is pressed within a short time frame.

VLC Playback Function

def vlc_play(source):
    if("loop." in source):
        vlc_instance = vlc.Instance('--input-repeat=999999999 -q -A alsa --alsa-audio-device hw:' + audiodevice)
    else:
        vlc_instance = vlc.Instance('-q -A alsa --alsa-audio-device hw:'+ audiodevice)

    global player
    player = vlc_instance.media_player_new()
    media = vlc_instance.media_new(source)
    player.set_media(media)
    player.play()
    time.sleep(1)
    current_state = player.get_state()
    while current_state == 3 or current_state == 4:
        time.sleep(.01)
        current_state = player.get_state()
    media.release()
    player.release()
  • This function initializes a VLC media player instance and plays the specified media file.
  • If the media file name contains “loop.”, it sets the player to repeat the media indefinitely.
  • It waits for the media to start playing and releases resources afterward.

File Search Function

def search_file(file_name):
    file_path_media = f'/media/*/{file_name}'
    file_path_boot = f'/boot/{file_name}'
    matching_files = glob.glob(file_path_media) + glob.glob(file_path_boot)

    if matching_files:
        return matching_files[0]

    return False
  • Searches for a file in specified directories (/media/*/ and /boot/) and returns the first match found.

Creation Date Function

def get_creation_date(file_path):
    return os.path.getctime(file_path)
  • Returns the creation date of a specified file.

Player Initialization

vlc_play("/home/pi/mp4museum-boot.mp4")
vlc_play("/home/pi/mp4museum-boot.mp4")
vlc_play("/home/pi/mp4museum.mp4")
  • Plays a boot video twice to ensure the player is working, followed by a logo screen.

GPIO Event Detection

GPIO.add_event_detect(11, GPIO.RISING, callback=buttonPause, bouncetime=234)
GPIO.add_event_detect(13, GPIO.RISING, callback=buttonNext, bouncetime=1234)
  • This code sets up event detection on the GPIO pins 11 and 13.
  • When a rising edge (button press) is detected on pin 11, the buttonPause function is called, and for pin 13, the buttonNext function is called.
  • The bouncetime parameter is used to prevent multiple detections from a single button press due to mechanical bouncing.

Sync Mode Check

enableSync = search_file("sync-leader.txt")
syncFile = search_file("sync.mp4")
if syncFile and enableSync:
    print("Sync Mode LEADER:" + syncFile)
    subprocess.run(["omxplayer-sync", "-u", "-m", syncFile]) 

enableSync = search_file("sync-player.txt")
syncFile = search_file("sync.mp4")
if syncFile and enableSync:
    print("Sync Mode PLAYER:" + syncFile)
    subprocess.run(["omxplayer-sync", "-u", "-l", syncFile]) 
  • This section checks for the presence of specific files (sync-leader.txt and sync-player.txt) to determine if the player should enter sync mode.
  • If the sync-leader.txt file is found, it runs the omxplayer-sync command with the -m option, indicating it is the leader in a synchronized playback setup.
  • If sync-player.txt is found, it runs omxplayer-sync with the -l option, indicating it is a player in sync mode.
  • The subprocess.run function is used to execute these commands in the shell.

Main Loop

while(1):
    usb_drive = '/media/usb/DCIM/'

    media_files = []
    for root, dirs, files in os.walk(os.path.join(usb_drive)):
        for file in files:
            if file.lower().endswith(('.jpg', '.jpeg', '.mp4', '.avi', '.mov')):
                file_path = os.path.join(root, file)
                media_files.append(file_path)

    for media_file in media_files:
        vlc_play(media_file)
  • This is the main loop of the program, which runs indefinitely (while(1)).
  • It sets the path to the USB drive where media files are expected to be found.
  • It uses os.walk to traverse the directory structure of the specified USB drive, looking for files with specific extensions (image and video formats).
  • Each matching file is added to the media_files list.
  • After collecting all media files, it iterates through the list and plays each file using the vlc_play function.

Summary

  • The code is designed to create a media player that can play video and audio files from a USB drive on a Raspberry Pi.
  • It uses GPIO buttons to control playback (pause and next).
  • It supports synchronization with other players if specific files are present.
  • The main loop continuously checks for media files on the USB drive and plays them in sequence.