benchmark.rs 9.7 KB

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