From f9cd9e128d06d5b65cfab36b6a6e381c52104cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 4 Dec 2016 23:51:38 +0200 Subject: [PATCH] Add support for more codecs Only Speex, AAC and H264 are missing now, which require a little bit more work. --- src/flvdemux.rs | 114 +++++++++++++++++++++++++++++++++--------------- src/rsdemuxer.c | 22 ++++++---- src/rsdemuxer.h | 1 - 3 files changed, 93 insertions(+), 44 deletions(-) diff --git a/src/flvdemux.rs b/src/flvdemux.rs index fd561fd8..284175ee 100644 --- a/src/flvdemux.rs +++ b/src/flvdemux.rs @@ -91,7 +91,8 @@ impl AudioFormat { (flavors::SoundFormat::NELLYMOSER_16KHZ_MONO, _) => 16000, (flavors::SoundFormat::NELLYMOSER_8KHZ_MONO, _) => 8000, (flavors::SoundFormat::MP3_8KHZ, _) => 8000, - (_, flavors::SoundRate::_5_5KHZ) => 5500, + (flavors::SoundFormat::SPEEX, _) => 16000, + (_, flavors::SoundRate::_5_5KHZ) => 5512, (_, flavors::SoundRate::_11KHZ) => 11025, (_, flavors::SoundRate::_22KHZ) => 22050, (_, flavors::SoundRate::_44KHZ) => 44100, @@ -128,20 +129,51 @@ impl AudioFormat { } fn to_string(&self) -> Option { - match self.format { - flavors::SoundFormat::MP3 => { - let mut format = String::from("audio/mpeg, mpegversion=(int) 1, layer=(int) 3"); - if self.rate != 0 { - format.push_str(&format!(", rate=(int) {}", self.rate)); - } - if self.channels != 0 { - format.push_str(&format!(", channels=(int) {}", self.channels)); - } - - Some(format) + let mut format = match self.format { + flavors::SoundFormat::MP3 | + flavors::SoundFormat::MP3_8KHZ => { + Some(String::from("audio/mpeg, mpegversion=(int) 1, layer=(int) 3")) } - _ => None, + flavors::SoundFormat::PCM_BE | + flavors::SoundFormat::PCM_LE => { + if self.rate != 0 && self.channels != 0 { + // Assume little-endian for "PCM_NE", it's probably more common and we have no + // way to know what the endianness of the system creating the stream was + Some(format!("audio/x-raw, layout=(string) interleaved, \ + format=(string) {}", + if self.width == 8 { "U8" } else { "S16LE" })) + } else { + None + } + } + flavors::SoundFormat::ADPCM => Some(String::from("audio/x-adpcm, layout=(string) swf")), + flavors::SoundFormat::NELLYMOSER_16KHZ_MONO | + flavors::SoundFormat::NELLYMOSER_8KHZ_MONO | + flavors::SoundFormat::NELLYMOSER => Some(String::from("audio/x-nellymoser")), + flavors::SoundFormat::PCM_ALAW => Some(String::from("audio/x-alaw")), + flavors::SoundFormat::PCM_ULAW => Some(String::from("audio/x-mulaw")), + flavors::SoundFormat::AAC => { + // TODO: This requires getting the codec config from the stream + None + } + flavors::SoundFormat::SPEEX => { + // TODO: This requires creating a Speex streamheader... + None + } + flavors::SoundFormat::DEVICE_SPECIFIC => { + // Nobody knows + None + } + }; + + if self.rate != 0 { + format.as_mut().map(|f| f.push_str(&format!(", rate=(int) {}", self.rate))); } + if self.channels != 0 { + format.as_mut().map(|f| f.push_str(&format!(", channels=(int) {}", self.channels))); + } + + format } } @@ -199,29 +231,43 @@ impl VideoFormat { } fn to_string(&self) -> Option { - match self.format { - flavors::CodecId::VP6 => { - let mut format = String::from("video/x-vp6-flash"); - if let (Some(width), Some(height)) = (self.width, self.height) { - format.push_str(&format!(", width=(int) {}, height=(int) {}", width, height)); - } - if let Some(par) = self.pixel_aspect_ratio { - if par.0 != 0 && par.1 != 0 { - format.push_str(&format!(", pixel-aspect-ratio=(fraction) {}/{}", - par.0, - par.1)); - } - } - if let Some(fps) = self.framerate { - if fps.1 != 0 { - format.push_str(&format!(", framerate=(fraction) {}/{}", fps.0, fps.1)); - } - } - - Some(format) + let mut format = match self.format { + flavors::CodecId::H263 => Some(String::from("video/x-flash-video, flvversion=(int) 1")), + flavors::CodecId::SCREEN => Some(String::from("video/x-flash-screen")), + flavors::CodecId::VP6 => Some(String::from("video/x-vp6-flash")), + flavors::CodecId::VP6A => Some(String::from("video/x-vp6-alpha")), + flavors::CodecId::SCREEN2 => Some(String::from("video/x-flash-screen2")), + flavors::CodecId::H264 => { + // TODO: Need codec_data from the stream + None } - _ => None, + flavors::CodecId::JPEG => { + // Unused according to spec + None + } + }; + + if let (Some(width), Some(height)) = (self.width, self.height) { + format.as_mut() + .map(|f| f.push_str(&format!(", width=(int) {}, height=(int) {}", width, height))); } + + if let Some(par) = self.pixel_aspect_ratio { + if par.0 != 0 && par.1 != 0 { + format.as_mut().map(|f| { + f.push_str(&format!(", pixel-aspect-ratio=(fraction) {}/{}", par.0, par.1)) + }); + } + } + + if let Some(fps) = self.framerate { + if fps.1 != 0 { + format.as_mut() + .map(|f| f.push_str(&format!(", framerate=(fraction) {}/{}", fps.0, fps.1))); + } + } + + format } } diff --git a/src/rsdemuxer.c b/src/rsdemuxer.c index e8fdb51d..6b3167bd 100644 --- a/src/rsdemuxer.c +++ b/src/rsdemuxer.c @@ -329,8 +329,10 @@ gst_rs_demuxer_change_state (GstElement * element, GstStateChange transition) gst_flow_combiner_clear (demuxer->flow_combiner); - for (i = 0; i < demuxer->n_srcpads; i++) - gst_element_remove_pad (GST_ELEMENT (demuxer), demuxer->srcpads[i]); + for (i = 0; i < G_N_ELEMENTS (demuxer->srcpads); i++) { + if (demuxer->srcpads[i]) + gst_element_remove_pad (GST_ELEMENT (demuxer), demuxer->srcpads[i]); + } memset (demuxer->srcpads, 0, sizeof (demuxer->srcpads)); break; } @@ -359,7 +361,6 @@ gst_rs_demuxer_add_stream (GstRsDemuxer * demuxer, guint32 index, gchar *name, *full_stream_id; g_assert (demuxer->srcpads[index] == NULL); - g_assert (demuxer->n_srcpads == index); templ = gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (demuxer), @@ -392,7 +393,6 @@ gst_rs_demuxer_add_stream (GstRsDemuxer * demuxer, guint32 index, gst_flow_combiner_add_pad (demuxer->flow_combiner, pad); gst_element_add_pad (GST_ELEMENT (demuxer), pad); - demuxer->n_srcpads++; } void @@ -424,14 +424,16 @@ gst_rs_demuxer_stream_eos (GstRsDemuxer * demuxer, guint32 index) GstCaps *caps; GstEvent *event; - g_assert (demuxer->srcpads[index] != NULL); + g_assert (index == -1 || demuxer->srcpads[index] != NULL); event = gst_event_new_eos (); if (index == -1) { gint i; - for (i = 0; i < demuxer->n_srcpads; i++) - gst_pad_push_event (demuxer->srcpads[i], gst_event_ref (event)); + for (i = 0; i < G_N_ELEMENTS (demuxer->srcpads); i++) { + if (demuxer->srcpads[i]) + gst_pad_push_event (demuxer->srcpads[i], gst_event_ref (event)); + } gst_event_unref (event); } else { @@ -461,8 +463,10 @@ gst_rs_demuxer_remove_all_streams (GstRsDemuxer * demuxer) gst_flow_combiner_clear (demuxer->flow_combiner); - for (i = 0; i < demuxer->n_srcpads; i++) - gst_element_remove_pad (GST_ELEMENT (demuxer), demuxer->srcpads[i]); + for (i = 0; i < G_N_ELEMENTS (demuxer->srcpads); i++) { + if (demuxer->srcpads[i]) + gst_element_remove_pad (GST_ELEMENT (demuxer), demuxer->srcpads[i]); + } memset (demuxer->srcpads, 0, sizeof (demuxer->srcpads)); } diff --git a/src/rsdemuxer.h b/src/rsdemuxer.h index 329f48a6..5f37d161 100644 --- a/src/rsdemuxer.h +++ b/src/rsdemuxer.h @@ -42,7 +42,6 @@ struct _GstRsDemuxer { guint64 upstream_size; GstPad *srcpads[32]; - guint n_srcpads; guint32 group_id; GstSegment segment;