/otrverwaltung/actions/decodeorcut.py

https://github.com/elbersb/otr-verwaltung · Python · 753 lines · 508 code · 176 blank · 69 comment · 169 complexity · 52bce7ff9b46e518faada9f79b486e24 MD5 · raw file

  1. # -*- coding: utf-8 -*-
  2. ### BEGIN LICENSE
  3. # Copyright (C) 2010 Benjamin Elbers <elbersb@gmail.com>
  4. #This program is free software: you can redistribute it and/or modify it
  5. #under the terms of the GNU General Public License version 3, as published
  6. #by the Free Software Foundation.
  7. #
  8. #This program is distributed in the hope that it will be useful, but
  9. #WITHOUT ANY WARRANTY; without even the implied warranties of
  10. #MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
  11. #PURPOSE. See the GNU General Public License for more details.
  12. #
  13. #You should have received a copy of the GNU General Public License along
  14. #with this program. If not, see <http://www.gnu.org/licenses/>.
  15. ### END LICENSE
  16. from gtk import events_pending, main_iteration, RESPONSE_OK
  17. import base64
  18. import subprocess
  19. import urllib
  20. import os
  21. from os.path import basename, join, dirname, exists, splitext
  22. import time
  23. from otrverwaltung import fileoperations
  24. from otrverwaltung.conclusions import FileConclusion
  25. from otrverwaltung.constants import Action, Cut_action, Status, Format, Program
  26. from otrverwaltung.actions.baseaction import BaseAction
  27. from otrverwaltung import codec
  28. from otrverwaltung import cutlists as cutlists_management
  29. from otrverwaltung import path
  30. from otrverwaltung.GeneratorTask import GeneratorTask
  31. class DecodeOrCut(BaseAction):
  32. def __init__(self, app, gui):
  33. self.update_list = True
  34. self.__app = app
  35. self.config = app.config
  36. self.__gui = gui
  37. def do(self, action, filenames, cut_action=None):
  38. self.rename_by_schema = self.__app.rename_by_schema
  39. decode, cut = False, False
  40. # prepare tasks
  41. if action == Action.DECODE:
  42. self.__gui.main_window.set_tasks_text('Dekodieren')
  43. decode = True
  44. elif action == Action.CUT:
  45. self.__gui.main_window.set_tasks_text('Schneiden')
  46. cut = True
  47. else: # decode and cut
  48. self.__gui.main_window.set_tasks_text('Dekodieren/Schneiden')
  49. decode, cut = True, True
  50. file_conclusions = []
  51. if decode:
  52. for otrkey in filenames:
  53. file_conclusions.append(FileConclusion(action, otrkey=otrkey))
  54. if cut and not decode: # dont add twice
  55. for uncut_video in filenames:
  56. file_conclusions.append(FileConclusion(action, uncut_video=uncut_video))
  57. # decode files
  58. if decode:
  59. if self.decode(file_conclusions) == False:
  60. return
  61. # cut files
  62. if cut:
  63. if self.cut(file_conclusions, action, cut_action) == False:
  64. return
  65. self.__gui.main_window.block_gui(False)
  66. # no more need for tasks view
  67. self.__gui.main_window.set_tasks_visible(False)
  68. show_conclusions = False
  69. # Only cut - don't show conclusions if all were cancelled
  70. if action == Action.CUT:
  71. for conclusion in file_conclusions:
  72. if conclusion.cut.status != Status.NOT_DONE:
  73. show_conclusions = True
  74. break
  75. # Only decode - don't show if everything is OK
  76. elif action == Action.DECODE:
  77. for conclusion in file_conclusions:
  78. if conclusion.decode.status != Status.OK:
  79. show_conclusions = True
  80. if not show_conclusions:
  81. self.__app.gui.main_window.change_status(0, "%i Datei(en) erfolgreich dekodiert" % len(file_conclusions), permanent=True)
  82. # Decode and cut - always show
  83. else:
  84. show_conclusions = True
  85. if show_conclusions:
  86. self.__app.conclusions_manager.add_conclusions(*file_conclusions)
  87. def decode(self, file_conclusions):
  88. # no decoder
  89. if not "decode" in self.config.get('general', 'decoder'): # no decoder specified
  90. # dialog box: no decoder
  91. self.__gui.message_error_box("Es ist kein korrekter Dekoder angegeben!")
  92. return False
  93. # retrieve email and password
  94. email = self.config.get('general', 'email')
  95. password = base64.b64decode(self.config.get('general', 'password'))
  96. if not email or not password:
  97. self.__gui.dialog_email_password.set_email_password(email, password)
  98. # let the user type in his data through a dialog
  99. response = self.__gui.dialog_email_password.run()
  100. self.__gui.dialog_email_password.hide()
  101. if response == RESPONSE_OK:
  102. email, password = self.__gui.dialog_email_password.get_email_password()
  103. else: # user pressed cancel
  104. return False
  105. # now this method may not return "False"
  106. self.__gui.main_window.set_tasks_visible(True)
  107. self.__gui.main_window.block_gui(True)
  108. # decode each file
  109. for count, file_conclusion in enumerate(file_conclusions):
  110. # update progress
  111. self.__gui.main_window.set_tasks_text("Datei %s/%s dekodieren" % (count + 1, len(file_conclusions)))
  112. verify = True
  113. command = [self.config.get('general', 'decoder'), "-i", file_conclusion.otrkey, "-e", email, "-p", password, "-o", self.config.get('general', 'folder_uncut_avis')]
  114. if not self.config.get('general', 'verify_decoded'):
  115. verify = False
  116. command += ["-q"]
  117. try:
  118. process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  119. except OSError:
  120. file_conclusion.decode.status = Status.ERROR
  121. file_conclusion.decode.message = "Dekoder wurde nicht gefunden."
  122. continue
  123. while True:
  124. l = ""
  125. while True:
  126. c = process.stdout.read(1)
  127. if c == "\r" or c == "\n":
  128. break
  129. l += c
  130. if not l:
  131. break
  132. try:
  133. if verify:
  134. file_count = count + 1, len(file_conclusions)
  135. if "input" in l:
  136. self.__gui.main_window.set_tasks_text("Eingabedatei %s/%s kontrollieren" % file_count)
  137. elif "output" in l:
  138. self.__gui.main_window.set_tasks_text("Ausgabedatei %s/%s kontrollieren" % file_count)
  139. elif "Decoding" in l:
  140. self.__gui.main_window.set_tasks_text("Datei %s/%s dekodieren" % file_count)
  141. progress = int(l[10:13])
  142. # update progress
  143. self.__gui.main_window.set_tasks_progress(progress)
  144. while events_pending():
  145. main_iteration(False)
  146. except ValueError:
  147. pass
  148. # errors?
  149. errors = process.stderr.readlines()
  150. error_message = ""
  151. for error in errors:
  152. error_message += error.strip()
  153. if len(errors) == 0: # dekodieren erfolgreich
  154. file_conclusion.decode.status = Status.OK
  155. file_conclusion.uncut_video = join(self.config.get('general', 'folder_uncut_avis'), basename(file_conclusion.otrkey[0:len(file_conclusion.otrkey)-7]))
  156. # move otrkey to trash
  157. target = self.config.get('general', 'folder_trash_otrkeys')
  158. fileoperations.move_file(file_conclusion.otrkey, target)
  159. else:
  160. file_conclusion.decode.status = Status.ERROR
  161. try:
  162. unicode(error_message)
  163. except UnicodeDecodeError:
  164. error_message = unicode(error_message, 'iso-8859-1')
  165. file_conclusion.decode.message = error_message
  166. return True
  167. def cut(self, file_conclusions, action, default_cut_action=None):
  168. # now this method may not return "False"
  169. self.__gui.main_window.set_tasks_visible(True)
  170. self.__gui.main_window.block_gui(True)
  171. if not default_cut_action:
  172. default_cut_action = self.config.get('general', 'cut_action')
  173. for count, file_conclusion in enumerate(file_conclusions):
  174. self.__gui.main_window.set_tasks_text("Cutlist %s/%s wählen" % (count + 1, len(file_conclusions)))
  175. self.__gui.main_window.set_tasks_progress((count + 1) / float(len(file_conclusions)) * 100)
  176. # file correctly decoded?
  177. if action == Action.DECODEANDCUT:
  178. if file_conclusion.decode.status != Status.OK:
  179. file_conclusion.cut.status = Status.NOT_DONE
  180. file_conclusion.cut.message = "Datei wurde nicht dekodiert."
  181. continue
  182. file_conclusion.cut.cut_action = default_cut_action
  183. if default_cut_action in [Cut_action.ASK, Cut_action.CHOOSE_CUTLIST]:
  184. # show dialog
  185. self.__gui.dialog_cut.setup(
  186. file_conclusion.uncut_video,
  187. self.config.get('general', 'folder_cut_avis'),
  188. default_cut_action == Cut_action.ASK)
  189. cutlists = []
  190. self.cutlists_error = False
  191. def error_cb(error):
  192. self.__gui.dialog_cut.builder.get_object('label_status').set_markup("<b>%s</b>" % error)
  193. self.cutlists_error = True
  194. def cutlist_found_cb(cutlist):
  195. self.__gui.dialog_cut.add_cutlist(cutlist)
  196. cutlists.append(cutlist)
  197. def completed():
  198. if not self.cutlists_error:
  199. self.__gui.dialog_cut.builder.get_object('label_status').set_markup("")
  200. GeneratorTask(cutlists_management.download_cutlists, None, completed).start(file_conclusion.uncut_video, self.config.get('general', 'server'), self.config.get('general', 'choose_cutlists_by'), self.config.get('general', 'cutlist_mp4_as_hq'), error_cb, cutlist_found_cb)
  201. response = self.__gui.dialog_cut.run()
  202. self.__gui.dialog_cut.hide()
  203. if response < 0:
  204. file_conclusion.cut.status = Status.NOT_DONE
  205. file_conclusion.cut.message = "Abgebrochen."
  206. else: # change cut_action accordingly
  207. file_conclusion.cut.cut_action = response
  208. if file_conclusion.cut.cut_action == Cut_action.MANUALLY: # MANUALLY
  209. error_message, cuts, executable = self.cut_file_manually(file_conclusion.uncut_video)
  210. if not error_message:
  211. file_conclusion.cut.create_cutlist = True
  212. file_conclusion.cut.cutlist.cuts_frames = cuts
  213. file_conclusion.cut.cutlist.intended_app = basename(executable)
  214. file_conclusion.cut.cutlist.usercomment = 'Mit OTR-Verwaltung geschnitten'
  215. fps, error = self.__get_fps(file_conclusion.uncut_video)
  216. if not error:
  217. file_conclusion.cut.cutlist.fps = fps
  218. else:
  219. file_conclusion.cut.cutlist.fps = 25.
  220. print "Achtung! Möglicherweise wurde eine falsche Fps-Anzahl eingetragen! (%s)" % error
  221. # calculate seconds
  222. for start_frame, duration_frames in cuts:
  223. file_conclusion.cut.cutlist.cuts_seconds.append((start_frame / fps, duration_frames / fps))
  224. else:
  225. file_conclusion.cut.status = Status.ERROR
  226. file_conclusion.cut.message = error_message
  227. elif file_conclusion.cut.cut_action == Cut_action.BEST_CUTLIST:
  228. error, cutlists = cutlists_management.download_cutlists(file_conclusion.uncut_video, self.config.get('general', 'server'), self.config.get('general', 'choose_cutlists_by'), self.config.get('general', 'cutlist_mp4_as_hq'))
  229. if error:
  230. file_conclusion.cut.status = Status.ERROR
  231. file_conclusion.cut.message = error
  232. continue
  233. if len(cutlists) == 0:
  234. file_conclusion.cut.status = Status.NOT_DONE
  235. file_conclusion.cut.message = "Keine Cutlist gefunden."
  236. continue
  237. file_conclusion.cut.cutlist = cutlists_management.get_best_cutlist(cutlists)
  238. elif file_conclusion.cut.cut_action == Cut_action.CHOOSE_CUTLIST:
  239. file_conclusion.cut.cutlist = self.__gui.dialog_cut.chosen_cutlist
  240. elif file_conclusion.cut.cut_action == Cut_action.LOCAL_CUTLIST:
  241. file_conclusion.cut.cutlist.local_filename = file_conclusion.uncut_video + ".cutlist"
  242. if not exists(file_conclusion.cut.cutlist.local_filename):
  243. file_conclusion.cut.status = Status.ERROR
  244. file_conclusion.cut.message = "Keine lokale Cutlist gefunden."
  245. # and finally cut the file
  246. for count, file_conclusion in enumerate(file_conclusions):
  247. if file_conclusion.cut.status in [Status.NOT_DONE, Status.ERROR]:
  248. continue
  249. print "[Decodeandcut] Datei %s wird geschnitten" % file_conclusion.uncut_video
  250. self.__gui.main_window.set_tasks_text("Datei %s/%s schneiden" % (count + 1, len(file_conclusions)))
  251. self.__gui.main_window.set_tasks_progress(0.5)
  252. # download cutlist
  253. if file_conclusion.cut.cut_action in [Cut_action.BEST_CUTLIST, Cut_action.CHOOSE_CUTLIST]:
  254. file_conclusion.cut.cutlist.download(self.config.get('general', 'server'), file_conclusion.uncut_video)
  255. cut_video, error = self.cut_file_by_cutlist(file_conclusion.uncut_video, file_conclusion.cut.cutlist)
  256. if cut_video == None:
  257. file_conclusion.cut.status = Status.ERROR
  258. file_conclusion.cut.message = error
  259. else:
  260. file_conclusion.cut.status = Status.OK
  261. file_conclusion.cut_video = cut_video
  262. if self.config.get('general', 'rename_cut'):
  263. file_conclusion.cut.rename = self.rename_by_schema(basename(file_conclusion.uncut_video))
  264. else:
  265. file_conclusion.cut.rename = basename(cut_video)
  266. return True
  267. def __get_format(self, filename):
  268. root, extension = splitext(filename)
  269. if extension == '.avi':
  270. if splitext(root)[1] == '.HQ':
  271. return Format.HQ
  272. elif splitext(root)[1] == '.HD':
  273. return Format.HD
  274. else:
  275. return Format.AVI
  276. elif extension == '.mp4':
  277. return Format.MP4
  278. else:
  279. return -1
  280. def __get_program(self, filename, manually=False):
  281. if manually:
  282. programs = { Format.AVI : self.config.get('general', 'cut_avis_man_by'),
  283. Format.HQ : self.config.get('general', 'cut_hqs_man_by'),
  284. Format.HD : self.config.get('general', 'cut_hqs_man_by'),
  285. Format.MP4 : self.config.get('general', 'cut_mp4s_man_by') }
  286. else:
  287. programs = { Format.AVI : self.config.get('general', 'cut_avis_by'),
  288. Format.HQ : self.config.get('general', 'cut_hqs_by'),
  289. Format.HD : self.config.get('general', 'cut_hqs_by'),
  290. Format.MP4 : self.config.get('general', 'cut_mp4s_by') }
  291. format = self.__get_format(filename)
  292. if format < 0:
  293. return -1, "Format konnte nicht bestimmt werden/wird noch nicht unterstützt."
  294. config_value = programs[format]
  295. if 'avidemux' in config_value:
  296. return Program.AVIDEMUX, config_value
  297. elif 'vdub' in config_value or 'VirtualDub' in config_value:
  298. return Program.VIRTUALDUB, config_value
  299. else:
  300. return -2, "Programm '%s' konnte nicht bestimmt werden. Es werden VirtualDub und Avidemux unterstützt." % config_value
  301. def __generate_filename(self, filename):
  302. """ generate filename for a cut video file. """
  303. root, extension = splitext(basename(filename))
  304. new_name = root + "-cut" + extension
  305. cut_video = join(self.config.get('general', 'folder_cut_avis'), new_name)
  306. return cut_video
  307. def __get_fps(self, filename):
  308. """ Gets the fps of a movie using mplayer.
  309. Returns without error:
  310. fps, None
  311. with error:
  312. None, error_message """
  313. mplayer = self.config.get('general', 'mplayer')
  314. if not mplayer:
  315. return None, "Der Mplayer ist nicht angegeben. Dieser wird zur Bestimmung der FPS benötigt."
  316. try:
  317. process = subprocess.Popen([mplayer, "-vo", "null", "-frames", "1", "-nosound", filename], stdout=subprocess.PIPE)
  318. except OSError:
  319. return None, "MPlayer wurde nicht gefunden!"
  320. stdout = process.communicate()[0]
  321. for line in stdout.split('\n'):
  322. if "VIDEO" in line:
  323. try:
  324. return float(line[line.index("bpp")+3 : line.index("fps")]), None
  325. except:
  326. return None, "FPS konnte nicht bestimmt werden " + line
  327. return None, "FPS konnte nicht bestimmt werden."
  328. def __get_aspect_ratio(self, filename):
  329. """ Gets the aspect ratio of a movie using mplayer.
  330. Returns without error:
  331. aspect_ratio, None
  332. with error:
  333. None, error_message """
  334. mplayer = self.config.get('general', 'mplayer')
  335. if not mplayer:
  336. return None, "Der Mplayer ist nicht angegeben. Dieser wird zur Bestimmung der Aspekt Ratio benötigt."
  337. try:
  338. process = subprocess.Popen([mplayer, "-vo", "null", "-frames", "1", "-nosound", filename], stdout=subprocess.PIPE)
  339. except OSError:
  340. return None, "MPlayer wurde nicht gefunden!"
  341. stdout = process.communicate()[0]
  342. for line in stdout.split('\n'):
  343. if "Aspe" in line:
  344. if "1.78:1" in line or "0.56:1" in line:
  345. return "16:9", None
  346. elif "1.33:1" in line or "0.75:1" in line:
  347. return "4:3", None
  348. else:
  349. return None, "Aspekt konnte nicht bestimmt werden " + line
  350. return None, "Aspekt Ratio konnte nicht bestimmt werden."
  351. def __create_cutlist_virtualdub(self, filename):
  352. """ returns: cuts, error_message """
  353. try:
  354. f = open(filename, 'r')
  355. except IOError:
  356. return None, "Die VirtualDub-Projektdatei konnte nicht gelesen werden.\nWurde das Projekt in VirtualDub nicht gespeichert?\n(Datei: %s)." % filename
  357. cuts_frames = [] # (start, duration)
  358. count = 0
  359. for line in f.readlines():
  360. if "VirtualDub.subset.AddRange" in line:
  361. try:
  362. start, duration = line[line.index('(') + 1 : line.index(')')].split(',')
  363. except (IndexError, ValueError), message:
  364. return None, "Konnte Schnitte nicht lesen, um Cutlist zu erstellen. (%s)" % message
  365. cuts_frames.append((int(start), int(duration)))
  366. if len(cuts_frames) == 0:
  367. return None, "Konnte keine Schnitte finden!"
  368. fileoperations.remove_file(filename)
  369. return cuts_frames, None
  370. def cut_file_manually(self, filename):
  371. """ Cuts a file manually with Avidemux or VirtualDub and gets cuts from
  372. possibly created project files (VD) or from output (AD).
  373. returns: error_message, cuts, executable """
  374. program, config_value = self.__get_program(filename, manually=True)
  375. if program < 0:
  376. return config_value, None, None
  377. if program == Program.AVIDEMUX:
  378. try:
  379. avidemux = subprocess.Popen([config_value, filename], stdout=subprocess.PIPE)
  380. except OSError:
  381. return "Avidemux konnte nicht aufgerufen werden: " + config_value, None, None
  382. while avidemux.poll() == None:
  383. time.sleep(1)
  384. pass
  385. seg_lines = []
  386. for line in avidemux.stdout.readlines():
  387. if line.startswith(' Seg'):
  388. # delete not interesting parts
  389. line = line[:line.find("audio")]
  390. parts = line.split(',')
  391. seg_id = int(parts[0].split(':')[-1])
  392. start = int(parts[1].split(':')[-1])
  393. size = int(parts[2].split(':')[-1])
  394. seg_lines.append((seg_id, start, size))
  395. # keep only necessary items
  396. seg_lines.reverse()
  397. temp_cuts = []
  398. for seg_id, start, duration in seg_lines:
  399. if seg_id == 0:
  400. temp_cuts.append((start, duration))
  401. break
  402. else:
  403. temp_cuts.append((start, duration))
  404. temp_cuts.reverse()
  405. cuts_frames = []
  406. count = 0
  407. for start, duration in temp_cuts:
  408. cuts_frames.append((start, duration))
  409. count += 1
  410. if len(cuts_frames) == 0:
  411. cutlist_error = "Es wurde nicht geschnitten."
  412. else:
  413. cutlist_error = None
  414. else: # VIRTUALDUB
  415. cut_video_is_none, error = self.__cut_file_virtualdub(filename, config_value, cuts=None, manually=True)
  416. if error != None:
  417. return error, None, None
  418. cuts_frames, cutlist_error = self.__create_cutlist_virtualdub(join(self.config.get('general', 'folder_uncut_avis'), "cutlist.vcf"))
  419. if cutlist_error:
  420. return cutlist_error, None, config_value
  421. else:
  422. return None, cuts_frames, config_value
  423. def cut_file_by_cutlist(self, filename, cutlist):
  424. """ Returns: cut_video, error """
  425. program, program_config_value = self.__get_program(filename)
  426. if program < 0:
  427. return None, program_config_value
  428. # get list of cuts
  429. error = cutlist.read_cuts()
  430. if error:
  431. return None, error
  432. if not cutlist.cuts_frames:
  433. fps, error = self.__get_fps(filename)
  434. if not error:
  435. cutlist.fps = fps
  436. else:
  437. return None, "Konnte FPS nicht bestimmen: " + error
  438. print "Calculate frame values from seconds."
  439. for start, duration in cutlist.cuts_seconds:
  440. cutlist.cuts_frames.append((start * cutlist.fps, duration * cutlist.fps))
  441. if program == Program.AVIDEMUX:
  442. cut_video, error = self.__cut_file_avidemux(filename, program_config_value, cutlist.cuts_frames)
  443. else: # VIRTUALDUB
  444. cut_video, error = self.__cut_file_virtualdub(filename, program_config_value, cutlist.cuts_frames)
  445. if error:
  446. return None, error
  447. else:
  448. return cut_video, None
  449. def __cut_file_avidemux(self, filename, config_value, cuts):
  450. # make file for avidemux scripting engine
  451. f = open("tmp.js", "w")
  452. f.writelines([
  453. '//AD\n',
  454. 'var app = new Avidemux();\n',
  455. '\n'
  456. '//** Video **\n',
  457. 'app.load("%s");\n' % filename,
  458. '\n',
  459. 'app.clearSegments();\n'
  460. ])
  461. for frame_start, frames_duration in cuts:
  462. f.write("app.addSegment(0, %i, %i);\n" %(frame_start, frames_duration))
  463. cut_video = self.__generate_filename(filename)
  464. f.writelines([
  465. '//** Postproc **\n',
  466. 'app.video.setPostProc(3,3,0);\n'
  467. ])
  468. if self.config.get('general', 'smart'):
  469. f.write('app.video.codec("Copy","CQ=4","0");\n')
  470. f.writelines([
  471. '//** Audio **\n',
  472. 'app.audio.reset();\n',
  473. 'app.audio.codec("copy",128,0,"");\n',
  474. 'app.audio.normalizeMode=0;\n',
  475. 'app.audio.normalizeValue=0;\n',
  476. 'app.audio.delay=0;\n',
  477. 'app.audio.mixer="NONE";\n',
  478. 'app.audio.scanVBR="";\n',
  479. 'app.setContainer="AVI";\n',
  480. 'setSuccess(app.save("%s"));\n' % cut_video
  481. ])
  482. f.close()
  483. # start avidemux:
  484. try:
  485. avidemux = subprocess.Popen([config_value, "--nogui", "--force-smart", "--run", "tmp.js", "--quit"], stderr=subprocess.PIPE)
  486. except OSError:
  487. return None, "Avidemux konnte nicht aufgerufen werden: " + config_value
  488. self.__gui.main_window.set_tasks_progress(50)
  489. while avidemux.poll() == None:
  490. time.sleep(1)
  491. # TODO: make it happen
  492. # line = avidemux.stderr.readline()
  493. #
  494. # if "Done:" in line:
  495. # progress = line[line.find(":") + 1 : line.find("%")]
  496. # self.__gui.main_window.set_tasks_progress(int(progress))
  497. #
  498. while events_pending():
  499. main_iteration(False)
  500. fileoperations.remove_file('tmp.js')
  501. return cut_video, None
  502. def __cut_file_virtualdub(self, filename, config_value, cuts=None, manually=False):
  503. format = self.__get_format(filename)
  504. if format == Format.HQ:
  505. aspect, error_message = self.__get_aspect_ratio(filename)
  506. if not aspect:
  507. return None, error_message
  508. if aspect == "16:9":
  509. comp_data = codec.get_comp_data_h264_169()
  510. else:
  511. comp_data = codec.get_comp_data_h264_43()
  512. elif format == Format.HD:
  513. aspect, error_message = self.__get_aspect_ratio(filename)
  514. if not aspect:
  515. return None, error_message
  516. if aspect == "16:9":
  517. comp_data = codec.get_comp_data_hd_169()
  518. else:
  519. comp_data = codec.get_comp_data_hd_43()
  520. elif format == Format.AVI:
  521. comp_data = codec.get_comp_data_dx50()
  522. else:
  523. return None, "Format nicht unterstützt (Nur Avi DX50, HQ H264 und HD sind möglich)."
  524. # make file for virtualdub scripting engine
  525. if manually:
  526. # TODO: kind of a hack
  527. curr_dir = os.getcwd()
  528. try:
  529. os.chdir(dirname(config_value))
  530. except OSError:
  531. return None, "VirtualDub konnte nicht aufgerufen werden: " + config_value
  532. self.__gui.main_window.set_tasks_progress(50)
  533. f = open("tmp.vcf", "w")
  534. if not manually:
  535. f.write('VirtualDub.Open("%s");\n' % filename)
  536. if self.config.get('general', 'smart'):
  537. f.writelines([
  538. 'VirtualDub.video.SetMode(1);\n',
  539. 'VirtualDub.video.SetSmartRendering(1);\n',
  540. 'VirtualDub.video.SetCompression(0x53444646,0,10000,0);\n'
  541. 'VirtualDub.video.SetCompData(%s);\n' % comp_data
  542. ])
  543. else:
  544. f.write('VirtualDub.video.SetMode(0);\n')
  545. f.write('VirtualDub.subset.Clear();\n')
  546. if not manually:
  547. for frame_start, frames_duration in cuts:
  548. f.write("VirtualDub.subset.AddRange(%i, %i);\n" % (frame_start, frames_duration))
  549. cut_video = self.__generate_filename(filename)
  550. f.writelines([
  551. 'VirtualDub.SaveAVI("%s");\n' % cut_video,
  552. 'VirtualDub.Close();'
  553. ])
  554. f.close()
  555. # start vdub
  556. if not exists(config_value):
  557. return None, "VirtualDub konnte nicht aufgerufen werden: " + config_value
  558. if manually:
  559. win_filename = "Z:" + filename.replace(r"/", r"\\")
  560. command = 'VirtualDub.exe /s tmp.vcf "%s"' % win_filename
  561. else:
  562. command = "%s /s tmp.vcf /x" % config_value
  563. command = "wineconsole " + command
  564. print command
  565. try:
  566. vdub = subprocess.Popen(command, shell=True)
  567. except OSError:
  568. return None, "VirtualDub konnte nicht aufgerufen werden: " + config_value
  569. while vdub.poll() == None:
  570. time.sleep(1)
  571. while events_pending():
  572. main_iteration(False)
  573. fileoperations.remove_file('tmp.vcf')
  574. if manually:
  575. os.chdir(curr_dir)
  576. return None, None
  577. return cut_video, None