VideoProcessor.vala 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. using Gtk;
  2. using Adw;
  3. namespace Publicate.Video {
  4. public class VideoProcessor : Adw.Window {
  5. private ProgressBar progress_bar;
  6. private Label label;
  7. private Button cancel_button;
  8. public VideoProcessor() {
  9. this.resizable = false;
  10. var hbox = new Box(Orientation.HORIZONTAL, 8);
  11. hbox.margin_bottom = 18;
  12. hbox.margin_top = 18;
  13. hbox.margin_start = 18;
  14. hbox.margin_end = 18;
  15. var vbox = new Box(Orientation.VERTICAL, 8);
  16. hbox.append (vbox);
  17. content = hbox;
  18. label = new Label("Reading Video…");
  19. progress_bar = new ProgressBar ();
  20. cancel_button = new Button.from_icon_name ("process-stop-symbolic");
  21. // hbox.append(cancel_button);
  22. vbox.append (label);
  23. vbox.append(progress_bar);
  24. }
  25. public async VideoProcessResult? process_video(string path, ViewerWindow window) {
  26. this.modal = true;
  27. this.transient_for = window;
  28. present();
  29. var video_file = File.new_for_path(path);
  30. var video_info = new VideoInfo(video_file);
  31. yield video_info.read_info();
  32. var profiles = construct_vp9_profiles().concat(construct_theora_profiles());
  33. var use_profiles = profiles.where(p => p.suitable_for(video_info));
  34. use_profiles.iterate(p => p.setup_for(video_info));
  35. var encoders = use_profiles.select<Encoder>(p => new Encoder(video_file, "/tmp/", p)).to_sequence();
  36. foreach (var encoder in encoders) {
  37. encoder.progress_changed.connect((frac, done) => {
  38. var amount = frac;
  39. amount = amount / (double)encoders.count();
  40. Idle.add(() => { progress_bar.fraction += amount; return false; });
  41. });
  42. }
  43. progress_bar.fraction = 0.0;
  44. label.label = "Encoding Video…";
  45. yield encode_video(encoders);
  46. progress_bar.fraction = 1;
  47. label.label = "Writing PPUB…";
  48. var manifest = new Ppub.VideoManifest();
  49. manifest.streams = encoders.select<Ppub.VideoDescription>(e => e.get_video_description()).to_sequence();
  50. manifest.duration = video_info.duration;
  51. var ratio_parts = video_info.aspect_ratio.split(":");
  52. manifest.ratio = new double[] { double.parse(ratio_parts[0]), double.parse(ratio_parts[1]) };
  53. return new VideoProcessResult(manifest, encoders.select<File>(e => e.get_output_file()).to_sequence());
  54. }
  55. private async void encode_video(Invercargill.Enumerable<Encoder> encoders) {
  56. SourceFunc callback = encode_video.callback;
  57. ThreadFunc<bool> run = () => {
  58. encoders.parallel_iterate(e => e.encode());
  59. Idle.add((owned) callback);
  60. return true;
  61. };
  62. new Thread<bool>("encoder thread", run);
  63. yield;
  64. }
  65. public void complete() {
  66. close();
  67. }
  68. }
  69. public class VideoProcessResult {
  70. public Ppub.VideoManifest manifest { get; private set; }
  71. public Invercargill.Enumerable<File> video_files { get; private set; }
  72. public VideoProcessResult(Ppub.VideoManifest manifest, Invercargill.Enumerable<File> videos) {
  73. this.manifest = manifest;
  74. video_files = videos;
  75. }
  76. }
  77. }