1
2
3
4
5
6 import os.path as OP
7 import os, sys, tempfile, shutil, datetime, time, locale
8 from hachoir_core.error import HachoirError
9 from hachoir_core.cmd_line import unicodeFilename
10 from hachoir_parser import createParser
11
12 from hachoir_metadata import extractMetadata
13
14
15 local = locale.getdefaultlocale()[1]
16 webEncoding = "latin1"
17 fileEncoding = "UTF8"
18
19 VBitrate = 600
20 ABitRate = 64
21 x264opts = "subq=7:nr=100:me=umh:partitions=all:direct_pred=auto:b_pyramid:bframes=3:frameref=5 -ofps 24"
22 mplayer = "/usr/bin/mplayer"
23 mencoder = "/usr/bin/mencoder"
24 sox = "/usr/bin/sox"
25 convert = "/usr/bin/convert"
26 avimerge = "/usr/bin/avimerge"
27
28 VideoExts = [".avi", ".mpeg", ".mpg", ".mp4", ".divx", ".mov"]
29 ThumbExts = [".thm", ".jpg"]
30
31 RootDir = os.getcwd()
32 UpperDir = OP.split(RootDir)[0]
33
34
36 """main Video class"""
38 """initialise the class"""
39 self.FullPath = OP.abspath(infile)
40 print "Processing %s" % self.FullPath
41 [self.Path, self.Video] = OP.split(self.FullPath)
42 self.title = u""
43 self.Width = 0
44 self.Height = 0
45 self.Rotate = None
46 self.Duration = 0
47 self.Producer = "Imagizer"
48 self.data = {}
49 self.DateTime = datetime.datetime.fromtimestamp(OP.getmtime(self.FullPath))
50 self.LoadMetadata()
51 if self.Producer.lower().strip() in ["mencoder", "transcode", "imagizer"]:
52 if self.Video.lower().startswith("dscf") :self.Producer = "Fuji"
53 elif self.Video.lower().startswith("mvi_"):self.Producer = "Canon"
54 elif self.Video.lower().startswith("mov") :self.Producer = "Sony"
55 elif self.Video.lower().startswith("sdc") :self.Producer = "Samsung"
56 print "DEBUG", self.Video.lower(), self.Producer
57 dirname = OP.split(self.Path)[1]
58 dirdate = None
59 if len(dirname) >= 10:
60 if dirname[0] == "M": dirname = dirname[1:]
61 try:
62 dirdate = datetime.datetime.fromtimestamp(time.mktime(time.strptime(dirname[:10], "%Y-%m-%d")))
63 except:
64 pass
65 if dirdate:
66 if dirdate.date() < self.DateTime.date():
67 self.DateTime = datetime.datetime.combine(dirdate.date(), self.DateTime.time())
68 self.data["ICRD"] = self.DateTime.strftime("%Y-%m-%d")
69 self.data["ISRF"] = self.Producer
70 self.data["IARL"] = self.Video.replace("-H264", "")
71 self.CommentFile = OP.splitext(self.FullPath.replace(" ", "_"))[0] + ".txt"
72 if OP.isfile(self.CommentFile):
73 for l in open(OP.splitext(self.FullPath.replace(" ", "_"))[0] + ".txt").readlines():
74 if len(l) > 2:
75 k, d = l.decode(fileEncoding).split(None, 1)
76 self.data[k] = d.strip()
77 self.Date = datetime.datetime.fromtimestamp(time.mktime(time.strptime(self.data["ICRD"], "%Y-%m-%d")))
78 if self.Date.date < self.DateTime.date:
79 self.DateTime = datetime.datetime.combine(self.Date.date(), self.DateTime.time())
80 self.Producer = self.data["ISRF"]
81
83 """Returns some information on the current video flux"""
84 txt = u"%s\n" % self.Video
85 txt += "Producer: %s\tWidth= %i\tHeigth= %i\n" % (self.Producer, self.Width, self.Height)
86 txt += "Type: %s,\t title:%s\n" % (type(self.title), self.title)
87 for i in self.data:
88 txt += "\t%s:\t%s\n" % (i, self.data[i])
89 return txt
90
92 if not OP.isdir("%s/%s" % (UpperDir, self.DateTime.date().isoformat())):
93 os.mkdir("%s/%s" % (UpperDir, self.DateTime.date().isoformat()))
94 self.DestFile = os.path.join(UpperDir, self.DateTime.date().isoformat(), "%s-%s.avi" % (self.DateTime.strftime("%Hh%Mm%Ss"), self.Producer))
95 if OP.isfile(self.DestFile):
96 print "*" * 80 + "\n** Warning Destination file exists ! **\n" + "*" * 80
97
170
183
185 """scan the current directory for the thumbnail image"""
186 for i in os.listdir(self.Path):
187 b, e = OP.splitext(i)
188 if self.Video.find(b) == 0 and e.lower() in ThumbExts:
189 self.Thumb = i
190 filename = OP.join(self.Path, self.Thumb)
191 filename, realname = unicodeFilename(filename), filename
192 parser = createParser(filename, realname)
193 try:
194 exif = extractMetadata(parser)
195 except:
196 return
197 try:
198 self.Rotate = exif.get("image_orientation")
199 except:
200 self.Rotate = None
201 print self.Rotate
202 ThmDate = exif.get("creation_date")
203 if (self.DateTime - ThmDate).days > 0:self.DateTime = ThmDate
205 """Plays the video using mplayer, tries to rotate the video of needed"""
206 if self.Rotate:
207 if self.Rotate == u"Rotated 90 clock-wise":
208 os.system('mplayer -vf rotate=1 "%s"' % self.FullPath)
209 elif self.Rotate == u"Rotated 90 counter clock-wise":
210 os.system('mplayer -vf rotate=2 "%s"' % self.FullPath)
211 else:
212 os.system('mplayer "%s"' % self.FullPath)
213 else:
214 os.system('mplayer "%s"' % self.FullPath)
215 rotate = raw_input("What rotation should be applied to the file ? [0] ")
216 rotate = rotate.strip().lower().decode(local)
217 print rotate
218 if rotate in ["90", "cw"]:
219 self.Rotate = u"Rotated 90 clock-wise"
220 elif rotate in ["-90", "270", "ccw"]:
221 self.Rotate = u"Rotated 90 counter clock-wise"
222 else:
223 self.Rotate = u"Horizontal (normal)"
225 """asks for a Title and comments for the video"""
226 print "Processing file %s" % self.FullPath
227 print "Producer : %s" % self.Producer
228 if self.data.has_key("INAM"):
229 print "Former title: %s" % self.data["INAM"]
230 title = raw_input("Title (INAM): ").decode(local)
231 if len(title) > 0:
232 self.data["INAM"] = title.strip()
233 if self.data.has_key("IKEY"):
234 print "Former keywords: " + "\t".join(self.data["IKEY"].split(";"))
235 keywords = raw_input("Keywords (IKEY): ").decode(local).split()
236 if len(keywords) > 0:
237 self.data["IKEY"] = ";".join(keywords)
238 f = open(self.CommentFile, "w")
239 for i in self.data:
240 f.write((u"%s %s\n" % (i, self.data[i])).encode(fileEncoding))
241 f.close()
242
244 """re-encode the video to the given quality"""
245 if self.Rotate:
246 if self.Rotate == u"Rotated 90 clock-wise":
247 rotate = " -vf rotate=1 "
248 elif self.Rotate == u"Rotated 90 counter clock-wise":
249 rotate = " -vf rotate=2 "
250 else:
251 rotate = " "
252 DoAudio = (self.AudioCodec.lower().find("pcm") >= 0)
253
254 DoVideo = (not (self.VideoCodec.lower().find("h264") >= 0 or self.VideoCodec.lower().find("avc1") >= 0)) or self.Video.lower().endswith(".mov")
255 print "DoAudio=%s\tDoVideo=%s" % (DoAudio, DoVideo)
256 if DoAudio:
257 __, rawaudio = tempfile.mkstemp(suffix=".raw")
258 os.system(mplayer + " %s -dumpaudio -dumpfile %s " % (self.FullPath, rawaudio))
259 __, wavaudio = tempfile.mkstemp(suffix=".wav")
260 print "AudioSampleRate= %s" % self.AudioSampleRate
261 if self.AudioSampleRate == 44100:
262 os.system(sox + " -r %s -c %s -u -b -t raw %s -r 44100 %s " % (self.AudioSampleRate, self.AudioChannel, rawaudio, wavaudio))
263 else:
264 os.system(sox + " -r %s -c %s -u -b -t raw %s -r 44100 %s resample " % (self.AudioSampleRate, self.AudioChannel, rawaudio, wavaudio))
265
266 __, tmpavi = tempfile.mkstemp(suffix=".avi")
267 if False:
268
269 os.system(mencoder + rotate + " -nosound -ovc x264 -x264encopts bitrate=%s:pass=1:turbo=1:%s -o %s %s" % (VBitrate, x264opts, tmpavi, self.FullPath))
270 os.remove(tmpavi)
271 os.system(mencoder + rotate + " -nosound -ovc x264 -x264encopts bitrate=%s:pass=3:%s -o %s %s" % (VBitrate, x264opts, tmpavi, self.FullPath))
272 os.remove(tmpavi)
273 if DoAudio:
274 os.system(mencoder + rotate + "-oac mp3lame -lameopts mode=3:vbr=3:br=%s -audiofile %s -ovc x264 -x264encopts bitrate=%s:pass=3:%s -o %s %s " % (ABitRate, wavaudio, VBitrate, x264opts, tmpavi, self.FullPath))
275
276 else:
277 os.system(mencoder + rotate + "-oac copy -ovc x264 -x264encopts bitrate=%s:pass=3:%s -o %s %s" % (VBitrate, x264opts, tmpavi, self.FullPath))
278 if os.path.isfile("divx2pass.log"):os.remove("divx2pass.log")
279 if os.path.isfile("divx2pass.log.temp"):os.remove("divx2pass.log.temp")
280 else:
281 shutil.copy(self.FullPath, tmpavi)
282 print "%s -o %s -i %s -f %s" % (avimerge, self.DestFile, tmpavi, self.CommentFile)
283 os.system("%s -o %s -i %s -f %s" % (avimerge, self.DestFile, tmpavi, self.CommentFile))
284
285
287 """re-encode the video to the given quality, using the PBS queuing system"""
288 pbsFilename = os.path.splitext(self.FullPath.replace(" ", "_"))[0] + ".pbs"
289 pbsfile = open(pbsFilename, "w")
290 pbsfile.write("#!/bin/bash\nif [ -d /tmp/$PBS_JOBID ] ; then cd /tmp/$PBS_JOBID ;else cd /tmp; fi\n")
291 if self.Rotate:
292 if self.Rotate == u"Rotated 90 clock-wise":
293 rotate = " -vf rotate=1 "
294 elif self.Rotate == u"Rotated 90 counter clock-wise":
295 rotate = " -vf rotate=2 "
296 else:
297 rotate = " "
298 Resize = False
299 DoAudio = (self.AudioCodec.lower().find("pcm") >= 0)
300
301 DoResize = (self.Width > 640)
302 DoAudio = DoAudio or DoResize
303 DoVideo = DoResize or not (self.Video.lower().endswith(".avi"))
304 DoVideo = DoVideo or not (self.VideoCodec.lower().find("h264") >= 0 or self.VideoCodec.lower().find("avc1") >= 0)
305 if DoAudio:
306 newSampleRate = 44100
307 wavaudio = "audio-%s.wav" % newSampleRate
308 if (self.AudioSampleRate == 11024) and (self.AudioChannel == 1):
309 rawaudio = "audio-%s.raw" % self.AudioSampleRate
310 pbsfile.write(mplayer + ' "%s" -dumpaudio -dumpfile %s \n' % (self.FullPath, rawaudio))
311 pbsfile.write(sox + " -r %s -c %s -u -b -t raw %s -r 44100 %s resample \n" % (self.AudioSampleRate, self.AudioChannel, rawaudio, wavaudio))
312 pbsfile.write("rm %s \n" % rawaudio)
313 else:
314 rawaudio = "audio-%s.wav" % self.AudioSampleRate
315 pbsfile.write(mplayer + ' -ao pcm:fast:file=%s -vo null "%s" \n' % (rawaudio, self.FullPath))
316 if self.AudioSampleRate == 44100:
317 wavaudio = rawaudio
318 else:
319 pbsfile.write(sox + " %s -r %s %s resample \n" % (rawaudio, newSampleRate, wavaudio))
320 pbsfile.write("rm %s \n" % rawaudio)
321
322 tmpavi = "temporary.avi"
323 if DoResize:
324
325 Resize = " -vf scale=640:%i " % (self.Height * 640 / self.Width)
326
327 else:
328 Resize = " "
329 if DoVideo:
330 pbsfile.write(mencoder + rotate + Resize + ' -nosound -ovc x264 -x264encopts bitrate=%s:pass=1:turbo=1:%s -o %s "%s" \n' % (VBitrate, x264opts, tmpavi, self.FullPath))
331 pbsfile.write("rm %s \n" % tmpavi)
332 pbsfile.write(mencoder + rotate + Resize + ' -nosound -ovc x264 -x264encopts bitrate=%s:pass=3:%s -o %s "%s" \n' % (VBitrate, x264opts, tmpavi, self.FullPath))
333 pbsfile.write("rm %s \n" % tmpavi)
334 if DoAudio:
335 pbsfile.write(mencoder + rotate + Resize + ' -oac mp3lame -lameopts mode=3:vbr=3:br=%s -audiofile %s -ovc x264 -x264encopts bitrate=%s:pass=3:%s -o %s "%s" \n' % (ABitRate, wavaudio, VBitrate, x264opts, tmpavi, self.FullPath))
336 pbsfile.write("rm %s \n" % wavaudio)
337 else:
338 pbsfile.write(mencoder + rotate + Resize + '-oac copy -ovc x264 -x264encopts bitrate=%s:pass=3:%s -o %s "%s" \n' % (VBitrate, x264opts, tmpavi, self.FullPath))
339 pbsfile.write("if [ -f divx2pass.log ]; then rm divx2pass.log ; fi\n")
340 pbsfile.write("if [ -f divx2pass.log.temp ]; then rm divx2pass.log.temp ; fi\n")
341 else:
342 pbsfile.write("cp %s %s\n" % (self.FullPath, tmpavi))
343
344 pbsfile.write('%s -o %s -i %s -f "%s" \n' % (avimerge, self.DestFile, tmpavi, self.CommentFile))
345 pbsfile.write("rm %s \n" % tmpavi)
346 pbsfile.close()
347 os.system('qsub "%s"' % pbsFilename)
348
350 """Generate a thumbnail for the image"""
351 Thumbdir = tempfile.mkdtemp()
352 os.system("%s %s -vo jpeg:outdir=%s -ao null -frames 1 " % (mplayer, self.FullPath, Thumbdir))
353 self.ThumbName = OP.splitext(self.FullPath)[0] + "--Thumb.jpg"
354 os.system("%s -geometry %ix%i %s/*.jpg %s" % (convert, size, size, Thumbdir, self.ThumbName))
355 for i in os.listdir(Thumbdir):os.remove(OP.join(Thumbdir, i))
356 os.rmdir(Thumbdir)
357
358
359
360
361
362
363
365 """returns a list of the files with the given suffix in the given dir
366 files=os.system('find "%s" -iname "*.%s"'%(RootDir,suffix)).readlines()
367 """
368 files = []
369 for i in VideoExts:
370 files += parser().FindExts(RootDir, i)
371 good = []
372 l = len(RootDir) + 1
373 for i in files: good.append(i.strip()[l:])
374 good.sort()
375 return good
376
378 """this class searches all the jpeg files"""
381
383 """ append all the imagesfiles to the list, then goes recursively to the subdirectories"""
384 ls = os.listdir(curent)
385 for i in ls:
386 a = os.path.join(curent, i)
387 if os.path.isdir(a):
388 self.OneDir(a)
389 if os.path.isfile(a):
390 if i.lower().endswith(self.suffix):
391 self.imagelist.append(os.path.join(curent, i))
393 self.root = root
394 self.suffix = suffix
395 self.OneDir(self.root)
396 return self.imagelist
397
399 - def __init__(self, title="Test", enc="latin1", favicon=None):
400 self.txt = u""
401 self.enc = enc
402 self.header(title, enc, favicon)
404 self.txt += '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\n<html>\n<head>\n'
405 if favicon:
406 self.txt += '<link rel="icon" type="image/%s" href="%s" />\n' % (OP.splitext(favicon)[1][1:], favicon)
407 if enc:self.txt += '<content="text/html; charset=%s">\n' % enc
408 self.txt += "<title>%s</title>\n" % title
409 self.txt += "</head>\n"
412 - def write(self, filename):
413 self.footer()
414 f = open(filename, "w")
415 f.write(self.txt.encode(self.enc))
416 f.close()
417 - def start(self, tag, dico={}):
418 self.txt += "<%s" % tag
419 for i in dico:
420 self.txt += ' %s="%s" ' % (i, dico[i])
421 self.txt += " >\n"
422 - def stop(self, tag):
423 self.txt += "</%s>\n" % tag
424 - def data(self, donnee, cod=""):
425 if cod:
426 d = donnee.decode(cod)
427 else:
428 d = donnee
429 self.txt += d.replace(u"&", u"&").replace(u"<", u"<").replace(u">", u">").replace(u'\xb0', u"°").replace(u"\xb9", u"¹").replace(u"\xb2", u"²").replace(u"\xb3", u"³").replace(u"\xb5", u"µ")
430
431
432 - def element(self, tag, data="", cod=""):
436
438 cur = []
439 a = RootDir
440 while len(a) > 1:
441 a, b = os.path.split(a)
442 cur.append(b)
443 cur.reverse()
444 fil = []
445 a = Name
446 while len(a) > 1:
447 a, b = os.path.split(a)
448 fil.append(b)
449 fil.reverse()
450 newfil = []
451 for i in range(len(fil)):
452
453 if len(cur) < i + 1:newfil.append(fil[i])
454 elif fil[i] == cur[i]:continue
455 return OP.join(*tuple(newfil))
456
457
458
459
460
461
462
463
464 if __name__ == "__main__":
465 if len(sys.argv) > 1:
466 if OP.isdir(sys.argv[1]):
467 RootDir = sys.argv[1]
468 if sys.argv[0].lower().find("nommevideo") >= 0:
469 Action = "Rename"
470 elif sys.argv[0].lower().find("genhtml") >= 0:
471 Action = "GenHTML"
472 else:
473 Action = "DEBUG"
474 UpperDir = OP.split(RootDir)[0]
475 if Action == "Rename":
476 for filename in FindFile(RootDir):
477
478
479 vi = Video(filename)
480 vi.FindThumb()
481 vi.MkDir()
482 if not OP.isfile(vi.DestFile):
483 vi.PlayVideo()
484 print vi
485 vi.SetTitle()
486 vi.PBSRencode()
487 elif Action == "GenHTML":
488 videos = {}
489 for filename in FindFile(RootDir):
490 vi = Video(filename)
491 if not videos.has_key(vi.DateTime.date().isoformat()):
492 videos[vi.DateTime.date().isoformat()] = [vi]
493 else:
494 videos[vi.DateTime.date().isoformat()].append(vi)
495 date = videos.keys()
496 date.sort()
497 print date
498 html = HTML("Videos", enc=webEncoding)
499 html.start("body")
500 html.element("a name='begin'")
501
502 for i in date:
503 html.element("b", videos[i][0].DateTime.date().strftime("%A, %d %B %Y").capitalize().decode(local))
504 html.start("table", {"cellspacing":10})
505 for j in videos[i]:
506 j.GenThumb()
507 html.start("tr")
508 html.start("td", {"width":200})
509 print RelativeName(j.FullPath)
510 html.start("a", {"href":RelativeName(j.FullPath)})
511 thumb = RelativeName(j.ThumbName)
512 html.start("img", {"src":thumb, "alt":thumb})
513 html.stop("img")
514 html.stop("a")
515 html.stop("td")
516 html.start("td")
517 html.data(j.DateTime.time().strftime("%Hh%Mm%Ss").decode(local))
518 html.start("br")
519
520 html.data(u"Dur\xe9e %is" % j.Duration.seconds)
521 html.stop("td")
522 html.element("td", j.title)
523 html.stop("tr")
524 html.stop("table")
525 html.start("hr/")
526 html.element("a name='end'")
527 html.stop("body")
528 html.write("index.html")
529 for j in videos[i]:
530 print j.DateTime
531
532 else:
533 videos = {}
534 for filename in FindFile(RootDir):
535 vi = Video(filename)
536 if not videos.has_key(vi.DateTime.date().isoformat()):
537 videos[vi.DateTime.date().isoformat()] = [vi]
538 else:
539 videos[vi.DateTime.date().isoformat()].append(vi)
540 date = videos.keys()
541 date.sort()
542 print date
543 for i in date:
544 for j in videos[i]:
545 try:
546 print j
547 except:
548 print "error"
549 sys.stdout.write(j.__repr__())
550 print "#" * 50
551