Now can launch one process per core, and launch new ones when the old ones end

This commit is contained in:
Sergio Costas 2014-07-23 23:53:11 +02:00
parent 13f9e67eb1
commit 86f77faa3f
13 changed files with 761 additions and 77 deletions

129
data/interface/wcreate.ui Normal file
View file

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.1 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkDialog" id="dialog_create">
<property name="width_request">380</property>
<property name="height_request">270</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">devede</property>
<property name="icon_name">devede.svg</property>
<property name="type_hint">dialog</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox1">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog-action_area1">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button1">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="accept">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Choose the folder where Devede will create the files and a name for it. Do not use a folder in a VFAT/FAT32 drive. Characters /, | and \ are not accepted and will be replaced by underscores.</property>
<property name="wrap">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFileChooserButton" id="path">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="action">select-folder</property>
<signal name="file-set" handler="on_iface_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="name">
<property name="visible">True</property>
<property name="can_focus">True</property>
<signal name="changed" handler="on_iface_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="shutdown">
<property name="label" translatable="yes">Shutdown computer when disc is done</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="0">button1</action-widget>
<action-widget response="1">accept</action-widget>
</action-widgets>
</object>
</interface>

View file

@ -728,6 +728,7 @@
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="clicked" handler="on_create_disc_clicked" swapped="no"/>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>

View file

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.1 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkWindow" id="progress">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Creating...</property>
<property name="resizable">False</property>
<property name="window_position">center</property>
<property name="icon_name">devede.svg</property>
<property name="deletable">False</property>
<property name="has_resize_grip">False</property>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkFrame" id="progress_frame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<placeholder/>
</child>
<child type="label_item">
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkProgressBar" id="progress_total">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="show_text">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="cancel">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_cancel_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">8</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View file

@ -17,14 +17,90 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/> # along with this program. If not, see <http://www.gnu.org/licenses/>
from gi.repository import GLib
import subprocess import subprocess
import os
import devede.configuration_data import devede.configuration_data
import devede.executor
class avconv_converter(devede.executor.executor):
supports_analize = False
supports_play = False
supports_convert = False
supports_menu = True
display_name = "AVCONV"
@staticmethod
def check_is_installed():
handle = subprocess.Popen(["avconv","-version"], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
(stdout, stderr) = handle.communicate()
if 0==handle.wait():
return True
else:
return False
class avconv_converter:
def __init__(self): def __init__(self):
devede.executor.executor.__init__(self)
self.config = devede.configuration_data.configuration.get_config() self.config = devede.configuration_data.configuration.get_config()
def create_mpg(self,n_page,background_music,sound_length,pal,output_path):
self.n_page = n_page
self.sound_length = float(sound_length)
self.text = _("Creating menu %(X)d") % {"X": self.n_page}
self.command_var=[]
self.command_var.append("avconv")
self.command_var.append("-loop")
self.command_var.append("1")
self.command_var.append("-f")
self.command_var.append("image2")
self.command_var.append("-i")
self.command_var.append(os.path.join(output_path,"menu_"+str(n_page)+"_bg.png"))
self.command_var.append("-i")
self.command_var.append(background_music)
self.command_var.append("-y")
self.command_var.append("-target")
if pal:
self.command_var.append("pal-dvd")
else:
self.command_var.append("ntsc-dvd")
self.command_var.append("-acodec")
self.command_var.append("mp2")
self.command_var.append("-s")
if pal:
self.command_var.append("720x576")
else:
self.command_var.append("720x480")
self.command_var.append("-g")
self.command_var.append("12")
self.command_var.append("-b:v")
self.command_var.append("2500k")
self.command_var.append("-b:a")
self.command_var.append("192k")
self.command_var.append("-aspect")
self.command_var.append("4:3")
self.command_var.append("-t")
self.command_var.append(str(1+sound_length))
self.command_var.append(os.path.join(output_path,"menu_"+str(n_page)+".mpg"))
def process_stdout(self,data):
pass
def process_stderr(self,data):
pos = data[0].find("time=")
if (pos != -1):
pos+=5
pos2 = data[0].find(" ",pos)
if (pos2 != -1):
t = float(data[0][pos:pos2])
self.progress_bar[1].set_fraction(t / self.sound_length)

View file

@ -33,6 +33,7 @@ class configuration(GObject.GObject):
configuration.current_configuration = None configuration.current_configuration = None
return configuration.current_configuration return configuration.current_configuration
def fill_config(self): def fill_config(self):
GObject.GObject.__init__(self) GObject.GObject.__init__(self)
@ -78,7 +79,7 @@ class configuration(GObject.GObject):
self.PAL = True self.PAL = True
self.tmp_folder = "/var/tmp" self.tmp_folder = "/var/tmp"
self.multicore = True self.multicore = True
self.final_folder = None self.final_folder = os.environ.get("HOME")
self.sub_language = None self.sub_language = None
self.sub_codepage = None self.sub_codepage = None
self.film_analizer = None self.film_analizer = None

View file

@ -17,6 +17,7 @@
import devede.configuration_data import devede.configuration_data
import devede.mplayer_detector import devede.mplayer_detector
import devede.avconv_converter
class converter: class converter:
@ -32,7 +33,8 @@ class converter:
def __init__(self): def __init__(self):
self.config = devede.configuration_data.configuration.get_config() self.config = devede.configuration_data.configuration.get_config()
self.c = [devede.mplayer_detector.mplayer_detector] # List of classes with conversion capabilities, in order of preference
self.c = [devede.mplayer_detector.mplayer_detector, devede.avconv_converter.avconv_converter]
self.analizers = {} self.analizers = {}
self.default_analizer = None self.default_analizer = None
@ -111,3 +113,11 @@ class converter:
return self.default_analizer return self.default_analizer
else: else:
return self.analizers[self.config.film_analizer] return self.analizers[self.config.film_analizer]
def get_menu_converter(self):
""" returns a class for the desired menu converter, or the most priviledged if the desired is not installed """
if (self.config.menu_converter == None) or (self.analizers.has_key(self.config.menu_converter) == False):
return self.default_menuer
else:
return self.menuers[self.config.menu_converter]

View file

@ -0,0 +1,64 @@
# Copyright 2014 (C) Raster Software Vigo (Sergio Costas)
#
# This file is part of DeVeDe-NG
#
# DeVeDe-NG is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# DeVeDe-NG is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
from gi.repository import Gtk
import os
import devede.configuration_data
class create_disk_window:
def __init__(self):
self.config = devede.configuration_data.configuration.get_config()
def run(self):
builder = Gtk.Builder()
builder.set_translation_domain(self.config.gettext_domain)
builder.add_from_file(os.path.join(self.config.glade,"wcreate.ui"))
builder.connect_signals(self)
wcreate_window = builder.get_object("dialog_create")
self.wpath = builder.get_object("path")
self.wname = builder.get_object("name")
wshutdown = builder.get_object("shutdown")
self.waccept = builder.get_object("accept")
self.wname.set_text("movie")
self.wpath.set_current_folder(self.config.final_folder)
wcreate_window.show_all()
self.on_iface_changed(None)
retval = wcreate_window.run()
self.path = self.wpath.get_current_folder()
self.name = self.wname.get_text()
self.shutdown = wshutdown.get_active()
wcreate_window.destroy()
if (retval == 1):
return True
else:
return False
def on_iface_changed(self,b):
path = self.wpath.get_current_folder()
name = self.wname.get_text()
if ((path == None) or (path == "") or (name == None) or (name == "")):
self.waccept.set_sensitive(False)
else:
self.waccept.set_sensitive(True)

View file

@ -20,6 +20,7 @@ from gi.repository import Gtk,Gdk,GdkPixbuf
import os import os
import devede.configuration_data import devede.configuration_data
import devede.interface_manager import devede.interface_manager
import devede.message
class dvd_menu(devede.interface_manager.interface_manager): class dvd_menu(devede.interface_manager.interface_manager):
@ -59,12 +60,28 @@ class dvd_menu(devede.interface_manager.interface_manager):
self.add_fontbutton("entry_font", "Sans 18", self.update_preview) self.add_fontbutton("entry_font", "Sans 18", self.update_preview)
self.add_filebutton("background_picture", self.default_background, self.update_preview) self.add_filebutton("background_picture", self.default_background, self.update_preview)
self.add_filebutton("background_music", self.default_sound, self.update_preview) self.add_filebutton("background_music", self.default_sound, self.update_music)
self.cached_menu_font = None self.cached_menu_font = None
self.cached_menu_size = 0 self.cached_menu_size = 0
self.sound_length = 30
def update_music(self,b=None):
self.store_ui(self.builder)
cv = devede.converter.converter()
film_analizer = (cv.get_film_analizer())()
(video, audio, length) = film_analizer.analize_film_data(self.background_music,True)
if (video != 0):
devede.message.message_window(_("The selected file is a video, not an audio file"),_("Error"))
self.on_no_sound_clicked(None)
elif (audio == 0):
devede.message.message_window(_("The selected file is not an audio file"),_("Error"))
self.on_no_sound_clicked(None)
else:
self.sound_length = length
def update_preview(self,b=None): def update_preview(self,b=None):
self.store_ui(self.builder) self.store_ui(self.builder)
@ -80,6 +97,7 @@ class dvd_menu(devede.interface_manager.interface_manager):
def on_no_sound_clicked(self,b): def on_no_sound_clicked(self,b):
self.background_music = self.default_sound self.background_music = self.default_sound
self.sound_length = 30
self.update_ui(self.builder) self.update_ui(self.builder)
@ -118,10 +136,6 @@ class dvd_menu(devede.interface_manager.interface_manager):
self.wmenu.destroy() self.wmenu.destroy()
def on_preview_menu_clicked(self,b):
pass
def get_font_params(self,font_name): def get_font_params(self,font_name):
font_elements=font_name.split(" ") font_elements=font_name.split(" ")
@ -161,7 +175,7 @@ class dvd_menu(devede.interface_manager.interface_manager):
elif arrow_type == "menu_entry_selected": elif arrow_type == "menu_entry_selected":
fgcolor = self.selected_color fgcolor = self.selected_color
elif arrow_type == "menu_entry_activated": elif arrow_type == "menu_entry_activated":
fgcolor = ( 1.0 - self.selected_color[0], 1.0 - self.selected_color[1], 1.0 - self.selected_color[2] ) fgcolor = ( 1.0 - self.selected_color[0], 1.0 - self.selected_color[1], 1.0 - self.selected_color[2], self.selected_color[3])
else: else:
return return
@ -210,7 +224,7 @@ class dvd_menu(devede.interface_manager.interface_manager):
hard_borders = True hard_borders = True
font = self.entry_font font = self.entry_font
elif text_type == "menu_entry_activated": elif text_type == "menu_entry_activated":
fgcolor = ( 1.0 - self.selected_color[0], 1.0 - self.selected_color[1], 1.0 - self.selected_color[2] ) fgcolor = ( 1.0 - self.selected_color[0], 1.0 - self.selected_color[1], 1.0 - self.selected_color[2], self.selected_color[3])
bgcolor = None bgcolor = None
hard_borders = True hard_borders = True
font = self.entry_font font = self.entry_font
@ -256,7 +270,7 @@ class dvd_menu(devede.interface_manager.interface_manager):
""" This method sets data that can't be changed from the dvd settings window. """ This method sets data that can't be changed from the dvd settings window.
It must be called before painting a menu """ It must be called before painting a menu """
if self.config.PAL: if self.project.pal:
self.y=576.0 self.y=576.0
else: else:
self.y=480.0 self.y=480.0
@ -270,6 +284,7 @@ class dvd_menu(devede.interface_manager.interface_manager):
self.sf = None self.sf = None
self.current_shown_page = 0 self.current_shown_page = 0
self.wcurrent_page = None
def paint_menu(self,paint_background, paint_selected, paint_activated, page_number): def paint_menu(self,paint_background, paint_selected, paint_activated, page_number):
@ -325,7 +340,8 @@ class dvd_menu(devede.interface_manager.interface_manager):
if (page_number >= self.pages) and (page_number > 0): if (page_number >= self.pages) and (page_number > 0):
page_number -= 1 page_number -= 1
self.wcurrent_page.set_text(_("Page %(X)d of %(Y)d") % {"X":page_number+1 , "Y":self.pages}) if self.wcurrent_page != None:
self.wcurrent_page.set_text(_("Page %(X)d of %(Y)d") % {"X":page_number+1 , "Y":self.pages})
xl = left_margin_p xl = left_margin_p
xr = 720.0 - right_margin_p xr = 720.0 - right_margin_p
y = top_margin_p + entry_height/2.0 y = top_margin_p + entry_height/2.0
@ -341,26 +357,26 @@ class dvd_menu(devede.interface_manager.interface_manager):
y += entry_height y += entry_height
if paint_arrows: if paint_arrows:
if page_number == 0: if page_number == 0:
self.paint_base(xl, xr, y, 0)
if paint_background: if paint_background:
self.paint_base(xl, xr, y, 0)
self.paint_arrow(xl, xr, y, "menu_entry", False) self.paint_arrow(xl, xr, y, "menu_entry", False)
if paint_selected: if paint_selected:
self.paint_arrow(xl, xr, y, "menu_entry_selected", False) self.paint_arrow(xl, xr, y, "menu_entry_selected", False)
if paint_activated: if paint_activated:
self.paint_arrow(xl, xr, y, "menu_entry_activated", False) self.paint_arrow(xl, xr, y, "menu_entry_activated", False)
elif page_number == (self.pages - 1): elif page_number == (self.pages - 1):
self.paint_base(xl, xr, y, 0)
if paint_background: if paint_background:
self.paint_base(xl, xr, y, 0)
self.paint_arrow(xl, xr, y, "menu_entry", True) self.paint_arrow(xl, xr, y, "menu_entry", True)
if paint_selected: if paint_selected:
self.paint_arrow(xl, xr, y, "menu_entry_selected", True) self.paint_arrow(xl, xr, y, "menu_entry_selected", True)
if paint_activated: if paint_activated:
self.paint_arrow(xl, xr, y, "menu_entry_activated", True) self.paint_arrow(xl, xr, y, "menu_entry_activated", True)
else: else:
self.paint_base(xl, xr, y, 1)
self.paint_base(xl, xr, y, 2)
med = (xl + xr) / 2.0 med = (xl + xr) / 2.0
if paint_background: if paint_background:
self.paint_base(xl, xr, y, 1)
self.paint_base(xl, xr, y, 2)
self.paint_arrow(med, xr, y, "menu_entry", False) self.paint_arrow(med, xr, y, "menu_entry", False)
self.paint_arrow(xl, med, y, "menu_entry", True) self.paint_arrow(xl, med, y, "menu_entry", True)
if paint_selected: if paint_selected:
@ -411,9 +427,6 @@ class dvd_menu(devede.interface_manager.interface_manager):
""" Callback to repaint the menu preview window when it """ Callback to repaint the menu preview window when it
sends the EXPOSE event """ sends the EXPOSE event """
if not self.config.menu_dynamic_preview:
return
if (self.sf == None): if (self.sf == None):
self.paint_menu(True, self.wshow_as_selected.get_active(), False, self.current_shown_page) self.paint_menu(True, self.wshow_as_selected.get_active(), False, self.current_shown_page)
if (self.current_shown_page >= self.pages): if (self.current_shown_page >= self.pages):
@ -421,3 +434,36 @@ class dvd_menu(devede.interface_manager.interface_manager):
cr.set_source_surface(self.sf) cr.set_source_surface(self.sf)
cr.paint() cr.paint()
def create_dvd_menus(self,base_path):
self.refresh_static_data()
cv = devede.converter.converter()
menu_folder = os.path.join(base_path,"menu")
try:
os.makedirs(menu_folder)
except:
pass
n_page = 0
self.pages = 1
processes = []
menu_converter = cv.get_menu_converter()
while n_page < self.pages:
self.sf = None
self.paint_menu(True, False, False, n_page)
self.sf.write_to_png(os.path.join(menu_folder,"menu_"+str(n_page)+"_bg.png"))
self.sf = None
self.paint_menu(False, False, False, n_page)
self.sf.write_to_png(os.path.join(menu_folder,"menu_"+str(n_page)+"_unselected_bg.png"))
self.sf = None
self.paint_menu(False, True, False, n_page)
self.sf.write_to_png(os.path.join(menu_folder,"menu_"+str(n_page)+"_selected_bg.png"))
self.sf = None
self.paint_menu(False, False, True, n_page)
self.sf.write_to_png(os.path.join(menu_folder,"menu_"+str(n_page)+"_active_bg.png"))
converter = menu_converter()
converter.create_mpg(n_page,self.background_music,self.sound_length,self.project.pal,menu_folder)
# add this process without dependencies
processes.append([converter, None])
n_page += 1
return processes

View file

@ -17,16 +17,132 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/> # along with this program. If not, see <http://www.gnu.org/licenses/>
from gi.repository import GLib,GObject
import subprocess import subprocess
import os
import signal
import devede.configuration_data import devede.configuration_data
class executor: class executor(GObject.GObject):
""" This class encapsulates everything needed for launching processes """ """ This class encapsulates everything needed for launching processes """
def __init__(self):
self.config = devede.configuration_data.configuration.get_config()
__gsignals__ = {'ended': (GObject.SIGNAL_RUN_FIRST, None,(int,))}
def __init__(self):
GObject.GObject.__init__(self)
self.config = devede.configuration_data.configuration.get_config()
self.channel_stdout = None
self.channel_stderr = None
self.text = ""
self.stdout_data = ""
self.stderr_data = ""
def run(self, progress_bar):
self.progress_bar = progress_bar
self.launch_process(self.command_var)
self.progress_bar[0].set_label(self.text)
self.progress_bar[1].set_fraction(0.0)
self.progress_bar[0].show_all()
def remove_ansi(self,line):
output=""
while True:
pos=line.find("\033[") # try with double-byte ESC
jump=2
if pos==-1:
pos=line.find("\233") # if not, try with single-byte ESC
jump=1
if pos==-1: # no ANSI characters; we ended
output+=line
break
output+=line[:pos]
line=line[pos+jump:]
while True:
if len(line)==0:
break
if (ord(line[0])<64) or (ord(line[0])>126):
line=line[1:]
else:
line=line[1:]
break
return output
def launch_process(self,command):
self.config.append_log("Launching:",False)
for e in command:
self.config.append_log(e+" ")
self.handle = subprocess.Popen(command,stdout = subprocess.PIPE, stderr = subprocess.PIPE)
self.channel_stdout = GLib.IOChannel(self.handle.stdout.fileno())
self.channel_stderr = GLib.IOChannel(self.handle.stderr.fileno())
self.channel_stdout.add_watch(GLib.IO_IN | GLib.IO_HUP,self.read_stdout)
self.channel_stderr.add_watch(GLib.IO_IN | GLib.IO_HUP,self.read_stderr)
self.stdout_buf = ""
self.stderr_buf = ""
def read_stdout(self,source,condition):
if (condition != GLib.IO_IN):
self.channel_stdout = None
if (self.channel_stderr == None):
self.wait_end()
return False
else:
line_data = self.stdout_buf+(self.handle.stdout.read1(4096).decode("utf-8"))
self.stdout_data += line_data
data = (line_data).replace("\r","\n").split("\n")
if (len(data) == 1):
final_data = []
self.stdout_buf = data[0]
else:
final_data = data[:-1]
self.stdout_buf = data[-1]
if (len(final_data) != 0):
self.process_stdout(final_data)
return True
def read_stderr(self,source,condition):
if (condition != GLib.IO_IN):
self.channel_stderr = None
if (self.channel_stdout == None):
self.wait_end()
return False
else:
line_data = self.stderr_buf+(self.handle.stderr.read1(4096).decode("utf-8"))
self.stderr_data += line_data
data = (line_data).replace("\r","\n").split("\n")
if (len(data) == 1):
final_data = []
self.stderr_buf = data[0]
else:
final_data = data[:-1]
self.stderr_buf = data[-1]
if (len(final_data) != 0):
self.process_stderr(final_data)
return True
def cancel(self):
""" Called to kill this process. """
if self.handle==None:
return
os.kill(self.handle.pid,signal.SIGKILL)
def wait_end(self):
self.config.append_log(self.text)
self.config.append_log(self.stdout_data)
self.config.append_log(self.stderr_data)
retval = self.handle.wait()
self.emit("ended",retval)

View file

@ -116,9 +116,21 @@ class file_movie(devede.interface_manager.interface_manager):
cv = devede.converter.converter() cv = devede.converter.converter()
film_analizer = (cv.get_film_analizer())() film_analizer = (cv.get_film_analizer())()
if (film_analizer.get_film_data(self)): if (film_analizer.get_film_data(self.file_name)):
self.error = True self.error = True
else: else:
self.audio_list = film_analizer.audio_list
self.audio_streams = film_analizer.audio_streams
self.video_streams = film_analizer.video_streams
self.original_width = film_analizer.original_width
self.original_height = film_analizer.original_height
self.original_length = film_analizer.original_length
self.original_size = film_analizer.original_size
self.original_aspect_ratio = film_analizer.original_aspect_ratio
self.original_videorate = film_analizer.original_videorate
self.original_audiorate = film_analizer.original_audiorate
self.original_audiorate_uncompressed = film_analizer.original_audiorate_uncompressed
self.original_fps = film_analizer.original_fps
self.error = False self.error = False

View file

@ -17,8 +17,9 @@
import subprocess import subprocess
import devede.configuration_data import devede.configuration_data
import devede.executor
class mplayer_detector: class mplayer_detector(devede.executor.executor):
supports_analize = True supports_analize = True
supports_play = True supports_play = True
@ -39,81 +40,92 @@ class mplayer_detector:
self.config = devede.configuration_data.configuration.get_config() self.config = devede.configuration_data.configuration.get_config()
def get_film_data(self,movie): def get_film_data(self, file_name):
""" processes a file, refered by the FILE_MOVIE movie object, and fills its """ processes a file, refered by the FILE_MOVIE movie object, and fills its
main data (resolution, FPS, length...) """ main data (resolution, FPS, length...) """
video = self.get_film_data2(movie, True) (video, audio, length) = self.analize_film_data(file_name, True)
if (video): if (video != 0):
self.get_film_data2(movie, False) self.analize_film_data(file_name, False)
return False # no error return False # no error
else: else:
return True # the file is not a video file; maybe an audio-only file, or another thing return True # the file is not a video file; maybe an audio-only file, or another thing
def get_film_data2(self,movie,check_audio): def analize_film_data(self,file_name,check_audio):
if (check_audio): if (check_audio):
frames = "0" frames = "0"
else: else:
frames = "1" frames = "1"
command_line = ["mplayer","-loop","1","-identify", "-vo", "null", "-ao", "null", "-frames", frames , movie.file_name] command_line = ["mplayer","-loop","1","-identify", "-vo", "null", "-ao", "null", "-frames", frames , file_name]
handle = subprocess.Popen(command_line, stdout = subprocess.PIPE, stderr = subprocess.PIPE) handle = subprocess.Popen(command_line, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
(stdout, stderr) = handle.communicate() (stdout, stderr) = handle.communicate()
minimum_audio=-1 minimum_audio=-1
movie.audio_list=[] self.audio_list=[]
movie.audio_streams = 0 self.audio_streams = 0
movie.video_streams = 0 self.video_streams = 0
movie.original_width = 0 self.original_width = 0
movie.original_height = 0 self.original_height = 0
self.original_length = 0
self.original_videorate = 0
self.original_audiorate = 0
self.original_audiorate_uncompressed = 0
self.original_fps = 0
for line in str(stdout).split("\\n"): for line in str(stdout).split("\\n"):
#line=self.remove_ansi(line) line=self.remove_ansi(line)
if line == "": if line == "":
continue continue
position=line.find("ID_") position=line.find("ID_")
if position==-1: if position==-1:
continue continue
line=line[position:] line=line[position:]
if (not check_audio):
if line[:16]=="ID_VIDEO_BITRATE": if line[:16]=="ID_VIDEO_BITRATE":
movie.original_videorate=int(int(line[17:])/1000) self.original_videorate=int(int(line[17:])/1000)
if line[:14]=="ID_VIDEO_WIDTH": if line[:14]=="ID_VIDEO_WIDTH":
movie.original_width=int(line[15:]) self.original_width=int(line[15:])
if line[:15]=="ID_VIDEO_HEIGHT": if line[:15]=="ID_VIDEO_HEIGHT":
movie.original_height=int(line[16:]) self.original_height=int(line[16:])
if line[:15]=="ID_VIDEO_ASPECT": if line[:15]=="ID_VIDEO_ASPECT":
movie.original_aspect_ratio=float(line[16:]) self.original_aspect_ratio=float(line[16:])
if line[:12]=="ID_VIDEO_FPS": if line[:12]=="ID_VIDEO_FPS":
movie.original_fps=float(line[13:]) self.original_fps=float(line[13:])
if line[:16]=="ID_AUDIO_BITRATE": if line[:16]=="ID_AUDIO_BITRATE":
movie.original_audiorate=int(int(line[17:])/1000) self.original_audiorate=int(int(line[17:])/1000)
if line[:13]=="ID_AUDIO_RATE": if line[:13]=="ID_AUDIO_RATE":
movie.original_audiorate_uncompressed=int(line[14:]) self.original_audiorate_uncompressed=int(line[14:])
if line[:9]=="ID_LENGTH": if line[:9]=="ID_LENGTH":
movie.original_length=int(float(line[10:])) self.original_length=int(float(line[10:]))
if line[:11]=="ID_VIDEO_ID": if line[:11]=="ID_VIDEO_ID":
movie.video_streams+=1 self.video_streams+=1
if line[:11]=="ID_AUDIO_ID": if line[:11]=="ID_AUDIO_ID":
movie.audio_streams+=1 self.audio_streams+=1
audio_track=int(line[12:]) audio_track=int(line[12:])
if (minimum_audio == -1) or (minimum_audio>audio_track): if (minimum_audio == -1) or (minimum_audio>audio_track):
minimum_audio=audio_track minimum_audio=audio_track
movie.audio_list.append(audio_track) self.audio_list.append(audio_track)
movie.original_size = str(movie.original_width)+"x"+str(movie.original_height) if (check_audio):
if (movie.original_aspect_ratio == None) or (movie.original_aspect_ratio <= 1.0):
if (movie.original_height != 0):
movie.original_aspect_ratio = (float(movie.original_width))/(float(movie.original_height))
if (movie.original_aspect_ratio != None): return (self.video_streams, self.audio_streams, self.original_length)
movie.original_aspect_ratio = (float(int(movie.original_aspect_ratio*1000.0)))/1000.0
if (movie.video_streams == 0):
return False
else: else:
return True
self.original_size = str(self.original_width)+"x"+str(self.original_height)
if (self.original_aspect_ratio == None) or (self.original_aspect_ratio <= 1.0):
if (self.original_height != 0):
self.original_aspect_ratio = (float(self.original_width))/(float(self.original_height))
if (self.original_aspect_ratio != None):
self.original_aspect_ratio = (float(int(self.original_aspect_ratio*1000.0)))/1000.0
if (self.video_streams == 0):
return False
else:
return True

View file

@ -23,6 +23,8 @@ import devede.ask
import devede.add_files import devede.add_files
import devede.message import devede.message
import devede.dvd_menu import devede.dvd_menu
import devede.create_disk_window
import devede.runner
class devede_project: class devede_project:
@ -70,8 +72,10 @@ class devede_project:
if (self.config.PAL): if (self.config.PAL):
self.wuse_pal.set_active(True) self.wuse_pal.set_active(True)
self.pal = True
else: else:
self.wuse_ntsc.set_active(True) self.wuse_ntsc.set_active(True)
self.pal = False
self.wcreate_menu.set_active(True) self.wcreate_menu.set_active(True)
@ -140,11 +144,11 @@ class devede_project:
self.wproperties_file.set_sensitive(True) self.wproperties_file.set_sensitive(True)
self.wpreview_file.set_sensitive(True) self.wpreview_file.set_sensitive(True)
self.config.PAL = self.wuse_pal.get_active()
status = self.wcreate_menu.get_active() status = self.wcreate_menu.get_active()
self.wmenu_options.set_sensitive(status) self.wmenu_options.set_sensitive(status)
self.pal = self.wuse_pal.get_active()
(element, position, model, treeiter) = self.get_current_file() (element, position, model, treeiter) = self.get_current_file()
if (element == None): if (element == None):
self.wdelete_file.set_sensitive(False) self.wdelete_file.set_sensitive(False)
@ -164,6 +168,7 @@ class devede_project:
def on_use_pal_toggled(self,b): def on_use_pal_toggled(self,b):
self.config.PAL = self.wuse_pal.get_active()
self.set_interface_status(None) self.set_interface_status(None)
@ -247,4 +252,16 @@ class devede_project:
def on_menu_options_clicked(self,b): def on_menu_options_clicked(self,b):
self.menu.show_configuration() self.menu.show_configuration()
def on_create_disc_clicked(self,b):
data = devede.create_disk_window.create_disk_window()
if (not data.run()):
return
run_window = devede.runner.runner()
p = self.menu.create_dvd_menus(data.path)
run_window.add_processes(p)
run_window.run()

132
src/devede/runner.py Normal file
View file

@ -0,0 +1,132 @@
# Copyright 2014 (C) Raster Software Vigo (Sergio Costas)
#
# This file is part of DeVeDe-NG
#
# DeVeDe-NG is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# DeVeDe-NG is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
from gi.repository import Gtk,GObject
import os
import devede.configuration_data
class runner(GObject.GObject):
def __init__(self):
self.config = devede.configuration_data.configuration.get_config()
if (self.config.multicore):
self.count_cores()
else:
self.cores = 1
self.proc_list = []
self.running = 0
self.builder = Gtk.Builder()
self.builder.set_translation_domain(self.config.gettext_domain)
self.builder.add_from_file(os.path.join(self.config.glade,"wprogress.ui"))
self.builder.connect_signals(self)
self.wprogress = self.builder.get_object("progress")
self.wprogress.show_all()
self.wtotal = self.builder.get_object("progress_total")
progress_frame = self.builder.get_object("progress_frame")
box = Gtk.Box(Gtk.Orientation.VERTICAL, 0)
progress_frame.add(box)
box.show()
self.progress_bars = []
self.used_progress_bars = []
for c in range(0,self.cores):
f = Gtk.Frame()
p = Gtk.ProgressBar()
p.set_orientation(Gtk.Orientation.HORIZONTAL)
f.add(p)
# A frame, a progress bar, and the process running in that bar
self.progress_bars.append([f, p, None])
box.pack_start(f,True,True,0)
box.set_orientation(Gtk.Orientation.VERTICAL)
self.total = 0
def add_processes(self,processes):
for p in processes:
p.append(None) # this will contain the progress bar being used by this process
self.proc_list.append(p)
self.total_processes = len(self.proc_list)
def on_cancel_clicked(self,b):
pass
def count_cores(self):
self.cores = 0
proc_file = open("/proc/cpuinfo","r")
for line in proc_file:
if (line.startswith("processor")):
self.cores += 1
def run(self):
for element in self.proc_list:
# each element has three items:
# * the process object
# * the list of dependencies, or None if there are no more dependencies
# * the progress bar being used by this process
if (element[1] == None) and (element[2] == None):
self.progress_bars[0][2] = element[0]
element[0].connect("ended",self.process_ended)
element[0].run(self.progress_bars[0])
element[2] = self.progress_bars[0]
self.used_progress_bars.append(self.progress_bars[0])
if (len(self.progress_bars) > 1):
self.progress_bars = self.progress_bars[1:]
else:
self.progress_bars = []
break
self.wtotal.set_text(str(len(self.proc_list)-self.total)+"/"+str(self.total))
def process_ended(self,process, retval):
# move the progress bar used by this process to the list of available progress bars
tmp = []
for e in self.used_progress_bars:
if (e[2] == process):
e[2] = None
self.progress_bars.append(e)
e[0].hide()
else:
tmp.append(e)
self.used_progress_bars = tmp
# remove this process from the list of processes, and remove it from the dependencies in other processes
tmp = []
for e in self.proc_list:
if (e[0] != process):
tmp.append(e)
if (e[1] != None):
tmp2 = []
for dep in e[1]:
if dep != process:
tmp2.append(dep)
if (len(tmp2) != 0):
e[1] = tmp2
else:
e[1] = None
self.proc_list = tmp
# launch a new process
if (len(self.proc_list) != 0):
self.run()
else:
self.wprogress.destroy()