use ratectl::*;
mod rdo;
+const VERSION_VP61: u8 = VERSION_VP60 + 1;
+
enum VP6Writer<'a, 'b> {
BoolCoder(BoolEncoder<'a, 'b>),
Huffman(HuffEncoder<'a, 'b>),
fenc: FrameEncoder,
ratectl: RateControl,
+ flipped: bool,
huffman: bool,
version: u8,
}
impl VP6Encoder {
- fn new() -> Self {
+ fn new(flipped: bool) -> Self {
let vt = alloc_video_buffer(NAVideoInfo::new(24, 24, false, VP_YUVA420_FORMAT), 4).unwrap();
let mc_buf = vt.get_vbuf().unwrap();
Self {
ratectl: RateControl::new(),
mc_buf,
+ flipped,
huffman: false,
version: VERSION_VP60,
self.pmodels.reset(false);
self.pmodels.reset_mbtype_models();
- let multistream = self.huffman;
+ let multistream = self.huffman || self.version != VERSION_VP60;
self.fenc.prepare_intra_blocks();
self.fenc.apply_dc_prediction(&mut self.dc_pred);
fn encode_inter(&mut self, bw: &mut ByteWriter, quant: usize) -> EncoderResult<bool> {
self.stats.reset();
- let multistream = !self.huffman;
+ let multistream = self.huffman || self.version != VERSION_VP60;
let loop_filter = false;
self.fenc.prepare_intra_blocks();
match encinfo.format {
NACodecTypeInfo::None => {
let mut ofmt = EncodeParameters::default();
- ofmt.format = NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, true, YUV420_FORMAT));
+ ofmt.format = NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, self.flipped, YUV420_FORMAT));
Ok(ofmt)
},
NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
NACodecTypeInfo::Video(vinfo) => {
- let outinfo = NAVideoInfo::new((vinfo.width + 3) & !3, (vinfo.height + 3) & !3, true, YUV420_FORMAT);
+ let outinfo = NAVideoInfo::new((vinfo.width + 3) & !3, (vinfo.height + 3) & !3, self.flipped, YUV420_FORMAT);
let mut ofmt = *encinfo;
ofmt.format = NACodecTypeInfo::Video(outinfo);
Ok(ofmt)
return Err(EncoderError::FormatError);
}
- let out_info = NAVideoInfo::new(vinfo.width, vinfo.height, true, vinfo.format);
- let info = NACodecInfo::new("vp6", NACodecTypeInfo::Video(out_info), None);
+ let out_info = NAVideoInfo::new(vinfo.width, vinfo.height, self.flipped, vinfo.format);
+ let info = NACodecInfo::new(if self.flipped { "vp6" } else { "vp6f" }, NACodecTypeInfo::Video(out_info), None);
let mut stream = NAStream::new(StreamType::Video, stream_id, info, encinfo.tb_num, encinfo.tb_den, 0);
stream.set_num(stream_id as usize);
let stream = stream.into_ref();
const HUFFMAN_OPTION: &str = "huffman";
const QUANT_OPTION: &str = "quant";
+const VERSION_OPTION: &str = "version";
const MV_SEARCH_OPTION: &str = "mv_mode";
const MV_RANGE_OPTION: &str = "mv_range";
NAOptionDefinition {
name: HUFFMAN_OPTION, description: "use Huffman encoding",
opt_type: NAOptionDefinitionType::Bool },
+ NAOptionDefinition {
+ name: VERSION_OPTION, description: "codec minor version",
+ opt_type: NAOptionDefinitionType::String(Some(&["vp60", "vp61", "vp62"])) },
NAOptionDefinition {
name: QUANT_OPTION, description: "force fixed quantiser for encoding",
opt_type: NAOptionDefinitionType::Int(Some(-1), Some(63)) },
self.huffman = bval;
}
},
+ VERSION_OPTION => {
+ if let NAValue::String(ref string) = option.value {
+ self.version = match string.as_str() {
+ "vp60" => VERSION_VP60,
+ "vp61" => VERSION_VP61,
+ "vp62" => VERSION_VP62,
+ _ => unreachable!(),
+ };
+ }
+ },
QUANT_OPTION => {
if let NAValue::Int(intval) = option.value {
self.force_q = if intval < 0 { None } else { Some(intval as usize) };
match name {
KEYFRAME_OPTION => Some(NAValue::Int(i64::from(self.key_int))),
HUFFMAN_OPTION => Some(NAValue::Bool(self.huffman)),
+ VERSION_OPTION => {
+ let ver = match self.version {
+ VERSION_VP60 => "vp60",
+ VERSION_VP61 => "vp61",
+ VERSION_VP62 => "vp62",
+ _ => unreachable!(),
+ };
+ Some(NAValue::String(ver.to_string()))
+ },
QUANT_OPTION => if let Some(q) = self.force_q {
Some(NAValue::Int(q as i64))
} else {
}
pub fn get_encoder() -> Box<dyn NAEncoder + Send> {
- Box::new(VP6Encoder::new())
+ Box::new(VP6Encoder::new(true))
+}
+
+pub fn get_encoder_flv() -> Box<dyn NAEncoder + Send> {
+ Box::new(VP6Encoder::new(false))
}
#[cfg(test)]
let mut enc_reg = RegisteredEncoders::new();
duck_register_all_encoders(&mut enc_reg);
+ // sample: https://samples.mplayerhq.hu/V-codecs/VP4/ot171_vp40.avi
let dec_config = DecoderTestParams {
demuxer: "avi",
in_name: "assets/Duck/ot171_vp40.avi",
let enc_options = &[
NAOption { name: super::QUANT_OPTION, value: NAValue::Int(42) },
];
- encode_test("vp6-bool.avi", enc_options, &[0x3649ebc5, 0x4ed1cd7d, 0x1ad40c7b, 0xadd30276]);
+ encode_test("vp6-bool.avi", enc_options, &[0xb57f49e5, 0x6b48accd, 0xc28fadb3, 0xc89a30d2]);
}
#[test]
fn test_vp6_encoder_rc() {
let enc_options = &[
];
- encode_test("vp6-rc.avi", enc_options, &[0x97f3ea9d, 0x5374d30f, 0xf900a594, 0xbfa34b0f]);
+ encode_test("vp6-rc.avi", enc_options, &[0x790baca9, 0x663eafcf, 0x36d1bed8, 0xddf882de]);
}
#[test]
fn test_vp6_encoder_huff() {
NAOption { name: super::HUFFMAN_OPTION, value: NAValue::Bool(true) },
NAOption { name: super::QUANT_OPTION, value: NAValue::Int(42) },
];
- encode_test("vp6-huff.avi", enc_options, &[0x4558af0a, 0x4d260b6b, 0x16b7c501, 0x178f42c5]);
+ encode_test("vp6-huff.avi", enc_options, &[0x6e9bb23d, 0xde296d92, 0x4c225bae, 0x3651e31f]);
}
}