1#!/usr/local/bin/python3.8 2 3 4import locale 5locale.setlocale(locale.LC_NUMERIC,"C") 6 7""" 8lives_avi_encoder3 9 10Front-end to various programs needed to create AVI 11movies with some image-enhancing capabilities through the use of 12ImageMagick. Meant as a companion to LiVES (to possibly call 13from within a plugin, see http://www.xs4all.nl/~salsaman/lives/ ) 14but can also be used as a stand-alone program. 15 16Requires MPlayer, ImageMagick (GraphicsMagick might also 17work), sox, lame, and Python 2.3.0 or greater. Note that 18this program can encode a SNOW video stream (if mencoder 19supports it), but that it is still highly experimental. 20This is also true for h.264. Use at your own risk. 21 22Copyright (C) 2004-2005 Marco De la Cruz (marco@reimeika.ca) 23It's a trivial program, but might as well GPL it, so see: 24http://www.gnu.org/copyleft/gpl.html for license. 25 26See my vids at http://amv.reimeika.ca ! 27 28Copyright (C) 2008 - 2018 Salsaman (salsaman+lives@gmail.com) 29""" 30import os 31version = '0.0.19' 32if os.name == 'nt': 33 convert = 'mgkvert' 34else: 35 convert = 'convert' 36mencoder = 'mencoder' 37lameenc = 'lame' 38sox = 'sox' 39 40usage = \ 41 """ 42lives_avi_encoder3 -h 43lives_avi_encoder3 -V 44lives_avi_encoder3 -C 45lives_avi_encoder3 [-o out] [-p pre] [-d dir] [-a aspect] [-D delay] 46 [-q|-v] [-t type] [-k] [-e [[-w dir] [-c geom] [-r geom]]] 47 [-s sndfile] [-b sndrate] [-f fpscode] [-L lv1file] 48 [firstframe lastframe] 49 """ 50 51help = \ 52 """ 53SUMMARY (ver. %s): 54 55Encodes a series of PNG or JPG images into an XviD/Snow/h.264 + MP3 56(AVI) stream and is also capable of performing some simple image 57enhacements using ImageMagick. The images and audio are assumed to 58be in an uncompressed LiVES format, hence making this encoder 59more suitable to be used within a LiVES plugin (but can also 60be used directly on a LiVES temporary directory). 61 62OPTIONS: 63 64-h for help. 65 66-V shows the version number. 67 68-C check external program dependencies and exit. 69 70-o out will save the video in file "out". 71 Default: "'type'_movie.avi". See below for 'type'. 72 73-p pre the encoder assumes that sound and images are named using 74 LiVES' conventions i.e. "audio" and "00000001.ext", 75 "00000002.ext"... where "ext" is either "jpg" or "png". 76 However, lives_avi_encoder3 will create temporary files 77 which can be saved for later use (for example, after 78 enhancing the images with "-e" , which may take a long 79 time). These temporary files will be named 80 "pre_00000001.ext", etc... where "pre" is either "eimg" 81 or "rimg" and will be kept if the "-k" option is used. 82 lives_avi_encoder3 can then be run over the enhanced images 83 only by selecting the appropriate prefix ("eimg" or 84 "rimg") here. See "-e" to see what each prefix means. 85 Default: "" (an empty string). 86 87-d dir "dir" is the directory containing the source image 88 files. These must be of the form "00000001.ext" or 89 "pre_00000001.ext" as explained above. 90 Default: "." 91 92-a aspect sets the aspect ratio of the resulting MPEG-4. This can be: 93 94 1 1:1 display 95 2 4:3 display 96 3 16:9 display 97 4 2.21:1 display 98 99 Default: "2" 100 101-D delay delay the audio stream by "delay" ms. Must be positive. 102 Default: "0" 103 104-q quiet operation, only complains on error. 105 106-v be verbose. 107 108-t type type of video created. The options here are: 109 110 "hi": a very high quality XviD file, suitable 111 for archiving images of 720x480. 112 113 "mh": medium-high quality XviD, which still allows 114 to watch small videos (352x240 and below) 115 fullscreen. 116 117 "ml": medium-low quality XviD, suitable for 118 most videos but in particular small videos 119 (352x240 and below) meant for online 120 distribution. 121 122 "lo": a low quality XviD format. Enlarging 123 small videos will result in noticeable 124 artifacts. Good for distributing over slow 125 connections. 126 127 "hi_x", "mh_x", "ml_x", "lo_x": same as above. 128 129 "hi_h", "mh_h", "ml_h", "lo_h": same as above, but 130 using the h.264 codec. 131 132 "hi_s", "mh_s", "ml_s", "lo_s": same as above, but 133 the experimental 134 SNOW codec. 135 136 Default: "ml" 137 138-e perform some simple filtering/enhancement to improve image 139 quality. The images created by using this option will be 140 stored in the directory specified by the "-w" option (or 141 "-d" if not present, see above) and each filename will be 142 prefixed with "eimg" (see "-p" above). Using this option will 143 take enormous amounts of disk space, and in reality does 144 not do anything that cannot be done within LiVES itself. 145 Using this option enables the following four: 146 147 -w dir "dir" is the working directory where the enhanced 148 images will be saved. Although these can all 149 co-exist with the original LiVES files it is 150 recommended you use a different directory. Note 151 that temporary files may take a huge amount of 152 space, perhaps twice as much as the LiVES files 153 themselves. If this directory does not exist is 154 will be created. 155 Default: same as "-d". 156 157 -k keep the temporary files, useful to experiment 158 with different encoding types without having 159 to repeatedly enhance the images (which can be 160 very time-consuming). See "-p" above. 161 162 -c geom in addition to enhancing the images, crop them 163 to the specified geometry e.g. "688x448+17+11". 164 Filename prefix remains "eimg". Note that the 165 dimensions of the images should both be multiples 166 of "16", otherwise some players may show artifacts 167 (such as garbage or green bars at the borders). 168 169 -r geom this will create a second set of images resulting 170 from resizing the images that have already been 171 enhanced and possibly cropped (if "-c" has been 172 specified). The geometry here is simple a new 173 image size e.g. "352x240!". This second set will have 174 filenames prefixed with the string "rimg" (see "-p" 175 above). Note that the dimensions of the images 176 should both be multiples of "16", otherwise some 177 players may show artifacts (such as garbage or 178 green bars at the borders). 179 180-s sndfile name of the audio file. Can be either raw "audio" or 181 "[/path/to/]soundfile.wav". 182 Default: "audio" inside "dir" as specified by "-d". 183 184-b sndrate sample rate of the sound file in Hertz. 185 Default: "44100". 186 187-f fpscode frame-rate code. Acceptable values are: 188 189 1 - 24000.0/1001.0 (NTSC 3:2 pulldown converted FILM) 190 2 - 24.0 (NATIVE FILM) 191 3 - 25.0 (PAL/SECAM VIDEO / converted FILM) 192 4 - 30000.0/1001.0 (NTSC VIDEO) 193 5 - 30.0 194 6 - 50.0 (PAL FIELD RATE) 195 7 - 60000.0/1001.0 (NTSC FIELD RATE) 196 8 - 60.0 197 198 If the input value is a float (e.g. 5.0, 14.555, etc.) 199 the encoder will use that as frame rate. 200 201 Default: "4". 202 203-L lv1file use the images stored in the LiVES file "lv1file" (e.g. 204 "movie.lv1"). Files will be extracted inside "dir" as 205 specified by "-d". Using this option allows to encode 206 a movie without having to restore it first with LiVES. 207 Note that the encoder will not delete the extracted 208 files after it has finished, this must be done manually 209 afterwards. If frame code/rate (-f) and/or sound rate (-b) 210 are not specified the defaults will be used (30000/1001 fps 211 and 44100 Hz). These, however, may not be correct, in which 212 case they should be specified explicitly. Furthermore, the 213 .lv1 audio (if present) is always assumed to have a sample 214 data size in 16-bit words with two channels, and to be signed 215 linear (this is usually the case, however). If any of these 216 latter parameters are incorrect the resulting file may be 217 corrupted and encoding will have to be done using LiVES. 218 219firstframe first frame number. If less than eight digits long it will 220 be padded with zeroes e.g. 234 -> 00000234. A prefix can 221 be added using the "-p" option. 222 Default: "00000001" 223 224lastframe last frame number, padded with zeroes if necessary, prefix 225 set by "-p". 226 Default: the last frame of its type in the "-d" directory, 227 where "type" is set by the prefix. 228 229Note that either no frames or both first and last frames must be specified. 230 231EXAMPLES: 232 233Suppose you have restored a LiVES' .lv1 file (in either JPG or PNG format), 234and that the images are stored in the directory "/tmp/livestmp/991319584/". 235In this example the movie is assumed to be 16:9. Then, in order to create 236an AVI file you can simply do the following: 237 238 lives_avi_encoder3 -d /tmp/livestmp/991319584 -o /movies/default.avi -a 3 239 240and the clip "default.avi" will be created in "/movies/" with the correct 241aspect ratio. 242 243Suppose we want to make a downloadable version of the clip, small in size 244but of good quality. The following command activates the generic enhancement 245filter and resizes the images to "352x240". Note that these operations 246are performed after cropping the originals a bit (using "704x464+5+6"). 247This is done because we are assuming that there is a black border around 248the original pictures which we want to get rid of (this might distort the 249images somewhat, so be careful about cropping/resizing, and remember to 250use dimensions which are multiples of 16): 251 252 lives_avi_encoder3 -v -d /tmp/livestmp/991319584 -w /tmp/tmpavi \\ 253 -o /movies/download.avi -a 3 -k -e -c "704x464+5+6" -r "352x240" 254 255Since we use the "-k" flag the enhanced images are kept (both full-size 256crops and the resized ones) in "/tmp/tmpavi". Beware that this may consume 257a lot of disk space (about 10x as much as the originals). The reason we 258keep them is because the above may take quite a long time and we may want 259to re-use the enhanced images. So, for example, creating a high-quality 260clip at full size can be accomplished now as follows: 261 262 lives_avi_encoder3 -d /tmp/tmpavi -t hi -o /movies/archive.avi \\ 263 -s /tmp/livestmp/991319584/audio -a 3 -k -p eimg 264 265If, for example, we only want to encode frames 100 to 150 we can run 266the following: 267 268 lives_avi_encoder3 -v -d /tmp/tmpavi -o /movies/selection.avi \\ 269 -a 3 -k -p eimg 100 150 270 271Note that no audio has been selected ("-s"). This is because 272lives_avi_encoder3 cannot trim the audio to the appropriate length. 273You would need to use LiVES to do this. 274 275To delete all the enhanced images you can just remove "/tmp/tmpavi". 276 277If you notice that the video and audio become out of sync so that 278near the end of the movie the video trails the audio by, say, 0.2s, 279you can use the "-D" option as follows: 280 281 lives_avi_encoder3 -d /tmp/livestmp/991319584 -o test.avi -D 200 282 283Suppose that you have "movie1.lv1", "movie2.lv1" and "movie3.lv1". 284Batch-encoding can be done as follows (zsh-syntax): 285 286 for i in movie?.lv1 287 do 288 mkdir /tmp/$i:r 289 lives_avi_encoder3 -d /tmp/$i:r -o /tmp/$i:r.avi -L $i 290 rm -rf /tmp/$i:r 291 done 292 293This will generate the files "movie1.avi", "movie2.avi" and 294"movie3.avi" in "/tmp". Note that is is not necessary to 295specify whether the files are stored in JPG or PNG format, 296and that potentially time-consuming options (e.g. "-e") may 297be enabled. It is not necessary to have a working LiVES 298installation to encode .lv1 files. 299 """ % version 300 301def run(command): 302 """ 303 Run a shell command 304 """ 305 306 if verbose: 307 print('Running: \n' + command + '\n=== ... ===') 308 std = '' 309 else: 310 std = ' > /dev/null 2>&1' 311 312 os.system(command + std) 313 314 315def do_enhance(): 316 """ 317 Image cleanup/crop/resize routine. Generic, but seems to work 318 well with anime :) 319 """ 320 321 if not quiet: 322 print('Enhancing images... please wait, this might take long...') 323 324 enh_opts = "-enhance -sharpen '0.0x0.5' -gamma 1.2 -contrast -depth 8" 325 326 if cgeom: 327 docrop = ' '.join(['-crop', "'%s!'" % cgeom]) 328 else: 329 docrop = '' 330 331 iframe = first_num 332 while True: 333 # File names are padded with zeroes to 8 characters 334 # (not counting the .ext). 335 frame = str(iframe).zfill(8) 336 fname = os.path.join(img_dir, frame + ext) 337 if not os.path.isfile(fname) or (iframe == last_num + 1): 338 break 339 eimg_fname = os.path.join(work_dir, 'eimg' + frame + '.png') 340 rimg_fname = os.path.join(work_dir, 'rimg' + frame + '.png') 341 command = ' '.join([convert, docrop, enh_opts, fname, eimg_fname]) 342 run(command) 343 if rgeom: 344 if os.path.exists(rimg_fname): os.remove(rimg_fname) 345 shrink = ' '.join([convert, '-resize', "'%s!'" % rgeom, '-depth 8']) 346 command = ' '.join([shrink, eimg_fname, rimg_fname]) 347 run(command) 348 else: 349 if os.path.exists(rimg_fname): os.remove(rimg_fname) 350 try: 351 os.symlink(eimg_fname, rimg_fname) 352 except (IOError, OSError): 353 shutil.copy(eimg_fname, rimg_fname) 354 iframe+=1 355 356 357def do_encode(): 358 """ 359 Encode a series of images into an XviD/Snow or h.264 stream, multiplexing 360 audio if necessary 361 """ 362 363 if not quiet: 364 print('Creating "%s"-quality video' % vtype) 365 366 if verbose: 367 std = '' 368 lameinfo = '--verbose' 369 meinfo = '-v' 370 hinfo = ':log=-1' 371 else: 372 std = ' > /dev/null 2>&1' 373 lameinfo = '--quiet' 374 meinfo = '-quiet' 375 hinfo = '' 376 377 common_vopts = meinfo + ' -mf type=%s:fps=%s -mc 0 -noskip ' % (ext[1:], fps) + \ 378 '-vf hqdn3d=2:1:3,pp=va:128:8/ha:128:8/dr,dsize=%s' % aspect 379 380 if vtype[-1] == 's': 381 codec_vopts = '-ovc lavc -lavcopts ' + \ 382 'vcodec=snow:vstrict=-2:mbcmp=1:subcmp=1:cmp=1:mbd=2:v4mv' + \ 383 ':qpel:pred=1:autoaspect:vqscale=' 384 cpass = '' 385 elif vtype[-1] == 'h': 386 codec_vopts = '-ovc x264 -x264encopts ' + \ 387 'frameref=15:subq=5' + hinfo + \ 388 ':bitrate=' 389 cpass = 'pass=' 390 else: 391 codec_vopts = '-ovc xvid -xvidencopts qpel:chroma_me:chroma_opt' + \ 392 ':max_bframes=1:autoaspect:hq_ac:vhq=4:bitrate=' 393 cpass = 'pass=' 394 395 vqual = vtype[0:-2] 396 if vqual == 'hi': 397 if vtype[-1] == 'x': rate = '2000:' 398 if vtype[-1] == 's': rate = '2' 399 if vtype[-1] == 'h': rate = '2000:' 400 mencoder_opts = ' '.join([common_vopts, codec_vopts + rate + cpass]) 401 lameenc_opts = '--vbr-new -h -V 0' 402 elif vqual == 'mh': 403 if vtype[-1] == 'x': rate = '1000:' 404 if vtype[-1] == 's': rate = '3' 405 if vtype[-1] == 'h': rate = '1000:' 406 mencoder_opts = ' '.join([common_vopts, codec_vopts + rate + cpass]) 407 lameenc_opts = '--vbr-new -h -V 2' 408 elif vqual == 'ml': 409 if vtype[-1] == 'x': rate = '500:' 410 if vtype[-1] == 's': rate = '4' 411 if vtype[-1] == 'h': rate = '500:' 412 mencoder_opts = ' '.join([common_vopts, codec_vopts + rate + cpass]) 413 lameenc_opts = '--vbr-new -h -V 4' 414 elif vqual == 'lo': 415 if vtype[-1] == 'x': rate = '200:' 416 if vtype[-1] == 's': rate = '6' 417 if vtype[-1] == 'h': rate = '200:' 418 mencoder_opts = ' '.join([common_vopts, codec_vopts + rate + cpass]) 419 lameenc_opts = '--vbr-new -h -V 6' 420 421 422 if img_dir != work_dir and not enhance: 423 source_dir = img_dir 424 else: 425 source_dir = work_dir 426 427 if frame_range: 428 frame_list = [img_pre + str(f).zfill(8) + ext \ 429 for f in range(first_num, last_num + 1)] 430 syml = 'temporary_symlink_' 431 for iframe in frame_list: 432 frfile = os.path.join(source_dir, iframe) 433 frlink = os.path.join(source_dir, syml + iframe) 434 if os.path.islink(frlink): os.remove(frlink) 435 try: 436 os.symlink(frfile, frlink) 437 except (IOError, OSError): 438 shutil.copy(frfile, frlink) 439 else: 440 syml = '' 441 442 aviopts = '-of avi -force-avi-aspect %s -ofps %s' % (aspect, fps) 443 444 all_vars = {} 445 all_vars.update(globals()) 446 all_vars.update(locals()) 447 448 if audio: 449 if not quiet: 450 print('Creating "%s"-quality mp3 file' % vtype) 451 452 mp3 = tempfile.mkstemp('.mp3', '', work_dir)[1] 453 if rawsndf: 454 wav = tempfile.mkstemp('.wav', '', work_dir)[1] 455 sox_opts = '-t raw -r %s -w -c 2 -s' % sndr 456 command = ' '.join([sox, sox_opts, sndf, wav]) 457 run(command) 458 else: 459 wav = sndf 460 command = ' '.join([lameenc, lameinfo, lameenc_opts, wav, mp3]) 461 run(command) 462 463 avimp3 = '-audiofile %s -oac copy -audio-delay %s' % (mp3, delay) 464 else: 465 wav = 'dummy' 466 mp3 = 'dummy' 467 avimp3 = '-nosound' 468 469 all_vars.update(locals()) 470 471 if not quiet: print('Encoding and multiplexing...') 472 if vtype[-1] == 's': 473 command = """cd %(source_dir)s ; \\ 474%(mencoder)s %(aviopts)s %(avimp3)s "mf://%(syml)s%(img_pre)s*%(ext)s" %(mencoder_opts)s -o "%(vidname)s" %(std)s""" % all_vars 475 run(command) 476 else: 477 command = """cd %(source_dir)s ; \\ 478%(mencoder)s %(aviopts)s -nosound "mf://%(syml)s%(img_pre)s*%(ext)s" %(mencoder_opts)s1 -o /dev/null %(std)s ; \\ 479%(mencoder)s %(aviopts)s %(avimp3)s "mf://%(syml)s%(img_pre)s*%(ext)s" %(mencoder_opts)s2 -o "%(vidname)s" %(std)s 480""" % all_vars 481 run(command) 482 483 if os.path.exists(os.path.join(source_dir, 'divx2pass.log')): 484 os.remove(os.path.join(source_dir, 'divx2pass.log')) 485 if os.path.exists(os.path.join(source_dir, 'xvid-twopass.stats')): 486 os.remove(os.path.join(source_dir, 'xvid-twopass.stats')) 487 if rawsndf and os.path.exists(wav): os.remove(wav) 488 if os.path.exists(mp3): os.remove(mp3) 489 490 if frame_range: 491 lframes = os.path.join(source_dir, syml) 492 for frame in glob.glob(lframes + '*'): 493 os.remove(frame) 494 495 496def do_clean(): 497 """ 498 Delete enhanced files 499 """ 500 501 if not quiet: 502 print('Deleting all enhanced images (if any)') 503 504 eframes = os.path.join(work_dir, 'eimg') 505 rframes = os.path.join(work_dir, 'rimg') 506 for frame in glob.glob(eframes + '*'): 507 os.remove(frame) 508 for frame in glob.glob(rframes + '*'): 509 os.remove(frame) 510 511 512def which(command): 513 """ 514 Finds (or not) a command a la "which" 515 """ 516 517 command_found = False 518 519 if command[0] == '/': 520 if os.path.isfile(command) and \ 521 os.access(command, os.X_OK): 522 command_found = True 523 abs_command = command 524 else: 525 path = os.environ.get('PATH', '').split(os.pathsep) 526 for dir in path: 527 abs_command = os.path.join(dir, command) 528 if os.path.isfile(abs_command) and \ 529 os.access(abs_command, os.X_OK): 530 command_found = True 531 break 532 533 if not command_found: 534 abs_command = '' 535 536 return abs_command 537 538 539def is_installed(prog): 540 """ 541 See whether "prog" is installed 542 """ 543 544 wprog = which(prog) 545 546 if wprog == '': 547 print(prog + ': command not found') 548 raise SystemExit(1) 549 else: 550 if verbose: 551 print(wprog + ': found') 552 553 554if __name__ == '__main__': 555 556 import os 557 import sys 558 import getopt 559 import shutil 560 import tempfile 561 import glob 562 import tarfile 563 564 try: 565 if sys.version_info[0:3] < (3, 0, 0): 566 raise SystemExit(1) 567 except: 568 print('You need Python 3.0.0 or greater to run me!') 569 raise SystemExit(1) 570 571 try: 572 (opts, args) = getopt.getopt(sys.argv[1:], \ 573 'ho:p:d:w:a:qvt:ekc:r:s:b:f:VCD:L:') 574 except: 575 print("Something's wrong. Try the '-h' flag.") 576 raise SystemExit(1) 577 578 opts = dict(opts) 579 580 if not opts and not args: 581 print(usage) 582 raise SystemExit(1) 583 584 if '-h' in opts: 585 print(usage + help) 586 raise SystemExit 587 588 if '-V' in opts: 589 print('lives_avi_encoder3 version ' + version) 590 raise SystemExit 591 592 if ('-v' in opts) or ('-C' in opts): 593 verbose = True 594 else: 595 verbose = False 596 597 if '-q' in opts: 598 quiet = True 599 verbose = False 600 else: 601 quiet = False 602 603 for i in [convert, mencoder, lameenc, sox]: 604 is_installed(i) 605 if '-C' in opts: raise SystemExit 606 607 img_pre = opts.get('-p', '') 608 609 if img_pre not in ['', 'eimg', 'rimg']: 610 print('Improper image name prefix.') 611 raise SystemExit(1) 612 613 temp_dir = '' 614 img_dir = opts.get('-d', '.') 615 img_dir = os.path.abspath(img_dir) 616 if ' ' in img_dir: 617 temp_dir = tempfile.mkdtemp('', '.lives-', '/tmp/') 618 try: 619 os.symlink(img_dir, temp_dir + '/img_dir') 620 except (IOError, OSError): 621 shutil.copy(img_dir, temp_dir + '/img_dir') 622 img_dir = temp_dir + '/img_dir' 623 624 if not os.path.isdir(img_dir): 625 print('The image source directory: ' + img_dir + \ 626 ' does not exist!') 627 raise SystemExit(1) 628 629 if len(args) not in [0, 2]: 630 print('If frames are specified both first and last ' + \ 631 'image numbers must be chosen.') 632 raise SystemExit(1) 633 elif len(args) == 0: 634 args = [None, None] 635 636 frame_range = False 637 if not args[0]: 638 first_frame_num = '1' 639 else: 640 frame_range = True 641 first_frame_num = args[0] 642 first_frame_num = first_frame_num.zfill(8) 643 first_num = int(first_frame_num) 644 645 if not args[1]: 646 last_frame_num = '99999999' 647 else: 648 last_frame_num = args[1] 649 last_frame_num = last_frame_num.zfill(8) 650 last_num = int(last_frame_num) 651 652 aspectc = opts.get('-a', '2') 653 654 if aspectc not in [str(i) for i in range(1,5)]: 655 print('Invalid aspect ratio.') 656 raise SystemExit(1) 657 else: 658 if aspectc == '1': aspect = 1.0/1.0 659 elif aspectc == '2': aspect = 4.0/3.0 660 elif aspectc == '3': aspect = 16.0/9.0 661 elif aspectc == '4': aspect = 2.21/1.0 662 663 vtype = opts.get('-t', 'ml') 664 665 out_avi = opts.get('-o', vtype + '_movie.avi') 666 667 if '_' not in vtype: 668 vtype = vtype + '_x' 669 670 if vtype not in ['hi_s', 'mh_s', 'ml_s', 'lo_s', \ 671 'hi_h', 'mh_h', 'ml_h', 'lo_h', \ 672 'hi_x', 'mh_x', 'ml_x', 'lo_x']: 673 print('Invalid video type.') 674 raise SystemExit(1) 675 676 fpsc = opts.get('-f', '4') 677 678 if fpsc not in [str(i) for i in range(1,9)]: 679 if not quiet: print('Invalid fps code, attempting float fps.') 680 foundfps = False 681 else: 682 if fpsc == '1': fps = 24000.0/1001.0 683 elif fpsc == '2': fps = 24.0 684 elif fpsc == '3': fps = 25.0 685 elif fpsc == '4': fps = 30000.0/1001.0 686 elif fpsc == '5': fps = 30.0 687 elif fpsc == '6': fps = 50.0 688 elif fpsc == '7': fps = 60000.0/1001.0 689 elif fpsc == '8': fps = 60.0 690 foundfps = True 691 692 if not foundfps: 693 try: 694 fps = locale.atof(fpsc) 695 if not quiet: print('Using fps = %s' % fps) 696 if fps > 0: foundfps = True 697 except: 698 pass 699 700 if not foundfps: 701 print('Invalid fps code or rate.') 702 raise SystemExit(1) 703 704 if '-e' not in opts: 705 enhance = False 706 else: 707 enhance = True 708 709 if enhance and img_pre: 710 print('Sorry, you cannot enhance already-enhanced images') 711 raise SystemExit(1) 712 713 if '-k' not in opts: 714 keep = False 715 else: 716 keep = True 717 718 cgeom = opts.get('-c', '') 719 rgeom = opts.get('-r', '') 720 721 if (cgeom or rgeom) and not enhance: 722 print('Missing "-e" option.') 723 raise SystemExit(1) 724 725 lv1file = opts.get('-L', None) 726 if lv1file: 727 if not quiet: print('Opening lv1 file...') 728 try: 729 lv1 = tarfile.open(os.path.abspath(lv1file)) 730 except: 731 print('This does not appear to be a valid LiVES file!') 732 raise SystemExit(1) 733 if 'header.tar' not in lv1.getnames(): 734 print('This does not appear to be a valid LiVES file!') 735 raise SystemExit(1) 736 for tfile in lv1.getmembers(): 737 lv1.extract(tfile, img_dir) 738 for tfile in glob.glob(os.path.join(img_dir, '*.tar')): 739 imgtar = tarfile.open(tfile) 740 for img in imgtar.getmembers(): 741 imgtar.extract(img, img_dir) 742 os.remove(tfile) 743 744 test_file = os.path.join(img_dir, img_pre + first_frame_num) 745 if os.path.isfile(test_file + '.jpg'): 746 ext = '.jpg' 747 elif os.path.isfile(test_file + '.png'): 748 ext = '.png' 749 else: 750 print('Cannot find any appropriate %s or %s files!' % ('.jpg','.png')) 751 raise SystemExit(1) 752 first_frame = test_file + ext 753 last_frame = os.path.join(img_dir, img_pre + last_frame_num + ext) 754 755 if not quiet: print('Found: ' + first_frame) 756 757 work_dir = opts.get('-w', img_dir) 758 work_dir = os.path.abspath(work_dir) 759 if not os.path.isdir(work_dir): 760 if not quiet: print('Creating ' + work_dir) 761 try: 762 os.makedirs(work_dir) 763 os.chmod(work_dir, 755) 764 except: 765 print('Could not create the work directory ' + \ 766 work_dir) 767 raise SystemExit(1) 768 if ' ' in work_dir: 769 if temp_dir == '': 770 temp_dir = tempfile.mkdtemp('', '.lives-', '/tmp/') 771 try: 772 os.symlink(work_dir, temp_dir + '/work_dir') 773 except (IOError, OSError): 774 shutil.copy(work_dir, temp_dir + '/work_dir') 775 work_dir = temp_dir + '/work_dir' 776 777 sndf = opts.get('-s', os.path.join(img_dir, 'audio')) 778# sndf = os.path.abspath(sndf) 779 rawsndf = True 780 if not os.path.isfile(sndf): 781 audio = False 782 rawsndf = False 783 else: 784 audio = True 785 if sndf[-4:] == '.wav': 786 rawsndf = False 787 if not quiet: print('Found audio file: ' + sndf) 788 789 sndr = opts.get('-b', '44100') 790 791 # We use here mencoder's -audio-delay which is not really 792 # the true linear delay of the other plugins. See the mencoder 793 # man page. Negative values do not work. Must be in seconds. 794 delay = opts.get('-D', '0') 795 try: 796 delay = '%s' % (locale.atof(delay)/1000.0,) 797 except: 798 print('Invalid audio delay: ' + delay) 799 if verbose and audio: print('Audio delay (ms): ' + delay) 800 801 if enhance: 802 do_enhance() 803 # Note that do_enhance() always creates images prefixed 804 # with 'rimg'. What's important to note if that if the 805 # images are resized the 'rimg' are indeed resized, but 806 # if not the 'rimg' are simply symlinks to the 'eimg' 807 # (enhanced) images. 808 img_pre = 'rimg' 809 ext = '.png' 810 vidname = os.path.join(work_dir, out_avi) 811 # do_encode() acts on images prefixed by img_pre. 812 do_encode() 813 if not keep: 814 do_clean() 815 if temp_dir != '': 816 shutil.rmtree(temp_dir) 817 if not quiet: print("Done!") 818 819 820""" 821CHANGELOG: 822 82303 Jan 2005 : 0.0.1 : first release, based on mkv_encoder. 82404 Jan 2005 : 0.0.2 : added support for h.264. 82510 Mar 2005 : 0.0.3 : fixed snow quality settings. 82626 Mar 2005 : 0.0.4 : use env python (hopefully >= 2.3). 827 replace denoise3d with hqdn3d. 82824 Aug 2005 : 0.0.5 : fixed 2.21:1 aspect ratio. 829 fine-tune mplayer filters. 830 expanded h.264 bit rates. 83109 Mar 2006 : 0.0.6 : added '-depth 8' to resize, as ImageMagick 832 keeps changing its damn behaviour. 833 Fixed snow encoding (still highly experimental). 834 Fixed bitrate levels. 83513 Mar 2006 : 0.0.7 : tweaked bitrate levels. 83628 Jun 2007 : 0.0.8 : handles paths with spaces appropriately 837 (thanks Gabriel). 83808 Dec 2007 : 0.0.9 : added "-mc 0" and "-noskip" options. 839""" 840