73 args = parse_arguments()
74 validate_arguments(args)
75 args.output.parent.mkdir(parents=True, exist_ok=True)
76
77 encoders = mxwrite_ext.available_video_encoders()
78 matching_encoders = [encoder for encoder in encoders if encoder.name == args.codec]
79 print(f"MXWrite reported {len(encoders)} video encoder(s).")
80 if matching_encoders:
81 encoder = matching_encoders[0]
82 mode = "hardware" if encoder.hardware else "software"
83 print(f"Using {encoder.name} ({encoder.long_name}, {mode}).")
84 options = mxwrite_ext.video_encoder_options(encoder.name)
85 print(f"The encoder exposes {len(options)} configurable option(s).")
86 elif args.codec not in {
87 "auto",
88 "software",
89 "cpu",
90 "x264",
91 "h264",
92 "hevc",
93 "h265",
94 "nvenc",
95 }:
96 names = ", ".join(encoder.name for encoder in encoders[:12])
97 raise SystemExit(
98 f"Requested encoder '{args.codec}' is unavailable. "
99 f"Available encoders include: {names}"
100 )
101
102 encode_options = mxwrite_ext.EncodeOptions()
103 encode_options.codec = args.codec
104 encode_options.preset = args.preset
105 encode_options.crf = args.crf
106 encode_options.block_when_full = True
107
108 writer = mxwrite_ext.Writer()
109 open_method = writer.open_ts if args.explicit_pts else writer.open
110 if not open_method(
111 str(args.output), args.width, args.height, float(args.fps), encode_options
112 ):
113 raise SystemExit(f"MXWrite could not open {args.output}")
114
115 x_coordinates = np.linspace(0.0, 1.0, args.width, dtype=np.float32)[None, :]
116 y_coordinates = np.linspace(0.0, 1.0, args.height, dtype=np.float32)[:, None]
117
118 try:
119 for frame_index in range(args.frames):
120 frame = make_frame(
121 x_coordinates, y_coordinates, frame_index, args.frames
122 )
123 if args.explicit_pts:
124 writer.write_at_pts(frame, frame_index)
125 else:
126 writer.write(frame)
127 finally:
128 writer.close()
129
130 frame_count = writer.get_frame_count()
131 duration = writer.get_duration()
132 byte_count = writer.get_bytes_written()
133 file_size = args.output.stat().st_size if args.output.is_file() else 0
134 expected_duration = args.frames / args.fps
135
136 if frame_count != args.frames:
137 raise SystemExit(f"Expected {args.frames} frames, but MXWrite reported {frame_count}.")
138 if not math.isclose(
139 duration, expected_duration, rel_tol=0.0, abs_tol=1.0 / args.fps
140 ):
141 raise SystemExit(
142 f"Expected about {expected_duration:.3f}s, "
143 f"but MXWrite reported {duration:.3f}s."
144 )
145 if file_size == 0:
146 raise SystemExit(f"MXWrite did not create a non-empty file at {args.output}.")
147
148 print(
149 f"PASS: wrote {frame_count} frames, {duration:.3f}s, "
150 f"{file_size} filesystem bytes to {args.output}"
151 )
152 print(f"MXWrite's muxer byte counter reported {byte_count} bytes.")
153
154