PageRenderTime 60ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/demultiplexer.py

https://bitbucket.org/josemaria.alkala/dv2mkv
Python | 260 lines | 255 code | 0 blank | 5 comment | 0 complexity | 454afa063801ff43cef489f0a0c1c53f MD5 | raw file
Possible License(s): Apache-2.0
  1. #!/usr/bin/python
  2. # -*- coding:utf-8 -*-
  3. '''
  4. Copyright 2010 José María García Pérez
  5. Licensed under the Apache License, Version 2.0 (the "License");
  6. you may not use this file except in compliance with the License.
  7. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. '''
  15. '''
  16. ToDo
  17. ----
  18. 1. Tolerant with multivideo or multiaudio: -vid / -aid
  19. '''
  20. isOK = True
  21. try:
  22. import os
  23. import subprocess
  24. except ImportError:
  25. raise Exception(u'[ERROR] Es necesario Python 2.6' )
  26. isOK = False
  27. try:
  28. from configuration import Configuration
  29. except ImportError:
  30. raise Exception(u'[ERROR] Asegúrate de que "configuration.py" es accesible')
  31. isOK = False
  32. try:
  33. from info import Info
  34. except ImportError:
  35. raise Exception(u'[ERROR] Asegúrate de que "info.py" es accesible')
  36. isOK = False
  37. class Demultiplexer:
  38. '''Descompone una película en video y audio'''
  39. def __init__(self,
  40. inputfile = None,
  41. outputdir = None,
  42. ini = None,
  43. end = None,
  44. verbose = False):
  45. '''inputfile:
  46. '''
  47. if inputfile == None or outputdir == None:
  48. raise Exception('Demultiplexer requires "inputfile" and "outputdir" to be provided')
  49. # The inputfile is info.Info instance.
  50. self.inputfile = Info( inputfile = inputfile )
  51. self.outputdir = outputdir
  52. self.ini = self.__ini__( ini )
  53. self.end = self.__ini__( end )
  54. self.verbose = verbose
  55. def getaudio(self,
  56. avoidexec = False):
  57. '''Extrae el audio de un video:
  58. - Nombre: tmp_audio.wav
  59. - Formato: PCM
  60. '''
  61. # ToDo: Usar un nombre genérico para poder trabajar en paralelo.
  62. _output_filename = os.path.join( self.outputdir, 'audio.wav' )
  63. _config = Configuration()
  64. _mplayer = _config.data['mplayer']
  65. _params1 = [ _mplayer ]
  66. # !! Mplayer no entiende rutas absolutas en "pcm:file=...."
  67. #_output_filename = _output_filename.replace('\\','/')
  68. _wavfile = os.path.relpath( _output_filename )
  69. #_output_filename = _output_filename.replace('C:','/cygdrive/c')
  70. # -idx: es más lento pero demostró evitar cortes en algunos DV.
  71. _params2 = [ '-quiet',
  72. '-idx',
  73. '-vc',
  74. 'null',
  75. '-vo',
  76. 'null',
  77. '-ao',
  78. 'pcm:waveheader:file=%s' % _wavfile ]
  79. _params3 = []
  80. _params4 = []
  81. if self.ini != None:
  82. _params3 = [ '-ss',
  83. self.ini ]
  84. if self.end != None:
  85. _params4 = [ '-endpos',
  86. self.end ]
  87. _params5 = [ self.inputfile.filename ]
  88. _orden = _params1 + _params2 + _params3 + _params4 + _params5
  89. if self.verbose:
  90. print u'>>> Extrayendo el audio: %s ..... ' % _output_filename
  91. try:
  92. if not avoidexec:
  93. if self.verbose:
  94. subprocess.call(_orden)
  95. else:
  96. subprocess.call(_orden,
  97. shell = False,
  98. stdout = subprocess.PIPE)
  99. _data = _process.communicate()[0]
  100. if self.verbose:
  101. print u' [OK]'
  102. except:
  103. if self.verbose:
  104. print u' [FAILED]'
  105. return os.path.realpath( _output_filename )
  106. def getvideo( self,
  107. avoidexec = False ):
  108. '''Extrae sólo video (sin audio) en el formato original y en el contenedor AVI.
  109. mencoder <input_file> -of avi -ovc copy -nosound -o tmp_video.avi
  110. "exe\mencoder.exe" .\video_sources\Nokia\Video005.3gp -of avi -nosound -ovc lavc -fps 7.750984 -ofps 7.750984 -lavcopts vcodec=ffv1:aspect=1.45/1:vstrict=-2:coder=1:context=1:format=bgr32 -o ffv1.avi
  111. FPS:
  112. * Móvil: 7.750984fps
  113. '''
  114. _output_filename = os.path.join( self.outputdir, 'video.avi' )
  115. _config = Configuration()
  116. _params1 = [ _config.data['mencoder'] ]
  117. #'-idx',
  118. _params2 = [ '-idx',
  119. '-of',
  120. 'avi',
  121. '-nosound',
  122. '-ovc',
  123. 'copy']
  124. _params3 = []
  125. _params4 = []
  126. if self.ini != None:
  127. _params3 = [ '-ss',
  128. '%s' % self.ini]
  129. if self.end != None:
  130. _params4 = [ '-endpos',
  131. '%s' % self.end]
  132. _params5 = [ '-fps',
  133. '%s' % self.inputfile.rate,
  134. '-ofps',
  135. '%s' % self.inputfile.rate,
  136. '-o',
  137. '%s' % _output_filename,
  138. self.inputfile.filename]
  139. _orden = _params1 + _params2 + _params3 + _params4 + _params5
  140. if self.verbose:
  141. print u'>>> Extrayendo el video: %s ..... ' % _output_filename
  142. try:
  143. if not avoidexec:
  144. subprocess.call(_orden)
  145. #if self.verbose:
  146. # subprocess.call(_orden)
  147. #else:
  148. # subprocess.call(_orden,
  149. # shell = False,
  150. # stdout = subprocess.PIPE)
  151. # _data = _process.communicate()[0]
  152. if self.verbose:
  153. print u' [OK]'
  154. except:
  155. if self.verbose:
  156. print u' [FAILED]'
  157. return os.path.realpath( _output_filename )
  158. def __ini__(self, _ini):
  159. # ToDo: habría que validar los valores proporcionados aquí.
  160. return _ini
  161. def __end__(self, _end):
  162. return _end
  163. #=======
  164. # MAIN
  165. #=======
  166. if __name__ == '__main__':
  167. if isOK:
  168. # Parser
  169. import optparse
  170. _usage = u'''
  171. Propósito: Este programa permite extraer audio/video de una película.
  172. Uso: %prog [options] input_file output_directory
  173. Ejemplos:
  174. - Extrae el audio de los primeros 5 segundos del fichero:
  175. python demultiplexer.py -a --ini 0:00:00 --end 0:00:05 video.avi ./tmp
  176. '''
  177. _parser = optparse.OptionParser( usage = _usage )
  178. # _parser.add_option("-f", "--force",
  179. # action="store_true",
  180. # dest="force",
  181. # default = False,
  182. # help = "Sobreescribe en los ficheros preexistentes.")
  183. _parser.add_option("-i", "--ini",
  184. action="store",
  185. dest="ini",
  186. default = None,
  187. help = "Marca el inicio del procesado en tiempo")
  188. _parser.add_option("-e", "--end",
  189. action="store",
  190. dest="end",
  191. default = None,
  192. help = "Marca el final del procesado en tiempo")
  193. _parser.add_option("-a", "--audio",
  194. action="store_true",
  195. dest="audio",
  196. default = False,
  197. help = "Extrae el audio.")
  198. _parser.add_option("-v", "--video",
  199. action="store_true",
  200. dest="video",
  201. default = False,
  202. help = "Extrae el video.")
  203. (_options, _args) = _parser.parse_args()
  204. # ========================
  205. # Verificamos las opciones
  206. # ========================
  207. # - Fichero de origen.
  208. _inputfile = os.path.realpath( _args[0] )
  209. if not os.path.isfile( _inputfile ):
  210. raise Exception( u'[ERROR] El fichero de entrada no existe' )
  211. # - Directorio de destino.
  212. _outputdir = os.path.realpath( _args[1] )
  213. if not os.path.isdir( _outputdir ):
  214. try:
  215. # Si no existe lo creamos.
  216. os.mkdir( _outputdir )
  217. except:
  218. raise Exception( u'[ERROR] El directorio de salida no existe' )
  219. # =============================
  220. # Extraemos el audio y el video
  221. # =============================
  222. _demux = Demultiplexer( inputfile = _inputfile,
  223. outputdir = _outputdir,
  224. ini = _options.ini,
  225. end = _options.end)
  226. if _options.audio:
  227. _demux.getaudio()
  228. if _options.video:
  229. _demux.getvideo()