benchmark.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. use docopt::Docopt;
  2. use hbb_common::{
  3. env_logger::{init_from_env, Env, DEFAULT_FILTER_ENV},
  4. log,
  5. };
  6. use scrap::{
  7. aom::{AomDecoder, AomEncoder, AomEncoderConfig},
  8. codec::{EncoderApi, EncoderCfg, Quality as Q},
  9. Capturer, Display, TraitCapturer, VpxDecoder, VpxDecoderConfig, VpxEncoder, VpxEncoderConfig,
  10. VpxVideoCodecId::{self, *},
  11. STRIDE_ALIGN,
  12. };
  13. use std::{
  14. io::Write,
  15. time::{Duration, Instant},
  16. };
  17. // cargo run --package scrap --example benchmark --release --features hwcodec
  18. const USAGE: &'static str = "
  19. Codec benchmark.
  20. Usage:
  21. benchmark [--count=COUNT] [--quality=QUALITY] [--i444]
  22. benchmark (-h | --help)
  23. Options:
  24. -h --help Show this screen.
  25. --count=COUNT Capture frame count [default: 100].
  26. --quality=QUALITY Video quality [default: Balanced].
  27. Valid values: Best, Balanced, Low.
  28. --i444 I444.
  29. ";
  30. #[derive(Debug, serde::Deserialize, Clone, Copy)]
  31. struct Args {
  32. flag_count: usize,
  33. flag_quality: Quality,
  34. flag_i444: bool,
  35. }
  36. #[derive(Debug, serde::Deserialize, Clone, Copy)]
  37. enum Quality {
  38. Best,
  39. Balanced,
  40. Low,
  41. }
  42. fn main() {
  43. init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info"));
  44. let args: Args = Docopt::new(USAGE)
  45. .and_then(|d| d.deserialize())
  46. .unwrap_or_else(|e| e.exit());
  47. let quality = args.flag_quality;
  48. let yuv_count = args.flag_count;
  49. let mut index = 0;
  50. let mut displays = Display::all().unwrap();
  51. for i in 0..displays.len() {
  52. if displays[i].is_primary() {
  53. index = i;
  54. break;
  55. }
  56. }
  57. let d = displays.remove(index);
  58. let mut c = Capturer::new(d).unwrap();
  59. let width = c.width();
  60. let height = c.height();
  61. println!(
  62. "benchmark {}x{} quality:{:?}, i444:{:?}",
  63. width, height, quality, args.flag_i444
  64. );
  65. let quality = match quality {
  66. Quality::Best => Q::Best,
  67. Quality::Balanced => Q::Balanced,
  68. Quality::Low => Q::Low,
  69. };
  70. [VP8, VP9].map(|codec| {
  71. test_vpx(
  72. &mut c,
  73. codec,
  74. width,
  75. height,
  76. quality,
  77. yuv_count,
  78. if codec == VP8 { false } else { args.flag_i444 },
  79. )
  80. });
  81. test_av1(&mut c, width, height, quality, yuv_count, args.flag_i444);
  82. #[cfg(feature = "hwcodec")]
  83. {
  84. hw::test(&mut c, width, height, quality, yuv_count);
  85. }
  86. }
  87. fn test_vpx(
  88. c: &mut Capturer,
  89. codec_id: VpxVideoCodecId,
  90. width: usize,
  91. height: usize,
  92. quality: Q,
  93. yuv_count: usize,
  94. i444: bool,
  95. ) {
  96. let config = EncoderCfg::VPX(VpxEncoderConfig {
  97. width: width as _,
  98. height: height as _,
  99. quality,
  100. codec: codec_id,
  101. keyframe_interval: None,
  102. });
  103. let mut encoder = VpxEncoder::new(config, i444).unwrap();
  104. let mut vpxs = vec![];
  105. let start = Instant::now();
  106. let mut size = 0;
  107. let mut yuv = Vec::new();
  108. let mut mid_data = Vec::new();
  109. let mut counter = 0;
  110. let mut time_sum = Duration::ZERO;
  111. loop {
  112. match c.frame(std::time::Duration::from_millis(30)) {
  113. Ok(frame) => {
  114. let tmp_timer = Instant::now();
  115. let frame = frame.to(encoder.yuvfmt(), &mut yuv, &mut mid_data).unwrap();
  116. let yuv = frame.yuv().unwrap();
  117. for ref frame in encoder
  118. .encode(start.elapsed().as_millis() as _, &yuv, STRIDE_ALIGN)
  119. .unwrap()
  120. {
  121. size += frame.data.len();
  122. vpxs.push(frame.data.to_vec());
  123. counter += 1;
  124. print!("\r{codec_id:?} {}/{}", counter, yuv_count);
  125. std::io::stdout().flush().ok();
  126. }
  127. for ref frame in encoder.flush().unwrap() {
  128. size += frame.data.len();
  129. vpxs.push(frame.data.to_vec());
  130. counter += 1;
  131. print!("\r{codec_id:?} {}/{}", counter, yuv_count);
  132. std::io::stdout().flush().ok();
  133. }
  134. time_sum += tmp_timer.elapsed();
  135. }
  136. Err(e) => {
  137. log::error!("{e:?}");
  138. }
  139. }
  140. if counter >= yuv_count {
  141. println!();
  142. break;
  143. }
  144. }
  145. assert_eq!(vpxs.len(), yuv_count);
  146. println!(
  147. "{:?} encode: {:?}, {} byte",
  148. codec_id,
  149. time_sum / yuv_count as _,
  150. size / yuv_count
  151. );
  152. let mut decoder = VpxDecoder::new(VpxDecoderConfig { codec: codec_id }).unwrap();
  153. let start = Instant::now();
  154. for vpx in vpxs {
  155. let _ = decoder.decode(&vpx);
  156. let _ = decoder.flush();
  157. }
  158. println!(
  159. "{:?} decode: {:?}",
  160. codec_id,
  161. start.elapsed() / yuv_count as _
  162. );
  163. }
  164. fn test_av1(
  165. c: &mut Capturer,
  166. width: usize,
  167. height: usize,
  168. quality: Q,
  169. yuv_count: usize,
  170. i444: bool,
  171. ) {
  172. let config = EncoderCfg::AOM(AomEncoderConfig {
  173. width: width as _,
  174. height: height as _,
  175. quality,
  176. keyframe_interval: None,
  177. });
  178. let mut encoder = AomEncoder::new(config, i444).unwrap();
  179. let start = Instant::now();
  180. let mut size = 0;
  181. let mut av1s: Vec<Vec<u8>> = vec![];
  182. let mut yuv = Vec::new();
  183. let mut mid_data = Vec::new();
  184. let mut counter = 0;
  185. let mut time_sum = Duration::ZERO;
  186. loop {
  187. match c.frame(std::time::Duration::from_millis(30)) {
  188. Ok(frame) => {
  189. let tmp_timer = Instant::now();
  190. let frame = frame.to(encoder.yuvfmt(), &mut yuv, &mut mid_data).unwrap();
  191. let yuv = frame.yuv().unwrap();
  192. for ref frame in encoder
  193. .encode(start.elapsed().as_millis() as _, &yuv, STRIDE_ALIGN)
  194. .unwrap()
  195. {
  196. size += frame.data.len();
  197. av1s.push(frame.data.to_vec());
  198. counter += 1;
  199. print!("\rAV1 {}/{}", counter, yuv_count);
  200. std::io::stdout().flush().ok();
  201. }
  202. time_sum += tmp_timer.elapsed();
  203. }
  204. Err(e) => {
  205. log::error!("{e:?}");
  206. }
  207. }
  208. if counter >= yuv_count {
  209. println!();
  210. break;
  211. }
  212. }
  213. assert_eq!(av1s.len(), yuv_count);
  214. println!(
  215. "AV1 encode: {:?}, {} byte",
  216. time_sum / yuv_count as _,
  217. size / yuv_count
  218. );
  219. let mut decoder = AomDecoder::new().unwrap();
  220. let start = Instant::now();
  221. for av1 in av1s {
  222. let _ = decoder.decode(&av1);
  223. let _ = decoder.flush();
  224. }
  225. println!("AV1 decode: {:?}", start.elapsed() / yuv_count as _);
  226. }
  227. #[cfg(feature = "hwcodec")]
  228. mod hw {
  229. use hwcodec::ffmpeg_ram::CodecInfo;
  230. use scrap::{
  231. hwcodec::{HwRamDecoder, HwRamEncoder, HwRamEncoderConfig},
  232. CodecFormat,
  233. };
  234. use super::*;
  235. pub fn test(c: &mut Capturer, width: usize, height: usize, quality: Q, yuv_count: usize) {
  236. let mut h264s = Vec::new();
  237. let mut h265s = Vec::new();
  238. if let Some(info) = HwRamEncoder::try_get(CodecFormat::H264) {
  239. test_encoder(width, height, quality, info, c, yuv_count, &mut h264s);
  240. }
  241. if let Some(info) = HwRamEncoder::try_get(CodecFormat::H265) {
  242. test_encoder(width, height, quality, info, c, yuv_count, &mut h265s);
  243. }
  244. test_decoder(CodecFormat::H264, &h264s);
  245. test_decoder(CodecFormat::H265, &h265s);
  246. }
  247. fn test_encoder(
  248. width: usize,
  249. height: usize,
  250. quality: Q,
  251. info: CodecInfo,
  252. c: &mut Capturer,
  253. yuv_count: usize,
  254. h26xs: &mut Vec<Vec<u8>>,
  255. ) {
  256. let mut encoder = HwRamEncoder::new(
  257. EncoderCfg::HWRAM(HwRamEncoderConfig {
  258. name: info.name.clone(),
  259. mc_name: None,
  260. width,
  261. height,
  262. quality,
  263. keyframe_interval: None,
  264. }),
  265. false,
  266. )
  267. .unwrap();
  268. let mut size = 0;
  269. let mut yuv = Vec::new();
  270. let mut mid_data = Vec::new();
  271. let mut counter = 0;
  272. let mut time_sum = Duration::ZERO;
  273. let start = std::time::Instant::now();
  274. loop {
  275. match c.frame(std::time::Duration::from_millis(30)) {
  276. Ok(frame) => {
  277. let tmp_timer = Instant::now();
  278. let frame = frame.to(encoder.yuvfmt(), &mut yuv, &mut mid_data).unwrap();
  279. let yuv = frame.yuv().unwrap();
  280. for ref frame in encoder
  281. .encode(&yuv, start.elapsed().as_millis() as _)
  282. .unwrap()
  283. {
  284. size += frame.data.len();
  285. h26xs.push(frame.data.to_vec());
  286. counter += 1;
  287. print!("\r{:?} {}/{}", info.name, counter, yuv_count);
  288. std::io::stdout().flush().ok();
  289. }
  290. time_sum += tmp_timer.elapsed();
  291. }
  292. Err(e) => {
  293. log::error!("{e:?}");
  294. }
  295. }
  296. if counter >= yuv_count {
  297. println!();
  298. break;
  299. }
  300. }
  301. println!(
  302. "{}: {:?}, {} byte",
  303. info.name,
  304. time_sum / yuv_count as u32,
  305. size / yuv_count,
  306. );
  307. }
  308. fn test_decoder(format: CodecFormat, h26xs: &Vec<Vec<u8>>) {
  309. let mut decoder = HwRamDecoder::new(format).unwrap();
  310. let start = Instant::now();
  311. let mut cnt = 0;
  312. for h26x in h26xs {
  313. let _ = decoder.decode(h26x).unwrap();
  314. cnt += 1;
  315. }
  316. let device = format!("{:?}", decoder.info.hwdevice).to_lowercase();
  317. let device = device.split("_").last().unwrap();
  318. println!(
  319. "{} {}: {:?}",
  320. decoder.info.name,
  321. device,
  322. start.elapsed() / cnt
  323. );
  324. }
  325. }