因为家里老人不会用智能设备,所以做了一个超级简易的播放器。
要实现的功能有
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.切换电视剧的时候不重新开始而是播放记录的部分