树莓派实现只有一个按键的播放器


因为家里老人不会用智能设备,所以做了一个超级简易的播放器。


要实现的功能有

1.拔电恢复

2.视频列表切换恢复

3.一键切换

4.自动切换电视剧

5.开机启动自动登录播放



先来看看开机自动登录吧:



实现自动登录:修改/etc/inittab文件
sudo nano /etc/inittab
向下滚动,找到行               1:2345:respawn:/sbin/getty 115200 tty1
注释掉这一行,修改为       #1:2345:respawn:/sbin/getty 115200 tty1
在该行下增加一行内容       1:2345:respawn:/bin/login -f pi tty1 </dev/tty1 >/dev/tty1 2>&1
按Ctrl+X退出,记得按Y键保存
原理:linux启动时,会读取inittab文件,执行其中的登录命令,以pi用户名自动登录



开机启动:


首先要开机挂载硬盘,不然无法播放视频:

开机挂载

/home/pi/start.sh 中写入下面的语句:
sudo -i
fdisk -l
mount /dev/sda1 /media/mymovie

其实用其他方式也可以的,后来也懒得去修改了。


开机启动

在/etc/rc.local 里面添加 ./home/pi/start.sh

然后start.sh里面添加播放脚本的运行



硬件连接


硬件连接必须先来,不然都没法调试了。

按键连接


这里是参考了帖子:http://hugozhu.myalert.info/2013/04/08/27-interrupts-with-gpio-pins.html


整体视图



程序代码


对于这整个系统,代码显得尤其重要。下面先贴上代码:

#!/usr/bin/env python2.7
#coding=utf-8
import os
import subprocess,time
import shutil
import thread
import string
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)

GPIO.setup(25,GPIO.IN,pull_up_down=GPIO.PUD_UP)

global playProcess

single_movie_arr=[]
global single_movie_index

folder_arr=[]
global folder_index
global movies_in_folder_index
movies_in_folder_arr = []
global setting_in_progress

#1:folder 0:single
global single_or_folder
#1:manual 0:auto die
global dead_reason

root_dir = '/media/mymovie/movie'



class record_last:
	def __init__(self):
		self.hour=0
		self.minute=0
		self.second=0
		self.is_folder=1
		self.index=0
		self.reseting=0
	
global my_record#history
global is_init


def write_history(name,current_index):
	f = file(os.path.join(name,'history.txt'),'w')
	f.write(str(current_index))
	f.close
	#must read after write or srt will be empyy
	f = file(os.path.join(name,'history.txt'),'r')
	f.close

def read_history(folder_name):
	dest_file = os.path.join(folder_name,'history.txt')
	if os.path.isfile(dest_file):
		f = file(dest_file,'r')
		line = f.readline()
		print 'restore status:'+line
		f.close
		if line == '':
			return 0
		try:
			return_val = int(line)
		except:
			return_val = 0
		return return_val
	else:
		print 'restore status,no status'
		return 0


def auto_switch():
	global playProcess,single_movie_arr,single_movie_index,folder_arr,folder_index,
		movies_in_folder_index,setting_in_progress,single_or_folder,dead_reason,
		root_dir,movies_in_folder_arr,is_init,my_record

	print 'auto switching...'
	if single_or_folder == 1:
		if movies_in_folder_index < len(movies_in_folder_arr) - 1:
			movies_in_folder_index = movies_in_folder_index + 1
			play_movie(folder_arr[folder_index],movies_in_folder_index,1)
		else:
			#special case:last movie in folder,we need to delete status
			write_history(folder_arr[folder_index],0);

			if folder_index < len(folder_arr) - 1:

				folder_index = folder_index + 1
				movies_in_folder_index = read_history(folder_arr[folder_index])#need change
				play_movie(folder_arr[folder_index],movies_in_folder_index,1)
			elif len(single_movie_arr) > 0:
				single_movie_index = 0
				single_or_folder = 0
				play_movie(single_movie_arr[single_movie_index],0,0)
			else:
				folder_index = 0
				movies_in_folder_index = read_history(folder_arr[folder_index])#need change
				play_movie(folder_arr[folder_index],movies_in_folder_index,1)		
	else:
		if single_movie_index < len(single_movie_arr) - 1:
			single_movie_index = single_movie_index + 1
			play_movie(single_movie_arr[single_movie_index],0,0)
		elif len(folder_arr) > 0:
			folder_index = 0
			movies_in_folder_index = read_history(folder_arr[folder_index])#need change
			single_or_folder = 1
			play_movie(folder_arr[folder_index],movies_in_folder_index,1)
		else:
			single_movie_index = 0	
			play_movie(single_movie_arr[single_movie_index],0,0)




	



def keyboard_event(thread_name):
	global playProcess,single_movie_arr,single_movie_index,folder_arr,folder_index,
		movies_in_folder_index,setting_in_progress,single_or_folder,dead_reason,
		root_dir,movies_in_folder_arr,is_init,my_record
	while 1:
		#raw_input('')
		try:
			GPIO.wait_for_edge(25,GPIO.FALLING)
			time.sleep(1)#in case on press causes multiple interrupts
			setting_in_progress = 1
			dead_reason = 1
	
			print 'switching...'
			global playProcess
			playProcess.stdin.write('q')
			playProcess.stdin.flush()
	
			if single_or_folder == 1:
				if folder_index < len(folder_arr) - 1:
					folder_index = folder_index + 1
					movies_in_folder_index = read_history(folder_arr[folder_index])#need change
				elif len(single_movie_arr) > 0:
					single_movie_index = 0
					single_or_folder = 0
				else:
					folder_index = 0
					movies_in_folder_index = read_history(folder_arr[folder_index])#need change
			else:
				if single_movie_index < len(single_movie_arr) - 1:
					single_movie_index = single_movie_index + 1
				elif len(folder_arr) > 0:
					folder_index = 0
					single_or_folder = 1
					movies_in_folder_index = read_history(folder_arr[folder_index])#need change
				else:
					single_movie_index = 0
	
			setting_in_progress = 0
		except KeyboardInterrupt:
			time.sleep(1)
			print 'GPIO fail!'
			GPIO.cleanup()
				



def init_list():
	global playProcess,single_movie_arr,single_movie_index,folder_arr,folder_index,
		movies_in_folder_index,setting_in_progress,single_or_folder,dead_reason,
		root_dir,movies_in_folder_arr,is_init,my_record

	#add files in root dir to the list
	nlist = os.listdir(root_dir)
	for name in nlist:
	    cur_name = os.path.join(root_dir, name)
	    isfile = os.path.isfile(cur_name)
	    if isfile:
		if name.endswith('.mp4') or name.endswith('.MP4'):
			single_movie_arr.append(cur_name)
	    else:
		folder_arr.append(cur_name)
	single_movie_arr.sort()

	print 'singles :'
	for i in range(0,len(single_movie_arr)):
		print single_movie_arr[i]
	print 'folders :'
	for i in range(0,len(folder_arr)):
		print folder_arr[i]



	


def player_folder(name,current_index):
	global playProcess,single_movie_arr,single_movie_index,folder_arr,folder_index,
		movies_in_folder_index,setting_in_progress,single_or_folder,dead_reason,
		root_dir,movies_in_folder_arr,is_init,my_record

	print 'playing folder:'+name
	movies_in_folder_arr=[]
	nlist = os.listdir(name)
	for single_name in nlist:
		cur_name = os.path.join(name, single_name)
		if single_name.endswith('.mp4') or single_name.endswith('.MP4'):
			movies_in_folder_arr.append(cur_name)
	movies_in_folder_arr.sort()

	#for i in range(0,len(movies_in_folder_arr)):
	#	print movies_in_folder_arr[i]


	write_history(name,current_index)

	player_single(movies_in_folder_arr[current_index],current_index,len(movies_in_folder_arr))
	


def write_srt(name,current_index,total_num):
	f = file('/media/mymovie/title/1.srt','w')
	f.write('0
')
	f.write('00:00:00,000 --> 00:00:10,000
')
	if total_num == 1:
		name = string.replace(name,'.mp4','',1)
		name = string.replace(name,'.MP4','',1)
		f.write('<b>正在播放 电影 '+name.split('/')[-1]+'<b>
')
	else:
		f.write('<b>正在播放 电视剧 '+name.split('/')[-2]+'<b>
')
		f.write('<b>第'+str(current_index+1)+'集,共'+str(total_num)+'集<b>
')
	f.close
	#must read after write or srt will be empyy
	f = file('/media/mymovie/title/1.srt','r')
	f.close


def player_single(name,current_index,total_num):
	global playProcess,single_movie_arr,single_movie_index,folder_arr,folder_index,
		movies_in_folder_index,setting_in_progress,single_or_folder,dead_reason,
		root_dir,movies_in_folder_arr,is_init,my_record

	print 'playing:'+name
	write_srt(name,current_index,total_num)
	

	if(is_init):
		is_init = 0
		pos_hour = str(my_record.hour)
		pos_minute = str(my_record.minute)
		pos_second = str(my_record.second)
		if len(pos_hour) == 1:
			pos_hour = '0'+pos_hour
		if len(pos_minute) == 1:
			pos_minute = '0'+pos_minute
		if len(pos_second) == 1:
			pos_second = '0'+pos_second
		playProcess=subprocess.Popen(['omxplayer','--pos',pos_hour+':'+pos_minute+':'+pos_second,'--subtitles',
			'/media/mymovie/title/1.srt','--font',
			'/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc','--blank',name],
			stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE, close_fds=True)
	else:
		my_record.reseting = 1
		playProcess=subprocess.Popen(['omxplayer','--subtitles','/media/mymovie/title/1.srt','--font',
			'/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc','--blank',name],
			stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE, close_fds=True)
	playProcess.wait()
	


def play_movie(name,current_index,is_folder):
	if is_folder == 1:
		player_folder(name,current_index)
	else:
		player_single(name,current_index,1)


def record_thread(thread_name):
	global playProcess,single_movie_arr,single_movie_index,folder_arr,folder_index,
		movies_in_folder_index,setting_in_progress,single_or_folder,dead_reason,
		root_dir,movies_in_folder_arr,is_init,my_record

	while 1:
		time.sleep(1)

		if my_record.reseting == 1:
			my_record.reseting = 0
			my_record.hour = 0
			my_record.minute = 0
			my_record.second = 0


		my_record.second = my_record.second + 1
		if(my_record.second == 60):
			my_record.minute = my_record.minute + 1
			my_record.second = 0
		if(my_record.minute == 60):
			my_record.hour = my_record.hour + 1
			my_record.minute = 0


		dest_file = os.path.join(root_dir,'record.txt')
		f = file(dest_file,'w')
		f.write(str(single_or_folder)+'
')
		if single_or_folder == 1:
			f.write(str(folder_index)+'
')
		else:
			f.write(str(single_movie_index)+'
')
		f.write(str(my_record.hour)+'
')
		f.write(str(my_record.minute)+'
')
		f.write(str(my_record.second)+'
')
		f.close

		#must read after write or srt will be empyy
		f = file(dest_file,'r')
		f.close

def read_from_record_file():
	dest_file = os.path.join(root_dir,'record.txt')
	record = record_last() #new structure
	if os.path.isfile(dest_file):
		#read
		f = file(dest_file,'r')
		line = f.readline()#single_or_folder
		if line != '':
			try:
				record.is_folder = int(line)
				line = f.readline()#index
				record.index = int(line)
				line = f.readline()#hour
				record.hour = int(line)
				line = f.readline()#minute
				record.minute = int(line)
				line = f.readline()#second
				record.second = int(line)
			except:
				record.hour=0
				record.minute=0
				record.second=0
				record.is_folder=1
				record.index=0	
		else:
			record.hour=0
			record.minute=0
			record.second=0
			record.is_folder=1
			record.index=0	

		f.close
	else:	
		record.hour=0
		record.minute=0
		record.second=0
		record.is_folder=1
		record.index=0

	record.reseting = 0
	return record



is_init = 1
init_list()
my_record = read_from_record_file()




if my_record.is_folder == 1:
	folder_index = my_record.index
	movies_in_folder_index = read_history(folder_arr[folder_index])

	single_or_folder = 1

	single_movie_index = 0
else:
	folder_index = 0
	movies_in_folder_index = 0

	single_or_folder = 0

	single_movie_index = my_record.index




setting_in_progress = 0
dead_reason = 1





try:
	thread.start_new_thread(keyboard_event,("Keyboard",))
except:
	print 'start thread error!'

try:
	thread.start_new_thread(record_thread,("Record Thread",))
except:
	print 'start thread error!'




while 1:
	while setting_in_progress == 1:
		time.sleep(1)


	if dead_reason == 1:
		dead_reason = 0

		if len(folder_arr) > 0 and single_or_folder == 1:
			play_movie(folder_arr[folder_index],movies_in_folder_index,1)
		elif len(single_movie_arr) > 0 and single_or_folder == 0:
			play_movie(single_movie_arr[single_movie_index],0,0)
		else:
			print 'No any movie here!'
			time.sleep(1000)
	else:
		auto_switch()	


GPIO.cleanup()





整个代码已经是比较短的了,下面一个个函数来分析吧:


程序一开始执行read_from_record_file,这个函数的功能是读取上次记忆的功能,记忆的应该是文件的位置和电影的时间。

由于时间久远已经不太记得它的格式了。



if my_record.is_folder == 1:
这个判断是判断是否记忆的是文件夹。这个程序支持在根目录放置文件和文件夹。若放置文件,则直接跳到那个文件播放,若放置文件夹,直接跳到文件夹对应的文件播放。

它的目的是区分电影和电视剧。


这一段的功能是开了两个线程,一个是记录按钮事件的,另一个是不断记录目前的进度,防止断电。

try:
	thread.start_new_thread(keyboard_event,("Keyboard",))
except:
	print 'start thread error!'

try:
	thread.start_new_thread(record_thread,("Record Thread",))
except:
	print 'start thread error!'




这一片代码是判断是否dead。这里的dead的意思是是否按键切换。如果是按键切换则执行手动切换代码,否则的话执行auto_switch

while 1:
	while setting_in_progress == 1:
		time.sleep(1)


	if dead_reason == 1:
		dead_reason = 0

		if len(folder_arr) > 0 and single_or_folder == 1:
			play_movie(folder_arr[folder_index],movies_in_folder_index,1)
		elif len(single_movie_arr) > 0 and single_or_folder == 0:
			play_movie(single_movie_arr[single_movie_index],0,0)
		else:
			print 'No any movie here!'
			time.sleep(1000)
	else:
		auto_switch()	




接下来看看上面的一些函数:


record_thread

这个是将当前进度写入到文件

player_single

是播放一个文件

write_srt

是一开始播放的时候注明这是第几集




因为需要考虑到电影和电视剧,还有自动切换和手动切换。所以代码显得比较复杂。

电影是放在根目录的,电视剧放在每个文件夹里面

自动切换分为两种,第一种是电视剧间切换,另一种是电影间切换

还要考虑到最后一个电视剧或者电影循环切回第一个。

若不用python的话相信会用掉更多的代码。



这个程序其实还可以改进,

1.再加一个按钮,方便后退

2.使用数据库记录历史数据

3.自动调整电视剧在屏幕上的缩放比例

4.断电恢复时也显示当前集数的字幕,而不是显示恢复播放

5.切换电视剧的时候不重新开始而是播放记录的部分



原文地址:https://www.cnblogs.com/tanhangbo/p/4282604.html