1#![forbid(unsafe_code)]
7#![allow(dead_code)]
8
9use crate::frame::{FrameType, VideoFrame};
10use crate::multipass::{
11 allocation::AllocationStrategy, EncoderConfig, EncodingResult, MultiPassEncoder, PassType,
12};
13
14pub struct TwoPassExample {
19 width: u32,
20 height: u32,
21 target_bitrate: u64,
22 stats_file: String,
23}
24
25impl TwoPassExample {
26 #[must_use]
28 pub fn new(width: u32, height: u32, target_bitrate: u64) -> Self {
29 Self {
30 width,
31 height,
32 target_bitrate,
33 stats_file: "/tmp/multipass_stats.txt".to_string(),
34 }
35 }
36
37 pub fn run_first_pass(&self, frames: &[VideoFrame]) -> Result<(), String> {
39 let config = EncoderConfig::new(self.width, self.height)
41 .with_pass(PassType::FirstPass)
42 .with_target_bitrate(self.target_bitrate)
43 .with_stats_file(&self.stats_file);
44
45 let mut encoder = MultiPassEncoder::new(config);
46
47 for frame in frames {
49 encoder
50 .encode_frame(frame)
51 .map_err(|e| format!("First pass encoding failed: {}", e))?;
52 }
53
54 encoder
56 .save_stats(&self.stats_file)
57 .map_err(|e| format!("Failed to save stats: {}", e))?;
58
59 Ok(())
60 }
61
62 pub fn run_second_pass(&self, frames: &[VideoFrame]) -> Result<Vec<EncodingResult>, String> {
64 let config = EncoderConfig::new(self.width, self.height)
66 .with_pass(PassType::SecondPass)
67 .with_target_bitrate(self.target_bitrate)
68 .with_stats_file(&self.stats_file)
69 .with_lookahead_frames(40)
70 .with_allocation_strategy(AllocationStrategy::TwoPass);
71
72 let mut encoder = MultiPassEncoder::new(config);
73
74 encoder
76 .load_stats(&self.stats_file)
77 .map_err(|e| format!("Failed to load stats: {}", e))?;
78
79 let mut results = Vec::new();
80
81 for frame in frames {
83 if let Some(result) = encoder
84 .encode_frame(frame)
85 .map_err(|e| format!("Second pass encoding failed: {}", e))?
86 {
87 results.push(result);
88 }
89 }
90
91 Ok(results)
92 }
93}
94
95pub struct SinglePassLookaheadExample {
100 width: u32,
101 height: u32,
102 target_bitrate: u64,
103 lookahead_frames: usize,
104}
105
106impl SinglePassLookaheadExample {
107 #[must_use]
109 pub fn new(width: u32, height: u32, target_bitrate: u64, lookahead_frames: usize) -> Self {
110 Self {
111 width,
112 height,
113 target_bitrate,
114 lookahead_frames,
115 }
116 }
117
118 pub fn run(&self, frames: &[VideoFrame]) -> Result<Vec<EncodingResult>, String> {
120 let config = EncoderConfig::new(self.width, self.height)
122 .with_pass(PassType::SinglePassLookahead)
123 .with_target_bitrate(self.target_bitrate)
124 .with_lookahead_frames(self.lookahead_frames)
125 .with_allocation_strategy(AllocationStrategy::Perceptual);
126
127 let mut encoder = MultiPassEncoder::new(config);
128 let mut results = Vec::new();
129
130 for frame in frames {
132 if let Some(result) = encoder
133 .encode_frame(frame)
134 .map_err(|e| format!("Encoding failed: {}", e))?
135 {
136 results.push(result);
137 }
138 }
139
140 Ok(results)
141 }
142}
143
144pub struct VbvConstrainedExample {
149 width: u32,
150 height: u32,
151 target_bitrate: u64,
152 max_bitrate: u64,
153 buffer_size: u64,
154}
155
156impl VbvConstrainedExample {
157 #[must_use]
159 pub fn new(
160 width: u32,
161 height: u32,
162 target_bitrate: u64,
163 max_bitrate: u64,
164 buffer_size: u64,
165 ) -> Self {
166 Self {
167 width,
168 height,
169 target_bitrate,
170 max_bitrate,
171 buffer_size,
172 }
173 }
174
175 pub fn run(&self, frames: &[VideoFrame]) -> Result<(Vec<EncodingResult>, VbvReport), String> {
177 let config = EncoderConfig::new(self.width, self.height)
179 .with_pass(PassType::SinglePassLookahead)
180 .with_target_bitrate(self.target_bitrate)
181 .with_vbv(self.buffer_size, self.max_bitrate)
182 .with_lookahead_frames(40);
183
184 let mut encoder = MultiPassEncoder::new(config);
185 let mut results = Vec::new();
186
187 for frame in frames {
189 if let Some(result) = encoder
190 .encode_frame(frame)
191 .map_err(|e| format!("VBV encoding failed: {}", e))?
192 {
193 results.push(result);
194 }
195 }
196
197 let vbv_stats = encoder
199 .vbv_statistics()
200 .ok_or("VBV statistics not available")?;
201
202 let report = VbvReport {
203 is_compliant: vbv_stats.is_compliant(),
204 underflow_count: vbv_stats.underflow_count,
205 overflow_count: vbv_stats.overflow_count,
206 utilization: vbv_stats.utilization(),
207 };
208
209 Ok((results, report))
210 }
211}
212
213#[derive(Clone, Debug)]
215pub struct VbvReport {
216 pub is_compliant: bool,
218 pub underflow_count: u64,
220 pub overflow_count: u64,
222 pub utilization: crate::multipass::vbv::BufferUtilization,
224}
225
226pub struct SceneChangeExample {
231 width: u32,
232 height: u32,
233 scene_threshold: f64,
234 min_keyint: u32,
235 max_keyint: u32,
236}
237
238impl SceneChangeExample {
239 #[must_use]
241 pub fn new(width: u32, height: u32) -> Self {
242 Self {
243 width,
244 height,
245 scene_threshold: 0.4,
246 min_keyint: 10,
247 max_keyint: 250,
248 }
249 }
250
251 #[must_use]
253 pub fn with_params(mut self, threshold: f64, min_keyint: u32, max_keyint: u32) -> Self {
254 self.scene_threshold = threshold;
255 self.min_keyint = min_keyint;
256 self.max_keyint = max_keyint;
257 self
258 }
259
260 pub fn run(&self, frames: &[VideoFrame]) -> Result<SceneChangeReport, String> {
262 let config = EncoderConfig::new(self.width, self.height)
264 .with_pass(PassType::SinglePassLookahead)
265 .with_lookahead_frames(40)
266 .with_keyint_range(self.min_keyint, self.max_keyint);
267
268 let mut encoder = MultiPassEncoder::new(config);
269 let mut keyframe_positions = Vec::new();
270 let mut total_frames = 0;
271
272 for frame in frames {
274 if let Some(result) = encoder
275 .encode_frame(frame)
276 .map_err(|e| format!("Encoding failed: {}", e))?
277 {
278 if result.frame_type == FrameType::Key {
279 keyframe_positions.push(result.frame_index);
280 }
281 total_frames += 1;
282 }
283 }
284
285 let keyframe_count = keyframe_positions.len();
286 let avg_gop_length = if keyframe_count > 1 {
287 total_frames as f64 / keyframe_count as f64
288 } else {
289 total_frames as f64
290 };
291
292 let report = SceneChangeReport {
293 total_frames,
294 keyframe_count,
295 keyframe_positions,
296 avg_gop_length,
297 };
298
299 Ok(report)
300 }
301}
302
303#[derive(Clone, Debug)]
305pub struct SceneChangeReport {
306 pub total_frames: u64,
308 pub keyframe_count: usize,
310 pub keyframe_positions: Vec<u64>,
312 pub avg_gop_length: f64,
314}
315
316pub struct AdaptiveQuantizationExample {
321 width: u32,
322 height: u32,
323 target_bitrate: u64,
324}
325
326impl AdaptiveQuantizationExample {
327 #[must_use]
329 pub fn new(width: u32, height: u32, target_bitrate: u64) -> Self {
330 Self {
331 width,
332 height,
333 target_bitrate,
334 }
335 }
336
337 pub fn run(&self, frames: &[VideoFrame]) -> Result<AqReport, String> {
339 let lookahead = if frames.len() > 10 {
342 frames.len() / 3
343 } else {
344 10
345 };
346 let config = EncoderConfig::new(self.width, self.height)
347 .with_pass(PassType::SinglePassLookahead)
348 .with_target_bitrate(self.target_bitrate)
349 .with_lookahead_frames(lookahead)
350 .with_allocation_strategy(AllocationStrategy::Perceptual);
351
352 let mut encoder = MultiPassEncoder::new(config);
353 let mut qp_values = Vec::new();
354 let mut complexity_values = Vec::new();
355
356 for frame in frames {
358 if let Some(result) = encoder
359 .encode_frame(frame)
360 .map_err(|e| format!("AQ encoding failed: {}", e))?
361 {
362 qp_values.push(result.qp);
363 complexity_values.push(result.complexity);
364 }
365 }
366
367 let avg_qp = qp_values.iter().sum::<f64>() / qp_values.len() as f64;
369 let avg_complexity = complexity_values.iter().sum::<f64>() / complexity_values.len() as f64;
370
371 let min_qp = qp_values
372 .iter()
373 .copied()
374 .min_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
375 .unwrap_or(0.0);
376
377 let max_qp = qp_values
378 .iter()
379 .copied()
380 .max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
381 .unwrap_or(0.0);
382
383 let report = AqReport {
384 frame_count: qp_values.len(),
385 avg_qp,
386 min_qp,
387 max_qp,
388 qp_range: max_qp - min_qp,
389 avg_complexity,
390 };
391
392 Ok(report)
393 }
394}
395
396#[derive(Clone, Debug)]
398pub struct AqReport {
399 pub frame_count: usize,
401 pub avg_qp: f64,
403 pub min_qp: f64,
405 pub max_qp: f64,
407 pub qp_range: f64,
409 pub avg_complexity: f64,
411}
412
413pub struct AllocationComparisonExample {
418 width: u32,
419 height: u32,
420 target_bitrate: u64,
421}
422
423impl AllocationComparisonExample {
424 #[must_use]
426 pub fn new(width: u32, height: u32, target_bitrate: u64) -> Self {
427 Self {
428 width,
429 height,
430 target_bitrate,
431 }
432 }
433
434 pub fn run(&self, frames: &[VideoFrame]) -> Result<ComparisonReport, String> {
436 let strategies = [
437 AllocationStrategy::Uniform,
438 AllocationStrategy::Complexity,
439 AllocationStrategy::Perceptual,
440 ];
441
442 let mut results = Vec::new();
443
444 for strategy in &strategies {
445 let config = EncoderConfig::new(self.width, self.height)
446 .with_pass(PassType::SinglePassLookahead)
447 .with_target_bitrate(self.target_bitrate)
448 .with_lookahead_frames(40)
449 .with_allocation_strategy(*strategy);
450
451 let mut encoder = MultiPassEncoder::new(config);
452 let mut total_bits = 0u64;
453 let mut qp_values = Vec::new();
454
455 for frame in frames {
456 if let Some(result) = encoder
457 .encode_frame(frame)
458 .map_err(|e| format!("Comparison encoding failed: {}", e))?
459 {
460 total_bits += result.target_bits;
461 qp_values.push(result.qp);
462 }
463 }
464
465 let avg_qp = qp_values.iter().sum::<f64>() / qp_values.len() as f64;
466 let qp_variance = qp_values
467 .iter()
468 .map(|qp| (qp - avg_qp).powi(2))
469 .sum::<f64>()
470 / qp_values.len() as f64;
471
472 results.push(StrategyResult {
473 strategy: *strategy,
474 total_bits,
475 avg_qp,
476 qp_variance,
477 frame_count: qp_values.len(),
478 });
479 }
480
481 Ok(ComparisonReport { results })
482 }
483}
484
485#[derive(Clone, Debug)]
487pub struct ComparisonReport {
488 pub results: Vec<StrategyResult>,
490}
491
492#[derive(Clone, Debug)]
494pub struct StrategyResult {
495 pub strategy: AllocationStrategy,
497 pub total_bits: u64,
499 pub avg_qp: f64,
501 pub qp_variance: f64,
503 pub frame_count: usize,
505}
506
507impl ComparisonReport {
508 #[must_use]
510 pub fn most_consistent(&self) -> Option<&StrategyResult> {
511 self.results.iter().min_by(|a, b| {
512 a.qp_variance
513 .partial_cmp(&b.qp_variance)
514 .unwrap_or(std::cmp::Ordering::Equal)
515 })
516 }
517
518 #[must_use]
520 pub fn most_efficient(&self) -> Option<&StrategyResult> {
521 self.results.iter().min_by_key(|r| r.total_bits)
522 }
523}
524
525#[cfg(test)]
526mod tests {
527 use super::*;
528 use crate::frame::Plane;
529 use oximedia_core::{PixelFormat, Rational, Timestamp};
530
531 fn create_test_frames(count: usize) -> Vec<VideoFrame> {
532 (0..count)
533 .map(|i| {
534 let mut frame = VideoFrame::new(PixelFormat::Yuv420p, 320, 240);
535 let size = 320 * 240;
536 let data = vec![(i % 256) as u8; size];
537 frame.planes.push(Plane::new(data, 320));
538 frame.timestamp = Timestamp::new(i as i64, Rational::new(1, 30));
539 frame
540 })
541 .collect()
542 }
543
544 #[test]
545 fn test_single_pass_lookahead_example() {
546 let example = SinglePassLookaheadExample::new(320, 240, 1_000_000, 20);
547 let frames = create_test_frames(30);
548 let result = example.run(&frames);
549 assert!(result.is_ok());
550 }
551
552 #[test]
553 fn test_scene_change_example() {
554 let example = SceneChangeExample::new(320, 240);
555 let frames = create_test_frames(50);
556 let result = example.run(&frames);
557 assert!(result.is_ok());
558 }
559
560 #[test]
561 fn test_adaptive_quantization_example() {
562 let example = AdaptiveQuantizationExample::new(320, 240, 1_000_000);
563 let frames = create_test_frames(30);
564 let result = example.run(&frames);
565 assert!(result.is_ok());
566
567 if let Ok(report) = result {
568 assert!(report.frame_count > 0);
569 assert!(report.avg_qp > 0.0);
570 }
571 }
572
573 #[test]
574 fn test_allocation_comparison_example() {
575 let example = AllocationComparisonExample::new(320, 240, 1_000_000);
576 let frames = create_test_frames(20);
577 let result = example.run(&frames);
578 assert!(result.is_ok());
579
580 if let Ok(report) = result {
581 assert_eq!(report.results.len(), 3);
582 assert!(report.most_consistent().is_some());
583 assert!(report.most_efficient().is_some());
584 }
585 }
586}