raw video "encoder"
authorKostya Shishkov <kostya.shishkov@gmail.com>
Sun, 4 Jun 2023 13:22:49 +0000 (15:22 +0200)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Sun, 4 Jun 2023 13:36:47 +0000 (15:36 +0200)
nihav-commonfmt/Cargo.toml
nihav-commonfmt/src/codecs/mod.rs
nihav-commonfmt/src/codecs/rawvideoenc.rs [new file with mode: 0644]

index 6e7d02094ed16f7eec60c40e5c9bb54947d14ab0..adea42f821871a902e48281035711e30a47a7d67 100644 (file)
@@ -52,8 +52,9 @@ decoder_aac = ["decoders"]
 
 all_encoders = ["all_video_encoders", "all_audio_encoders"]
 
-all_video_encoders = ["encoder_cinepak", "encoder_zmbv"]
+all_video_encoders = ["encoder_cinepak", "encoder_rawvideo", "encoder_zmbv"]
 encoder_cinepak = ["encoders"]
+encoder_rawvideo = ["encoders"]
 encoder_zmbv = ["encoders"]
 
 all_audio_encoders = ["encoder_pcm"]
index f69fc6441e5b6c70627713f2eed1350645bb33d5..4c6569ecef66845c484ee6b0669ce6e8b613d22a 100644 (file)
@@ -77,6 +77,8 @@ pub fn generic_register_all_decoders(rd: &mut RegisteredDecoders) {
 
 #[cfg(feature="encoder_cinepak")]
 mod cinepakenc;
+#[cfg(feature="encoder_rawvideo")]
+mod rawvideoenc;
 #[cfg(feature="encoder_zmbv")]
 mod zmbvenc;
 
@@ -84,6 +86,8 @@ mod zmbvenc;
 const ENCODERS: &[EncoderInfo] = &[
 #[cfg(feature="encoder_cinepak")]
     EncoderInfo { name: "cinepak", get_encoder: cinepakenc::get_encoder },
+#[cfg(feature="encoder_rawvideo")]
+    EncoderInfo { name: "rawvideo", get_encoder: rawvideoenc::get_encoder },
 #[cfg(feature="encoder_zmbv")]
     EncoderInfo { name: "zmbv", get_encoder: zmbvenc::get_encoder },
 
diff --git a/nihav-commonfmt/src/codecs/rawvideoenc.rs b/nihav-commonfmt/src/codecs/rawvideoenc.rs
new file mode 100644 (file)
index 0000000..8847520
--- /dev/null
@@ -0,0 +1,100 @@
+use nihav_core::codecs::*;
+
+struct RawEncoder {
+    stream: Option<NAStreamRef>,
+    pkt:    Option<NAPacket>,
+}
+
+impl RawEncoder {
+    fn new() -> Self {
+        Self {
+            stream: None,
+            pkt:    None,
+        }
+    }
+}
+
+impl NAEncoder for RawEncoder {
+    fn negotiate_format(&self, encinfo: &EncodeParameters) -> EncoderResult<EncodeParameters> {
+        match encinfo.format {
+            NACodecTypeInfo::None => {
+                Ok(EncodeParameters {
+                    format: NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, false, YUV420_FORMAT)),
+                    ..Default::default()
+                })
+            },
+            NACodecTypeInfo::Video(_) => Ok(*encinfo),
+            NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
+        }
+    }
+    fn get_capabilities(&self) -> u64 { ENC_CAPS_CBR }
+    fn init(&mut self, stream_id: u32, encinfo: EncodeParameters) -> EncoderResult<NAStreamRef> {
+        match encinfo.format {
+            NACodecTypeInfo::None => Err(EncoderError::FormatError),
+            NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
+            NACodecTypeInfo::Video(_) => {
+                let info = NACodecInfo::new("rawvideo", encinfo.format, 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();
+                self.stream = Some(stream.clone());
+                Ok(stream)
+            }
+        }
+    }
+    fn encode(&mut self, frm: &NAFrame) -> EncoderResult<()> {
+        let buf = frm.get_buffer();
+        let mut dbuf;
+        match buf {
+            NABufferType::Video(ref vbuf) => {
+                let vinfo = vbuf.get_info();
+                if !vinfo.format.model.is_yuv() || !vinfo.format.is_unpacked() {
+                    return Err(EncoderError::NotImplemented);
+                }
+
+                let src = vbuf.get_data();
+                dbuf = Vec::with_capacity(src.len());
+                for (comp, cinfo) in vinfo.format.comp_info.iter().enumerate() {
+                    if cinfo.is_none() {
+                        continue;
+                    }
+                    let (width, height) = vbuf.get_dimensions(comp);
+                    let off = vbuf.get_offset(comp);
+                    let stride = vbuf.get_stride(comp);
+
+                    for line in src[off..].chunks(stride).take(height) {
+                        dbuf.extend_from_slice(&line[..width]);
+                    }
+                }
+            },
+            NABufferType::VideoPacked(ref _vbuf) => return Err(EncoderError::NotImplemented),
+            NABufferType::Video16(ref _vbuf) => return Err(EncoderError::NotImplemented),
+            NABufferType::Video32(ref _vbuf) => return Err(EncoderError::NotImplemented),
+            NABufferType::None => {
+                self.pkt = None;
+                return Ok(());
+            },
+            _ => return Err(EncoderError::FormatError),
+        };
+        self.pkt = Some(NAPacket::new(self.stream.clone().unwrap(), frm.ts, true, dbuf));
+        Ok(())
+    }
+    fn get_packet(&mut self) -> EncoderResult<Option<NAPacket>> {
+        let mut npkt = None;
+        std::mem::swap(&mut self.pkt, &mut npkt);
+        Ok(npkt)
+    }
+    fn flush(&mut self) -> EncoderResult<()> {
+        Ok(())
+    }
+}
+
+impl NAOptionHandler for RawEncoder {
+    fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+    fn set_options(&mut self, _options: &[NAOption]) { }
+    fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+pub fn get_encoder() -> Box<dyn NAEncoder + Send> {
+    Box::new(RawEncoder::new())
+}