]> git.nihav.org Git - nihav.git/blame - nihav-duck/src/codecs/vp7enc/mod.rs
avimux: do not record palette change chunks in OpenDML index
[nihav.git] / nihav-duck / src / codecs / vp7enc / mod.rs
CommitLineData
c5d5793c
KS
1use nihav_core::codecs::*;
2use nihav_core::io::byteio::*;
3
4mod blocks;
5mod coder;
6use coder::*;
7mod frame_coder;
8use frame_coder::*;
9mod mb_coding;
10mod models;
11use models::*;
12mod motion_est;
13use motion_est::MVSearchMode;
14mod rdo;
15use rdo::*;
16
17#[derive(PartialEq,Debug)]
18enum EncodingState {
19 Intra,
20 Refinement,
21 JustEncode,
22}
23
c5d5793c
KS
24struct VP7Encoder {
25 stream: Option<NAStreamRef>,
26 pkt: Option<NAPacket>,
27 version: u8,
28 key_int: u8,
29 frmcount: u8,
30 width: usize,
31 height: usize,
32 mb_w: usize,
33 mb_h: usize,
34
35 metric: RateDistMetric,
36 fenc: FrameEncoder,
37 pmodels: VP7Models,
38 br_ctl: BitRateControl,
39
40 last_frame: NABufferType,
41 gold_frame: NABufferType,
42 last_gold: bool,
43 me_mode: MVSearchMode,
44 me_range: i16,
45 lf_level: Option<u8>,
46
47 mbt_depth: usize,
48 mb_weight: Vec<usize>,
49 mb_map: Vec<usize>,
50 mb_map2: Vec<usize>,
51 qframes: Vec<NAFrame>,
52 frm_pool: NAVideoBufferPool<u8>,
53 i_frame: NAVideoBufferRef<u8>,
54 enc_state: EncodingState,
55}
56
57impl VP7Encoder {
58 fn new() -> Self {
59 let vt = alloc_video_buffer(NAVideoInfo::new(24, 24, false, YUV420_FORMAT), 4).unwrap();
60 let mc_buf1 = vt.get_vbuf().unwrap();
61 let vt = alloc_video_buffer(NAVideoInfo::new(24, 24, false, YUV420_FORMAT), 4).unwrap();
62 let mc_buf2 = vt.get_vbuf().unwrap();
63 let vt = alloc_video_buffer(NAVideoInfo::new(24, 24, false, YUV420_FORMAT), 4).unwrap();
64 let i_frame = vt.get_vbuf().unwrap();
65 Self {
66 stream: None,
67 pkt: None,
68 version: 0,
69 key_int: 10,
70 frmcount: 0,
71 width: 0,
72 height: 0,
73 mb_w: 0,
74 mb_h: 0,
75
76 metric: RateDistMetric::new(),
77 fenc: FrameEncoder::new(mc_buf1, mc_buf2),
78 pmodels: VP7Models::new(),
79 br_ctl: BitRateControl::new(),
80
81 last_frame: NABufferType::None,
82 gold_frame: NABufferType::None,
83 last_gold: false,
84 me_mode: MVSearchMode::default(),
85 me_range: 16,
86 lf_level: None,
87
88 mbt_depth: 0,
89 mb_weight: Vec::new(),
90 mb_map: Vec::new(),
91 mb_map2: Vec::new(),
92 qframes: Vec::new(),
93 frm_pool: NAVideoBufferPool::new(0),
94 i_frame,
95 enc_state: EncodingState::JustEncode,
96 }
97 }
98 fn encode_frame(&mut self, frm: &NAFrame) -> EncoderResult<()> {
99 let buf = frm.get_buffer();
100 if let Some(ref vbuf) = buf.get_vbuf() {
101 self.fenc.set_me_params(self.me_mode, self.me_range, self.version);
102 self.fenc.load_frame(vbuf);
103
104 let mut dbuf = Vec::with_capacity(4);
105 let mut gw = GrowableMemoryWriter::new_write(&mut dbuf);
106 let mut bw = ByteWriter::new(&mut gw);
107
108 let is_intra = self.frmcount == 0;
109 let golden_frame = is_intra;
110
111 self.br_ctl.set_key_interval(self.key_int);
112 let cur_quant = self.br_ctl.get_frame_quant(is_intra);
113
114 if let Some(level) = self.lf_level {
115 self.fenc.loop_params.loop_filter_level = level;
116 } else {
117 self.fenc.loop_params.loop_filter_level = if cur_quant <= 16 { 0 } else { (cur_quant / 4) as u8 };
118 }
119
120 if is_intra {
121 self.pmodels.reset();
122 let mbt_frames = self.mbt_depth.min(self.key_int as usize);
123 self.fenc.intra_blocks(cur_quant, &self.metric, &self.pmodels, if mbt_frames > 0 { Some(&self.mb_weight) } else { None });
124 } else {
125 let gold_ref = if !self.last_gold { &self.gold_frame } else { &NABufferType::None };
126 self.fenc.inter_blocks(cur_quant, &self.metric, &self.pmodels, &self.last_frame, gold_ref);
127 }
128
129 let mut stats = VP7ModelsStat::new();
130 let mut models = self.pmodels;
131 self.fenc.generate_models(is_intra, &mut stats);
132 stats.generate(&mut models, is_intra);
133
134 bw.write_u24le(0)?; // frame tag
135 if self.version == 0 {
136 bw.write_byte(0)?; // unused
137 }
138
139 let start = bw.tell();
140
141 let mut bc = BoolEncoder::new(&mut bw);
142 if is_intra {
143 bc.put_bits(self.width as u32, 12)?;
144 bc.put_bits(self.height as u32, 12)?;
145 bc.put_bits(0, 2)?; // scale vertical
146 bc.put_bits(0, 2)?; // scale horizontal
147 }
148
149 self.fenc.encode_features(&mut bc, cur_quant, &models)?;
150
151 bc.put_bits(cur_quant as u32, 7)?; // y_ac_q
152 bc.put_bool(false, 128)?; // y_dc_q
153 bc.put_bool(false, 128)?; // y2_ac_q
154 bc.put_bool(false, 128)?; // y2_dc_q
155 bc.put_bool(false, 128)?; // uv_ac_q
156 bc.put_bool(false, 128)?; // uv_dc_q
157
158 if !is_intra {
159 bc.put_bool(false, 128)?; // update golden frame
160 }
161
162 let has_fading = self.version == 0 || is_intra;
163 if self.version != 0 {
164 bc.put_bool(true, 128)?; // keep probabilities
165 if !is_intra {
166 bc.put_bool(false, 128)?; // has fading feature
167 }
168 }
169 if has_fading {
170 bc.put_bool(false, 128)?; // fading
171 }
172
173 if self.version == 0 {
174 bc.put_bool(self.fenc.loop_params.lf_simple, 128)?;
175 }
176
177 // scan
178 bc.put_bool(false, 128)?;
179
180 if self.version != 0 {
181 bc.put_bool(self.fenc.loop_params.lf_simple, 128)?;
182 }
183
184 bc.put_bits(u32::from(self.fenc.loop_params.loop_filter_level), 6)?;
185 bc.put_bits(u32::from(self.fenc.loop_params.loop_sharpness), 3)?;
186
187 encode_dct_coef_prob_upd(&mut bc, &models.coef_probs, &self.pmodels.coef_probs)?;
188
189 if !is_intra {
190 bc.put_byte(models.prob_intra_pred)?;
191 bc.put_byte(models.prob_last_pred)?;
192
193 let ymode_differs = models.kf_ymode_prob != self.pmodels.kf_ymode_prob;
194 bc.put_bool(ymode_differs, 128)?;
195 if ymode_differs {
196 for &el in models.kf_ymode_prob.iter() {
197 bc.put_byte(el)?;
198 }
199 }
200
201 let uvmode_differs = models.kf_uvmode_prob != self.pmodels.kf_uvmode_prob;
202 bc.put_bool(uvmode_differs, 128)?;
203 if uvmode_differs {
204 for &el in models.kf_uvmode_prob.iter() {
205 bc.put_byte(el)?;
206 }
207 }
208
209 encode_mv_prob_upd(&mut bc, &models.mv_probs, &self.pmodels.mv_probs)?;
210 }
211
212 self.fenc.encode_mb_types(&mut bc, is_intra, &models)?;
213
214 bc.flush()?;
215 let end = bw.tell();
216
217 let mut bc = BoolEncoder::new(&mut bw);
218 self.fenc.encode_residues(&mut bc, &models)?;
219 bc.flush()?;
220
221 bw.seek(SeekFrom::Start(0))?;
222 bw.write_u24le((((end - start) as u32) << 4) |
223 (u32::from(self.version) << 1) |
224 if is_intra { 0 } else { 1 })?;
225
226 let cur_size = dbuf.len();
227
228 self.pkt = Some(NAPacket::new(self.stream.clone().unwrap(), frm.ts, is_intra, dbuf));
229
230 self.pmodels = models;
231
232 if self.key_int > 0 {
233 self.frmcount += 1;
234 }
235 if self.frmcount == self.key_int {
236 self.frmcount = 0;
237 }
238
239 if let Some(ref mut vbuf) = self.last_frame.get_vbuf() {
240 let mut frm = NASimpleVideoFrame::from_video_buf(vbuf).unwrap();
241 self.fenc.reconstruct_frame(&mut frm, is_intra);
242 }
243 self.last_gold = golden_frame;
244 if golden_frame {
245 let mut dfrm = self.gold_frame.get_vbuf().unwrap();
246 let src = self.last_frame.get_vbuf().unwrap();
247
248 let dst = dfrm.get_data_mut().unwrap();
249 dst.copy_from_slice(src.get_data());
250 }
251
252 self.br_ctl.update(cur_size);
253 if self.br_ctl.has_bitrate() {
254 let tgt_size = (self.br_ctl.get_target_size(is_intra) / 8) as usize;
255 self.metric.adjust_br(cur_size, tgt_size);
256 }
257
258 Ok(())
259 } else {
260 Err(EncoderError::InvalidParameters)
261 }
262 }
263}
264
265impl NAEncoder for VP7Encoder {
266 fn negotiate_format(&self, encinfo: &EncodeParameters) -> EncoderResult<EncodeParameters> {
267 match encinfo.format {
268 NACodecTypeInfo::None => {
6f263099
KS
269 Ok(EncodeParameters {
270 format: NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, false, YUV420_FORMAT)),
271 ..Default::default() })
c5d5793c
KS
272 },
273 NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
274 NACodecTypeInfo::Video(vinfo) => {
275 let outinfo = NAVideoInfo::new((vinfo.width + 15) & !15, (vinfo.height + 15) & !15, false, YUV420_FORMAT);
276 let mut ofmt = *encinfo;
277 ofmt.format = NACodecTypeInfo::Video(outinfo);
278 Ok(ofmt)
279 }
280 }
281 }
2757a028 282 fn get_capabilities(&self) -> u64 { 0 }
c5d5793c
KS
283 fn init(&mut self, stream_id: u32, encinfo: EncodeParameters) -> EncoderResult<NAStreamRef> {
284 match encinfo.format {
285 NACodecTypeInfo::None => Err(EncoderError::FormatError),
286 NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
287 NACodecTypeInfo::Video(vinfo) => {
288 if vinfo.format != YUV420_FORMAT {
289 return Err(EncoderError::FormatError);
290 }
291 if ((vinfo.width | vinfo.height) & 15) != 0 {
292 return Err(EncoderError::FormatError);
293 }
294 if (vinfo.width | vinfo.height) >= (1 << 12) {
295 return Err(EncoderError::FormatError);
296 }
297
298 let out_info = NAVideoInfo::new(vinfo.width, vinfo.height, false, vinfo.format);
299 let info = NACodecInfo::new("vp7", NACodecTypeInfo::Video(out_info), None);
300 let mut stream = NAStream::new(StreamType::Video, stream_id, info, encinfo.tb_num, encinfo.tb_den, 0);
301 stream.set_num(stream_id as usize);
302 let stream = stream.into_ref();
303
304 self.last_frame = alloc_video_buffer(out_info, 4)?;
305 self.gold_frame = alloc_video_buffer(out_info, 4)?;
306
307 self.stream = Some(stream.clone());
308
309 self.width = vinfo.width;
310 self.height = vinfo.height;
311 self.mb_w = (vinfo.width + 15) >> 4;
312 self.mb_h = (vinfo.height + 15) >> 4;
313 self.fenc.resize(self.mb_w, self.mb_h);
314
315 self.br_ctl.set_params(encinfo.tb_num, encinfo.tb_den, encinfo.bitrate, self.key_int, self.mb_w * self.mb_h);
316
317 self.frm_pool.reset();
318 self.frm_pool.set_dec_bufs(self.mbt_depth + 1);
319 self.frm_pool.prealloc_video(out_info, 4)?;
320 self.i_frame = self.frm_pool.get_free().unwrap();
321 self.mb_weight.resize(self.mb_w * self.mb_h, 0);
322 self.mb_map.resize(self.mb_w * self.mb_h, 0);
323 self.mb_map2.resize(self.mb_w * self.mb_h, 0);
324 self.qframes.clear();
325 self.enc_state = if self.mbt_depth.min(self.key_int as usize) > 0 {
326 EncodingState::Intra
327 } else {
328 EncodingState::JustEncode
329 };
330
331 Ok(stream)
332 },
333 }
334 }
335 fn encode(&mut self, frm: &NAFrame) -> EncoderResult<()> {
336 if let Some(ref vbuf) = frm.get_buffer().get_vbuf() {
337 let mbt_frames = self.mbt_depth.min(self.key_int as usize);
338 if !self.qframes.is_empty() || (mbt_frames > 0 && self.enc_state != EncodingState::JustEncode) {
339 if let Some(dbuf) = self.frm_pool.get_copy(vbuf) {
340 let newfrm = NAFrame::new(frm.ts, frm.frame_type, frm.key, frm.get_info(), NABufferType::Video(dbuf));
341 if self.enc_state == EncodingState::Intra {
342 for (i, el) in self.mb_map.iter_mut().enumerate() {
343 *el = i;
344 }
345 for el in self.mb_weight.iter_mut() {
346 *el = 1;
347 }
348 let frm = NASimpleVideoFrame::from_video_buf(&mut self.i_frame).unwrap();
349 let src = vbuf.get_data();
350 for plane in 0..3 {
351 let soff = vbuf.get_offset(plane);
352 let sstride = vbuf.get_stride(plane);
353 let copy_len = sstride.min(frm.stride[plane]);
354 for (dst, src) in frm.data[frm.offset[plane]..].chunks_mut(frm.stride[plane]).zip(src[soff..].chunks(sstride)).take(frm.height[plane]) {
355 dst[..copy_len].copy_from_slice(&src[..copy_len]);
356 }
357 }
358 self.enc_state = EncodingState::Refinement;
359 } else {
360 self.fenc.set_me_params(self.me_mode, self.me_range, self.version);
361 self.fenc.load_frame(vbuf);
362 self.fenc.mb_tree_search(self.i_frame.clone(), &self.mb_map, &mut self.mb_map2, &mut self.mb_weight);
363 std::mem::swap(&mut self.mb_map, &mut self.mb_map2);
364 }
365 self.qframes.push(newfrm);
366 Ok(())
367 } else {
368 self.enc_state = EncodingState::JustEncode;
369 self.encode_frame(frm)
370 }
371 } else {
372 self.encode_frame(frm)
373 }
374 } else {
375 Err(EncoderError::FormatError)
376 }
377 }
378 fn get_packet(&mut self) -> EncoderResult<Option<NAPacket>> {
379 let mbt_frames = self.mbt_depth.min(self.key_int as usize);
380 if self.qframes.len() >= mbt_frames {
381 self.enc_state = EncodingState::JustEncode;
382 }
383 if self.pkt.is_none() && !self.qframes.is_empty() && self.enc_state == EncodingState::JustEncode {
384 let frm = self.qframes.remove(0);
385 self.encode_frame(&frm)?;
386 if self.qframes.is_empty() && self.mbt_depth > 0 && self.frmcount == 0 {
387 self.enc_state = EncodingState::Intra;
388 }
389 }
390 let mut npkt = None;
391 std::mem::swap(&mut self.pkt, &mut npkt);
392 Ok(npkt)
393 }
394 fn flush(&mut self) -> EncoderResult<()> {
395 self.frmcount = 0;
396 self.enc_state = EncodingState::JustEncode;
397 Ok(())
398 }
399}
400
401const VERSION_OPTION: &str = "version";
402const LF_LEVEL_OPTION: &str = "lf_level";
403const LF_SHARP_OPTION: &str = "lf_sharpness";
404const LF_SIMPLE_OPTION: &str = "lf_simple";
405const QUANT_OPTION: &str = "quant";
406const MV_SEARCH_OPTION: &str = "mv_mode";
407const MV_RANGE_OPTION: &str = "mv_range";
408const MBTREE_DEPTH: &str = "mbtree_depth";
409
410const ENCODER_OPTS: &[NAOptionDefinition] = &[
411 NAOptionDefinition {
412 name: KEYFRAME_OPTION, description: KEYFRAME_OPTION_DESC,
413 opt_type: NAOptionDefinitionType::Int(Some(0), Some(128)) },
414 NAOptionDefinition {
415 name: VERSION_OPTION, description: "internal codec version",
416 opt_type: NAOptionDefinitionType::Int(Some(0), Some(1)) },
417 NAOptionDefinition {
418 name: LF_LEVEL_OPTION, description: "loop filter level (-1 = automatic)",
419 opt_type: NAOptionDefinitionType::Int(Some(-1), Some(63)) },
420 NAOptionDefinition {
421 name: LF_SHARP_OPTION, description: "loop filter sharpness",
422 opt_type: NAOptionDefinitionType::Int(Some(0), Some(7)) },
423 NAOptionDefinition {
424 name: LF_SIMPLE_OPTION, description: "use simple loop filter",
425 opt_type: NAOptionDefinitionType::Bool },
426 NAOptionDefinition {
427 name: QUANT_OPTION, description: "force fixed quantiser for encoding",
428 opt_type: NAOptionDefinitionType::Int(Some(-1), Some(127)) },
429 NAOptionDefinition {
430 name: MV_SEARCH_OPTION, description: "motion search mode",
431 opt_type: NAOptionDefinitionType::String(Some(&["sea", "dia", "hex", "epzs"])) },
432 NAOptionDefinition {
433 name: MV_RANGE_OPTION, description: "motion search range (in pixels)",
434 opt_type: NAOptionDefinitionType::Int(Some(0), Some(30)) },
435 NAOptionDefinition {
436 name: MBTREE_DEPTH, description: "number of frames in MB tree analysis buffer",
437 opt_type: NAOptionDefinitionType::Int(Some(0), Some(128)) },
438];
439
440impl NAOptionHandler for VP7Encoder {
441 fn get_supported_options(&self) -> &[NAOptionDefinition] { ENCODER_OPTS }
442 fn set_options(&mut self, options: &[NAOption]) {
443 for option in options.iter() {
444 for opt_def in ENCODER_OPTS.iter() {
445 if opt_def.check(option).is_ok() {
446 match option.name {
447 KEYFRAME_OPTION => {
448 if let NAValue::Int(intval) = option.value {
449 self.key_int = intval as u8;
450 }
451 },
452 VERSION_OPTION => {
453 if let NAValue::Int(intval) = option.value {
454 self.version = intval as u8;
455 }
456 },
457 LF_LEVEL_OPTION => {
458 if let NAValue::Int(intval) = option.value {
459 self.lf_level = if intval < 0 { None } else { Some(intval as u8) };
460 }
461 },
462 LF_SHARP_OPTION => {
463 if let NAValue::Int(intval) = option.value {
464 self.fenc.loop_params.loop_sharpness = intval as u8;
465 }
466 },
467 LF_SIMPLE_OPTION => {
468 if let NAValue::Bool(flag) = option.value {
469 self.fenc.loop_params.lf_simple = flag;
470 }
471 },
472 QUANT_OPTION => {
473 if let NAValue::Int(intval) = option.value {
474 self.br_ctl.set_quant(if intval < 0 { None } else { Some(intval as usize) });
475 }
476 },
477 MV_SEARCH_OPTION => {
478 if let NAValue::String(ref string) = option.value {
479 if let Ok(mv_mode) = string.parse::<MVSearchMode>() {
480 self.me_mode = mv_mode;
481 }
482 }
483 },
484 MV_RANGE_OPTION => {
485 if let NAValue::Int(intval) = option.value {
486 self.me_range = intval as i16;
487 }
488 },
489 MBTREE_DEPTH => {
490 if let NAValue::Int(intval) = option.value {
491 self.mbt_depth = intval as usize;
492 }
493 },
494 _ => {},
495 };
496 }
497 }
498 }
499 }
500 fn query_option_value(&self, name: &str) -> Option<NAValue> {
501 match name {
502 KEYFRAME_OPTION => Some(NAValue::Int(i64::from(self.key_int))),
503 VERSION_OPTION => Some(NAValue::Int(i64::from(self.version))),
504 QUANT_OPTION => if let Some(q) = self.br_ctl.get_quant() {
505 Some(NAValue::Int(q as i64))
506 } else {
507 Some(NAValue::Int(-1))
508 },
509 LF_LEVEL_OPTION => if let Some(lev) = self.lf_level {
510 Some(NAValue::Int(i64::from(lev)))
511 } else {
512 Some(NAValue::Int(-1))
513 },
514 LF_SHARP_OPTION => Some(NAValue::Int(i64::from(self.fenc.loop_params.loop_sharpness))),
515 LF_SIMPLE_OPTION => Some(NAValue::Bool(self.fenc.loop_params.lf_simple)),
516 MV_SEARCH_OPTION => Some(NAValue::String(self.me_mode.to_string())),
517 MV_RANGE_OPTION => Some(NAValue::Int(i64::from(self.me_range))),
518 MBTREE_DEPTH => Some(NAValue::Int(self.mbt_depth as i64)),
519 _ => None,
520 }
521 }
522}
523
524pub fn get_encoder() -> Box<dyn NAEncoder + Send> {
525 Box::new(VP7Encoder::new())
526}
527
528#[cfg(test)]
529mod test {
530 use nihav_core::codecs::*;
531 use nihav_core::demuxers::*;
532 use nihav_core::muxers::*;
533 use crate::*;
534 use nihav_commonfmt::*;
535 use nihav_codec_support::test::enc_video::*;
536
537 fn encode_test(out_name: &'static str, enc_options: &[NAOption], hash: &[u32; 4]) {
538 let mut dmx_reg = RegisteredDemuxers::new();
539 generic_register_all_demuxers(&mut dmx_reg);
540 let mut dec_reg = RegisteredDecoders::new();
541 duck_register_all_decoders(&mut dec_reg);
542 let mut mux_reg = RegisteredMuxers::new();
543 generic_register_all_muxers(&mut mux_reg);
544 let mut enc_reg = RegisteredEncoders::new();
545 duck_register_all_encoders(&mut enc_reg);
546
547 // sample: https://samples.mplayerhq.hu/V-codecs/VP4/ot171_vp40.avi
548 let dec_config = DecoderTestParams {
549 demuxer: "avi",
550 in_name: "assets/Duck/ot171_vp40.avi",
551 stream_type: StreamType::Video,
552 limit: Some(9),
553 dmx_reg, dec_reg,
554 };
555 let enc_config = EncoderTestParams {
556 muxer: "avi",
557 enc_name: "vp7",
558 out_name,
559 mux_reg, enc_reg,
560 };
561 let dst_vinfo = NAVideoInfo {
562 width: 0,
563 height: 0,
564 format: YUV420_FORMAT,
565 flipped: false,
566 bits: 12,
567 };
568 let enc_params = EncodeParameters {
569 format: NACodecTypeInfo::Video(dst_vinfo),
570 quality: 0,
571 bitrate: 50000,
572 tb_num: 0,
573 tb_den: 0,
574 flags: 0,
575 };
576 //test_encoding_to_file(&dec_config, &enc_config, enc_params, enc_options);
577 test_encoding_md5(&dec_config, &enc_config, enc_params, enc_options,
578 hash);
579 }
580 #[test]
581 fn test_vp7_encoder() {
582 let enc_options = &[
583 NAOption { name: super::QUANT_OPTION, value: NAValue::Int(42) },
584 ];
585 encode_test("vp7-q42.avi", enc_options, &[0xa5079e5b, 0x33dd8a63, 0xfc189e21, 0xee08332b]);
586 }
587 #[test]
588 fn test_vp7_encoder_noloop() {
589 let enc_options = &[
590 NAOption { name: super::QUANT_OPTION, value: NAValue::Int(42) },
591 NAOption { name: super::LF_LEVEL_OPTION, value: NAValue::Int(0) },
592 ];
593 encode_test("vp7-noloop.avi", enc_options, &[0xc7d41732, 0x09b03059, 0x8550921c, 0xa99d4c29]);
594 }
595 #[test]
596 fn test_vp7_encoder_mbtree() {
597 let enc_options = &[
598 NAOption { name: super::QUANT_OPTION, value: NAValue::Int(24) },
599 NAOption { name: super::MBTREE_DEPTH, value: NAValue::Int(10) },
600 ];
601 encode_test("vp7-mbt.avi", enc_options, &[0xd0d90d31, 0x0253275d, 0xbe502d3c, 0xacf2b6e7]);
602 }
603 #[test]
604 fn test_vp7_encoder_ratectl() {
605 let enc_options = &[
606 NAOption { name: super::QUANT_OPTION, value: NAValue::Int(-1) },
607 ];
608 encode_test("vp7-br.avi", enc_options, &[0x47dcd4da, 0x04b06feb, 0x386163c1, 0x54899da3]);
609 }
610}