aboutsummaryrefslogtreecommitdiffstats
path: root/nihav-commonfmt/src/muxers/y4m.rs
blob: 600f78e8a16863adbfc42ef195855aaccc896e60 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use nihav_core::muxers::*;

struct Y4MMuxer<'a> {
    bw:             &'a mut ByteWriter<'a>,
}

impl<'a> Y4MMuxer<'a> {
    fn new(bw: &'a mut ByteWriter<'a>) -> Self {
        Self {
            bw,
        }
    }
}

fn get_format_name(fmt: NAPixelFormaton) -> MuxerResult<&'static str> {
    if fmt.model.is_yuv() && fmt.get_max_depth() == 8 {
        match fmt.components {
            1 => Ok("mono"),
            3 => {
                let uinfo = fmt.comp_info[1].unwrap();
                let vinfo = fmt.comp_info[2].unwrap();
                if uinfo.h_ss != vinfo.h_ss || uinfo.v_ss != vinfo.v_ss {
                    return Err(MuxerError::UnsupportedFormat);
                }
                match (uinfo.h_ss, vinfo.v_ss) {
                    (0, 0) => Ok("444"),
                    (1, 0) => Ok("422"),
                    (1, 1) => Ok("420"),
                    (2, 0) => Ok("411"),
                    _ => Err(MuxerError::UnsupportedFormat),
                }
            },
            _ => Err(MuxerError::UnsupportedFormat),
        }
    } else {
        Err(MuxerError::UnsupportedFormat)
    }
}

impl<'a> MuxCore<'a> for Y4MMuxer<'a> {
    fn create(&mut self, strmgr: &StreamManager) -> MuxerResult<()> {
        if strmgr.get_num_streams() != 1 {
            return Err(MuxerError::InvalidArgument);
        }
        let vstr = strmgr.get_stream(0).unwrap();
        if vstr.get_media_type() != StreamType::Video {
            return Err(MuxerError::UnsupportedFormat);
        }
        let info = vstr.get_info();
        let vinfo = info.get_properties().get_video_info().unwrap();
        self.bw.write_buf(format!("YUV4MPEG2 W{} H{} F{}:{} C{}\n", vinfo.width, vinfo.height, vstr.tb_den, vstr.tb_num, get_format_name(vinfo.format)?).as_bytes())?;

        Ok(())
    }
    fn mux_frame(&mut self, _strmgr: &StreamManager, pkt: NAPacket) -> MuxerResult<()> {
        if self.bw.tell() == 0 {
            return Err(MuxerError::NotCreated);
        }
        let src = pkt.get_buffer();
        self.bw.write_buf(b"FRAME\n")?;
        self.bw.write_buf(&src)?;
        Ok(())
    }
    fn flush(&mut self) -> MuxerResult<()> {
        Ok(())
    }
    fn end(&mut self) -> MuxerResult<()> {
        Ok(())
    }
}

impl<'a> NAOptionHandler for Y4MMuxer<'a> {
    fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
    fn set_options(&mut self, _options: &[NAOption]) { }
    fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
}

pub struct Y4MMuxerCreator {}

impl MuxerCreator for Y4MMuxerCreator {
    fn new_muxer<'a>(&self, bw: &'a mut ByteWriter<'a>) -> Box<dyn MuxCore<'a> + 'a> {
        Box::new(Y4MMuxer::new(bw))
    }
    fn get_name(&self) -> &'static str { "yuv4mpeg" }
    fn get_capabilities(&self) -> MuxerCapabilities { MuxerCapabilities::SingleVideo("rawvideo") }
}

#[cfg(test)]
mod test {
    use nihav_core::codecs::*;
    use nihav_core::demuxers::*;
    use nihav_core::muxers::*;
    use nihav_codec_support::test::enc_video::*;
    use crate::*;

    #[test]
    fn test_y4m_muxer() {
        let mut dmx_reg = RegisteredDemuxers::new();
        generic_register_all_demuxers(&mut dmx_reg);
        // sample: self-created with avconv
        let dec_config = DecoderTestParams {
                demuxer:        "yuv4mpeg",
                in_name:        "assets/Misc/test.y4m",
                limit:          None,
                stream_type:    StreamType::None,
                dmx_reg, dec_reg: RegisteredDecoders::new(),
            };
        let mut mux_reg = RegisteredMuxers::new();
        generic_register_all_muxers(&mut mux_reg);
        /*let enc_config = EncoderTestParams {
                muxer:      "yuv4mpeg",
                enc_name:   "",
                out_name:   "muxed.y4m",
                mux_reg, enc_reg: RegisteredEncoders::new(),
            };
        test_remuxing(&dec_config, &enc_config);*/
        test_remuxing_md5(&dec_config, "yuv4mpeg", &mux_reg,
                          [0x7586c1c5, 0x388209b8, 0xe08af8f8, 0x4b6b96c7]);
    }
}