ff.py 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import os
  2. import json
  3. import subprocess
  4. def probe_file(p):
  5. args = [
  6. 'ffprobe',
  7. '-loglevel', 'error',
  8. '-show_streams', '-show_format',
  9. '-print_format', 'json',
  10. '-i', p
  11. ]
  12. p = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  13. if p.returncode != 0:
  14. raise RuntimeError(p.stderr.replace('\n', ' '))
  15. data = json.loads(p.stdout)
  16. return data
  17. def extract_stream_props(probe):
  18. dur = int(round(float(probe['format']['duration'])))
  19. br = int(probe['format']['bit_rate'])
  20. title = None
  21. if 'tags' in probe['format']:
  22. tags = probe['format']['tags']
  23. if 'title' in tags:
  24. title = tags['title']
  25. for s in probe['streams']:
  26. if s['codec_type'] == 'video':
  27. return {
  28. 'title': title,
  29. 'res_w': s['width'],
  30. 'res_h': s['height'],
  31. 'duration_sec': dur,
  32. 'bitrate_bps': br,
  33. 'codec': s['codec_name'],
  34. }
  35. def reencode(src, dest, target_br_kbps, preset='veryfast', maxheight=1080, dryrun=False):
  36. baseargs = [
  37. 'ffmpeg',
  38. '-i', src,
  39. '-c:v', 'libx265',
  40. '-preset', preset,
  41. '-vf', 'scale=-1:\'min(%s,ih)\'' % maxheight,
  42. '-b:v', '%sk' % target_br_kbps,
  43. '-y',
  44. ]
  45. p1args = baseargs + [
  46. '-x265-params', 'pass=1',
  47. '-an',
  48. '-f', 'null',
  49. '/dev/null'
  50. ]
  51. p2args = baseargs + [
  52. '-map', '0',
  53. '-x265-params', 'pass=2',
  54. '-c:a', 'aac',
  55. '-b:a', '400k',
  56. '-c:s', 'copy',
  57. #'-c:d', 'copy',
  58. #'-c:t', 'copy',
  59. dest
  60. ]
  61. print('PASS1', ' '.join(p1args))
  62. if not dryrun:
  63. res1 = subprocess.run(p1args)
  64. res1.check_returncode()
  65. print('PASS2', ' '.join(p2args))
  66. if not dryrun:
  67. res2 = subprocess.run(p2args)
  68. res2.check_returncode()
  69. # Do cleanup
  70. if not dryrun:
  71. destdir = os.path.dirname(os.path.realpath(dest))
  72. for f in os.listdir(destdir):
  73. if f.startswith('x265_2pass.log'):
  74. os.unlink(os.path.join(destdir, f))